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

时间:2022-06-01 10:46:12

原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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注册流程分析实现

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

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

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

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

三.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:SIP协议组件开发-----------第三篇SIP注册流程分析实现

四.GBT28181注册流程如下

 1.UAC--->UAS 发送请求登录,传送未鉴权信息

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

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注册流程分析实现

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

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

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

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

五.源代码

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

UAS_test部分代码:


1.主要功能文件method.h

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #ifndef METHOD_H_
#define METHOD_H_
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include "callback.h"
#include "IGBT28181Comm.h"
#include "sipserver.h" using namespace GBT28181::Vsp;
using namespace std; //启动UAS角色的服务器
int server_start(void*addr);
//停止UAS角色服务器
void server_stop(); #endif /* METHOD_H_ */

2.method.cpp 实现文件中,开启服务包括启动服务和设置回调函数。

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #include "method.h"
#include <semaphore.h> static IGBT28181Comm* g_SIPComm = NULL; //启动SIP服务
int server_start(void*addr)
{
COMM_PAIR *addr_entry = (COMM_PAIR *) addr;
if (g_SIPComm != NULL)
{
delete g_SIPComm;
}
if (!(g_SIPComm = new IGBT28181Comm(true)))
{
return -;
}
//回调函数
g_SIPComm->SetResponseCallback(&server_callback, (void_t*) g_SIPComm);
g_SIPComm->StartSip(addr_entry->local_addr, addr_entry->local_port);
return ;
} //停止SIP服务
void server_stop()
{ if (g_SIPComm != NULL)
{
g_SIPComm->StopSip();
sleep();
delete g_SIPComm;
}
g_SIPComm = NULL;
}

3.回调函数callback.h

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #ifndef CALLBACK_H_
#define CALLBACK_H_
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include "sipserver.h"
#include "IGBT28181Comm.h"
#include "method.h" using namespace GBT28181::Vsp;
using namespace std; //回调函数
void_t server_callback(const SipRequestInfo& info, void_t* user); #endif /* LIBINTERFACE_H_ */

4.callback.cpp 实现文件

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #include "callback.h"
#include "algorithm.h" //客户端主动请求,服务器端回调
const char * client_request_method[] =
{
"GBT28181.Vsp.Sip.SipMethod.Register",
"GBT28181.Vsp.Sip.SipMethod.Notify",
"GBT28181.Vsp.Sip.SipMethod.Subscribenotify"
}; //打印SIP消息
static void SIP_PKG_Print(const SipRequestInfo& infomation)
{
SipRegisterContextInfo* info = (SipRegisterContextInfo*) &infomation;
cout << "\n"
<< "**************************************************"
<< "**************************"
<< endl;
cout << "packet receive " << endl;
cout << "status :" << info->status << endl;
cout << "sipRequestId :" << info->sipRequestId << endl;
cout << "requestId :" << info->requestId << endl;
cout << "method :" << info->method << endl;
cout << "from :" << info->from << endl;
cout << "proxy :" << info->proxy << endl;
cout << "contact :" << info->contact << endl;
cout << "handle :" << info->handle << endl;
cout << "sipIp :" << info->sipIp << endl;
cout << "sipPort :" << info->sipPort << endl;
cout << "subscribeEvent :" << info->subscribeEvent << endl;
cout << "expires :" << info->expires << endl;
cout << "content :" << info->content << endl;
cout<<"Call ID:"<<info->callid<<endl;
if (!info->registerInfo.userName.empty())
{
cout<<"********************************************"<<endl;
cout<<"authendication infomation as follows:"<<endl;
cout<<"username:"<<info->registerInfo.userName<<endl;
cout<<"algorithm:"<<info->registerInfo.algorithm<<endl;
cout<<"Realm:"<<info->registerInfo.digestRealm<<endl;
cout<<"nonce:"<<info->registerInfo.nonce<<endl;
cout<<"response:"<<info->registerInfo.response<<endl;
cout<<"uri:"<<info->registerInfo.uri<<endl; }
cout
<< "**************************************************"
<< "**************************"
<< endl;
} static void_t register_response(const GBT28181::Vsp::SipRequestInfo& info,
void_t* user)
{
cout << "receive register request packet from client" << endl;
SIP_PKG_Print(info);
char temp[];
SipRegisterContextInfo* regInfo = (SipRegisterContextInfo*) &info;
SipRegisterContextInfo repinfo;
repinfo.sipRequestId = info.sipRequestId;
repinfo.from = info.proxy;
repinfo.proxy = info.from;
repinfo.method = info.method;
//repinfo.expires = 300;
repinfo.registerInfo.nonce = "9bd055";
sscanf(info.contact.c_str(), "%*[^@]@%[^:]", temp);
repinfo.registerInfo.digestRealm = temp;
sscanf(info.proxy.c_str(), "%*[^@]@%[^:]", temp);
repinfo.sipIp = temp;
sscanf(info.proxy.c_str(), "%*[^:]:%s", temp);
repinfo.sipPort = atoi(temp);
repinfo.registerInfo.userName = regInfo->registerInfo.userName;
repinfo.content="sfsdfsdf";
GBT28181::Vsp::IGBT28181Comm* p_this = (GBT28181::Vsp::IGBT28181Comm*) user; if (repinfo.registerInfo.userName.empty())
{
cout<<"this register packet is unauthendicatin"<<endl;
cout<<"send 401"<<endl;
repinfo.status = "";
p_this->Downcast(repinfo);
}
else
{
cout<<"this register packet is authendicatin"<<endl;
//验证
HASHHEX HA1;
HASHHEX Response;
DigestCalcHA1(regInfo->registerInfo.algorithm.c_str(),
regInfo->registerInfo.userName.c_str(),
regInfo->registerInfo.digestRealm.c_str(), UAC_PASSWD,
regInfo->registerInfo.nonce.c_str(), NULL, HA1);
DigestCalcResponse(HA1, regInfo->registerInfo.nonce.c_str(),
NULL, NULL, NULL, , "REGISTER",
regInfo->registerInfo.uri.c_str(),
NULL, Response);
if (!strcmp(Response, regInfo->registerInfo.response.c_str()))
{
cout<<"认证成功发送 200 OK!!!"<<endl;
repinfo.expires = ;
repinfo.status = "";
}
else
{
cout<<"认证失败发送 404 OK!!!"<<endl;
repinfo.expires = ;
repinfo.status = "";
} p_this->Downcast(repinfo); }
} //
void_t server_callback(const SipRequestInfo& info, void_t* user)
{
//注册报文的情况,调用注册回调
if (strncmp(info.method.c_str(), client_request_method[], strlen(
client_request_method[])) == )
{
register_response(info, user);
}
//其他情况报文
else
{
cout << "server receive wrong packer" << endl;
SIP_PKG_Print(info);
exit();
}
}
 

5.sip认证 algorithm.h

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/
#ifndef B_REGISTER__ALGORITHM_H_
#define B_REGISTER__ALGORITHM_H_ #include <stdio.h>
#include "osip_md5.h" #define HASHLEN 16
typedef char HASH[HASHLEN]; #define HASHHEXLEN 32
typedef char HASHHEX[HASHHEXLEN + ]; void DigestCalcHA1(const char *pszAlg, const char *pszUserName,
const char *pszRealm, const char *pszPassword,
const char *pszNonce, const char *pszCNonce,
HASHHEX SessionKey); void DigestCalcResponse(HASHHEX HA1, const char *pszNonce,
const char *pszNonceCount, const char *pszCNonce,
const char *pszQop, int Aka, const char *pszMethod,
const char *pszDigestUri, HASHHEX HEntity, HASHHEX Response); #endif /* B_REGISTER__ALGORITHM_H_ */

5.sip认证 algorithm.cpp,这部分参考代码可以在exosip2源代码中找到。

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #include "algorithm.h"
#include "string.h" static void CvtHex(HASH Bin, HASHHEX Hex)
{
unsigned short i;
unsigned char j; for (i = ; i < HASHLEN; i++)
{
j = (Bin[i] >> ) & 0xf;
if (j <= )
Hex[i * ] = (j + '');
else
Hex[i * ] = (j + 'a' - );
j = Bin[i] & 0xf;
if (j <= )
Hex[i * + ] = (j + '');
else
Hex[i * + ] = (j + 'a' - );
};
Hex[HASHHEXLEN] = '\0';
} void DigestCalcHA1(const char *pszAlg, const char *pszUserName,
const char *pszRealm, const char *pszPassword,
const char *pszNonce, const char *pszCNonce,
HASHHEX SessionKey)
{
osip_MD5_CTX Md5Ctx;
HASH HA1; osip_MD5Init(&Md5Ctx);
osip_MD5Update(&Md5Ctx, (unsigned char *) pszUserName, strlen(pszUserName));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszRealm, strlen(pszRealm));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszPassword, strlen(pszPassword));
osip_MD5Final((unsigned char *) HA1, &Md5Ctx);
if ((pszAlg != NULL) && strcmp(pszAlg, "md5-sess") == )
{
osip_MD5Init(&Md5Ctx);
osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHLEN);
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce));
osip_MD5Final((unsigned char *) HA1, &Md5Ctx);
}
CvtHex(HA1, SessionKey);
} void DigestCalcResponse(HASHHEX HA1, const char *pszNonce,
const char *pszNonceCount, const char *pszCNonce,
const char *pszQop, int Aka, const char *pszMethod,
const char *pszDigestUri, HASHHEX HEntity, HASHHEX Response)
{
osip_MD5_CTX Md5Ctx;
HASH HA2;
HASH RespHash;
HASHHEX HA2Hex; /* calculate H(A2) */
osip_MD5Init(&Md5Ctx);
osip_MD5Update(&Md5Ctx, (unsigned char *) pszMethod, strlen(pszMethod));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszDigestUri,
strlen(pszDigestUri)); if (pszQop == NULL)
{
goto auth_withoutqop;
}
else if ( == strcmp(pszQop, "auth-int"))
{
goto auth_withauth_int;
}
else if ( == strcmp(pszQop, "auth"))
{
goto auth_withauth;
} auth_withoutqop: osip_MD5Final((unsigned char *) HA2, &Md5Ctx);
CvtHex(HA2, HA2Hex); /* calculate response */
osip_MD5Init(&Md5Ctx);
osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN);
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", ); goto end; auth_withauth_int: osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) HEntity, HASHHEXLEN); auth_withauth: osip_MD5Final((unsigned char *) HA2, &Md5Ctx);
CvtHex(HA2, HA2Hex); /* calculate response */
osip_MD5Init(&Md5Ctx);
osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN);
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
if (Aka == )
{
osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonceCount, strlen(
pszNonceCount));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
osip_MD5Update(&Md5Ctx, (unsigned char *) pszQop, strlen(pszQop));
osip_MD5Update(&Md5Ctx, (unsigned char *) ":", );
}
end: osip_MD5Update(&Md5Ctx, (unsigned char *) HA2Hex, HASHHEXLEN);
osip_MD5Final((unsigned char *) RespHash, &Md5Ctx);
CvtHex(RespHash, Response);
}

由于我采用的是MD5验证,所以还需要从exosip2代码中引用osip_md5.h 文件。也可以直接把osip_md5.h和osip_md5.cpp拷到你的工程中,我就采用这个方法。

6.主程序 sipserver.h,该测试程序中,UAS值管理一个UAC 地址编码为100110000201000000 密码123456,UAS端口写死5060,地址编码写死100110000000000000

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #ifndef SIPCLIENT_H_
#define SIPCLIENT_H_ #include "IGBT28181Comm.h" using namespace GBT28181::Vsp; //默认端口
#define UASPORT (5060)
//#define UACPORT (5061)
//UAS自己地址编码 具体地址编码什么含义参考标准
#define UASADD_CODE ("100110000000000000")
//UAC地址编码 地址编码相当于用户名
//实际应用中每个UAS保存该UAS所管理的一大堆UAC地址编码以及用户密码等信息 用于注册验证
//当前测试UAS只管理一个UAC 地址编码如下
#define UACADD_CODE ("100110000201000000")
#define UAC_PASSWD ("123456") //该枚举类型列举类UAS角色 所主动请求的方法
//
typedef enum
{
INVITE, ACK, MESSAGE, BYE, SUBSCRIBE, CALLMESSAGE,
} METHOD; //通信实体对 UAS服务器的IP与端口
typedef struct
{
char local_addr[];
int local_port;
} COMM_PAIR; #endif /* SIPCLIENT_H_ */

7.sipserver.cpp,当前只支持启动服务,退出服务功能。其他功能后续添加。

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "sipserver.h"
#include "method.h" using namespace std; static void usage()
{
const char
*b = "-------------------------------------------------------------------------------\n"
"SIP Library test process - sipserver v 1.0 (June 13, 2014)\n\n"
"Author: 程序人生\n\n"
"博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n"
"-------------------------------------------------------------------------------\n"
"\n"
"-s local server ipv4 address\n"
"-h Print this help and exit\n\n"
"-------------------------------------------------------------------------------\n"
"\n"
"example1: ./sipserver -s127.0.0.1\n"
"example2: ./sipserver -h\n"
"server default port|server address code|client default port|client address code\n"
"5060 |100110000000000000 |5061 |100110000201000000 \n"
"-------------------------------------------------------------------------------\n"
"\n";
fprintf(stderr, b, strlen(b));
} static void help()
{
const char
*b = "-------------------------------------------------------------------------------\n"
"SIP Library test process - sipserver v 1.0 (June 13, 2014)\n\n"
"Current test Register method,only number 6 7 8 9 is useful\n\n"
"Author: 程序人生\n\n"
"博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n"
"-------------------------------------------------------------------------------\n"
"\n"
" 0:Invite\n"
" 1:Ack\n"
" 2:Message\n"
" 3:Bye\n"
" 4:Subscribe\n"
" 5:CallMessage unused\n"
" 6:start service\n"
" 7:stop service\n"
" 8:clear scream\n"
" 9:exit\n"
"-------------------------------------------------------------------------------\n"
"\n";
fprintf(stderr, b, strlen(b));
cout << "please select method :";
} int main(int argc, char*argv[])
{
int ch;
/*METHOD meth;*/
COMM_PAIR comm_entry;
comm_entry.local_port = UASPORT;
opterr = ;
if (argc == )
{
while ((ch = getopt(argc, argv, "s:h:")) != -)
{
switch (ch)
{
case 's':
{
strcpy(comm_entry.local_addr, optarg);
break;
}
case 'h':
{
usage();
return EXIT_SUCCESS;
break;
}
default:
{
fprintf(stderr, "Illegal argument \n");
usage();
return EXIT_FAILURE;
}
}
}
}
else
{
fprintf(stderr, "Illegal argument \n");
usage();
return EXIT_FAILURE;
}
if (system("clear") < )
{
cout << "clear scream error" << endl;
exit();
}
help();
ch = getchar();
getchar();
while ()
{
switch (ch)
{
case '':
//启动服务
if (server_start(&comm_entry) < )
{
cout << "service start failure" << endl;
break;
}
cout << "service start success ......" << endl;
cout << "uas address :" << comm_entry.local_addr << " uas port :"
<< comm_entry.local_port << " address code :" << UASADD_CODE
<< endl;
break;
case '':
cout << "stop service......" << endl;
server_stop();
break;
case '':
if (system("clear") < )
{
cout << "clear scream error" << endl;
exit();
}
break;
case '':
cout << "exit sipserver......" << endl;
getchar();
exit();
default:
cout << "select error" << endl;
break;
}
cout << "press any key to continue......" << endl;
getchar();
help();
ch = getchar();
getchar();
}
return ;
}
 

UAC_test 代码如下:

这部分实现简单,只是演示,包含一个文件UAC_test.cpp,UAC地址编码100110000201000000,端口5061写死。UAS端口写死5060。

 /*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址:http://blog.csdn.net/hiwubihe
QQ:1269122125
注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
================================================================
*/ #include <iostream>
#include <string.h>
#include <stdio.h> #include "IGBT28181Comm.h"
using namespace GBT28181::Vsp;
using namespace std; //默认端口
#define UASPORT (5060)
#define UACPORT (5061) static char pwd[]; //通信实体对
typedef struct
{
char local_addr[];
char remote_addr[];
int local_port;
int remote_port;
} COMM_PAIR; static void_t SIP_PKG_Print(const SipRequestInfo& info)
{
cout << "packet receive :" << endl;
cout
<< "****************************************************************************"
<< endl;
cout << "status :" << info.status << endl;
cout << "sipRequestId :" << info.sipRequestId << endl;
cout << "requestId :" << info.requestId << endl;
cout << "method :" << info.method << endl;
cout << "from :" << info.from << endl;
cout << "proxy :" << info.proxy << endl;
cout << "contact :" << info.contact << endl;
cout << "content :" << info.content << endl;
cout << "status :" << info.status << endl;
cout << "handle :" << info.handle << endl;
cout << "sipIp :" << info.sipIp << endl;
cout << "sipPort :" << info.sipPort << endl;
cout << "subscribeEvent :" << info.subscribeEvent << endl;
cout << "expires :" << info.expires << endl;
cout
<< "****************************************************************************"
<< endl;
} //消息处理回调函数
void_t SIP_PKG_Receive(const SipRequestInfo& info, void_t* user)
{
//打印从服务器接收的消息
SIP_PKG_Print(info);
//UAC向服务器发送响应报文
char buf[];
const char*mthd=info.method.data();
snprintf(buf, , "response from client,for test method:%s", mthd);
if(memcmp(mthd,"Nari.Vsp.Sip.SipMethod.Register",strlen("Nari.Vsp.Sip.SipMethod.Register"))==)
{
return ;
}
} void Communicator_init(void*comm,IGBT28181Comm *SIPComm)
{
if (NULL != SIPComm)
{
delete SIPComm;
}
SIPComm = new IGBT28181Comm(false);
//回调函数
SIPComm->SetResponseCallback(SIP_PKG_Receive, (void_t*) SIPComm);
//启动SIP协议
COMM_PAIR *comm_entry = (COMM_PAIR *) comm;
SIPComm->StartSip(comm_entry->local_addr, comm_entry->local_port);
} //客户端主动发送向服务器发送注册报文
void sip_register(IGBT28181Comm* uac, COMM_PAIR *entry)
{
cout << "enter" << endl;
SipRegisterContextInfo info;
char temp[];
// 失效时间
info.expires = ;
// 用户100110000201000000 在 entry->remote_addr 远程IP上
snprintf(temp, , "100110000201000000@%s:%d", entry->remote_addr,
entry->remote_port);
info.from = temp;
info.proxy = temp;
// 发起会话的方式
info.method = SipMethod::METHOD_REGISTER;
// 本地ip
snprintf(temp, , "100110000201000000@%s:%d", entry->local_addr,
entry->local_port);
//info.proxy = temp;
// contact
//info.contact = info.from;
info.contact = temp;
// 端口
info.sipPort = entry->local_port;
snprintf(temp, , "100110000201000000@%s", entry->local_addr);
info.sipIp = temp;
info.requestId = "";
info.sipRequestId = "";
info.registerInfo.userName = "";
info.registerInfo.response = pwd;
if (NULL != uac)
{
uac->Downcast(info);
cout << "downcast success" << endl;
}
else
{
cout << "downcast failure" << endl;
}
} int main(int argc, char*argv[])
{
if(argc!=)
{
cout<<"usage: ./UAC_test 127.0.0.1 127.0.0.1 123456"<<endl;
return ;
}
COMM_PAIR comm_entry;
comm_entry.local_port = UACPORT;
comm_entry.remote_port = UASPORT;
strcpy(comm_entry.local_addr, argv[]);
strcpy(comm_entry.remote_addr, argv[]);
strcpy(pwd, argv[]); IGBT28181Comm *SIPComm=NULL;
SIPComm = new IGBT28181Comm(false);
//回调函数
SIPComm->SetResponseCallback(SIP_PKG_Receive, (void_t*) SIPComm);
//启动SIP协议
SIPComm->StartSip(comm_entry.local_addr, comm_entry.local_port);
//向服务器发送注册报文
sip_register(SIPComm, &comm_entry);
while()
{
sleep();
}
}

六.测试

笔者用的环境为centos 6.0 32bit系统。成功启动的前提是上一节所讲的libGBT28181SipComponent.so必须拷到系统库目录下,或者设置LD_LIBRARY_PATH环境变量。同时安装libGBT28181SipComponent.so库所依赖的库。可以用ldd UAS_test 查看程序依赖的库以及哪些库找不到。

1.启动UAS

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

2.启动后效果

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

3.填写6 start service后效果

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

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

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

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

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

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

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

6.UAC_test收到401报文如下

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

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

7.UAS_test收到鉴权信息

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

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

8.UAC_test收到200OK

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

整个验证过程结束。

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

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

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

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

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