原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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 &regInfo)
{
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实现(一)的更多相关文章

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

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3941172.html,qq:1269122125. 上两章节简要的 ...

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

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3966794.html. 上章节讲解了讲解一个用eXosip2库实现 ...

  3. 基于GBT28181:SIP协议组件开发-----------第一篇环境搭建

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3930018.html,qq:1269122125. SIP协议在安 ...

  4. 基于GBT28181:SIP协议组件开发-----------第二篇SIP组件开发原理

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3937590.html,qq:1269122125. 上一节中讲的S ...

  5. ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl

    原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经 ...

  6. ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡

    原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡 CompositeControl  后篇 --事件冒泡 系列文章链接: ASP.NET ...

  7. 基于vue的新组件开发

    前天完成了一个新组件的开发,做的过程也是各种遇到问题,彻底弄懂了slot,巩固了一些flex布局和jquery的知识,比起自己第一次做组件开发,现在已经是能够下手做,遇到问题解决问题,还算有进步. 但 ...

  8. ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第四篇:传递表单数据

    摘要      本文将完成我们“MVC公告发布系统”的公告发布功能,以此展示在ASP.NET MVC中如何传递处理表单的数据. 前言      通过前几篇文章,我们已经能比较自如的使用ASP.NET ...

  9. tornado 基于MongoDB存储 session组件开发

    1.开发伊始 根据源码中RequestHandler类中发现__init__函数中会调用自身initialize函数,此函数中为pass,即可以围绕initialize开发一系列的组件 2.开发实现 ...

随机推荐

  1. dt dd 如何在同一行上

    <style> dl{clear:left;} dt,dd{float:left;} </style> <dl> <dt>test </dt> ...

  2. Data 语义学(1)

    一.Data Member 的绑定(The binding of Data Member) extern float x; class Point3d { public: Point3d( float ...

  3. HDU 1151 Air Raid(最小路径覆盖)

    题目大意: 有n个城市,m条道路,城市的道路是单向.  现在我们的伞兵要降落在城市里,然后我门的伞兵要搜索所有道路.问我们最少占领多少个城市就可以搜索所有的道路了. 我们可以沿着道路向前走到达另一个城 ...

  4. page-object使用(1)

    创建你的page 你必须做的第一件事情是创建你的page,这是一些包含了PageObject模块的简单的ruby类,请不要创建你自己的initialize方法,因为已经有一个存在而且不能被覆盖.如果你 ...

  5. Ubuntu频率较高的操作

    一.切换超级用户 由于 Ubuntu 是基于 Debian 的 linux 操作系统,在默认的情况下,是没有超级用户(superuser, root)的,但有些系统操作必须有超级用户的权限才能进行,如 ...

  6. SSL证书的分类(按功能)

    SSL证书的分类(按功能) 一.域名型证书 DV SSL DV SSL 证书是 Domain Validation SSL Certificate 英文全称的简写,翻译成中文是域名型 SSL证书 或 ...

  7. java中字节流和字符流的区别

    流分类: 1.Java的字节流   InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先.2.Java的字符流  Reader是所有读取字符串输入流的祖先,而 ...

  8. 【最长上升子序列】HDU 1087——Super Jumping! Jumping! Jumping!

    来源:点击打开链接 最长上升子序列的考察,是一个简单的DP问题.我们每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序 ...

  9. .net core4

  10. 提取HTML的正文类

    本文转载:http://blog.csdn.net/cjh200102/article/details/6824895 //2.提取html的正文 类 using System; using Syst ...