原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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库去发送。
本章中要用的eXosip2库的API做个简单的介绍和使用方法。
在使用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事件了。
初始化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;
实际在应用的时候为了提高服务的并发性,一般并不用上面这种服务方式,因为上面这样,如果接受到某个事件,而这个事件的处理事件非常长的话,会影响效率,导致其他事件阻塞等待,得不到即使处理。所以一般采用并发服务器的设计思想,即在接受到一个事件后,分配一个线程来处理。当然如果想效率更高,想节省创建线程的时间,可以在系统一起动后,分配一定大小的线程池,有事件到来的话,直接从线程池中获取线程处理。
每个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
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 }
可以看到第一次收到了401报文,库自动发送鉴权信息,然后收到了200OK报文。
可以看到收到200OK报文
收到200OK报文。并且可以看到expires为0了。
至此eXosip2库实现注册,全部功能完成。