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