基于GBT28181:SIP协议组件开发-----------第四篇SIP注册流程eXosip2实现(一)
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3945294.html。
上章节讲解了利用自主开发的组件SIP组件libGBT28181SipComponent.so实现Linux 32平台的UAS和UAC,因为该组件采用很多新的技术,所以采用该组件效率无疑是很高的。但是对于想学习SIP协议,或者想了解eXosip2开发流程的程序员,是不能从根本上了解学习的。因为所有的功能都封装在libGBT28181SipComponent.so中。本讲将讲解一个用eXosip2库实现的Demo 程序。该Demo中包括UAS和UAC的实现。当然Demo实现比较粗糙,主要目的就是讲解eXosip2库的用法。该Demo讲的也是注册的过程,注册的流程在上一节已经有了详细的讲解,再次不赘述。源代码不多,直接上代码。
一.源代码UAS main.cpp
/*
===============================================================
GBT28181 SIP组件libGBT28181SipComponent.so注册实现
作者:程序人生
博客地址: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; #define LISTEN_ADDR ("192.168.50.57")
#define UASPORT (5060) //该系数是由UAS维护的,UAS在接收到UAC的未鉴权报文后,给UAC回复401,在该报文中必须要带相关认证系数和认证方法
//UAS赋值的认证随机数
#define NONCE "9bd055"
//UAS默认加密算法
#define ALGORITHTHM "MD5" //SIP From头部
class CSipFromHeader
{
public:
CSipFromHeader()
{
}
~CSipFromHeader()
{
}
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 GetRealName()
{
std::stringstream stream;
stream << addrIp;
return stream.str();
}
private:
string addrCode;
string addrIp;
string addrPort;
}; //SIP Contract头部
class CContractHeader: public CSipFromHeader
{
public:
CContractHeader()
{
}
~CContractHeader()
{
}
void SetContractHeader(string addrCod, string addrI, string addrPor,
int expire)
{
SetHeader(addrCod, addrI, addrPor);
expires = expire;
}
string GetContractFormatHeader(bool bExpires)
{
if (!bExpires)
{
return GetFormatHeader();
}
else
{
string sTmp = GetFormatHeader();
std::stringstream stream;
stream << ";" << "expires=" << expires;
sTmp += stream.str();
return sTmp;
} }
private:
int expires;
}; struct SipContextInfo
{
//Sip层返回的请求的标志 响应时返回即可
int sipRequestId;
//维护一次注册
string callId;
//消息所属的功能方法名字符串
string method;
//地址编码@域名或IP地址:连接端口,例如sip:1111@127.0.0.1:5060
CSipFromHeader from;
//地址编码@域名或IP地址:连接端口,例如sip:1111@127.0.0.1:5060
CSipFromHeader proxy;
//地址编码@域名或IP地址:连接端口,例如sip:1111@127.0.0.1:5060
CContractHeader contact;
//消息内容,一般为DDCP消息体XML文档,或者具体协议帧要求的其他字符串文本
string content;
//响应状态信息
string status;
//超时,时间单位为秒
int expires;
}; struct SipAuthInfo
{
//平台主机名
string digestRealm;
//平台提供的随机数
string nonce;
//用户名
string userName;
//密码
string response;
//“sip:平台地址”,不需要uac赋值
string uri;
//加密算法MD5
string algorithm;
}; struct sipRegisterInfo
{
SipContextInfo baseInfo;
SipAuthInfo authInfo;
bool isAuthNull;
}; void parserRegisterInfo(osip_message_t*request, int iReqId,
sipRegisterInfo ®Info)
{
std::stringstream stream;
regInfo.baseInfo.method = request->sip_method;
regInfo.baseInfo.from.SetHeader(request->from->url->username,
request->from->url->host, request->from->url->port);
regInfo.baseInfo.proxy.SetHeader(request->to->url->username,
request->to->url->host, request->to->url->port);
//获取expires
osip_header_t* header = NULL;
{
osip_message_header_get_byname(request, "expires",
, &header);
if (NULL != header && NULL != header->hvalue)
{
regInfo.baseInfo.expires = atoi(header->hvalue);
}
}
//contact字段
osip_contact_t* contact = NULL;
osip_message_get_contact(request, , &contact);
if (NULL != contact)
{
regInfo.baseInfo.contact.SetContractHeader(contact->url->username,
contact->url->host, contact->url->port,
regInfo.baseInfo.expires);
}
//注册返回 由发送方维护的请求ID 接收方接收后原样返回即可
regInfo.baseInfo.sipRequestId = iReqId;
//CALL_ID
{
stream.str("");
stream << request->call_id->number;
regInfo.baseInfo.callId = stream.str();
}
//解析content消息
osip_body_t * body = NULL;
osip_message_get_body(request, , &body);
if (body != NULL)
{
stream.str("");
stream << body->body;
regInfo.baseInfo.content = stream.str();
}
//鉴权信息
osip_authorization_t* authentication = NULL;
{
osip_message_get_authorization(request, , &authentication);
if (NULL == authentication)
{
regInfo.isAuthNull = true;
}
else
{
regInfo.isAuthNull = false;
stream.str("");
stream << authentication->username;
regInfo.authInfo.userName = stream.str();
stream.str("");
stream << authentication->algorithm;
regInfo.authInfo.algorithm = stream.str();
stream.str("");
stream << authentication->realm;
regInfo.authInfo.digestRealm = stream.str();
stream.str("");
stream << authentication->nonce;
regInfo.authInfo.nonce = stream.str();
stream.str("");
stream << authentication->response;
regInfo.authInfo.response = stream.str();
stream.str("");
stream << authentication->uri;
regInfo.authInfo.uri = stream.str();
}
}
authentication = NULL;
} //打印接收到的响应报文
void printRegisterPkt( sipRegisterInfo&info)
{
cout<<"接收到报文:"<<endl;
cout<<"=============================================="
"=================="<<endl;
cout << "method:" << info.baseInfo.method << endl;
cout << "from: " << info.baseInfo.from.GetFormatHeader() << endl;
cout << "to:" << info.baseInfo.proxy.GetFormatHeader() << endl;
cout << "contact:" << info.baseInfo.contact.GetContractFormatHeader(false)
<< endl; //注册返回 由发送方维护的请求ID 接收方接收后原样返回即可
cout << "sipRequestId:" << info.baseInfo.sipRequestId << endl;
//CALL_ID
cout << "CallId:" << info.baseInfo.callId << endl;
//解析content消息
cout << "body:" << info.baseInfo.content << endl;
//获取expires
cout << "expires:" << info.baseInfo.expires << endl;
//鉴权信息
if (info.isAuthNull)
{
cout << "当前报文未提供鉴权信息!!!" << endl;
}
else
{
cout << "当前报文鉴权信息如下:" << endl;
cout << "username:" << info.authInfo.userName << endl;
cout << "algorithm:" << info.authInfo.algorithm << endl;
cout << "Realm:" << info.authInfo.digestRealm << endl;
cout << "nonce:" << info.authInfo.nonce << endl;
cout << "response:" << info.authInfo.response << endl;
cout << "uri:" << info.authInfo.uri << endl;
}
cout<<"=================================================="
"=============="<<endl;
return;
}
void sendRegisterAnswer( sipRegisterInfo&info)
{
osip_message_t* answer = NULL;
int iStatus;
if (info.isAuthNull)
{
iStatus = ;
}
else
{
iStatus = ;
}eXosip_lock();
{
int result = ::eXosip_message_build_answer(info.baseInfo.sipRequestId,
iStatus, &answer);
if (iStatus == )
{
//由SIP库生成认证方法和认证参数发送客户端
std::stringstream stream;
string nonce=NONCE;
string algorithm=ALGORITHTHM;
stream << "Digest realm=\"" << info.baseInfo.from.GetRealName()
<< "\",nonce=\"" << nonce
<< "\",algorithm=" << algorithm; osip_message_set_header(answer, "WWW-Authenticate",
stream.str().c_str());
cout<<"======================================================="
"========="<<endl;
cout<<"发送401报文"<<endl;
cout<<"========================================================"
"========"<<endl;
}
else if (iStatus == )
{
osip_message_set_header(answer, "Contact",
info.baseInfo.contact.GetContractFormatHeader(true).c_str());
cout<<"========================================================="
"======="<<endl;
cout<<"发送200报文"<<endl;
cout<<"=========================================================="
"======"<<endl;
//string_t b = "<sip: 100110000101000000@192.168.31.18:5061>;expires=600";
//osip_message_set_header(answer, "Contact", b.c_str());
}
else
{
//Do nothing
} if (OSIP_SUCCESS != result)
{
::eXosip_message_send_answer(info.baseInfo.sipRequestId, , NULL);
}
else
{
//发送消息体
::eXosip_message_send_answer(info.baseInfo.sipRequestId, iStatus,
answer);
}
if ( == info.baseInfo.expires)
{
eXosip_register_remove(info.baseInfo.sipRequestId);
}
}eXosip_unlock();
}
void OnRegister(eXosip_event_t *osipEvent)
{
sipRegisterInfo regInfo;
parserRegisterInfo(osipEvent->request, osipEvent->tid, regInfo);
//打印报文
printRegisterPkt(regInfo);
//发送应答报文
sendRegisterAnswer(regInfo); } int main()
{ int result = OSIP_SUCCESS;
// init exosip.
if (OSIP_SUCCESS != (result = eXosip_init()))
{
printf("eXosip_init failure.\n");
return ;
}
cout << "eXosip_init success." << endl;
//
// if (null_ptr != this->receiveSipMessageCallback || null_ptr
// != this->sendSipMessageCallback)
// {
// if (OSIP_SUCCESS != (result = ::eXosip_set_cbsip_message(
// &Sip::MessageCallback)))
// {
// return;
// }
// }
eXosip_set_user_agent(NULL); if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UASPORT, AF_INET,
))
{
printf("eXosip_listen_addr failure.\n");
return ;
} if (OSIP_SUCCESS != eXosip_set_option(
EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,
LISTEN_ADDR))
{
return -;
}
//开启循环消息,实际应用中可以开启多线程同时接收信号
eXosip_event_t* osipEventPtr = NULL; while (true)
{
// Wait the osip event.
osipEventPtr = ::eXosip_event_wait(, );// 0的单位是秒,500是毫秒
// If get nothing osip event,then continue the loop.
if (NULL == osipEventPtr)
{
continue;
}
// 事件处理 switch (osipEventPtr->type)
{ //需要继续验证REGISTER是什么类型
case EXOSIP_REGISTRATION_NEW:
OnRegister(osipEventPtr);
break;
case EXOSIP_MESSAGE_NEW:
{
if (!strncmp(osipEventPtr->request->sip_method, "REGISTER",
strlen("REGISTER")))
{
OnRegister(osipEventPtr);
}
else if (!strncmp(osipEventPtr->request->sip_method, "MESSAGE",
strlen("MESSAGE")))
{
//
}
}
break;
default:
cout
<< "The sip event type that not be precessed.the event "
"type is : "
<< osipEventPtr->type;
break;
}
//ProcessSipEvent(this->osipEventPtrParam);
eXosip_event_free(osipEventPtr);
osipEventPtr = NULL;
} return ;
}
二.UAC源代码
参看下一篇 基于GBT28181:SIP协议组件开发-----------第四篇SIP注册流程eXosip2实现(二)
三.测试效果
1.UAS启动后,接受到报文效果

2.UAS发送401回复报文

3.UAS接受到带鉴权报文

4.UAS回复200OK

基于GBT28181:SIP协议组件开发-----------第四篇SIP注册流程eXosip2实现(一)的更多相关文章
- 基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3941172.html,qq:1269122125. 上两章节简要的 ...
- 基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3966794.html. 上章节讲解了讲解一个用eXosip2库实现 ...
- 基于GBT28181:SIP协议组件开发-----------第一篇环境搭建
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3930018.html,qq:1269122125. SIP协议在安 ...
- 基于GBT28181:SIP协议组件开发-----------第二篇SIP组件开发原理
原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3937590.html,qq:1269122125. 上一节中讲的S ...
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl
原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经 ...
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡 CompositeControl 后篇 --事件冒泡 系列文章链接: ASP.NET ...
- 基于vue的新组件开发
前天完成了一个新组件的开发,做的过程也是各种遇到问题,彻底弄懂了slot,巩固了一些flex布局和jquery的知识,比起自己第一次做组件开发,现在已经是能够下手做,遇到问题解决问题,还算有进步. 但 ...
- ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第四篇:传递表单数据
摘要 本文将完成我们“MVC公告发布系统”的公告发布功能,以此展示在ASP.NET MVC中如何传递处理表单的数据. 前言 通过前几篇文章,我们已经能比较自如的使用ASP.NET ...
- tornado 基于MongoDB存储 session组件开发
1.开发伊始 根据源码中RequestHandler类中发现__init__函数中会调用自身initialize函数,此函数中为pass,即可以围绕initialize开发一系列的组件 2.开发实现 ...
随机推荐
- 【转】eclipse -- the project was not built due to a resource exists with a different case...
原文网址:http://blog.csdn.net/mylinx/article/details/44280563 进行编码时,工程前面莫名有个红X,正当百思不得其解时,发现在[problems]下有 ...
- 【转】Android中设置TextView的颜色setTextColor
原文网址:http://www.cnblogs.com/myphoebe/archive/2012/01/06/2314728.html android中设置TextView的颜色有方法setText ...
- 后缀数组:SPOJ SUBST1 - New Distinct Substrings
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- supesite 连 discuz 论坛记录
上一篇,网站supesite里 有 config.php 这里记录访问地址,到时候可以更改这里变更域名或者外网地址. 这里同样也是 下载discuz,解压,bbs 下的文件为有效的内容,放到supe ...
- hdu 4579 博弈+区间dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4597 #include <cstdio> #include <cstring> ...
- [转载]Linux服务器性能评估与优化
转载自:Linux服务器性能评估与优化 一.影响Linux服务器性能的因素 1. 操作系统级 CPU 内存 磁盘I/O带宽 网络I/O带宽 2. 程序应用级 二.系统性能评估标准 影响性 ...
- 348. Design Tic-Tac-Toe
提示给的太直白了.. 比如player 1占据了(0,1),那么row[0]++ col[1]++ 表示第一行有1个O,第一列有1个X,假设PLAYER 1最终在第一行连成一排,那最终row[0] = ...
- boost库在工作(32)网络服务端之二
在这个例子里,服务器对象主要使用boost::asio::io_service对象,这个对象主要用来构造异步接收数据使用,接着定义boost::asio::ip::tcp::acceptor对象,这个 ...
- STM8S 独立看门狗配置及使用
//独立看门口的时钟来源 内部低速时钟 128khz 除以2 即64khz //选择 IWDG_Prescaler_128 //64/128 =0.5 khz 2ms周期 #define IWDG_5 ...
- Android 网络框架--Retrofit
1.导入Jar包 compile 'com.google.code.gson:gson:2.8.0' compile 'com.squareup.retrofit2:retrofit:2.1.0' c ...