• 基于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 << "
    "
     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] = '';
     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 =        "-------------------------------------------------------------------------------
    "
     25                         "SIP Library test process - sipserver v 1.0 (June 13, 2014)
    
    "
     26                         "Author: 程序人生
    
    "
     27                         "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125
    
    "
     28                         "-------------------------------------------------------------------------------
    "
     29                         "
    "
     30                         "-s            local server ipv4 address
    "
     31                         "-h            Print this help and exit
    
    "
     32                         "-------------------------------------------------------------------------------
    "
     33                         "
    "
     34                         "example1: ./sipserver -s127.0.0.1
    "
     35                         "example2: ./sipserver -h
    "
     36                         "server default port|server address code|client default port|client address code
    "
     37                         "5060               |100110000000000000 |5061               |100110000201000000 
    "
     38                         "-------------------------------------------------------------------------------
    "
     39                         "
    ";
     40     fprintf(stderr, b, strlen(b));
     41 }
     42 
     43 static void help()
     44 {
     45     const char
     46             *b =        "-------------------------------------------------------------------------------
    "
     47                         "SIP Library test process - sipserver v 1.0 (June 13, 2014)
    
    "
     48                         "Current test Register method,only number 6 7 8 9 is useful
    
    "
     49                         "Author: 程序人生
    
    "
     50                         "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125
    
    "
     51                         "-------------------------------------------------------------------------------
    "
     52                         "
    "
     53                         "              0:Invite
    "
     54                         "              1:Ack
    "
     55                         "              2:Message
    "
     56                         "              3:Bye
    "
     57                         "              4:Subscribe
    "
     58                         "              5:CallMessage  unused
    "
     59                         "              6:start service
    "
     60                         "              7:stop service
    "
     61                         "              8:clear scream
    "
     62                         "              9:exit
    "
     63                         "-------------------------------------------------------------------------------
    "
     64                         "
    ";
     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 
    ");
     96                 usage();
     97                 return EXIT_FAILURE;
     98             }
     99             }
    100         }
    101     }
    102     else
    103     {
    104         fprintf(stderr, "Illegal argument 
    ");
    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的接口实现,有空再整理。

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

    欢迎技术交流沟通,转载请注明出处并保持作品的完整性。 作者:程序人生 qq1269122125
  • 相关阅读:
    Beta 冲刺day 6
    Beta冲刺day5
    Beta冲刺day4
    Beta 冲刺day3
    Beta 冲刺day2
    Beta冲刺day1
    Beta预备
    城市安全风险管理项目Postmortem结果
    项目总结
    Alpha冲刺置顶随笔
  • 原文地址:https://www.cnblogs.com/qq1269122125/p/3941172.html
Copyright © 2020-2023  润新知