原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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部分代码:
主要功能文件method.h
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #ifndef METHOD_H_ #define METHOD_H_ #include <iostream> #include <cstdlib> #include <stdio.h> #include "callback.h" #include "IGBT28181Comm.h" #include "sipserver.h" using namespace GBT28181::Vsp; using namespace std; //启动UAS角色的服务器 int server_start(void*addr); //停止UAS角色服务器 void server_stop(); #endif /* METHOD_H_ */
2.method.cpp 实现文件中,开启服务包括启动服务和设置回调函数。
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #include "method.h" #include <semaphore.h> static IGBT28181Comm* g_SIPComm = NULL; //启动SIP服务 int server_start(void*addr) { COMM_PAIR *addr_entry = (COMM_PAIR *) addr; if (g_SIPComm != NULL) { delete g_SIPComm; } if (!(g_SIPComm = new IGBT28181Comm(true))) { return -1; } //回调函数 g_SIPComm->SetResponseCallback(&server_callback, (void_t*) g_SIPComm); g_SIPComm->StartSip(addr_entry->local_addr, addr_entry->local_port); return 0; } //停止SIP服务 void server_stop() { if (g_SIPComm != NULL) { g_SIPComm->StopSip(); sleep(2); delete g_SIPComm; } g_SIPComm = NULL; }
3.回调函数callback.h
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #ifndef CALLBACK_H_ #define CALLBACK_H_ #include <stdio.h> #include <string.h> #include <iostream> #include <stdlib.h> #include "sipserver.h" #include "IGBT28181Comm.h" #include "method.h" using namespace GBT28181::Vsp; using namespace std; //回调函数 void_t server_callback(const SipRequestInfo& info, void_t* user); #endif /* LIBINTERFACE_H_ */
4.callback.cpp 实现文件
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #include "callback.h" #include "algorithm.h" //客户端主动请求,服务器端回调 const char * client_request_method[] = { "GBT28181.Vsp.Sip.SipMethod.Register", "GBT28181.Vsp.Sip.SipMethod.Notify", "GBT28181.Vsp.Sip.SipMethod.Subscribenotify" }; //打印SIP消息 static void SIP_PKG_Print(const SipRequestInfo& infomation) { SipRegisterContextInfo* info = (SipRegisterContextInfo*) &infomation; cout << "\n" << "**************************************************" << "**************************" << endl; cout << "packet receive " << endl; cout << "status :" << info->status << endl; cout << "sipRequestId :" << info->sipRequestId << endl; cout << "requestId :" << info->requestId << endl; cout << "method :" << info->method << endl; cout << "from :" << info->from << endl; cout << "proxy :" << info->proxy << endl; cout << "contact :" << info->contact << endl; cout << "handle :" << info->handle << endl; cout << "sipIp :" << info->sipIp << endl; cout << "sipPort :" << info->sipPort << endl; cout << "subscribeEvent :" << info->subscribeEvent << endl; cout << "expires :" << info->expires << endl; cout << "content :" << info->content << endl; cout<<"Call ID:"<<info->callid<<endl; if (!info->registerInfo.userName.empty()) { cout<<"********************************************"<<endl; cout<<"authendication infomation as follows:"<<endl; cout<<"username:"<<info->registerInfo.userName<<endl; cout<<"algorithm:"<<info->registerInfo.algorithm<<endl; cout<<"Realm:"<<info->registerInfo.digestRealm<<endl; cout<<"nonce:"<<info->registerInfo.nonce<<endl; cout<<"response:"<<info->registerInfo.response<<endl; cout<<"uri:"<<info->registerInfo.uri<<endl; } cout << "**************************************************" << "**************************" << endl; } static void_t register_response(const GBT28181::Vsp::SipRequestInfo& info, void_t* user) { cout << "receive register request packet from client" << endl; SIP_PKG_Print(info); char temp[16]; SipRegisterContextInfo* regInfo = (SipRegisterContextInfo*) &info; SipRegisterContextInfo repinfo; repinfo.sipRequestId = info.sipRequestId; repinfo.from = info.proxy; repinfo.proxy = info.from; repinfo.method = info.method; //repinfo.expires = 300; repinfo.registerInfo.nonce = "9bd055"; sscanf(info.contact.c_str(), "%*[^@]@%[^:]", temp); repinfo.registerInfo.digestRealm = temp; sscanf(info.proxy.c_str(), "%*[^@]@%[^:]", temp); repinfo.sipIp = temp; sscanf(info.proxy.c_str(), "%*[^:]:%s", temp); repinfo.sipPort = atoi(temp); repinfo.registerInfo.userName = regInfo->registerInfo.userName; repinfo.content="sfsdfsdf"; GBT28181::Vsp::IGBT28181Comm* p_this = (GBT28181::Vsp::IGBT28181Comm*) user; if (repinfo.registerInfo.userName.empty()) { cout<<"this register packet is unauthendicatin"<<endl; cout<<"send 401"<<endl; repinfo.status = "401"; p_this->Downcast(repinfo); } else { cout<<"this register packet is authendicatin"<<endl; //验证 HASHHEX HA1; HASHHEX Response; DigestCalcHA1(regInfo->registerInfo.algorithm.c_str(), regInfo->registerInfo.userName.c_str(), regInfo->registerInfo.digestRealm.c_str(), UAC_PASSWD, regInfo->registerInfo.nonce.c_str(), NULL, HA1); DigestCalcResponse(HA1, regInfo->registerInfo.nonce.c_str(), NULL, NULL, NULL, 0, "REGISTER", regInfo->registerInfo.uri.c_str(), NULL, Response); if (!strcmp(Response, regInfo->registerInfo.response.c_str())) { cout<<"认证成功发送 200 OK!!!"<<endl; repinfo.expires = 5; repinfo.status = "200"; } else { cout<<"认证失败发送 404 OK!!!"<<endl; repinfo.expires = 5; repinfo.status = "404"; } p_this->Downcast(repinfo); } } // void_t server_callback(const SipRequestInfo& info, void_t* user) { //注册报文的情况,调用注册回调 if (strncmp(info.method.c_str(), client_request_method[0], strlen( client_request_method[0])) == 0) { register_response(info, user); } //其他情况报文 else { cout << "server receive wrong packer" << endl; SIP_PKG_Print(info); exit(1); } }
5.sip认证 algorithm.h
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #ifndef B_REGISTER__ALGORITHM_H_ #define B_REGISTER__ALGORITHM_H_ #include <stdio.h> #include "osip_md5.h" #define HASHLEN 16 typedef char HASH[HASHLEN]; #define HASHHEXLEN 32 typedef char HASHHEX[HASHHEXLEN + 1]; void DigestCalcHA1(const char *pszAlg, const char *pszUserName, const char *pszRealm, const char *pszPassword, const char *pszNonce, const char *pszCNonce, HASHHEX SessionKey); void DigestCalcResponse(HASHHEX HA1, const char *pszNonce, const char *pszNonceCount, const char *pszCNonce, const char *pszQop, int Aka, const char *pszMethod, const char *pszDigestUri, HASHHEX HEntity, HASHHEX Response); #endif /* B_REGISTER__ALGORITHM_H_ */
5.sip认证 algorithm.cpp,这部分参考代码可以在exosip2源代码中找到。
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #include "algorithm.h" #include "string.h" static void CvtHex(HASH Bin, HASHHEX Hex) { unsigned short i; unsigned char j; for (i = 0; i < HASHLEN; i++) { j = (Bin[i] >> 4) & 0xf; if (j <= 9) Hex[i * 2] = (j + '0'); else Hex[i * 2] = (j + 'a' - 10); j = Bin[i] & 0xf; if (j <= 9) Hex[i * 2 + 1] = (j + '0'); else Hex[i * 2 + 1] = (j + 'a' - 10); }; Hex[HASHHEXLEN] = '\0'; } void DigestCalcHA1(const char *pszAlg, const char *pszUserName, const char *pszRealm, const char *pszPassword, const char *pszNonce, const char *pszCNonce, HASHHEX SessionKey) { osip_MD5_CTX Md5Ctx; HASH HA1; osip_MD5Init(&Md5Ctx); osip_MD5Update(&Md5Ctx, (unsigned char *) pszUserName, strlen(pszUserName)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszRealm, strlen(pszRealm)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszPassword, strlen(pszPassword)); osip_MD5Final((unsigned char *) HA1, &Md5Ctx); if ((pszAlg != NULL) && strcmp(pszAlg, "md5-sess") == 0) { osip_MD5Init(&Md5Ctx); osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHLEN); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce)); osip_MD5Final((unsigned char *) HA1, &Md5Ctx); } CvtHex(HA1, SessionKey); } void DigestCalcResponse(HASHHEX HA1, const char *pszNonce, const char *pszNonceCount, const char *pszCNonce, const char *pszQop, int Aka, const char *pszMethod, const char *pszDigestUri, HASHHEX HEntity, HASHHEX Response) { osip_MD5_CTX Md5Ctx; HASH HA2; HASH RespHash; HASHHEX HA2Hex; /* calculate H(A2) */ osip_MD5Init(&Md5Ctx); osip_MD5Update(&Md5Ctx, (unsigned char *) pszMethod, strlen(pszMethod)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszDigestUri, strlen(pszDigestUri)); if (pszQop == NULL) { goto auth_withoutqop; } else if (0 == strcmp(pszQop, "auth-int")) { goto auth_withauth_int; } else if (0 == strcmp(pszQop, "auth")) { goto auth_withauth; } auth_withoutqop: osip_MD5Final((unsigned char *) HA2, &Md5Ctx); CvtHex(HA2, HA2Hex); /* calculate response */ osip_MD5Init(&Md5Ctx); osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); goto end; auth_withauth_int: osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) HEntity, HASHHEXLEN); auth_withauth: osip_MD5Final((unsigned char *) HA2, &Md5Ctx); CvtHex(HA2, HA2Hex); /* calculate response */ osip_MD5Init(&Md5Ctx); osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); if (Aka == 0) { osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonceCount, strlen( pszNonceCount)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); osip_MD5Update(&Md5Ctx, (unsigned char *) pszQop, strlen(pszQop)); osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1); } end: osip_MD5Update(&Md5Ctx, (unsigned char *) HA2Hex, HASHHEXLEN); osip_MD5Final((unsigned char *) RespHash, &Md5Ctx); CvtHex(RespHash, Response); } 由于我采用的是MD5验证,所以还需要从exosip2代码中引用osip_md5.h 文件。也可以直接把osip_md5.h和osip_md5.cpp拷到你的工程中,我就采用这个方法。
6.主程序 sipserver.h,该测试程序中,UAS值管理一个UAC 地址编码为100110000201000000 密码123456,UAS端口写死5060,地址编码写死100110000000000000
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #ifndef SIPCLIENT_H_ #define SIPCLIENT_H_ #include "IGBT28181Comm.h" using namespace GBT28181::Vsp; //默认端口 #define UASPORT (5060) //#define UACPORT (5061) //UAS自己地址编码 具体地址编码什么含义参考标准 #define UASADD_CODE ("100110000000000000") //UAC地址编码 地址编码相当于用户名 //实际应用中每个UAS保存该UAS所管理的一大堆UAC地址编码以及用户密码等信息 用于注册验证 //当前测试UAS只管理一个UAC 地址编码如下 #define UACADD_CODE ("100110000201000000") #define UAC_PASSWD ("123456") //该枚举类型列举类UAS角色 所主动请求的方法 // typedef enum { INVITE, ACK, MESSAGE, BYE, SUBSCRIBE, CALLMESSAGE, } METHOD; //通信实体对 UAS服务器的IP与端口 typedef struct { char local_addr[16]; int local_port; } COMM_PAIR; #endif /* SIPCLIENT_H_ */
7.sipserver.cpp,当前只支持启动服务,退出服务功能。其他功能后续添加。
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include "sipserver.h" #include "method.h" using namespace std; static void usage() { const char *b = "-------------------------------------------------------------------------------\n" "SIP Library test process - sipserver v 1.0 (June 13, 2014)\n\n" "Author: 程序人生\n\n" "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n" "-------------------------------------------------------------------------------\n" "\n" "-s local server ipv4 address\n" "-h Print this help and exit\n\n" "-------------------------------------------------------------------------------\n" "\n" "example1: ./sipserver -s127.0.0.1\n" "example2: ./sipserver -h\n" "server default port|server address code|client default port|client address code\n" "5060 |100110000000000000 |5061 |100110000201000000 \n" "-------------------------------------------------------------------------------\n" "\n"; fprintf(stderr, b, strlen(b)); } static void help() { const char *b = "-------------------------------------------------------------------------------\n" "SIP Library test process - sipserver v 1.0 (June 13, 2014)\n\n" "Current test Register method,only number 6 7 8 9 is useful\n\n" "Author: 程序人生\n\n" "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n" "-------------------------------------------------------------------------------\n" "\n" " 0:Invite\n" " 1:Ack\n" " 2:Message\n" " 3:Bye\n" " 4:Subscribe\n" " 5:CallMessage unused\n" " 6:start service\n" " 7:stop service\n" " 8:clear scream\n" " 9:exit\n" "-------------------------------------------------------------------------------\n" "\n"; fprintf(stderr, b, strlen(b)); cout << "please select method :"; } int main(int argc, char*argv[]) { int ch; /*METHOD meth;*/ COMM_PAIR comm_entry; comm_entry.local_port = UASPORT; opterr = 0; if (argc == 2) { while ((ch = getopt(argc, argv, "s:h:")) != -1) { switch (ch) { case 's': { strcpy(comm_entry.local_addr, optarg); break; } case 'h': { usage(); return EXIT_SUCCESS; break; } default: { fprintf(stderr, "Illegal argument \n"); usage(); return EXIT_FAILURE; } } } } else { fprintf(stderr, "Illegal argument \n"); usage(); return EXIT_FAILURE; } if (system("clear") < 0) { cout << "clear scream error" << endl; exit(0); } help(); ch = getchar(); getchar(); while (1) { switch (ch) { case '6': //启动服务 if (server_start(&comm_entry) < 0) { cout << "service start failure" << endl; break; } cout << "service start success ......" << endl; cout << "uas address :" << comm_entry.local_addr << " uas port :" << comm_entry.local_port << " address code :" << UASADD_CODE << endl; break; case '7': cout << "stop service......" << endl; server_stop(); break; case '8': if (system("clear") < 0) { cout << "clear scream error" << endl; exit(1); } break; case '9': cout << "exit sipserver......" << endl; getchar(); exit(0); default: cout << "select error" << endl; break; } cout << "press any key to continue......" << endl; getchar(); help(); ch = getchar(); getchar(); } return 0; }
UAC_test 代码如下:
这部分实现简单,只是演示,包含一个文件UAC_test.cpp,UAC地址编码100110000201000000,端口5061写死。UAS端口写死5060。
/* =============================================================== GBT28181 SIP组件libGBT28181SipComponent.so注册实现 作者:程序人生 博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究! ================================================================ */ #include <iostream> #include <string.h> #include <stdio.h> #include "IGBT28181Comm.h" using namespace GBT28181::Vsp; using namespace std; //默认端口 #define UASPORT (5060) #define UACPORT (5061) static char pwd[20]; //通信实体对 typedef struct { char local_addr[16]; char remote_addr[16]; int local_port; int remote_port; } COMM_PAIR; static void_t SIP_PKG_Print(const SipRequestInfo& info) { cout << "packet receive :" << endl; cout << "****************************************************************************" << endl; cout << "status :" << info.status << endl; cout << "sipRequestId :" << info.sipRequestId << endl; cout << "requestId :" << info.requestId << endl; cout << "method :" << info.method << endl; cout << "from :" << info.from << endl; cout << "proxy :" << info.proxy << endl; cout << "contact :" << info.contact << endl; cout << "content :" << info.content << endl; cout << "status :" << info.status << endl; cout << "handle :" << info.handle << endl; cout << "sipIp :" << info.sipIp << endl; cout << "sipPort :" << info.sipPort << endl; cout << "subscribeEvent :" << info.subscribeEvent << endl; cout << "expires :" << info.expires << endl; cout << "****************************************************************************" << endl; } //消息处理回调函数 void_t SIP_PKG_Receive(const SipRequestInfo& info, void_t* user) { //打印从服务器接收的消息 SIP_PKG_Print(info); //UAC向服务器发送响应报文 char buf[1024]; const char*mthd=info.method.data(); snprintf(buf, 1024, "response from client,for test method:%s", mthd); if(memcmp(mthd,"Nari.Vsp.Sip.SipMethod.Register",strlen("Nari.Vsp.Sip.SipMethod.Register"))==0) { return ; } } void Communicator_init(void*comm,IGBT28181Comm *SIPComm) { if (NULL != SIPComm) { delete SIPComm; } SIPComm = new IGBT28181Comm(false); //回调函数 SIPComm->SetResponseCallback(SIP_PKG_Receive, (void_t*) SIPComm); //启动SIP协议 COMM_PAIR *comm_entry = (COMM_PAIR *) comm; SIPComm->StartSip(comm_entry->local_addr, comm_entry->local_port); } //客户端主动发送向服务器发送注册报文 void sip_register(IGBT28181Comm* uac, COMM_PAIR *entry) { cout << "enter" << endl; SipRegisterContextInfo info; char temp[128]; // 失效时间 info.expires = 300; // 用户100110000201000000 在 entry->remote_addr 远程IP上 snprintf(temp, 128, "100110000201000000@%s:%d", entry->remote_addr, entry->remote_port); info.from = temp; info.proxy = temp; // 发起会话的方式 info.method = SipMethod::METHOD_REGISTER; // 本地ip snprintf(temp, 128, "100110000201000000@%s:%d", entry->local_addr, entry->local_port); //info.proxy = temp; // contact //info.contact = info.from; info.contact = temp; // 端口 info.sipPort = entry->local_port; snprintf(temp, 128, "100110000201000000@%s", entry->local_addr); info.sipIp = temp; info.requestId = "0"; info.sipRequestId = "0"; info.registerInfo.userName = "100110000201000000"; info.registerInfo.response = pwd; if (NULL != uac) { uac->Downcast(info); cout << "downcast success" << endl; } else { cout << "downcast failure" << endl; } } int main(int argc, char*argv[]) { if(argc!=4) { cout<<"usage: ./UAC_test 127.0.0.1 127.0.0.1 123456"<<endl; return 1; } COMM_PAIR comm_entry; comm_entry.local_port = UACPORT; comm_entry.remote_port = UASPORT; strcpy(comm_entry.local_addr, argv[1]); strcpy(comm_entry.remote_addr, argv[2]); strcpy(pwd, argv[3]); IGBT28181Comm *SIPComm=NULL; SIPComm = new IGBT28181Comm(false); //回调函数 SIPComm->SetResponseCallback(SIP_PKG_Receive, (void_t*) SIPComm); //启动SIP协议 SIPComm->StartSip(comm_entry.local_addr, comm_entry.local_port); //向服务器发送注册报文 sip_register(SIPComm, &comm_entry); while(1) { sleep(5); } }
六.测试
笔者用的环境为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的接口实现,有空再整理。
本文源码下载,正在整理中。。。。。。。。。。。。。。。。