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.\n");
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.\n");
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, ®Msg);
164 if (registerId <= 0)
165 {
166 return -1;
167 }
168 }
169 else
170 {
171 // 构建注册消息
172 ret = ::eXosip_register_build_register(registerId, expires, ®Msg);
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(®Msg->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 "-------------------------------------------------------------------------------\n"
283 "SIP Library test process - uac v 1.0 (June 13, 2014)\n\n"
284 "SIP UAC端 注册,刷新注册,注销实现\n\n"
285 "Author: 程序人生\n\n"
286 "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n"
287 "-------------------------------------------------------------------------------\n"
288 "\n"
289 " 0:Register\n"
290 " 1:RefreshRegister\n"
291 " 2:UnRegister\n"
292 " 3:clear scream\n"
293 " 4:exit\n"
294 "-------------------------------------------------------------------------------\n"
295 "\n";
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.\n");
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.\n");
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("创建主服务失败\n");
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("创建线程处理事件失败\n");
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