原创文章,引用请保证原文完整性,尊重作者劳动,原文地址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, ®Msg);
if (registerId <= 0)
{
return -1;
}
}
else
{
// 构建注册消息
ret = ::eXosip_register_build_register(registerId, expires, ®Msg);
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(®Msg->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