原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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的接口实现,有空再整理。

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

基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现相关推荐

  1. 基于GBT28181:SIP协议组件开发-----------第四篇SIP注册流程eXosip2实现(一)

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3945294.html. 上章节讲解了利用自主开发的组件SIP组件l ...

  2. 基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3966794.html. 上章节讲解了讲解一个用eXosip2库实现 ...

  3. ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇

    第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是行不 通.如果大家开发的是WinForm中的事件,之前的定义可能没有什 ...

  4. ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇

    第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.N ...

  5. Qt (高仿Visio)流程图组件开发(三) 图元基类如何定义,流程图多种图元类型实现

    文章目录 本系列目录 前言 一.图元基类的定义 1.图元信息基类结构体 2.图元位置 3.父子对象关系 二.自定义图元实现 1.自定义图元基类(FlowchartGraphicsItem)与Qt原生图 ...

  6. Agv、Rgv 车辆控制调度系统开发第三篇

    Agv.Rgv 车辆控制调度系统开发第三篇地图编辑器 Agv.Rgv 车辆控制调度系统开发第三篇地图编辑器 Agv.Rgv 车辆控制调度系统开发第三篇地图编辑器 前言 一.GOJS 二.使用步骤 1. ...

  7. h3c无线管理 dns服务器,H3C FIT AP与AC连接时三种的注册流程

    H3C FIT AP与AC连接时三种的注册流程 在无线网络实际应用中,存在一种场景,如客户需要覆盖一个校园,而校园的不同区域被划分了不同子网.在这种场景中,AC位于骨干网中,而AP需要分布在不同区域中 ...

  8. SIP协议简介(一)之SIP基本的概述

    本篇文章主要是对RFC3261翻译进行的,也包含着自己的一些理解.希望能给需要的人带来一些帮助 补充说明:RFC即Request For Comments(RFC),是一系列以编号排定的文件.文件收集 ...

  9. python基于什么语言-一种基于Python语言的EDA开发平台及其使用方法与流程

    本发明涉及EDA开发的技术领域,尤其是指一种基于Python语言的EDA开发平台及其使用方法. 背景技术: 目前,主流的EDA设计语言Verilog HDL能实现完整的芯片硬件逻辑电路开发,但是其代码 ...

最新文章

  1. 【RAC】RAC 实现IP访问控制
  2. 函数传参字典_Python 函数参数解包
  3. struts2 s:if标签以及 #,%{},%{#}的使用方法
  4. Tinyhttpd源码--实现http服务器
  5. java中单列集合的根接口是_java 单列集合总结
  6. C#将dataGridView中显示的数据导出到Excel(大数据量超实用版)
  7. 训练效率低?GPU利用率上不去?快来看看别人家的tricks吧~
  8. linux删除文件里夹命令,Linux删除文件(夹)、创建文件(夹)命令是什么
  9. 基于JAVA+Swing+MYSQL的图书馆管理系统
  10. multipartfile转excel_SpringMVC 上传文件 MultipartFile 转为 File的方法
  11. 基于 Sharding Sphere,实现数据 “一键脱敏”!
  12. 通达信买入离场信号选股公式,精准买卖点 不加密无未来
  13. C语言:用指针求字符串长度
  14. HBuilderX 打包 vue 项目生成 apk
  15. Deep Learning: The Big Picture 深度学习大局观 Pluralsight课程中文字幕
  16. LeetCode 1419. Minimum Number of Frogs Croaking
  17. 2016年俄罗斯M2M市场达100亿俄罗斯卢布
  18. 听课笔记-名校启程大学规划课
  19. 视频传输协议之MPEG-DASH
  20. Navicat premium 导入大数据的Excel文件失败的方法

热门文章

  1. 一天一天学做外挂@第二天-实现VB显示游戏数据[武林外传]
  2. vue实现调用showModalDialog传递参数
  3. 机器学习笔记 - ENet论文解读
  4. RenderDoc 调试web
  5. 移动安全-BTS-Potentially Harmful Applications (PHAs)
  6. 2020 人工智能人才报告
  7. pandas中的ix,iloc,loc方法获取数据
  8. 视频面试需要格外注重哪些呢?
  9. 人工智能基础复习1——人工智能概述
  10. 年度回忆录(2011.01----2011.07)