基于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
1 /*
2 ===============================================================
3 GBT28181 SIP组件libGBT28181SipComponent.so注册实现
4 作者:程序人生
5 博客地址:http://blog.csdn.net/hiwubihe
6 QQ:1269122125
7 注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!
8 ================================================================
9 */
10
11 #include <iostream>
12 #include <string>
13 #include <sstream>
14 #include <osipparser2/osip_message.h>
15 #include <osipparser2/osip_parser.h>
16 #include <osipparser2/osip_port.h>
17
18 #include <eXosip2/eXosip.h>
19 #include <eXosip2/eX_setup.h>
20 #include <eXosip2/eX_register.h>
21 #include <eXosip2/eX_options.h>
22 #include <eXosip2/eX_message.h>
23 #include <arpa/inet.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26
27 using namespace std;
28
29 #define LISTEN_ADDR ("192.168.50.57")
30 #define UASPORT (5060)
31
32
33 //该系数是由UAS维护的,UAS在接收到UAC的未鉴权报文后,给UAC回复401,在该报文中必须要带相关认证系数和认证方法
34 //UAS赋值的认证随机数
35 #define NONCE "9bd055"
36 //UAS默认加密算法
37 #define ALGORITHTHM "MD5"
38
39
40 //SIP From头部
41 class CSipFromHeader
42 {
43 public:
44 CSipFromHeader()
45 {
46 }
47 ~CSipFromHeader()
48 {
49 }
50 void SetHeader(string addrCod, string addrI, string addrPor)
51 {
52 addrCode = addrCod;
53 addrIp = addrI;
54 addrPort = addrPor;
55 }
56 string GetFormatHeader()
57 {
58 std::stringstream stream;
59 stream << "<sip: " << addrCode << "@" << addrIp << ":" << addrPort
60 << ">";
61 return stream.str();
62 }
63 //主机名称
64 string GetRealName()
65 {
66 std::stringstream stream;
67 stream << addrIp;
68 return stream.str();
69 }
70 private:
71 string addrCode;
72 string addrIp;
73 string addrPort;
74 };
75
76 //SIP Contract头部
77 class CContractHeader: public CSipFromHeader
78 {
79 public:
80 CContractHeader()
81 {
82 }
83 ~CContractHeader()
84 {
85 }
86 void SetContractHeader(string addrCod, string addrI, string addrPor,
87 int expire)
88 {
89 SetHeader(addrCod, addrI, addrPor);
90 expires = expire;
91 }
92 string GetContractFormatHeader(bool bExpires)
93 {
94 if (!bExpires)
95 {
96 return GetFormatHeader();
97 }
98 else
99 {
100 string sTmp = GetFormatHeader();
101 std::stringstream stream;
102 stream << ";" << "expires=" << expires;
103 sTmp += stream.str();
104 return sTmp;
105 }
106
107 }
108 private:
109 int expires;
110 };
111
112 struct SipContextInfo
113 {
114 //Sip层返回的请求的标志 响应时返回即可
115 int sipRequestId;
116 //维护一次注册
117 string callId;
118 //消息所属的功能方法名字符串
119 string method;
120 //地址编码@域名或IP地址:连接端口,例如sip:1111@127.0.0.1:5060
121 CSipFromHeader from;
122 //地址编码@域名或IP地址:连接端口,例如sip:1111@127.0.0.1:5060
123 CSipFromHeader proxy;
124 //地址编码@域名或IP地址:连接端口,例如sip:1111@127.0.0.1:5060
125 CContractHeader contact;
126 //消息内容,一般为DDCP消息体XML文档,或者具体协议帧要求的其他字符串文本
127 string content;
128 //响应状态信息
129 string status;
130 //超时,时间单位为秒
131 int expires;
132 };
133
134 struct SipAuthInfo
135 {
136 //平台主机名
137 string digestRealm;
138 //平台提供的随机数
139 string nonce;
140 //用户名
141 string userName;
142 //密码
143 string response;
144 //“sip:平台地址”,不需要uac赋值
145 string uri;
146 //加密算法MD5
147 string algorithm;
148 };
149
150 struct sipRegisterInfo
151 {
152 SipContextInfo baseInfo;
153 SipAuthInfo authInfo;
154 bool isAuthNull;
155 };
156
157 void parserRegisterInfo(osip_message_t*request, int iReqId,
158 sipRegisterInfo ®Info)
159 {
160 std::stringstream stream;
161 regInfo.baseInfo.method = request->sip_method;
162 regInfo.baseInfo.from.SetHeader(request->from->url->username,
163 request->from->url->host, request->from->url->port);
164 regInfo.baseInfo.proxy.SetHeader(request->to->url->username,
165 request->to->url->host, request->to->url->port);
166 //获取expires
167 osip_header_t* header = NULL;
168 {
169 osip_message_header_get_byname(request, "expires",
170 0, &header);
171 if (NULL != header && NULL != header->hvalue)
172 {
173 regInfo.baseInfo.expires = atoi(header->hvalue);
174 }
175 }
176 //contact字段
177 osip_contact_t* contact = NULL;
178 osip_message_get_contact(request, 0, &contact);
179 if (NULL != contact)
180 {
181 regInfo.baseInfo.contact.SetContractHeader(contact->url->username,
182 contact->url->host, contact->url->port,
183 regInfo.baseInfo.expires);
184 }
185 //注册返回 由发送方维护的请求ID 接收方接收后原样返回即可
186 regInfo.baseInfo.sipRequestId = iReqId;
187 //CALL_ID
188 {
189 stream.str("");
190 stream << request->call_id->number;
191 regInfo.baseInfo.callId = stream.str();
192 }
193 //解析content消息
194 osip_body_t * body = NULL;
195 osip_message_get_body(request, 0, &body);
196 if (body != NULL)
197 {
198 stream.str("");
199 stream << body->body;
200 regInfo.baseInfo.content = stream.str();
201 }
202 //鉴权信息
203 osip_authorization_t* authentication = NULL;
204 {
205 osip_message_get_authorization(request, 0, &authentication);
206 if (NULL == authentication)
207 {
208 regInfo.isAuthNull = true;
209 }
210 else
211 {
212 regInfo.isAuthNull = false;
213 stream.str("");
214 stream << authentication->username;
215 regInfo.authInfo.userName = stream.str();
216 stream.str("");
217 stream << authentication->algorithm;
218 regInfo.authInfo.algorithm = stream.str();
219 stream.str("");
220 stream << authentication->realm;
221 regInfo.authInfo.digestRealm = stream.str();
222 stream.str("");
223 stream << authentication->nonce;
224 regInfo.authInfo.nonce = stream.str();
225 stream.str("");
226 stream << authentication->response;
227 regInfo.authInfo.response = stream.str();
228 stream.str("");
229 stream << authentication->uri;
230 regInfo.authInfo.uri = stream.str();
231 }
232 }
233 authentication = NULL;
234 }
235
236 //打印接收到的响应报文
237 void printRegisterPkt( sipRegisterInfo&info)
238 {
239 cout<<"接收到报文:"<<endl;
240 cout<<"=============================================="
241 "=================="<<endl;
242 cout << "method:" << info.baseInfo.method << endl;
243 cout << "from: " << info.baseInfo.from.GetFormatHeader() << endl;
244 cout << "to:" << info.baseInfo.proxy.GetFormatHeader() << endl;
245 cout << "contact:" << info.baseInfo.contact.GetContractFormatHeader(false)
246 << endl;
247
248 //注册返回 由发送方维护的请求ID 接收方接收后原样返回即可
249 cout << "sipRequestId:" << info.baseInfo.sipRequestId << endl;
250 //CALL_ID
251 cout << "CallId:" << info.baseInfo.callId << endl;
252 //解析content消息
253 cout << "body:" << info.baseInfo.content << endl;
254 //获取expires
255 cout << "expires:" << info.baseInfo.expires << endl;
256 //鉴权信息
257 if (info.isAuthNull)
258 {
259 cout << "当前报文未提供鉴权信息!!!" << endl;
260 }
261 else
262 {
263 cout << "当前报文鉴权信息如下:" << endl;
264 cout << "username:" << info.authInfo.userName << endl;
265 cout << "algorithm:" << info.authInfo.algorithm << endl;
266 cout << "Realm:" << info.authInfo.digestRealm << endl;
267 cout << "nonce:" << info.authInfo.nonce << endl;
268 cout << "response:" << info.authInfo.response << endl;
269 cout << "uri:" << info.authInfo.uri << endl;
270 }
271 cout<<"=================================================="
272 "=============="<<endl;
273 return;
274 }
275 void sendRegisterAnswer( sipRegisterInfo&info)
276 {
277 osip_message_t* answer = NULL;
278 int iStatus;
279 if (info.isAuthNull)
280 {
281 iStatus = 401;
282 }
283 else
284 {
285 iStatus = 200;
286 }eXosip_lock();
287 {
288 int result = ::eXosip_message_build_answer(info.baseInfo.sipRequestId,
289 iStatus, &answer);
290 if (iStatus == 401)
291 {
292 //由SIP库生成认证方法和认证参数发送客户端
293 std::stringstream stream;
294 string nonce=NONCE;
295 string algorithm=ALGORITHTHM;
296 stream << "Digest realm=\"" << info.baseInfo.from.GetRealName()
297 << "\",nonce=\"" << nonce
298 << "\",algorithm=" << algorithm;
299
300 osip_message_set_header(answer, "WWW-Authenticate",
301 stream.str().c_str());
302 cout<<"======================================================="
303 "========="<<endl;
304 cout<<"发送401报文"<<endl;
305 cout<<"========================================================"
306 "========"<<endl;
307 }
308 else if (iStatus == 200)
309 {
310 osip_message_set_header(answer, "Contact",
311 info.baseInfo.contact.GetContractFormatHeader(true).c_str());
312 cout<<"========================================================="
313 "======="<<endl;
314 cout<<"发送200报文"<<endl;
315 cout<<"=========================================================="
316 "======"<<endl;
317 //string_t b = "<sip: 100110000101000000@192.168.31.18:5061>;expires=600";
318 //osip_message_set_header(answer, "Contact", b.c_str());
319 }
320 else
321 {
322 //Do nothing
323 }
324
325 if (OSIP_SUCCESS != result)
326 {
327 ::eXosip_message_send_answer(info.baseInfo.sipRequestId, 400, NULL);
328 }
329 else
330 {
331 //发送消息体
332 ::eXosip_message_send_answer(info.baseInfo.sipRequestId, iStatus,
333 answer);
334 }
335 if (0 == info.baseInfo.expires)
336 {
337 eXosip_register_remove(info.baseInfo.sipRequestId);
338 }
339 }eXosip_unlock();
340 }
341 void OnRegister(eXosip_event_t *osipEvent)
342 {
343 sipRegisterInfo regInfo;
344 parserRegisterInfo(osipEvent->request, osipEvent->tid, regInfo);
345 //打印报文
346 printRegisterPkt(regInfo);
347 //发送应答报文
348 sendRegisterAnswer(regInfo);
349
350 }
351
352 int main()
353 {
354
355 int result = OSIP_SUCCESS;
356 // init exosip.
357 if (OSIP_SUCCESS != (result = eXosip_init()))
358 {
359 printf("eXosip_init failure.\n");
360 return 1;
361 }
362 cout << "eXosip_init success." << endl;
363 //
364 // if (null_ptr != this->receiveSipMessageCallback || null_ptr
365 // != this->sendSipMessageCallback)
366 // {
367 // if (OSIP_SUCCESS != (result = ::eXosip_set_cbsip_message(
368 // &Sip::MessageCallback)))
369 // {
370 // return;
371 // }
372 // }
373 eXosip_set_user_agent(NULL);
374
375 if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UASPORT, AF_INET,
376 0))
377 {
378 printf("eXosip_listen_addr failure.\n");
379 return 1;
380 }
381
382 if (OSIP_SUCCESS != eXosip_set_option(
383 EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,
384 LISTEN_ADDR))
385 {
386 return -1;
387 }
388 //开启循环消息,实际应用中可以开启多线程同时接收信号
389 eXosip_event_t* osipEventPtr = NULL;
390
391 while (true)
392 {
393 // Wait the osip event.
394 osipEventPtr = ::eXosip_event_wait(0, 200);// 0的单位是秒,500是毫秒
395 // If get nothing osip event,then continue the loop.
396 if (NULL == osipEventPtr)
397 {
398 continue;
399 }
400 // 事件处理
401
402 switch (osipEventPtr->type)
403 {
404
405 //需要继续验证REGISTER是什么类型
406 case EXOSIP_REGISTRATION_NEW:
407 OnRegister(osipEventPtr);
408 break;
409 case EXOSIP_MESSAGE_NEW:
410 {
411 if (!strncmp(osipEventPtr->request->sip_method, "REGISTER",
412 strlen("REGISTER")))
413 {
414 OnRegister(osipEventPtr);
415 }
416 else if (!strncmp(osipEventPtr->request->sip_method, "MESSAGE",
417 strlen("MESSAGE")))
418 {
419 //
420 }
421 }
422 break;
423 default:
424 cout
425 << "The sip event type that not be precessed.the event "
426 "type is : "
427 << osipEventPtr->type;
428 break;
429 }
430 //ProcessSipEvent(this->osipEventPtrParam);
431 eXosip_event_free(osipEventPtr);
432 osipEventPtr = NULL;
433 }
434
435 return 0;
436 }
二.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库实现 ...
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl
第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经知道了,要开发自定义的控件一般继承三个基 类:Control,WebControl,还有一个就 ...
- Agv、Rgv 车辆控制调度系统开发第四篇
Agv.Rgv 车辆控制调度系统开发第四篇 车辆调度模拟器 前言 一.车辆模拟器是什么? 二.如何做模拟器 1.动作仿真模拟器 2.完全仿真模拟器 总结 下期预告 系列文章链接 其他文章 新篇章 前言 ...
- 基于Mozilla Thunderbird的扩展开发(四)---修改Thunderbird源代码实现自动保存附件...
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace ...
- SIP协议简介(一)之SIP基本的概述
本篇文章主要是对RFC3261翻译进行的,也包含着自己的一些理解.希望能给需要的人带来一些帮助 补充说明:RFC即Request For Comments(RFC),是一系列以编号排定的文件.文件收集 ...
- python基于什么语言-一种基于Python语言的EDA开发平台及其使用方法与流程
本发明涉及EDA开发的技术领域,尤其是指一种基于Python语言的EDA开发平台及其使用方法. 背景技术: 目前,主流的EDA设计语言Verilog HDL能实现完整的芯片硬件逻辑电路开发,但是其代码 ...
- python语言的编程模式_一种基于Python语言的EDA开发平台及其使用方法与流程
本发明涉及EDA开发的技术领域,尤其是指一种基于Python语言的EDA开发平台及其使用方法. 背景技术: 目前,主流的EDA设计语言Verilog HDL能实现完整的芯片硬件逻辑电路开发,但是其代码 ...
- uniapp中使用ucharts组件开发App中的折线图流程
uniapp中使用ucharts组件开发流程 官方ucharts地址 我是在uniapp使用echarts后发现在安卓手机app上不显示,所以使用ucharts来代替echarts 组件地址 在这里导 ...
最新文章
- svg animation应用之-描边效果
- QMouseEvent
- excel vba 调用webbrowser_Python杀死Excel?我只会用Python来增强Excel!
- maven 之 setting.xm 的配置详解、说明
- Cause: java.lang.IllegalArgumentException: No enum constant org.apache.ibatis.type.JdbcType.Date
- 【WCF】WCF服务库和WCF服务应用程序的区别
- bc显示小数点前的0
- python逐行读取txt文件-在python 3.4上逐行读取文本文件
- android framework 触摸屏事件传递
- 《转载》python爬虫实践之模拟登录
- WPF-21:WPF实现仿安卓的图案密码键盘(改进)
- project安装包_Microsoft project 2019软件功能介绍(附安装包)
- Android Builder模式
- python热身教程_[转载]技术教程-MayaPython教程二之Python
- 宝塔nginx自编译云锁web防护教程
- RK3399:HDMI输出固定频率与热插拔
- 吴恩达《机器学习》第四章:多元线性回归
- Python爬虫:js加密实例-有道翻译
- linux火车游戏,火车路路通安卓版下载-火车路路通手机版下载v1.0-Linux公社
- ZZNUOJ_C语言1123:最佳校友(附完整源码)