基于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注册流程分析实现_第1张图片

          电力系统注册稍微复杂点,但原来基本相同。多了个刷新注册的过程。

             基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第2张图片

 

 

二.GBT28181关于注册的解释如下

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第3张图片

 

三.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 发送请求登录,传送未鉴权信息

 基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第4张图片

   

 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值)。

 

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第5张图片

 

3.UAC--->UAS  UAC在收到401信息后,根据UAS发送的401信息中的认证体制和认证参数,结合用户名和密码,生成response值。发送鉴权消息。

 基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第6张图片

 

4.UAS--->UAC UAS收到鉴权信息后,根据自己自身的管理体制,找到UAC用户在服务器中的密码,根据UAC发送的认证体制和认证参数,结合用户名和密码,生成response值,在把response和UAC发送的response比较,相等则认证通过发送 200 ok。不等发送404验证失败。

 

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第7张图片

 

五.源代码

这里注册功能虽然简单,但是为了后续其他功能的添加,这里还是根据功能划分了几个模块。后续添加功能,只是在这个框架中添加。

 

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 
14 #include 
15 #include 
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 
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 
14 #include <string.h>
15 #include 
16 #include 
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:"<callid<<endl;
 46     if (!info->registerInfo.userName.empty())
 47     {
 48         cout<<"********************************************"<<endl;
 49         cout<<"authendication infomation as follows:"<<endl;
 50         cout<<"username:"<registerInfo.userName<<endl;
 51         cout<<"algorithm:"<registerInfo.algorithm<<endl;
 52         cout<<"Realm:"<registerInfo.digestRealm<<endl;
 53         cout<<"nonce:"<registerInfo.nonce<<endl;
 54         cout<<"response:"<registerInfo.response<<endl;
 55         cout<<"uri:"<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 
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 
 12 #include 
 13 #include 
 14 #include <string.h>
 15 #include 
 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 
 12 #include <string.h>
 13 #include 
 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.启动后效果

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第8张图片

3.填写6 start service后效果


此时,UAS注册服务程序已经成功启动。等待UAC的注册。

4.笔者UAS_test和UAC_test是在一台机器上测试的。格式UAC_test 本机IP UASIP 密码


5.启动后UAS_test收到未鉴权报文

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第9张图片

从打印的报文看,没有用户名等信息,同时提示发送了401回复报文

6.UAC_test收到401报文如下

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第10张图片

可以看到UAC_test已经成功接受401报文,准备发送具有鉴权信息给UAS_test

7.UAS_test收到鉴权信息

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第11张图片

可以看到有用户名等鉴权信息。UAS_test鉴权后,发现用户合法,给与回复200ok!

8.UAC_test收到200OK

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第12张图片

整个验证过程结束。

9.其实验证还用很多情况,标准中都有定义,发送什么响应码。如密码错误响应404错误码。上例中

./UAC_test 192.168.50.57 192.168.50.57 12345,密码不正确。将会收到404报文。

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现_第13张图片

关于SIP注册怎么调用exosip2的接口实现,有空再整理。

本文源码下载,正在整理中。。。。。。。。。。。。。。。。

 


你可能感兴趣的:(SIP开发基础)