基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3966794.html。

上章节讲解了讲解一个用eXosip2库实现的Demo 程序。Demo讲的是注册的过程,因为篇幅比较长,再分一节写。本节是上一节的继续,主要实现UAC用eXosip2库实现的Demo 程序。本节讲的比较全面,处理实现注册问题还添加了注销和刷新注册的过程。刷新相当于心跳的功能。注意这个函数eXosip_default_action()实现在sip中401和407错误类型的eXosip2库的自动处理。网上有的人问注册报文发送后,只收到401返回码。这是对SIP注册不了解造成的。至于这个过程在前面注册理论部分已经讲解。我也尝试不用eXosip_default_action()这个函数,我自己发送鉴权信息,可惜没成功,不知道什么原因,有时返回200OK,有时不返回,所以还是用了eXosip_default_action()这个函数,让401的响应报文由eXosip2库去发送。

1.eXosip2 API介绍

本章中要用的eXosip2库的API做个简单的介绍和使用方法

1.1 初始化库

在使用eXosip2前你需要初始化eXosip环境和libeXosip2.so库,这一步必须在所有使用之前完成。

 1     #include <eXosip2/eXosip.h>
 2     //库处理结果
 3     int result = OSIP_SUCCESS;
 4     //初始化库
 5     if (OSIP_SUCCESS != (result = eXosip_init()))
 6     {
 7         printf("eXosip_init failure.
");
 8         return 1;
 9     }
10     cout << "eXosip_init success." << endl;
11     //监听
12     if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT,
13             AF_INET, 0))
14     {
15         printf("eXosip_listen_addr failure.
");
16                 eXosip_quit ();
17         return 1;
18     }                        

初始化完成之后,用户就可以发送SIP消息和等待接受SIP事件了。

1.2 接受事件

初始化eXosip2库后,主服务程序就可以接受事件并处理事件了,下面是一些从eXosip2协议栈接受处理事件的实例代码。

 1         //开启循环消息,实际应用中可以开启多线程同时接收信号
 2     eXosip_event_t* osipEventPtr = NULL;
 3 
 4     while (true)
 5     {
 6         // Wait the osip event.
 7         osipEventPtr = ::eXosip_event_wait(0, 200);
 8                 eXosip_lock();
 9         //一般处理401/407采用库默认处理
10         eXosip_default_action(osipEventPtr);
11         eXosip_unlock();
12         // If get nothing osip event,then continue the loop.
13         if (NULL == osipEventPtr)
14         {
15             continue;
16         }
17         // 事件处理
18 
19         switch (osipEventPtr->type)
20         {
21         //需要继续验证REGISTER是什么类型
22         case EXOSIP_REGISTRATION_NEW:
23         {
24             //注册事件处理
25         }
26             break;
27         case EXOSIP_MESSAGE_NEW:
28         {
29                 //消息事件处理
30         }
31             break;
32             case XXXXX:
33         {
34                 //事件处理
35         }
36             break;
37            case XXXXX:
38         {
39                 //事件处理
40         }
41             break;
42         default:
43             cout << "未处理消息 : " << osipEventPtr->type<<endl;
44             break;
45         }
46         eXosip_event_free(osipEventPtr);
47         osipEventPtr = NULL;                    

实际在应用的时候为了提高服务的并发性,一般并不用上面这种服务方式,因为上面这样,如果接受到某个事件,而这个事件的处理事件非常长的话,会影响效率,导致其他事件阻塞等待,得不到即使处理。所以一般采用并发服务器的设计思想,即在接受到一个事件后,分配一个线程来处理。当然如果想效率更高,想节省创建线程的时间,可以在系统一起动后,分配一定大小的线程池,有事件到来的话,直接从线程池中获取线程处理。

1.3 消息分析

每个UAC或者UAS发送一个SIP信息后,相对应的UAS或者UAC都会接受到响应的,即事件。每个事件包含两个部分,一个是request和response。request即是这个事件的请求报文, 而response是本次会话建立过程中,最后一次响应请求的报文。用户可以从获取的消息中,分析出message并且获取SIP头部,保存成用户自己的数据形式。下面实例获取expires头部内容。

1     osip_header_t* header = NULL;
2     osip_message_header_get_byname(request, "expires", 0, &header);
3     if (NULL != header && NULL != header->hvalue)
4     {
5            ......
6     }
7     

2.UAC代码实例 

  1 /*
  2  ===============================================================
  3  GBT28181 基于eXosip2,osip库实现注册UAC功能
  4  作者:程序人生
  5  博客地址:http://blog.csdn.net/hiwubihe
  6  QQ:1269122125
  7  注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
  8  ================================================================
  9  */
 10 
 11 #include <iostream>
 12 #include <string>
 13 #include <sstream>
 14 #include <osipparser2/osip_message.h>
 15 #include <osipparser2/osip_parser.h>
 16 #include <osipparser2/osip_port.h>
 17 
 18 #include <eXosip2/eXosip.h>
 19 #include <eXosip2/eX_setup.h>
 20 #include <eXosip2/eX_register.h>
 21 #include <eXosip2/eX_options.h>
 22 #include <eXosip2/eX_message.h>
 23 #include <arpa/inet.h>
 24 #include <sys/types.h>
 25 #include <sys/socket.h>
 26 
 27 using namespace std;
 28 
 29 //本地监听IP
 30 #define LISTEN_ADDR ("192.168.50.57")
 31 //本地监听端口
 32 #define UACPORT ("5061")
 33 #define UACPORTINT (5061)
 34 //本UAC地址编码
 35 #define UACCODE ("100110000201000000")
 36 //本地UAC密码
 37 #define UACPWD ("12345")
 38 //远程UAS IP
 39 #define UAS_ADDR ("192.168.50.57")
 40 //远程UAS 端口
 41 #define UAS_PORT ("5060")
 42 //超时
 43 #define EXPIS 300
 44 
 45 //当前服务状态 1 已经注册 0 未注册
 46 static int iCurrentStatus;
 47 //注册成功HANDLE
 48 static int iHandle = -1;
 49 
 50 //SIP From/To 头部
 51 class CSipFromToHeader
 52 {
 53 public:
 54     CSipFromToHeader()
 55     {
 56     }
 57     ~CSipFromToHeader()
 58     {
 59     }
 60     void SetHeader(string addrCod, string addrI, string addrPor)
 61     {
 62         addrCode = addrCod;
 63         addrIp = addrI;
 64         addrPort = addrPor;
 65     }
 66     string GetFormatHeader()
 67     {
 68         std::stringstream stream;
 69         stream << "sip: " << addrCode << "@" << addrIp << ":" << addrPort;
 70         return stream.str();
 71     }
 72     //主机名称
 73     string GetCode()
 74     {
 75         std::stringstream stream;
 76         stream << addrCode;
 77         return stream.str();
 78     }
 79     //主机地址
 80     string GetAddr()
 81     {
 82         std::stringstream stream;
 83         stream << addrIp;
 84         return stream.str();
 85     }
 86     //端口
 87     string GetPort()
 88     {
 89         std::stringstream stream;
 90         stream << addrPort;
 91         return stream.str();
 92     }
 93 
 94 private:
 95     string addrCode;
 96     string addrIp;
 97     string addrPort;
 98 };
 99 
100 //SIP Contract头部
101 class CContractHeader: public CSipFromToHeader
102 {
103 public:
104     CContractHeader()
105     {
106     }
107     ~CContractHeader()
108     {
109     }
110     void SetContractHeader(string addrCod, string addrI, string addrPor)
111     {
112         SetHeader(addrCod, addrI, addrPor);
113     }
114     string GetContractFormatHeader()
115     {
116 
117         std::stringstream stream;
118         stream << "<sip:" << GetCode() << "@" << GetAddr() << ":" << GetPort()
119                 << ">";
120         return stream.str();
121     }
122 };
123 
124 //发送注册信息
125 int SendRegister(int& registerId, CSipFromToHeader &from, CSipFromToHeader &to,
126         CContractHeader &contact, const string& userName, const string& pwd,
127         const int expires, int iType)
128 {
129     cout << "=============================================" << endl;
130     if (iType == 0)
131     {
132         cout << "注册请求信息:" << endl;
133     }
134     else if (iType == 1)
135     {
136         cout << "刷新注册信息:" << endl;
137     }
138     else
139     {
140         cout << "注销信息:" << endl;
141     }
142     cout << "registerId " << registerId << endl;
143     cout << "from " << from.GetFormatHeader() << endl;
144     cout << "to " << to.GetFormatHeader() << endl;
145     cout << "contact" << contact.GetContractFormatHeader() << endl;
146     cout << "userName" << userName << endl;
147     cout << "pwd" << pwd << endl;
148     cout << "expires" << expires << endl;
149     cout << "=============================================" << endl;
150     //服务器注册
151     static osip_message_t *regMsg = 0;
152     int ret;
153 
154     ::eXosip_add_authentication_info(userName.c_str(), userName.c_str(),
155             pwd.c_str(), "MD5", NULL);
156     eXosip_lock();
157     //发送注册信息 401响应由eXosip2库自动发送
158     if (0 == registerId)
159     {
160         // 注册消息的初始化
161         registerId = ::eXosip_register_build_initial_register(
162                 from.GetFormatHeader().c_str(), to.GetFormatHeader().c_str(),
163                 contact.GetContractFormatHeader().c_str(), expires, &regMsg);
164         if (registerId <= 0)
165         {
166             return -1;
167         }
168     }
169     else
170     {
171         // 构建注册消息
172         ret = ::eXosip_register_build_register(registerId, expires, &regMsg);
173         if (ret != OSIP_SUCCESS)
174         {
175             return ret;
176         }
177         //添加注销原因
178         if (expires == 0)
179         {
180             osip_contact_t *contact = NULL;
181             char tmp[128];
182 
183             osip_message_get_contact(regMsg, 0, &contact);
184             {
185                 sprintf(tmp, "<sip:%s@%s:%s>;expires=0",
186                         contact->url->username, contact->url->host,
187                         contact->url->port);
188             }
189             //osip_contact_free(contact);
190             //reset contact header
191             osip_list_remove(&regMsg->contacts, 0);
192             osip_message_set_contact(regMsg, tmp);
193             osip_message_set_header(regMsg, "Logout-Reason", "logout");
194         }
195     }
196     // 发送注册消息
197     ret = ::eXosip_register_send_register(registerId, regMsg);
198     if (ret != OSIP_SUCCESS)
199     {
200         registerId = 0;
201     }eXosip_unlock();
202 
203     return ret;
204 }
205 
206 //注册
207 void Register()
208 {
209     if (iCurrentStatus == 1)
210     {
211         cout << "当前已经注册" << endl;
212         return;
213     }
214     CSipFromToHeader stFrom;
215     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
216     CSipFromToHeader stTo;
217     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
218     CContractHeader stContract;
219     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
220     //发送注册信息
221     int registerId = 0;
222     if (0 > SendRegister(registerId, stFrom, stTo, stContract, UACCODE, UACPWD,
223             3000, 0))
224     {
225         cout << "发送注册失败" << endl;
226         return;
227     }
228     iCurrentStatus = 1;
229     iHandle = registerId;
230 }
231 //刷新注册
232 void RefreshRegister()
233 {
234     if (iCurrentStatus == 0)
235     {
236         cout << "当前未注册,不允许刷新" << endl;
237         return;
238     }
239     CSipFromToHeader stFrom;
240     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
241     CSipFromToHeader stTo;
242     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
243     CContractHeader stContract;
244     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
245     //发送注册信息
246     if (0 > SendRegister(iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,
247             3000, 1))
248     {
249         cout << "发送刷新注册失败" << endl;
250         return;
251     }
252 }
253 //注销
254 void UnRegister()
255 {
256     if (iCurrentStatus == 0)
257     {
258         cout << "当前未注册,不允许注销" << endl;
259         return;
260     }
261     CSipFromToHeader stFrom;
262     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
263     CSipFromToHeader stTo;
264     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
265     CContractHeader stContract;
266     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
267     //发送注册信息
268269     if (0 > SendRegister( iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,
270             0, 2))
271     {
272         cout << "发送注销失败" << endl;
273         return;
274     }
275     iCurrentStatus = 0;
276     iHandle = -1;
277 }
278 static void help()
279 {
280     const char
281             *b =
282     "-------------------------------------------------------------------------------
"
283     "SIP Library test process - uac v 1.0 (June 13, 2014)

"
284     "SIP UAC端 注册,刷新注册,注销实现

"
285     "Author: 程序人生

"
286     "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125

"
287     "-------------------------------------------------------------------------------
"
288     "
"
289     "              0:Register
"
290     "              1:RefreshRegister
"
291     "              2:UnRegister
"
292     "              3:clear scream
"
293     "              4:exit
"
294     "-------------------------------------------------------------------------------
"
295     "
";
296     fprintf(stderr, b, strlen(b));
297     cout << "please select method :";
298 }
299 //服务处理线程
300 void *serverHandle(void *pUser)
301 {
302     sleep(3);
303     help();
304     char ch = getchar();
305     getchar();
306     while (1)
307     {
308         switch (ch)
309         {
310         case '0':
311             //注册
312             Register();
313             break;
314         case '1':
315             //刷新注册
316             RefreshRegister();
317             break;
318         case '2':
319             //注销
320             UnRegister();
321             break;
322         case '3':
323             if (system("clear") < 0)
324             {
325                 cout << "clear scream error" << endl;
326                 exit(1);
327             }
328             break;
329         case '4':
330             cout << "exit sipserver......" << endl;
331             getchar();
332             exit(0);
333         default:
334             cout << "select error" << endl;
335             break;
336         }
337         cout << "press any key to continue......" << endl;
338         getchar();
339         help();
340         ch = getchar();
341         getchar();
342     }
343     return NULL;
344 }
345 
346 //事件处理线程
347 void *eventHandle(void *pUser)
348 {
349     eXosip_event_t* osipEventPtr = (eXosip_event_t*) pUser;
350     switch (osipEventPtr->type)
351     {
352     //需要继续验证REGISTER是什么类型
353     case EXOSIP_REGISTRATION_SUCCESS:
354     case EXOSIP_REGISTRATION_FAILURE:
355     {
356         cout<<"收到状态码:"<<osipEventPtr->response->status_code<<"报文"<<endl;
357         if(osipEventPtr->response->status_code == 401)
358         {
359             cout<<"发送鉴权报文"<<endl;
360         }
361         else if(osipEventPtr->response->status_code == 200)
362         {
363             cout<<"接收成功"<<endl;
364         }
365         else
366         {}
367     }
368         break;
369     default:
370         cout << "The sip event type that not be precessed.the event "
371             "type is : " << osipEventPtr->type << endl;
372         break;
373     }
374     eXosip_event_free(osipEventPtr);
375     return NULL;
376 }
377 
378 int main()
379 {
380     iCurrentStatus = 0;
381     //库处理结果
382     int result = OSIP_SUCCESS;
383     //初始化库
384     if (OSIP_SUCCESS != (result = eXosip_init()))
385     {
386         printf("eXosip_init failure.
");
387         return 1;
388     }
389     cout << "eXosip_init success." << endl;
390     eXosip_set_user_agent(NULL);
391     //监听
392     if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT,
393             AF_INET, 0))
394     {
395         printf("eXosip_listen_addr failure.
");
396         return 1;
397     }
398     //设置监听网卡
399     if (OSIP_SUCCESS != eXosip_set_option(
400     EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,
401             LISTEN_ADDR))
402     {
403         return -1;
404     }
405     //开启服务线程
406     pthread_t pthser;
407     if (0 != pthread_create(&pthser, NULL, serverHandle, NULL))
408     {
409         printf("创建主服务失败
");
410         return -1;
411     }
412     //事件用于等待
413     eXosip_event_t* osipEventPtr = NULL;
414     //开启事件循环
415     while (true)
416     {
417         //等待事件 0的单位是秒,500是毫秒
418         osipEventPtr = ::eXosip_event_wait(0, 200);
419         //处理eXosip库默认处理
420         {
421             usleep(500 * 1000);
422             eXosip_lock();
423             //一般处理401/407采用库默认处理
424             eXosip_default_action(osipEventPtr);
425             eXosip_unlock();
426         }
427         //事件空继续等待
428         if (NULL == osipEventPtr)
429         {
430             continue;
431         }
432         //开启线程处理事件并在事件处理完毕将事件指针释放
433         pthread_t pth;
434         if (0 != pthread_create(&pth, NULL, eventHandle, (void*) osipEventPtr))
435         {
436             printf("创建线程处理事件失败
");
437             continue;
438         }
439         osipEventPtr = NULL;
440     }
441 }

3.测试效果

 3.1 启动后

3.2 输入0 注册

可以看到第一次收到了401报文,库自动发送鉴权信息,然后收到了200OK报文。

3.3 然后输入1刷新

可以看到收到200OK报文

3.4 输入2注销后

收到200OK报文。并且可以看到expires为0了。

至此eXosip2库实现注册,全部功能完成。

欢迎技术交流沟通,转载请注明出处并保持作品的完整性。 作者:程序人生 qq1269122125
原文地址:https://www.cnblogs.com/qq1269122125/p/3966794.html