基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3941172.html,qq:1269122125。
上两章节简要的讲解了SIP组件开发接口和开发环境的搭建。在本节将实现Linux 32平台的UAS和UAC,当然该UAS和UAC只实现了注册功能,并且是基于自主开发SIP组件libGBT28181SipComponent.so的,没有这个组件是运行不了的。其他功能在后续章节中讲解。
首先简单讲解一下GBT28181关于注册描述
一. GBT28181注册的流程如下图
电力系统注册稍微复杂点,但原来基本相同。多了个刷新注册的过程。
二.GBT28181关于注册的解释如下
三.SIP协议简介
一个合法的SIP请求必须至少包含如下头域:TO,FROM,Cseq,Call-ID,Max-Forwards, Via;这些字段在所有SIP请求中必须包含。这6个字段是SIP消息的基本组成部分,他们提供了用于路由用的核心信息,包含了消息的地址,响应的路由,消息传递次数,详细的顺序,事务的唯一标志。
这些头域字段是必须包含在请求行之后的,请求行包含了请求的方法,Request-URI,SIP的版本号码。请求行例子:REGISTER sip:192.168.10.177:5060 SIP/2.0
四.GBT28181注册流程如下
1.UAC--->UAS 发送请求登录,传送未鉴权信息
From 字段,由UAS管理的UAC地址编码@UAS IP:UAS端口号。在实际过程中,UAS管理很多的UAC每个UAC都会保存一个地址编码(可以理解为用户名)和密码等UAC的信息,当UAC登录时,用于验证UAC身份的合法性。
To字段,From相同
Contact字段是通讯信息字段,保存是本地UAC地址编码@本地IP:UAC端口号
Call-ID地段,对应用层是必须要的,一次成功登录完成后要保存这个Call_id值,因为这个ID是标志这次注册的唯一标志。在后续的注销登录及刷新登录都必须要这个ID.。
Cseq值保证了REGISTER请求的正确顺序
Expires字段:表示该登记生存期为3600s。
Content-Length字段:表明此请求消息消息体的长度为空,即此消息不带会话描述
2.UAS--->UAC exosip库在发送注册请求时,第一次发送未鉴权信息,UAS收到后回复401,并携带认证体制(如MD4)和认证参数(如nonce值)。
3.UAC--->UAS UAC在收到401信息后,根据UAS发送的401信息中的认证体制和认证参数,结合用户名和密码,生成response值。发送鉴权消息。
4.UAS--->UAC UAS收到鉴权信息后,根据自己自身的管理体制,找到UAC用户在服务器中的密码,根据UAC发送的认证体制和认证参数,结合用户名和密码,生成response值,在把response和UAC发送的response比较,相等则认证通过发送 200 ok。不等发送404验证失败。
五.源代码
这里注册功能虽然简单,但是为了后续其他功能的添加,这里还是根据功能划分了几个模块。后续添加功能,只是在这个框架中添加。
UAS_test部分代码:
1.主要功能文件method.h
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #ifndef METHOD_H_ 12 #define METHOD_H_ 13 #include <iostream> 14 #include <cstdlib> 15 #include <stdio.h> 16 #include "callback.h" 17 #include "IGBT28181Comm.h" 18 #include "sipserver.h" 19 20 21 using namespace GBT28181::Vsp; 22 using namespace std; 23 24 //启动UAS角色的服务器 25 int server_start(void*addr); 26 //停止UAS角色服务器 27 void server_stop(); 28 29 30 #endif /* METHOD_H_ */
2.method.cpp 实现文件中,开启服务包括启动服务和设置回调函数。
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #include "method.h" 12 #include <semaphore.h> 13 14 static IGBT28181Comm* g_SIPComm = NULL; 15 16 //启动SIP服务 17 int server_start(void*addr) 18 { 19 COMM_PAIR *addr_entry = (COMM_PAIR *) addr; 20 if (g_SIPComm != NULL) 21 { 22 delete g_SIPComm; 23 } 24 if (!(g_SIPComm = new IGBT28181Comm(true))) 25 { 26 return -1; 27 } 28 //回调函数 29 g_SIPComm->SetResponseCallback(&server_callback, (void_t*) g_SIPComm); 30 g_SIPComm->StartSip(addr_entry->local_addr, addr_entry->local_port); 31 return 0; 32 } 33 34 //停止SIP服务 35 void server_stop() 36 { 37 38 if (g_SIPComm != NULL) 39 { 40 g_SIPComm->StopSip(); 41 sleep(2); 42 delete g_SIPComm; 43 } 44 g_SIPComm = NULL; 45 }
3.回调函数callback.h
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #ifndef CALLBACK_H_ 12 #define CALLBACK_H_ 13 #include <stdio.h> 14 #include <string.h> 15 #include <iostream> 16 #include <stdlib.h> 17 #include "sipserver.h" 18 #include "IGBT28181Comm.h" 19 #include "method.h" 20 21 using namespace GBT28181::Vsp; 22 using namespace std; 23 24 //回调函数 25 void_t server_callback(const SipRequestInfo& info, void_t* user); 26 27 28 #endif /* LIBINTERFACE_H_ */
4.callback.cpp 实现文件
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #include "callback.h" 12 #include "algorithm.h" 13 14 15 //客户端主动请求,服务器端回调 16 const char * client_request_method[] = 17 { 18 "GBT28181.Vsp.Sip.SipMethod.Register", 19 "GBT28181.Vsp.Sip.SipMethod.Notify", 20 "GBT28181.Vsp.Sip.SipMethod.Subscribenotify" 21 }; 22 23 //打印SIP消息 24 static void SIP_PKG_Print(const SipRequestInfo& infomation) 25 { 26 SipRegisterContextInfo* info = (SipRegisterContextInfo*) &infomation; 27 cout << "\n" 28 << "**************************************************" 29 << "**************************" 30 << endl; 31 cout << "packet receive " << endl; 32 cout << "status :" << info->status << endl; 33 cout << "sipRequestId :" << info->sipRequestId << endl; 34 cout << "requestId :" << info->requestId << endl; 35 cout << "method :" << info->method << endl; 36 cout << "from :" << info->from << endl; 37 cout << "proxy :" << info->proxy << endl; 38 cout << "contact :" << info->contact << endl; 39 cout << "handle :" << info->handle << endl; 40 cout << "sipIp :" << info->sipIp << endl; 41 cout << "sipPort :" << info->sipPort << endl; 42 cout << "subscribeEvent :" << info->subscribeEvent << endl; 43 cout << "expires :" << info->expires << endl; 44 cout << "content :" << info->content << endl; 45 cout<<"Call ID:"<<info->callid<<endl; 46 if (!info->registerInfo.userName.empty()) 47 { 48 cout<<"********************************************"<<endl; 49 cout<<"authendication infomation as follows:"<<endl; 50 cout<<"username:"<<info->registerInfo.userName<<endl; 51 cout<<"algorithm:"<<info->registerInfo.algorithm<<endl; 52 cout<<"Realm:"<<info->registerInfo.digestRealm<<endl; 53 cout<<"nonce:"<<info->registerInfo.nonce<<endl; 54 cout<<"response:"<<info->registerInfo.response<<endl; 55 cout<<"uri:"<<info->registerInfo.uri<<endl; 56 57 } 58 cout 59 << "**************************************************" 60 << "**************************" 61 << endl; 62 } 63 64 static void_t register_response(const GBT28181::Vsp::SipRequestInfo& info, 65 void_t* user) 66 { 67 cout << "receive register request packet from client" << endl; 68 SIP_PKG_Print(info); 69 char temp[16]; 70 SipRegisterContextInfo* regInfo = (SipRegisterContextInfo*) &info; 71 SipRegisterContextInfo repinfo; 72 repinfo.sipRequestId = info.sipRequestId; 73 repinfo.from = info.proxy; 74 repinfo.proxy = info.from; 75 repinfo.method = info.method; 76 //repinfo.expires = 300; 77 repinfo.registerInfo.nonce = "9bd055"; 78 sscanf(info.contact.c_str(), "%*[^@]@%[^:]", temp); 79 repinfo.registerInfo.digestRealm = temp; 80 sscanf(info.proxy.c_str(), "%*[^@]@%[^:]", temp); 81 repinfo.sipIp = temp; 82 sscanf(info.proxy.c_str(), "%*[^:]:%s", temp); 83 repinfo.sipPort = atoi(temp); 84 repinfo.registerInfo.userName = regInfo->registerInfo.userName; 85 repinfo.content="sfsdfsdf"; 86 GBT28181::Vsp::IGBT28181Comm* p_this = (GBT28181::Vsp::IGBT28181Comm*) user; 87 88 if (repinfo.registerInfo.userName.empty()) 89 { 90 cout<<"this register packet is unauthendicatin"<<endl; 91 cout<<"send 401"<<endl; 92 repinfo.status = "401"; 93 p_this->Downcast(repinfo); 94 } 95 else 96 { 97 cout<<"this register packet is authendicatin"<<endl; 98 //验证 99 HASHHEX HA1; 100 HASHHEX Response; 101 DigestCalcHA1(regInfo->registerInfo.algorithm.c_str(), 102 regInfo->registerInfo.userName.c_str(), 103 regInfo->registerInfo.digestRealm.c_str(), UAC_PASSWD, 104 regInfo->registerInfo.nonce.c_str(), NULL, HA1); 105 DigestCalcResponse(HA1, regInfo->registerInfo.nonce.c_str(), 106 NULL, NULL, NULL, 0, "REGISTER", 107 regInfo->registerInfo.uri.c_str(), 108 NULL, Response); 109 if (!strcmp(Response, regInfo->registerInfo.response.c_str())) 110 { 111 cout<<"认证成功发送 200 OK!!!"<<endl; 112 repinfo.expires = 5; 113 repinfo.status = "200"; 114 } 115 else 116 { 117 cout<<"认证失败发送 404 OK!!!"<<endl; 118 repinfo.expires = 5; 119 repinfo.status = "404"; 120 } 121 122 p_this->Downcast(repinfo); 123 124 } 125 } 126 127 // 128 void_t server_callback(const SipRequestInfo& info, void_t* user) 129 { 130 //注册报文的情况,调用注册回调 131 if (strncmp(info.method.c_str(), client_request_method[0], strlen( 132 client_request_method[0])) == 0) 133 { 134 register_response(info, user); 135 } 136 //其他情况报文 137 else 138 { 139 cout << "server receive wrong packer" << endl; 140 SIP_PKG_Print(info); 141 exit(1); 142 } 143 }
5.sip认证 algorithm.h
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 #ifndef B_REGISTER__ALGORITHM_H_ 11 #define B_REGISTER__ALGORITHM_H_ 12 13 #include <stdio.h> 14 #include "osip_md5.h" 15 16 #define HASHLEN 16 17 typedef char HASH[HASHLEN]; 18 19 #define HASHHEXLEN 32 20 typedef char HASHHEX[HASHHEXLEN + 1]; 21 22 23 void DigestCalcHA1(const char *pszAlg, const char *pszUserName, 24 const char *pszRealm, const char *pszPassword, 25 const char *pszNonce, const char *pszCNonce, 26 HASHHEX SessionKey); 27 28 void DigestCalcResponse(HASHHEX HA1, const char *pszNonce, 29 const char *pszNonceCount, const char *pszCNonce, 30 const char *pszQop, int Aka, const char *pszMethod, 31 const char *pszDigestUri, HASHHEX HEntity, HASHHEX Response); 32 33 #endif /* B_REGISTER__ALGORITHM_H_ */
5.sip认证 algorithm.cpp,这部分参考代码可以在exosip2源代码中找到。
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #include "algorithm.h" 12 #include "string.h" 13 14 static void CvtHex(HASH Bin, HASHHEX Hex) 15 { 16 unsigned short i; 17 unsigned char j; 18 19 for (i = 0; i < HASHLEN; i++) 20 { 21 j = (Bin[i] >> 4) & 0xf; 22 if (j <= 9) 23 Hex[i * 2] = (j + '0'); 24 else 25 Hex[i * 2] = (j + 'a' - 10); 26 j = Bin[i] & 0xf; 27 if (j <= 9) 28 Hex[i * 2 + 1] = (j + '0'); 29 else 30 Hex[i * 2 + 1] = (j + 'a' - 10); 31 }; 32 Hex[HASHHEXLEN] = '\0'; 33 } 34 35 void DigestCalcHA1(const char *pszAlg, const char *pszUserName, 36 const char *pszRealm, const char *pszPassword, 37 const char *pszNonce, const char *pszCNonce, 38 HASHHEX SessionKey) 39 { 40 osip_MD5_CTX Md5Ctx; 41 HASH HA1; 42 43 osip_MD5Init(&Md5Ctx); 44 osip_MD5Update(&Md5Ctx, (unsigned char *) pszUserName, strlen(pszUserName)); 45 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 46 osip_MD5Update(&Md5Ctx, (unsigned char *) pszRealm, strlen(pszRealm)); 47 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 48 osip_MD5Update(&Md5Ctx, (unsigned char *) pszPassword, strlen(pszPassword)); 49 osip_MD5Final((unsigned char *) HA1, &Md5Ctx); 50 if ((pszAlg != NULL) && strcmp(pszAlg, "md5-sess") == 0) 51 { 52 osip_MD5Init(&Md5Ctx); 53 osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHLEN); 54 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 55 osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce)); 56 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 57 osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce)); 58 osip_MD5Final((unsigned char *) HA1, &Md5Ctx); 59 } 60 CvtHex(HA1, SessionKey); 61 } 62 63 void DigestCalcResponse(HASHHEX HA1, const char *pszNonce, 64 const char *pszNonceCount, const char *pszCNonce, 65 const char *pszQop, int Aka, const char *pszMethod, 66 const char *pszDigestUri, HASHHEX HEntity, HASHHEX Response) 67 { 68 osip_MD5_CTX Md5Ctx; 69 HASH HA2; 70 HASH RespHash; 71 HASHHEX HA2Hex; 72 73 /* calculate H(A2) */ 74 osip_MD5Init(&Md5Ctx); 75 osip_MD5Update(&Md5Ctx, (unsigned char *) pszMethod, strlen(pszMethod)); 76 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 77 osip_MD5Update(&Md5Ctx, (unsigned char *) pszDigestUri, 78 strlen(pszDigestUri)); 79 80 if (pszQop == NULL) 81 { 82 goto auth_withoutqop; 83 } 84 else if (0 == strcmp(pszQop, "auth-int")) 85 { 86 goto auth_withauth_int; 87 } 88 else if (0 == strcmp(pszQop, "auth")) 89 { 90 goto auth_withauth; 91 } 92 93 auth_withoutqop: osip_MD5Final((unsigned char *) HA2, &Md5Ctx); 94 CvtHex(HA2, HA2Hex); 95 96 /* calculate response */ 97 osip_MD5Init(&Md5Ctx); 98 osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN); 99 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 100 osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce)); 101 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 102 103 goto end; 104 105 auth_withauth_int: 106 107 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 108 osip_MD5Update(&Md5Ctx, (unsigned char *) HEntity, HASHHEXLEN); 109 110 auth_withauth: osip_MD5Final((unsigned char *) HA2, &Md5Ctx); 111 CvtHex(HA2, HA2Hex); 112 113 /* calculate response */ 114 osip_MD5Init(&Md5Ctx); 115 osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN); 116 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 117 osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce)); 118 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 119 if (Aka == 0) 120 { 121 osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonceCount, strlen( 122 pszNonceCount)); 123 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 124 osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce)); 125 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 126 osip_MD5Update(&Md5Ctx, (unsigned char *) pszQop, strlen(pszQop)); 127 osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); 128 } 129 end: osip_MD5Update(&Md5Ctx, (unsigned char *) HA2Hex, HASHHEXLEN); 130 osip_MD5Final((unsigned char *) RespHash, &Md5Ctx); 131 CvtHex(RespHash, Response); 132 }
由于我采用的是MD5验证,所以还需要从exosip2代码中引用osip_md5.h 文件。也可以直接把osip_md5.h和osip_md5.cpp拷到你的工程中,我就采用这个方法。
6.主程序 sipserver.h,该测试程序中,UAS值管理一个UAC 地址编码为100110000201000000 密码123456,UAS端口写死5060,地址编码写死100110000000000000
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #ifndef SIPCLIENT_H_ 12 #define SIPCLIENT_H_ 13 14 #include "IGBT28181Comm.h" 15 16 using namespace GBT28181::Vsp; 17 18 19 //默认端口 20 #define UASPORT (5060) 21 //#define UACPORT (5061) 22 //UAS自己地址编码 具体地址编码什么含义参考标准 23 #define UASADD_CODE ("100110000000000000") 24 //UAC地址编码 地址编码相当于用户名 25 //实际应用中每个UAS保存该UAS所管理的一大堆UAC地址编码以及用户密码等信息 用于注册验证 26 //当前测试UAS只管理一个UAC 地址编码如下 27 #define UACADD_CODE ("100110000201000000") 28 #define UAC_PASSWD ("123456") 29 30 //该枚举类型列举类UAS角色 所主动请求的方法 31 // 32 typedef enum 33 { 34 INVITE, ACK, MESSAGE, BYE, SUBSCRIBE, CALLMESSAGE, 35 } METHOD; 36 37 38 //通信实体对 UAS服务器的IP与端口 39 typedef struct 40 { 41 char local_addr[16]; 42 int local_port; 43 } COMM_PAIR; 44 45 46 47 #endif /* SIPCLIENT_H_ */
7.sipserver.cpp,当前只支持启动服务,退出服务功能。其他功能后续添加。
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #include <unistd.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <iostream> 16 #include "sipserver.h" 17 #include "method.h" 18 19 using namespace std; 20 21 static void usage() 22 { 23 const char 24 *b = "-------------------------------------------------------------------------------\n" 25 "SIP Library test process - sipserver v 1.0 (June 13, 2014)\n\n" 26 "Author: 程序人生\n\n" 27 "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n" 28 "-------------------------------------------------------------------------------\n" 29 "\n" 30 "-s local server ipv4 address\n" 31 "-h Print this help and exit\n\n" 32 "-------------------------------------------------------------------------------\n" 33 "\n" 34 "example1: ./sipserver -s127.0.0.1\n" 35 "example2: ./sipserver -h\n" 36 "server default port|server address code|client default port|client address code\n" 37 "5060 |100110000000000000 |5061 |100110000201000000 \n" 38 "-------------------------------------------------------------------------------\n" 39 "\n"; 40 fprintf(stderr, b, strlen(b)); 41 } 42 43 static void help() 44 { 45 const char 46 *b = "-------------------------------------------------------------------------------\n" 47 "SIP Library test process - sipserver v 1.0 (June 13, 2014)\n\n" 48 "Current test Register method,only number 6 7 8 9 is useful\n\n" 49 "Author: 程序人生\n\n" 50 "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n" 51 "-------------------------------------------------------------------------------\n" 52 "\n" 53 " 0:Invite\n" 54 " 1:Ack\n" 55 " 2:Message\n" 56 " 3:Bye\n" 57 " 4:Subscribe\n" 58 " 5:CallMessage unused\n" 59 " 6:start service\n" 60 " 7:stop service\n" 61 " 8:clear scream\n" 62 " 9:exit\n" 63 "-------------------------------------------------------------------------------\n" 64 "\n"; 65 fprintf(stderr, b, strlen(b)); 66 cout << "please select method :"; 67 } 68 69 int main(int argc, char*argv[]) 70 { 71 int ch; 72 /*METHOD meth;*/ 73 COMM_PAIR comm_entry; 74 comm_entry.local_port = UASPORT; 75 opterr = 0; 76 if (argc == 2) 77 { 78 while ((ch = getopt(argc, argv, "s:h:")) != -1) 79 { 80 switch (ch) 81 { 82 case 's': 83 { 84 strcpy(comm_entry.local_addr, optarg); 85 break; 86 } 87 case 'h': 88 { 89 usage(); 90 return EXIT_SUCCESS; 91 break; 92 } 93 default: 94 { 95 fprintf(stderr, "Illegal argument \n"); 96 usage(); 97 return EXIT_FAILURE; 98 } 99 } 100 } 101 } 102 else 103 { 104 fprintf(stderr, "Illegal argument \n"); 105 usage(); 106 return EXIT_FAILURE; 107 } 108 if (system("clear") < 0) 109 { 110 cout << "clear scream error" << endl; 111 exit(0); 112 } 113 help(); 114 ch = getchar(); 115 getchar(); 116 while (1) 117 { 118 switch (ch) 119 { 120 case '6': 121 //启动服务 122 if (server_start(&comm_entry) < 0) 123 { 124 cout << "service start failure" << endl; 125 break; 126 } 127 cout << "service start success ......" << endl; 128 cout << "uas address :" << comm_entry.local_addr << " uas port :" 129 << comm_entry.local_port << " address code :" << UASADD_CODE 130 << endl; 131 break; 132 case '7': 133 cout << "stop service......" << endl; 134 server_stop(); 135 break; 136 case '8': 137 if (system("clear") < 0) 138 { 139 cout << "clear scream error" << endl; 140 exit(1); 141 } 142 break; 143 case '9': 144 cout << "exit sipserver......" << endl; 145 getchar(); 146 exit(0); 147 default: 148 cout << "select error" << endl; 149 break; 150 } 151 cout << "press any key to continue......" << endl; 152 getchar(); 153 help(); 154 ch = getchar(); 155 getchar(); 156 } 157 return 0; 158 }
UAC_test 代码如下:
这部分实现简单,只是演示,包含一个文件UAC_test.cpp,UAC地址编码100110000201000000,端口5061写死。UAS端口写死5060。
1 /* 2 =============================================================== 3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现 4 作者:程序人生 5 博客地址:http://blog.csdn.net/hiwubihe 6 QQ:1269122125 7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! 8 ================================================================ 9 */ 10 11 #include <iostream> 12 #include <string.h> 13 #include <stdio.h> 14 15 #include "IGBT28181Comm.h" 16 using namespace GBT28181::Vsp; 17 using namespace std; 18 19 //默认端口 20 #define UASPORT (5060) 21 #define UACPORT (5061) 22 23 static char pwd[20]; 24 25 //通信实体对 26 typedef struct 27 { 28 char local_addr[16]; 29 char remote_addr[16]; 30 int local_port; 31 int remote_port; 32 } COMM_PAIR; 33 34 static void_t SIP_PKG_Print(const SipRequestInfo& info) 35 { 36 cout << "packet receive :" << endl; 37 cout 38 << "****************************************************************************" 39 << endl; 40 cout << "status :" << info.status << endl; 41 cout << "sipRequestId :" << info.sipRequestId << endl; 42 cout << "requestId :" << info.requestId << endl; 43 cout << "method :" << info.method << endl; 44 cout << "from :" << info.from << endl; 45 cout << "proxy :" << info.proxy << endl; 46 cout << "contact :" << info.contact << endl; 47 cout << "content :" << info.content << endl; 48 cout << "status :" << info.status << endl; 49 cout << "handle :" << info.handle << endl; 50 cout << "sipIp :" << info.sipIp << endl; 51 cout << "sipPort :" << info.sipPort << endl; 52 cout << "subscribeEvent :" << info.subscribeEvent << endl; 53 cout << "expires :" << info.expires << endl; 54 cout 55 << "****************************************************************************" 56 << endl; 57 } 58 59 //消息处理回调函数 60 void_t SIP_PKG_Receive(const SipRequestInfo& info, void_t* user) 61 { 62 //打印从服务器接收的消息 63 SIP_PKG_Print(info); 64 //UAC向服务器发送响应报文 65 char buf[1024]; 66 const char*mthd=info.method.data(); 67 snprintf(buf, 1024, "response from client,for test method:%s", mthd); 68 if(memcmp(mthd,"Nari.Vsp.Sip.SipMethod.Register",strlen("Nari.Vsp.Sip.SipMethod.Register"))==0) 69 { 70 return ; 71 } 72 } 73 74 75 void Communicator_init(void*comm,IGBT28181Comm *SIPComm) 76 { 77 if (NULL != SIPComm) 78 { 79 delete SIPComm; 80 } 81 SIPComm = new IGBT28181Comm(false); 82 //回调函数 83 SIPComm->SetResponseCallback(SIP_PKG_Receive, (void_t*) SIPComm); 84 //启动SIP协议 85 COMM_PAIR *comm_entry = (COMM_PAIR *) comm; 86 SIPComm->StartSip(comm_entry->local_addr, comm_entry->local_port); 87 } 88 89 90 //客户端主动发送向服务器发送注册报文 91 void sip_register(IGBT28181Comm* uac, COMM_PAIR *entry) 92 { 93 cout << "enter" << endl; 94 SipRegisterContextInfo info; 95 char temp[128]; 96 // 失效时间 97 info.expires = 300; 98 // 用户100110000201000000 在 entry->remote_addr 远程IP上 99 snprintf(temp, 128, "100110000201000000@%s:%d", entry->remote_addr, 100 entry->remote_port); 101 info.from = temp; 102 info.proxy = temp; 103 // 发起会话的方式 104 info.method = SipMethod::METHOD_REGISTER; 105 // 本地ip 106 snprintf(temp, 128, "100110000201000000@%s:%d", entry->local_addr, 107 entry->local_port); 108 //info.proxy = temp; 109 // contact 110 //info.contact = info.from; 111 info.contact = temp; 112 // 端口 113 info.sipPort = entry->local_port; 114 snprintf(temp, 128, "100110000201000000@%s", entry->local_addr); 115 info.sipIp = temp; 116 info.requestId = "0"; 117 info.sipRequestId = "0"; 118 info.registerInfo.userName = "100110000201000000"; 119 info.registerInfo.response = pwd; 120 if (NULL != uac) 121 { 122 uac->Downcast(info); 123 cout << "downcast success" << endl; 124 } 125 else 126 { 127 cout << "downcast failure" << endl; 128 } 129 } 130 131 132 133 int main(int argc, char*argv[]) 134 { 135 if(argc!=4) 136 { 137 cout<<"usage: ./UAC_test 127.0.0.1 127.0.0.1 123456"<<endl; 138 return 1; 139 } 140 COMM_PAIR comm_entry; 141 comm_entry.local_port = UACPORT; 142 comm_entry.remote_port = UASPORT; 143 strcpy(comm_entry.local_addr, argv[1]); 144 strcpy(comm_entry.remote_addr, argv[2]); 145 strcpy(pwd, argv[3]); 146 147 IGBT28181Comm *SIPComm=NULL; 148 SIPComm = new IGBT28181Comm(false); 149 //回调函数 150 SIPComm->SetResponseCallback(SIP_PKG_Receive, (void_t*) SIPComm); 151 //启动SIP协议 152 SIPComm->StartSip(comm_entry.local_addr, comm_entry.local_port); 153 //向服务器发送注册报文 154 sip_register(SIPComm, &comm_entry); 155 while(1) 156 { 157 sleep(5); 158 } 159 }
六.测试
笔者用的环境为centos 6.0 32bit系统。成功启动的前提是上一节所讲的libGBT28181SipComponent.so必须拷到系统库目录下,或者设置LD_LIBRARY_PATH环境变量。同时安装libGBT28181SipComponent.so库所依赖的库。可以用ldd UAS_test 查看程序依赖的库以及哪些库找不到。
1.启动UAS
2.启动后效果
3.填写6 start service后效果
此时,UAS注册服务程序已经成功启动。等待UAC的注册。
4.笔者UAS_test和UAC_test是在一台机器上测试的。格式UAC_test 本机IP UASIP 密码
5.启动后UAS_test收到未鉴权报文
从打印的报文看,没有用户名等信息,同时提示发送了401回复报文
6.UAC_test收到401报文如下
可以看到UAC_test已经成功接受401报文,准备发送具有鉴权信息给UAS_test
7.UAS_test收到鉴权信息
可以看到有用户名等鉴权信息。UAS_test鉴权后,发现用户合法,给与回复200ok!
8.UAC_test收到200OK
整个验证过程结束。
9.其实验证还用很多情况,标准中都有定义,发送什么响应码。如密码错误响应404错误码。上例中
./UAC_test 192.168.50.57 192.168.50.57 12345,密码不正确。将会收到404报文。
关于SIP注册怎么调用exosip2的接口实现,有空再整理。
本文源码下载,正在整理中。。。。。。。。。。。。。。。。