原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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 << " " 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] = '