基于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的接口实现,有空再整理。
本文源码下载,正在整理中。。。。。。。。。。。。。。。。
基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现相关推荐
- 基于GBT28181:SIP协议组件开发-----------第四篇SIP注册流程eXosip2实现(一)
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3945294.html. 上章节讲解了利用自主开发的组件SIP组件l ...
- 基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3966794.html. 上章节讲解了讲解一个用eXosip2库实现 ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇
第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是行不 通.如果大家开发的是WinForm中的事件,之前的定义可能没有什 ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.N ...
- Qt (高仿Visio)流程图组件开发(三) 图元基类如何定义,流程图多种图元类型实现
文章目录 本系列目录 前言 一.图元基类的定义 1.图元信息基类结构体 2.图元位置 3.父子对象关系 二.自定义图元实现 1.自定义图元基类(FlowchartGraphicsItem)与Qt原生图 ...
- Agv、Rgv 车辆控制调度系统开发第三篇
Agv.Rgv 车辆控制调度系统开发第三篇地图编辑器 Agv.Rgv 车辆控制调度系统开发第三篇地图编辑器 Agv.Rgv 车辆控制调度系统开发第三篇地图编辑器 前言 一.GOJS 二.使用步骤 1. ...
- h3c无线管理 dns服务器,H3C FIT AP与AC连接时三种的注册流程
H3C FIT AP与AC连接时三种的注册流程 在无线网络实际应用中,存在一种场景,如客户需要覆盖一个校园,而校园的不同区域被划分了不同子网.在这种场景中,AC位于骨干网中,而AP需要分布在不同区域中 ...
- SIP协议简介(一)之SIP基本的概述
本篇文章主要是对RFC3261翻译进行的,也包含着自己的一些理解.希望能给需要的人带来一些帮助 补充说明:RFC即Request For Comments(RFC),是一系列以编号排定的文件.文件收集 ...
- python基于什么语言-一种基于Python语言的EDA开发平台及其使用方法与流程
本发明涉及EDA开发的技术领域,尤其是指一种基于Python语言的EDA开发平台及其使用方法. 背景技术: 目前,主流的EDA设计语言Verilog HDL能实现完整的芯片硬件逻辑电路开发,但是其代码 ...
最新文章
- 【RAC】RAC 实现IP访问控制
- 函数传参字典_Python 函数参数解包
- struts2 s:if标签以及 #,%{},%{#}的使用方法
- Tinyhttpd源码--实现http服务器
- java中单列集合的根接口是_java 单列集合总结
- C#将dataGridView中显示的数据导出到Excel(大数据量超实用版)
- 训练效率低?GPU利用率上不去?快来看看别人家的tricks吧~
- linux删除文件里夹命令,Linux删除文件(夹)、创建文件(夹)命令是什么
- 基于JAVA+Swing+MYSQL的图书馆管理系统
- multipartfile转excel_SpringMVC 上传文件 MultipartFile 转为 File的方法
- 基于 Sharding Sphere,实现数据 “一键脱敏”!
- 通达信买入离场信号选股公式,精准买卖点 不加密无未来
- C语言:用指针求字符串长度
- HBuilderX 打包 vue 项目生成 apk
- Deep Learning: The Big Picture 深度学习大局观 Pluralsight课程中文字幕
- LeetCode 1419. Minimum Number of Frogs Croaking
- 2016年俄罗斯M2M市场达100亿俄罗斯卢布
- 听课笔记-名校启程大学规划课
- 视频传输协议之MPEG-DASH
- Navicat premium 导入大数据的Excel文件失败的方法