zoukankan      html  css  js  c++  java
  • 基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3966794.html。

    上章节讲解了讲解一个用eXosip2库实现的Demo 程序。Demo讲的是注册的过程,因为篇幅比较长,再分一节写。本节是上一节的继续,主要实现UAC用eXosip2库实现的Demo 程序。本节讲的比较全面,处理实现注册问题还添加了注销和刷新注册的过程。刷新相当于心跳的功能。注意这个函数eXosip_default_action()实现在sip中401和407错误类型的eXosip2库的自动处理。网上有的人问注册报文发送后,只收到401返回码。这是对SIP注册不了解造成的。至于这个过程在前面注册理论部分已经讲解。我也尝试不用eXosip_default_action()这个函数,我自己发送鉴权信息,可惜没成功,不知道什么原因,有时返回200OK,有时不返回,所以还是用了eXosip_default_action()这个函数,让401的响应报文由eXosip2库去发送。

    1.eXosip2 API介绍

    本章中要用的eXosip2库的API做个简单的介绍和使用方法

    1.1 初始化库

    在使用eXosip2前你需要初始化eXosip环境和libeXosip2.so库,这一步必须在所有使用之前完成。

     1     #include <eXosip2/eXosip.h>
     2     //库处理结果
     3     int result = OSIP_SUCCESS;
     4     //初始化库
     5     if (OSIP_SUCCESS != (result = eXosip_init()))
     6     {
     7         printf("eXosip_init failure.
    ");
     8         return 1;
     9     }
    10     cout << "eXosip_init success." << endl;
    11     //监听
    12     if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT,
    13             AF_INET, 0))
    14     {
    15         printf("eXosip_listen_addr failure.
    ");
    16                 eXosip_quit ();
    17         return 1;
    18     }                        

    初始化完成之后,用户就可以发送SIP消息和等待接受SIP事件了。

    1.2 接受事件

    初始化eXosip2库后,主服务程序就可以接受事件并处理事件了,下面是一些从eXosip2协议栈接受处理事件的实例代码。

     1         //开启循环消息,实际应用中可以开启多线程同时接收信号
     2     eXosip_event_t* osipEventPtr = NULL;
     3 
     4     while (true)
     5     {
     6         // Wait the osip event.
     7         osipEventPtr = ::eXosip_event_wait(0, 200);
     8                 eXosip_lock();
     9         //一般处理401/407采用库默认处理
    10         eXosip_default_action(osipEventPtr);
    11         eXosip_unlock();
    12         // If get nothing osip event,then continue the loop.
    13         if (NULL == osipEventPtr)
    14         {
    15             continue;
    16         }
    17         // 事件处理
    18 
    19         switch (osipEventPtr->type)
    20         {
    21         //需要继续验证REGISTER是什么类型
    22         case EXOSIP_REGISTRATION_NEW:
    23         {
    24             //注册事件处理
    25         }
    26             break;
    27         case EXOSIP_MESSAGE_NEW:
    28         {
    29                 //消息事件处理
    30         }
    31             break;
    32             case XXXXX:
    33         {
    34                 //事件处理
    35         }
    36             break;
    37            case XXXXX:
    38         {
    39                 //事件处理
    40         }
    41             break;
    42         default:
    43             cout << "未处理消息 : " << osipEventPtr->type<<endl;
    44             break;
    45         }
    46         eXosip_event_free(osipEventPtr);
    47         osipEventPtr = NULL;                    

    实际在应用的时候为了提高服务的并发性,一般并不用上面这种服务方式,因为上面这样,如果接受到某个事件,而这个事件的处理事件非常长的话,会影响效率,导致其他事件阻塞等待,得不到即使处理。所以一般采用并发服务器的设计思想,即在接受到一个事件后,分配一个线程来处理。当然如果想效率更高,想节省创建线程的时间,可以在系统一起动后,分配一定大小的线程池,有事件到来的话,直接从线程池中获取线程处理。

    1.3 消息分析

    每个UAC或者UAS发送一个SIP信息后,相对应的UAS或者UAC都会接受到响应的,即事件。每个事件包含两个部分,一个是request和response。request即是这个事件的请求报文, 而response是本次会话建立过程中,最后一次响应请求的报文。用户可以从获取的消息中,分析出message并且获取SIP头部,保存成用户自己的数据形式。下面实例获取expires头部内容。

    1     osip_header_t* header = NULL;
    2     osip_message_header_get_byname(request, "expires", 0, &header);
    3     if (NULL != header && NULL != header->hvalue)
    4     {
    5            ......
    6     }
    7     

    2.UAC代码实例 

      1 /*
      2  ===============================================================
      3  GBT28181 基于eXosip2,osip库实现注册UAC功能
      4  作者:程序人生
      5  博客地址:http://blog.csdn.net/hiwubihe
      6  QQ:1269122125
      7  注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
      8  ================================================================
      9  */
     10 
     11 #include <iostream>
     12 #include <string>
     13 #include <sstream>
     14 #include <osipparser2/osip_message.h>
     15 #include <osipparser2/osip_parser.h>
     16 #include <osipparser2/osip_port.h>
     17 
     18 #include <eXosip2/eXosip.h>
     19 #include <eXosip2/eX_setup.h>
     20 #include <eXosip2/eX_register.h>
     21 #include <eXosip2/eX_options.h>
     22 #include <eXosip2/eX_message.h>
     23 #include <arpa/inet.h>
     24 #include <sys/types.h>
     25 #include <sys/socket.h>
     26 
     27 using namespace std;
     28 
     29 //本地监听IP
     30 #define LISTEN_ADDR ("192.168.50.57")
     31 //本地监听端口
     32 #define UACPORT ("5061")
     33 #define UACPORTINT (5061)
     34 //本UAC地址编码
     35 #define UACCODE ("100110000201000000")
     36 //本地UAC密码
     37 #define UACPWD ("12345")
     38 //远程UAS IP
     39 #define UAS_ADDR ("192.168.50.57")
     40 //远程UAS 端口
     41 #define UAS_PORT ("5060")
     42 //超时
     43 #define EXPIS 300
     44 
     45 //当前服务状态 1 已经注册 0 未注册
     46 static int iCurrentStatus;
     47 //注册成功HANDLE
     48 static int iHandle = -1;
     49 
     50 //SIP From/To 头部
     51 class CSipFromToHeader
     52 {
     53 public:
     54     CSipFromToHeader()
     55     {
     56     }
     57     ~CSipFromToHeader()
     58     {
     59     }
     60     void SetHeader(string addrCod, string addrI, string addrPor)
     61     {
     62         addrCode = addrCod;
     63         addrIp = addrI;
     64         addrPort = addrPor;
     65     }
     66     string GetFormatHeader()
     67     {
     68         std::stringstream stream;
     69         stream << "sip: " << addrCode << "@" << addrIp << ":" << addrPort;
     70         return stream.str();
     71     }
     72     //主机名称
     73     string GetCode()
     74     {
     75         std::stringstream stream;
     76         stream << addrCode;
     77         return stream.str();
     78     }
     79     //主机地址
     80     string GetAddr()
     81     {
     82         std::stringstream stream;
     83         stream << addrIp;
     84         return stream.str();
     85     }
     86     //端口
     87     string GetPort()
     88     {
     89         std::stringstream stream;
     90         stream << addrPort;
     91         return stream.str();
     92     }
     93 
     94 private:
     95     string addrCode;
     96     string addrIp;
     97     string addrPort;
     98 };
     99 
    100 //SIP Contract头部
    101 class CContractHeader: public CSipFromToHeader
    102 {
    103 public:
    104     CContractHeader()
    105     {
    106     }
    107     ~CContractHeader()
    108     {
    109     }
    110     void SetContractHeader(string addrCod, string addrI, string addrPor)
    111     {
    112         SetHeader(addrCod, addrI, addrPor);
    113     }
    114     string GetContractFormatHeader()
    115     {
    116 
    117         std::stringstream stream;
    118         stream << "<sip:" << GetCode() << "@" << GetAddr() << ":" << GetPort()
    119                 << ">";
    120         return stream.str();
    121     }
    122 };
    123 
    124 //发送注册信息
    125 int SendRegister(int& registerId, CSipFromToHeader &from, CSipFromToHeader &to,
    126         CContractHeader &contact, const string& userName, const string& pwd,
    127         const int expires, int iType)
    128 {
    129     cout << "=============================================" << endl;
    130     if (iType == 0)
    131     {
    132         cout << "注册请求信息:" << endl;
    133     }
    134     else if (iType == 1)
    135     {
    136         cout << "刷新注册信息:" << endl;
    137     }
    138     else
    139     {
    140         cout << "注销信息:" << endl;
    141     }
    142     cout << "registerId " << registerId << endl;
    143     cout << "from " << from.GetFormatHeader() << endl;
    144     cout << "to " << to.GetFormatHeader() << endl;
    145     cout << "contact" << contact.GetContractFormatHeader() << endl;
    146     cout << "userName" << userName << endl;
    147     cout << "pwd" << pwd << endl;
    148     cout << "expires" << expires << endl;
    149     cout << "=============================================" << endl;
    150     //服务器注册
    151     static osip_message_t *regMsg = 0;
    152     int ret;
    153 
    154     ::eXosip_add_authentication_info(userName.c_str(), userName.c_str(),
    155             pwd.c_str(), "MD5", NULL);
    156     eXosip_lock();
    157     //发送注册信息 401响应由eXosip2库自动发送
    158     if (0 == registerId)
    159     {
    160         // 注册消息的初始化
    161         registerId = ::eXosip_register_build_initial_register(
    162                 from.GetFormatHeader().c_str(), to.GetFormatHeader().c_str(),
    163                 contact.GetContractFormatHeader().c_str(), expires, &regMsg);
    164         if (registerId <= 0)
    165         {
    166             return -1;
    167         }
    168     }
    169     else
    170     {
    171         // 构建注册消息
    172         ret = ::eXosip_register_build_register(registerId, expires, &regMsg);
    173         if (ret != OSIP_SUCCESS)
    174         {
    175             return ret;
    176         }
    177         //添加注销原因
    178         if (expires == 0)
    179         {
    180             osip_contact_t *contact = NULL;
    181             char tmp[128];
    182 
    183             osip_message_get_contact(regMsg, 0, &contact);
    184             {
    185                 sprintf(tmp, "<sip:%s@%s:%s>;expires=0",
    186                         contact->url->username, contact->url->host,
    187                         contact->url->port);
    188             }
    189             //osip_contact_free(contact);
    190             //reset contact header
    191             osip_list_remove(&regMsg->contacts, 0);
    192             osip_message_set_contact(regMsg, tmp);
    193             osip_message_set_header(regMsg, "Logout-Reason", "logout");
    194         }
    195     }
    196     // 发送注册消息
    197     ret = ::eXosip_register_send_register(registerId, regMsg);
    198     if (ret != OSIP_SUCCESS)
    199     {
    200         registerId = 0;
    201     }eXosip_unlock();
    202 
    203     return ret;
    204 }
    205 
    206 //注册
    207 void Register()
    208 {
    209     if (iCurrentStatus == 1)
    210     {
    211         cout << "当前已经注册" << endl;
    212         return;
    213     }
    214     CSipFromToHeader stFrom;
    215     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    216     CSipFromToHeader stTo;
    217     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    218     CContractHeader stContract;
    219     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
    220     //发送注册信息
    221     int registerId = 0;
    222     if (0 > SendRegister(registerId, stFrom, stTo, stContract, UACCODE, UACPWD,
    223             3000, 0))
    224     {
    225         cout << "发送注册失败" << endl;
    226         return;
    227     }
    228     iCurrentStatus = 1;
    229     iHandle = registerId;
    230 }
    231 //刷新注册
    232 void RefreshRegister()
    233 {
    234     if (iCurrentStatus == 0)
    235     {
    236         cout << "当前未注册,不允许刷新" << endl;
    237         return;
    238     }
    239     CSipFromToHeader stFrom;
    240     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    241     CSipFromToHeader stTo;
    242     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    243     CContractHeader stContract;
    244     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
    245     //发送注册信息
    246     if (0 > SendRegister(iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,
    247             3000, 1))
    248     {
    249         cout << "发送刷新注册失败" << endl;
    250         return;
    251     }
    252 }
    253 //注销
    254 void UnRegister()
    255 {
    256     if (iCurrentStatus == 0)
    257     {
    258         cout << "当前未注册,不允许注销" << endl;
    259         return;
    260     }
    261     CSipFromToHeader stFrom;
    262     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    263     CSipFromToHeader stTo;
    264     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    265     CContractHeader stContract;
    266     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
    267     //发送注册信息
    268269     if (0 > SendRegister( iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,
    270             0, 2))
    271     {
    272         cout << "发送注销失败" << endl;
    273         return;
    274     }
    275     iCurrentStatus = 0;
    276     iHandle = -1;
    277 }
    278 static void help()
    279 {
    280     const char
    281             *b =
    282     "-------------------------------------------------------------------------------
    "
    283     "SIP Library test process - uac v 1.0 (June 13, 2014)
    
    "
    284     "SIP UAC端 注册,刷新注册,注销实现
    
    "
    285     "Author: 程序人生
    
    "
    286     "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125
    
    "
    287     "-------------------------------------------------------------------------------
    "
    288     "
    "
    289     "              0:Register
    "
    290     "              1:RefreshRegister
    "
    291     "              2:UnRegister
    "
    292     "              3:clear scream
    "
    293     "              4:exit
    "
    294     "-------------------------------------------------------------------------------
    "
    295     "
    ";
    296     fprintf(stderr, b, strlen(b));
    297     cout << "please select method :";
    298 }
    299 //服务处理线程
    300 void *serverHandle(void *pUser)
    301 {
    302     sleep(3);
    303     help();
    304     char ch = getchar();
    305     getchar();
    306     while (1)
    307     {
    308         switch (ch)
    309         {
    310         case '0':
    311             //注册
    312             Register();
    313             break;
    314         case '1':
    315             //刷新注册
    316             RefreshRegister();
    317             break;
    318         case '2':
    319             //注销
    320             UnRegister();
    321             break;
    322         case '3':
    323             if (system("clear") < 0)
    324             {
    325                 cout << "clear scream error" << endl;
    326                 exit(1);
    327             }
    328             break;
    329         case '4':
    330             cout << "exit sipserver......" << endl;
    331             getchar();
    332             exit(0);
    333         default:
    334             cout << "select error" << endl;
    335             break;
    336         }
    337         cout << "press any key to continue......" << endl;
    338         getchar();
    339         help();
    340         ch = getchar();
    341         getchar();
    342     }
    343     return NULL;
    344 }
    345 
    346 //事件处理线程
    347 void *eventHandle(void *pUser)
    348 {
    349     eXosip_event_t* osipEventPtr = (eXosip_event_t*) pUser;
    350     switch (osipEventPtr->type)
    351     {
    352     //需要继续验证REGISTER是什么类型
    353     case EXOSIP_REGISTRATION_SUCCESS:
    354     case EXOSIP_REGISTRATION_FAILURE:
    355     {
    356         cout<<"收到状态码:"<<osipEventPtr->response->status_code<<"报文"<<endl;
    357         if(osipEventPtr->response->status_code == 401)
    358         {
    359             cout<<"发送鉴权报文"<<endl;
    360         }
    361         else if(osipEventPtr->response->status_code == 200)
    362         {
    363             cout<<"接收成功"<<endl;
    364         }
    365         else
    366         {}
    367     }
    368         break;
    369     default:
    370         cout << "The sip event type that not be precessed.the event "
    371             "type is : " << osipEventPtr->type << endl;
    372         break;
    373     }
    374     eXosip_event_free(osipEventPtr);
    375     return NULL;
    376 }
    377 
    378 int main()
    379 {
    380     iCurrentStatus = 0;
    381     //库处理结果
    382     int result = OSIP_SUCCESS;
    383     //初始化库
    384     if (OSIP_SUCCESS != (result = eXosip_init()))
    385     {
    386         printf("eXosip_init failure.
    ");
    387         return 1;
    388     }
    389     cout << "eXosip_init success." << endl;
    390     eXosip_set_user_agent(NULL);
    391     //监听
    392     if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT,
    393             AF_INET, 0))
    394     {
    395         printf("eXosip_listen_addr failure.
    ");
    396         return 1;
    397     }
    398     //设置监听网卡
    399     if (OSIP_SUCCESS != eXosip_set_option(
    400     EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,
    401             LISTEN_ADDR))
    402     {
    403         return -1;
    404     }
    405     //开启服务线程
    406     pthread_t pthser;
    407     if (0 != pthread_create(&pthser, NULL, serverHandle, NULL))
    408     {
    409         printf("创建主服务失败
    ");
    410         return -1;
    411     }
    412     //事件用于等待
    413     eXosip_event_t* osipEventPtr = NULL;
    414     //开启事件循环
    415     while (true)
    416     {
    417         //等待事件 0的单位是秒,500是毫秒
    418         osipEventPtr = ::eXosip_event_wait(0, 200);
    419         //处理eXosip库默认处理
    420         {
    421             usleep(500 * 1000);
    422             eXosip_lock();
    423             //一般处理401/407采用库默认处理
    424             eXosip_default_action(osipEventPtr);
    425             eXosip_unlock();
    426         }
    427         //事件空继续等待
    428         if (NULL == osipEventPtr)
    429         {
    430             continue;
    431         }
    432         //开启线程处理事件并在事件处理完毕将事件指针释放
    433         pthread_t pth;
    434         if (0 != pthread_create(&pth, NULL, eventHandle, (void*) osipEventPtr))
    435         {
    436             printf("创建线程处理事件失败
    ");
    437             continue;
    438         }
    439         osipEventPtr = NULL;
    440     }
    441 }

    3.测试效果

     3.1 启动后

    3.2 输入0 注册

    可以看到第一次收到了401报文,库自动发送鉴权信息,然后收到了200OK报文。

    3.3 然后输入1刷新

    可以看到收到200OK报文

    3.4 输入2注销后

    收到200OK报文。并且可以看到expires为0了。

    至此eXosip2库实现注册,全部功能完成。

    欢迎技术交流沟通,转载请注明出处并保持作品的完整性。 作者:程序人生 qq1269122125
  • 相关阅读:
    网站设计
    keepass口令管理实践
    Wireshark实践
    SSH
    Nmap
    python模拟进程状态
    简易计算器
    2020-2021-1 20201210 《信息安全专业导论》第十周学习总结
    助教总结 第八章
    Chapter 7. Chapter 8.
  • 原文地址:https://www.cnblogs.com/qq1269122125/p/3966794.html
Copyright © 2011-2022 走看看