文档章节

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

程序人生
 程序人生
发布于 2014/09/11 18:15
字数 1648
阅读 293
收藏 0

原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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库去发送。

一.UAC代码main.cpp

 

 /*
 ===============================================================
 GBT28181 基于eXosip2,osip库实现注册UAC功能
 作者:程序人生
 博客地址:http://blog.csdn.net/hiwubihe
 QQ:1269122125
 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
 ================================================================
 */
#include <iostream>
#include <string>
#include <sstream>
#include <osipparser2/osip_message.h>
#include <osipparser2/osip_parser.h>
#include <osipparser2/osip_port.h>
#include <eXosip2/eXosip.h>
#include <eXosip2/eX_setup.h>
#include <eXosip2/eX_register.h>
#include <eXosip2/eX_options.h>
#include <eXosip2/eX_message.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
using namespace std;
//本地监听IP
#define LISTEN_ADDR ("192.168.50.57")
//本地监听端口
#define UACPORT ("5061")
#define UACPORTINT (5061)
//本UAC地址编码
#define UACCODE ("100110000201000000")
//本地UAC密码
#define UACPWD ("12345")
//远程UAS IP
#define UAS_ADDR ("192.168.50.57")
//远程UAS 端口
#define UAS_PORT ("5060")
//超时
#define EXPIS 300
//当前服务状态 1 已经注册 0 未注册
static int iCurrentStatus;
//注册成功HANDLE
static int iHandle = -1;
//SIP From/To 头部
class CSipFromToHeader
{
public:
    CSipFromToHeader()
    {
    }
    ~CSipFromToHeader()
    {
    }
    void SetHeader(string addrCod, string addrI, string addrPor)
    {
        addrCode = addrCod;
        addrIp = addrI;
        addrPort = addrPor;
    }
    string GetFormatHeader()
    {
        std::stringstream stream;
        stream << "sip: " << addrCode << "@" << addrIp << ":" << addrPort;
        return stream.str();
    }
    //主机名称
    string GetCode()
    {
        std::stringstream stream;
        stream << addrCode;
        return stream.str();
    }
    //主机地址
    string GetAddr()
    {
        std::stringstream stream;
        stream << addrIp;
        return stream.str();
    }
    //端口
    string GetPort()
    {
        std::stringstream stream;
        stream << addrPort;
        return stream.str();
    }
private:
    string addrCode;
    string addrIp;
    string addrPort;
};
//SIP Contract头部
class CContractHeader: public CSipFromToHeader
{
public:
    CContractHeader()
    {
    }
    ~CContractHeader()
    {
    }
    void SetContractHeader(string addrCod, string addrI, string addrPor)
    {
        SetHeader(addrCod, addrI, addrPor);
    }
    string GetContractFormatHeader()
    {
        std::stringstream stream;
        stream << "<sip:" << GetCode() << "@" << GetAddr() << ":" << GetPort()
                << ">";
        return stream.str();
    }
};
//发送注册信息
int SendRegister(int& registerId, CSipFromToHeader &from, CSipFromToHeader &to,
        CContractHeader &contact, const string& userName, const string& pwd,
        const int expires, int iType)
{
    cout << "=============================================" << endl;
    if (iType == 0)
    {
        cout << "注册请求信息:" << endl;
    }
    else if (iType == 1)
    {
        cout << "刷新注册信息:" << endl;
    }
    else
    {
        cout << "注销信息:" << endl;
    }
    cout << "registerId " << registerId << endl;
    cout << "from " << from.GetFormatHeader() << endl;
    cout << "to " << to.GetFormatHeader() << endl;
    cout << "contact" << contact.GetContractFormatHeader() << endl;
    cout << "userName" << userName << endl;
    cout << "pwd" << pwd << endl;
    cout << "expires" << expires << endl;
    cout << "=============================================" << endl;
    //服务器注册
    static osip_message_t *regMsg = 0;
    int ret;
    ::eXosip_add_authentication_info(userName.c_str(), userName.c_str(),
            pwd.c_str(), "MD5", NULL);
    eXosip_lock();
    //发送注册信息 401响应由eXosip2库自动发送
    if (0 == registerId)
    {
        // 注册消息的初始化
        registerId = ::eXosip_register_build_initial_register(
                from.GetFormatHeader().c_str(), to.GetFormatHeader().c_str(),
                contact.GetContractFormatHeader().c_str(), expires, &regMsg);
        if (registerId <= 0)
        {
            return -1;
        }
    }
    else
    {
        // 构建注册消息
        ret = ::eXosip_register_build_register(registerId, expires, &regMsg);
        if (ret != OSIP_SUCCESS)
        {
            return ret;
        }
        //添加注销原因
        if (expires == 0)
        {
            osip_contact_t *contact = NULL;
            char tmp[128];
            osip_message_get_contact(regMsg, 0, &contact);
            {
                sprintf(tmp, "<sip:%s@%s:%s>;expires=0",
                        contact->url->username, contact->url->host,
                        contact->url->port);
            }
            //osip_contact_free(contact);
            //reset contact header
            osip_list_remove(&regMsg->contacts, 0);
            osip_message_set_contact(regMsg, tmp);
            osip_message_set_header(regMsg, "Logout-Reason", "logout");
        }
    }
    // 发送注册消息
    ret = ::eXosip_register_send_register(registerId, regMsg);
    if (ret != OSIP_SUCCESS)
    {
        registerId = 0;
    }eXosip_unlock();
    return ret;
}
//注册
void Register()
{
    if (iCurrentStatus == 1)
    {
        cout << "当前已经注册" << endl;
        return;
    }
    CSipFromToHeader stFrom;
    stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    CSipFromToHeader stTo;
    stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    CContractHeader stContract;
    stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
    //发送注册信息
    int registerId = 0;
    if (0 > SendRegister(registerId, stFrom, stTo, stContract, UACCODE, UACPWD,
            3000, 0))
    {
        cout << "发送注册失败" << endl;
        return;
    }
    iCurrentStatus = 1;
    iHandle = registerId;
}
//刷新注册
void RefreshRegister()
{
    if (iCurrentStatus == 0)
    {
        cout << "当前未注册,不允许刷新" << endl;
        return;
    }
    CSipFromToHeader stFrom;
    stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    CSipFromToHeader stTo;
    stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    CContractHeader stContract;
    stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
    //发送注册信息
    if (0 > SendRegister(iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,
            3000, 1))
    {
        cout << "发送刷新注册失败" << endl;
        return;
    }
}
//注销
void UnRegister()
{
    if (iCurrentStatus == 0)
    {
        cout << "当前未注册,不允许注销" << endl;
        return;
    }
    CSipFromToHeader stFrom;
    stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    CSipFromToHeader stTo;
    stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);
    CContractHeader stContract;
    stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);
    //发送注册信息
    if (0 > SendRegister( iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,
            0, 2))
    {
        cout << "发送注销失败" << endl;
        return;
    }
    iCurrentStatus = 0;
    iHandle = -1;
}
static void help()
{
    const char
            *b =
    "-------------------------------------------------------------------------------\n"
    "SIP Library test process - uac v 1.0 (June 13, 2014)\n\n"
    "SIP UAC端 注册,刷新注册,注销实现\n\n"
    "Author: 程序人生\n\n"
    "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n"
    "-------------------------------------------------------------------------------\n"
    "\n"
    "              0:Register\n"
    "              1:RefreshRegister\n"
    "              2:UnRegister\n"
    "              3:clear scream\n"
    "              4:exit\n"
    "-------------------------------------------------------------------------------\n"
    "\n";
    fprintf(stderr, b, strlen(b));
    cout << "please select method :";
}
//服务处理线程
void *serverHandle(void *pUser)
{
    sleep(3);
    help();
    char ch = getchar();
    getchar();
    while (1)
    {
        switch (ch)
        {
        case '0':
            //注册
            Register();
            break;
        case '1':
            //刷新注册
            RefreshRegister();
            break;
        case '2':
            //注销
            UnRegister();
            break;
        case '3':
            if (system("clear") < 0)
            {
                cout << "clear scream error" << endl;
                exit(1);
            }
            break;
        case '4':
            cout << "exit sipserver......" << endl;
            getchar();
            exit(0);
        default:
            cout << "select error" << endl;
            break;
        }
        cout << "press any key to continue......" << endl;
        getchar();
        help();
        ch = getchar();
        getchar();
    }
    return NULL;
}
//事件处理线程
void *eventHandle(void *pUser)
{
    eXosip_event_t* osipEventPtr = (eXosip_event_t*) pUser;
    switch (osipEventPtr->type)
    {
    //需要继续验证REGISTER是什么类型
    case EXOSIP_REGISTRATION_SUCCESS:
    case EXOSIP_REGISTRATION_FAILURE:
    {
        cout<<"收到状态码:"<<osipEventPtr->response->status_code<<"报文"<<endl;
        if(osipEventPtr->response->status_code == 401)
        {
            cout<<"发送鉴权报文"<<endl;
        }
        else if(osipEventPtr->response->status_code == 200)
        {
            cout<<"接收成功"<<endl;
        }
        else
        {}
    }
        break;
    default:
        cout << "The sip event type that not be precessed.the event "
            "type is : " << osipEventPtr->type << endl;
        break;
    }
    eXosip_event_free(osipEventPtr);
    return NULL;
}
int main()
{
    iCurrentStatus = 0;
    //库处理结果
    int result = OSIP_SUCCESS;
    //初始化库
    if (OSIP_SUCCESS != (result = eXosip_init()))
    {
        printf("eXosip_init failure.\n");
        return 1;
    }
    cout << "eXosip_init success." << endl;
    eXosip_set_user_agent(NULL);
    //监听
    if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT,
            AF_INET, 0))
    {
        printf("eXosip_listen_addr failure.\n");
        return 1;
    }
    //设置监听网卡
    if (OSIP_SUCCESS != eXosip_set_option(
    EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,
            LISTEN_ADDR))
    {
        return -1;
    }
    //开启服务线程
    pthread_t pthser;
    if (0 != pthread_create(&pthser, NULL, serverHandle, NULL))
    {
        printf("创建主服务失败\n");
        return -1;
    }
    //事件用于等待
    eXosip_event_t* osipEventPtr = NULL;
    //开启事件循环
    while (true)
    {
        //等待事件 0的单位是秒,500是毫秒
        osipEventPtr = ::eXosip_event_wait(0, 200);
        //处理eXosip库默认处理
        {
            usleep(500 * 1000);
            eXosip_lock();
            //一般处理401/407采用库默认处理
            eXosip_default_action(osipEventPtr);
            eXosip_unlock();
        }
        //事件空继续等待
        if (NULL == osipEventPtr)
        {
            continue;
        }
        //开启线程处理事件并在事件处理完毕将事件指针释放
        pthread_t pth;
        if (0 != pthread_create(&pth, NULL, eventHandle, (void*) osipEventPtr))
        {
            printf("创建线程处理事件失败\n");
            continue;
        }
        osipEventPtr = NULL;
    }
}

二.测试效果

 1.启动后

2.输入0 注册后,可以看到第一次收到了401报文,库自动发送鉴权信息,然后收到了200OK报文。

3.然后输入1,刷新后,可以看到收到200OK报文

4.输入2,注销后。收到200OK报文。并且可以看到expires为0了。

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

欢迎技术交流沟通,转载请注明出处并保持作品的完整性。 作者:程序人生 qq1269122125

© 著作权归作者所有

程序人生
粉丝 2
博文 7
码字总数 8911
作品 0
合肥
程序员
私信 提问
Osip2扩展协议集--eXosip

eXosip是Osip2的一个扩展协议集,它部分封装了Osip2协议栈,使得它更容易被使用。它实现了作为单个SIP终端的大部分功能,如register、call、subseription等。 eXosip2使用UDP socket套接字实...

匿名
2011/06/12
3.2K
2
GNU SIP Witch 1.8.0 发布,电话呼叫服务器

GNU SIP Witch 1.8.0 改进内容包括: Support for systemd init. Multi-protocol context aware when built with exosip2 4.x for concurrent TCP/UDP/TLS sip sessions in a single server ......

oschina
2013/09/09
1K
7
NGN学习笔记5——IMS技术

1.移动网络的发展--引子 20世纪80年代,商业性移动通信网络得到发展 第一代移动通信系统:TACS、NMT等模拟系统 第二代移动通信系统:GSM、IS-95、DECT、IS-136等数字系统,目前建设的2G移动网...

AlphaJay
2010/05/31
2.2K
0
全网第一篇SIP协议之GB28181注册(JAVA版本)

鉴于网上大部分关于SIP注册服务器编写都是C/C++/python,故开此贴,JAVA实现也贴出分享 GB28181定义了了 基于SIP架构的 视频监控互联规范,而对于多数私有协议实现的监控系统如果想接入SIP架...

沧海一刀
2018/11/22
0
0
NGN学习笔记6——NGN的业务提供技术

1.NGN业务的基本概念 1)定义: 下一代网络的根本目标是提供业务,业务可以被定义为一种软件应用,能够向用户提供有用的、完善的功能。它通过分布在网络中的多个计算元素上的软件组件的交互来...

AlphaJay
2010/05/31
689
0

没有更多内容

加载失败,请刷新页面

加载更多

texlive安装

Installing to: D:/bin/texlive/texlive/2019Installing [001/307, time/total: ??:??/??:??]: adobemapping [2130k]Installing [002/307, time/total: 00:03/08:57]: ae [84k]Installing......

MtrS
今天
2
0
运维规范

命名规范 发布流程 监控告警 故障定位 状态 日志 监控

以谁为师
今天
2
0
约瑟夫环(报数游戏)java实现

开端 公司组织考试,一拿到考题,就是算法里说的约瑟夫环,仔细想想 以前老师将的都忘了,还是自己琢磨把~ package basic.gzy;import java.util.Iterator;import java.util.LinkedList;...

无极之岚
今天
3
0
Kernel字符设备驱动框架

Linux设备分为三大类:字符设备,块设备和网络设备,这三种设备基于不同的设备框架。相较于块设备和网络设备,字符设备在kernel中是最简单的,也是唯一没有基于设备基础框架(device结构)的...

yepanl
今天
3
0
Jenkins 中文本地化的重大进展

本文首发于:Jenkins 中文社区 我从2017年开始,参与 Jenkins 社区贡献。作为一名新成员,翻译可能是帮助社区项目最简单的方法。 本地化的优化通常是较小的改动,你无需了解项目完整的上下文...

Jenkins中文社区
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部