接上篇SIP协议栈OSIP分析:

https://blog.csdn.net/wwwyue1985/article/details/119520682

eXosip2基于OSIP,提供上层接口,版本也为2-3.1.0,仅供参考。

关于exosip 2

exosip的模块构成 2

关键数据结构说明 2

exosip的初始化 6

数据收发整体框架 8

exosip与上层应用以及osip之间的流程关系 10

数据结构体之间的关系 11

参考资料 12

一 关于exosip

使用sip协议建立多媒体会话是一个复杂的过程,exosip库开发的目的在于隐藏这种复杂性。正如它的名称所表示的,eXosip2 - the eXtended osip Library,它扩展了osip库,实现了一个简单的高层API。通过使用exosip,我们可以避免直接使用osip带来的困难。

需要注意,exosip并不是对osip的简单封装包裹,而是扩展。Osip专注于sip消息的解析,事务状态机的实现,而exosip则基于osip实现了call、options、register、publish等更倾向于功能性的接口。当然,这些实现都是依赖于底层osip库已有的功能的。

二 exosip的模块构成

1 底层连接管理

extl.c、extl_udp.c、extl_tcp.c、extl_dtls.c、extl_tls.c是与网络连接有关的文件。实现了连接的建立,数据的接收以及发送等相关的接口。其中,extl_udp.c为使用UDP连接的实现,extl_tcp.c为使用TCP连接的实现。Extl_dtls.c以及extl_tls.c都是使用安全socket连接的实现。

2内部功能模块实现

Jauth.c、jcall.c、jdialog.c、jevents.c、jnotify.c、jpublish.c、jreg.c、jrequest.c、jresponse.c、jsubscribe.c等文件实现了内部对一些模块的管理,这些模块正如其文件名所表示的,jauth.c主要是认证,jcall.c则是通话等等。

3 上层API封装实现

Excall_api.c、exinsubsription_api.c、exmessag_api.c、exoptions_api.c、expublish_api.c、exrefer_api.c、exregister_api.c、exsubsribtion_api.c这几个以api为后缀的文件,实现各个子模块的管理。应用程序可以调用这里提供的接口,方便的构造或者发送sip消息。

4 操作系统移植接口

Jpipe.c利用管道实现进程间通信机制。对于windows平台,这是通过模拟建立socket连接实现的,也就是在本机内部建立两个连接(使用本机地址),实现进程间通信。因为使用socket建立连接,本质上就是实现两个进程间的通信,只不过大部分情况下,这被用在网络上的两台设备之间。

5 其他

Inet_ntop.c实现ip地址的点分十进制与十六进制表示之间的转换。

Jcallback.c实现一堆回调函数,这些回调函数就是用来注册到osip库的。我们使用exosip库,就是避免直接使用osip库,因为一些工作exosip已经帮我们做了,所以这样一来,可以简化上层的实现。

Udp.c文件主要用来对通过UDP连接接收到的消息进行分类处理。

Exutilis.c文件实现一些杂项的函数。有ip地址到字符串之间的转换,域名的解析等一些辅助的功能函数。

Exconf.c文件实现了exosip的初始化相关的接口,包括后台任务的实现。实际上是“configuration api”的实现。

Exosip.c文件实现了与exconf.c文件相似的功能。比如管道的使用,exosip上事务的创建和查找,register和subscribe的更新,认证信息的处理等。

三 关键数据结构说明

1 eXtl_protocol

eXtl_protocol是为实现网络通信专门定义的一个数据结构,包括了变量和方法两部分。其中,变量包括了建立网络连接过程中使用的ip地址、端口等;方法部分封装了网络socket编程常用的系统调用接口。

代码中定义了四个该数据结构体的全局变量:eXtl_udp、eXtl_tcp、eXtl_tls以及eXtl_dtls。分别针对使用UDP、TCP以及安全加密连接进行了实现。

2 eXosip_call_t

Exosip_call_t定义了call相关的信息,包括call的id,call的dialogs,call上incoming的事务和outgoing的事务。另外,还包括了前向和后向指针,所以,所有的call可以通过该结构体串接起来。

3 eXosip_dialog_t

Exosip_dialog_t包含了dialog相关的信息。

4 eXosip_reg_t

用来管理Register模块。

5 eXosip_subscribe_t

用于管理subscribe模块。

6 eXosip_pub_t

用于管理publish模块。

7 eXosip_notify_t

用于管理notify模块。

8 jinfo_t

这个结构体关联了dialog、call、subscribe以及notify几个结构体。

9 eXosip_event_t

与event有关的结构体。这个结构体主要用来在应用层和exosip之间通信。Exosip在处理事务的过程中,如果需要将结果反馈给上层应用,则会生成如上结构类型的事件,并将其放到exosip的事件队列中。应用层会不断循环从事件队列中读取事件,然后进行应用层的处理。

10 eXosip_t

exosip_t是exosip中最重要的结构体之一。从上图可以看出,这个结构体比较大,其中包含了exosip中用到的各个子模块的结构。比如call、reg、pub等等。代码中定义了一个该结构类型的全局变量,通过该全局变量,就可以对exosip当前的状态进行掌控(许多相关的信息要么包含在该结构上,要么可以通过该结构找到)。

eXtl是eXtl_protocol类型的指针,保存了网络接口类。

J_osip保存了osip初始化时返回的osip结构体。

J_transactions一般是等待释放的事务。在事务经过osip处理完后,不再需要时,exosip会将其放在j_transactions上,等待释放。

四 exosip的初始化

Exosip的初始化有两部分组成,这主要是从使用exosip的角度看。首先是对exosip全局结构体变量的配置。这步通过调用接口eXosip_init完成。主要完成工作如下:

1 初始化条件变量和互斥信号量。

2 调用osip_init初始化osip库,并将生成osip结构体给exosip,同时也让osip的application_contexgt指针指向exosip,也就是二者相互指向。

3 调用eXosip_set_callbacks设置osip的回调函数,所以回调函数都是exosip自己实现。

4 调用jpipe创建通信用的pipe,之前已经说了,对于windows平台,是通过socket接口模拟实现的。

5 初始化初始化其上的事务和事件队列。主要,这不同于osip的事务和事件队列。

6 调用extl指向的结构体的init函数指针,初始化网络接口。

初始化完后,全局exosip结构在内存中的状态基本如下图:

其中的橘红色标识了初始化过程中涉及到的部分。

第二部分,就是在socket接口上进行监听。这步通过调用eXosip_listen_addr接口完成。主要完成工作如下:

1 将eXosip全局变量的eXtl指针指向eXtl_udp全局变量。这步在上图中已有体现。

2 根据参数,配置extl_protocol和exosip上有关ip端口地址等信息。另外,调用extl_udp的tl_open函数指针,完成在本机指定的端口上监听连接的工作。需要注意的是,虽然是监听,但是使用的UDP来建立连接的,所以消息的recv和发送在同一个socket上完成。在osip中设置的out_socket并不会起作用。

3 调用osip_thread_create创建exosip后台任务,用于驱动osip的状态机。(在osip中,在发送sip消息部分,提到将9个函数放到一个线程中执行,exosip就是这样做的)。

这部分工作完成后,内存状态如下图所示:

上图中浅绿色部分显示了这部分工作所作的配置。J_thread保存了任务的句柄。

下面展示了初始化的示例代码:

include <eXosip2/eXosip.h>int i;TRACE_INITIALIZE (6, stdout);i=eXosip_init();if (i!=0)return -1;i = eXosip_listen_addr (IPPROTO_UDP, NULL, port, AF_INET, 0);if (i!=0){eXosip_quit();fprintf (stderr, "could not initialize transport layer\n");return -1;}... then you have to send messages and wait for eXosip events...

这样,在初始化完成后,我们基本上完成了对内存中所用数据结构的配置,同时启动了一个后台任务负责osip状态机的驱动。

五 数据收发整体框架

1 接收过程

在初始化过程中我们创建了一个后台任务,现在可以看看这个后台任务都做了哪些操作。任务的执行函数为_eXosip_thread,在该接口中,循环不断的调用eXosip_execute。在每一次的eXosip_execute执行中,完成如下的工作:

  1. 首先计算出底层osip离当前时间最近的超时时间。也就是查看底层所有的超时事件,找出其中的最小值,然后将其与当前时间做差,结果就是最小的超时间隔了。这步是通过调用接口osip_timers_gettimeout完成的。主要检查osip全局结构体上的ict、ist、nict、nist以及ixt上所有事务的事件的超时时间。 如果ict事务队列上没有事件,则说明没有有效的数据交互存在,返回值为默认的一年,实际上就是让后面的接收接口死等。如果有事务队列上的事件的超时时间小于当前值,则说明已经超时了,需要马上处理,此时将超时时间清为零,并返回。
  2. 调用eXosip_read_message接口从底层接收消息并处理。如果返回-2,则任务退出。
  3. 执行osip的状态机。具体为执行osip_timers_ict(ist|nict|nist)_execute和osip_ict(ist|nict|nist)_execute这几个函数。最后还检查释放已经终结的call、registrations以及publications。
  4. 如果keep_alive设置了,则调用_eXosip_keep_alive检查发送keep_alive消息。

这样,当远端的终端代理发送sip消息过来时,会被之前创建的监听端口捕获(sip协议默认的端口为5060)。在调用eXosip_read_message接口时会将其接收上来。

接收上来的数据存放在buffer中交给接口_eXosip_handle_incoming_message来处理。在其中首先调用osip_parse进行消息的解析,这是osip的核心功能之一。数据解析后,会生成一个osip_event类型的事件。接着调用osip_message_fix_last_via_header将接收到该消息的ip地址和端口根据需要设置到数据头的via域中。这在消息返回时有可能发挥作用。为了能够让消息正确的被处理,调用osip_find_transaction_and_add_event接口将其添加到osip的事务队列上。处理在这之后发生了分叉,如果osip接纳了该事件,接口直接返回,因为这说明该事件在osip上已经有匹配的事务了,或者说该事件是某一个事务过程的一部分。这样在后面执行状态机的接口时,该事件会被正确的处理。如果osip没有拿走该事件,则说明针对该事件还没有事务与之对应。此时,我们首先检查其类型,如果是request,则说明很可能是一个新的事件到来(这将触发服务端的状态机的建立),调用eXosip_process_newrequest接口进行处理。如果是response,则调用接口eXosip_process_response_out_of_transaction处理。

在eXosip_process_newrequest接口中,如果是合法的事件,则会为其创建一个新的事务。也就是说这是新事务的第一个事件。经过一大堆的处理后,该事件可能就被osip消化了,或者被exosip消化了。如果需要上报给应用,由应用拿来对一些信息进行存储或者进行图形显示之类,则会将该事件添加到exosip的事件队列上。如下图所示:

应用程序在exosip初始化完之后需要调用如下类似的代码,不断从事件队列上读取事件,并进行处理。

eXosip_event_t *je;for (;;) {je = eXosip_event_wait (0, 50);eXosip_lock();eXosip_automatic_action ();eXosip_unlock();if (je == NULL)break;if (je->type == EXOSIP_CALL_NEW){........}else if (je->type == EXOSIP_CALL_ACK){........}else if (je->type == EXOSIP_CALL_ANSWERED){........}else .............eXosip_event_free(je);}

读到事件后,判断其类型进行对应的处理。这样整个接收流程就完成了。

2 发送过程

要发送数据时,需要根据消息类型,调用exosip对应模块的api接口函数来完成。如果要发送的sip消息不属于当前已有的任何事务,则类似接收过程,调用osip的相关接口创建一个新的事务,同时根据消息生成一个事件,加到事务的事件队列上。最后,唤醒exosip后台进程,使其驱动osip状态机,执行刚添加的事件,从而完成数据的状态处理和发送。当然,也有一些消息并不通过osip状态机,而是由exosip直接调用回调函数cb_snd_message完成发送。

六 exosip与上层应用以及osip之间的流程关系

在本文档的开头,我们已经强调了exosip是对osip库的扩展,那么它与osip之间是什么样的关系呢,这可参看下图:

上图为接收过程的示意图。Exosip后台任务不断从网络另一端读取sip消息,交给osip的parser模块解析,并将其转换为events,添加到事务队列上。同时,exosip后台任务在不断的驱动osip的状态机,这样,事务队列上的事件就会被处理。如果需要响应对端,状态机会根据回调函数的设置,直接完成数据的发送。同样,如果要将当前处理反馈给应用,则将其发送到事件队列上(这里是exosip的事件队列),并通过e-ctl管道通知应用进行处理。

应用需要发送数据时,流程如下图所示:

此时,应用调用exosip提供的辅助函数(上图中虚线示意此关系),构造osip事件,将其添加到osip的事务队列上。同时,应用通过s-ctl管道通知exosip后台任务执行状态机。在exosip执行状态机的过程中,sip消息会被发送到网络另一端的终端。

七 数据结构体之间的关系

在exosip中,有一个比较大的数据结构图是exosip_t,这个在前面的数据结构说明中就介绍了。这个结构体中包含了一些子模块的数据结构,比如call,register等等。程序中,定义了一个exosip_t类型的全局变量,这样,通过该全局变量,就可以获取各个子模块的信息。

在许多的开源软件中,经常会看到这种设计方法。

上图中,像call、register、subscribe等等,都有指向自身类型的前后指针,因此,实际运行中,多个实例都是串接在一起,形成一个双向链。

八 参考资料

1 http://www.antisip.com/documentation/exosip2/index.html

2 exosip开发手册(网络资料)

SIP协议栈eXosip2分析相关推荐

  1. SIP协议栈OSIP分析

    之前整理的linephone中使用的OSIP协议栈文档,版本为2-3.1.0,仅供参考. 一关于osip 2 二osip库的模块构成 2 三关键数据结构及其说明 2 四初始化所做的工作 6 五sip消 ...

  2. Asterisk 1.8 sip 协议栈分析

    引用自:http://blog.csdn.net/z1623866465/archive/2011/01/02/6113057.aspx 看了一下 asterisk 1.8 ,chan_sip 更新了 ...

  3. 开源的SIP协议栈 PJSIP

    PJSIP是一个开放源代码的SIP协议栈.它支持多种SIP的扩展功能,目前可说算是最流行的sip协议栈之一了. 下面列出其重要的几种优点: 1)代码层次非常清晰,从低级到高级都提供了很方便的接口供开发 ...

  4. 开源协议栈 rlc rrc_从ReSIProcate SIP协议栈库到GB28181

    背景 最近Gemfield团队在使用其它部门的某三方库进行GB28181协议的适配,然后在Docker化的过程中遇到了问题:SIP信令在Docker网络上无法正常工作.具体来说,当服务部署在宿主机(1 ...

  5. android sip协议栈,基于Android平台及SIP协议的软电话系统的研究

    摘要: 随着互联网通信技术不断发展以及智能手机的日益流行,VoIP(Voice Over InternetProtocol)技术得到了越来越广泛的应用.VoIP技术能结合这两者改变传统长途电话费用高昂 ...

  6. 几种开源SIP协议栈对比OPAL,VOCAL,sipX,ReSIProcate,oSIP

    随着VoIP和NGN技术的发展,H.323时代即将过渡到SIP时代,在H.323的开源协议栈中,Openh323占统治地位,它把一个复杂而又先进 的H.323协议栈展现在普通程序员的眼前,为H.323 ...

  7. 智能视屏会议系统(19)---开源视频会议SIP协议栈

    开源视频会议SIP协议栈 最近接触了一些视频通讯方面的知识,为方便以后查阅,因此整理到这里.  以下是几个比较重要的开源SIP协议栈  视频会议系统由于需要与不同的终端进行连接,因此我们需要视频会议终 ...

  8. 几种开源SIP协议栈对比

    随着VoIP和NGN技术的发展,H.323时代即将过渡到SIP时代,在 H.323的开源协议栈中,Openh323占统治地位,它把一个复杂而又先进的H.323协议栈展现在普通程序员的眼前,为H.323 ...

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

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

  10. 语音业务VOIP开发之SIP协议篇(一) —— SIP基本场景分析

    一.SIP业务基本知识 1.业务介绍 会话初始协议(Session Initiation Protocol)是一种信令协议,用于初始.管理和终止网络中的语音和视频会话,具体地说就是用来生成.修改和终结 ...

最新文章

  1. 笔记本独显无输出_高价位笔记本电脑推荐(一万一以上)
  2. docker linux redis 安装
  3. python中加入绝对路径_理解Python中的绝对路径和相对路径
  4. 对动画教程的坐标反转公式求证
  5. java中int,char,string三种类型的相互转换
  6. UE3 内存使用和分析
  7. 適合.net開發人員的UML自由軟件
  8. Linux tmux
  9. 量体裁衣:将DevOps转型融入到企业文化
  10. 【机器学习】今天详细谈下Soft Margin SVM和 SVM正则化
  11. 人工神经网络图像识别,人脸识别神经网络模型
  12. 酷软 正在连接服务器,酷软一直显示正在连接服务器...系统日志有大量错误信息...
  13. c语言中eof的作用,C语言中EOF是什么意思?
  14. 【NLP】LSTM 唐诗生成器
  15. Next.js 中的路由初学者指南,附有示例
  16. 家装家居自救指南:线上线下大融合
  17. win10任务栏图标居中
  18. gsoap中文文档(1.介绍)
  19. Xgboost算法之原理+代码
  20. 面试官喜欢问的 设计模式之观察者模式

热门文章

  1. 用服务器日志监控软件、服务器日志分析工具软件教你如何查看服务器日志?
  2. 教你流程化梳理外贸工作(附18个全流程邮件模板分享)
  3. python爬虫贴吧_Python爬虫——抓取贴吧帖子
  4. 山东计算机软考题库,软考习题库
  5. ubuntu mysql卸载教程_ubuntu下安装mysql及卸载mysql详细教程/方法
  6. hash表 C++的使用以及理解
  7. 单系统 台电x80pro_台电x80 pro (ID:E3E6)安装remix OS系统教程整理
  8. DFS和BFS算法框架
  9. WPS表格 JSA 学习笔记 - 实现贪吃蛇
  10. java语言特点概述