77范文网 - 专业文章范例文档资料分享平台

osip2协议栈原理分析以及总结(2)

来源:网络收集 时间:2019-03-22 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:或QQ: 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

//设置四个状态机下消息传输失败的处理函数。 osip_set_message_callback ();

//设置各种状态机下各种事件发生后用户的回调

(3)打开接收远端消息接收通道

打开通道就是保证远方的消息能够顺利的被本地接收到,然后交给SIP CORE处理,它包括以下几个步骤

? Step1:监听端口

? 打开SIP端口SOCKET,然后监听此端口,如5060。需要注意的是,SIP支持TCP

和UDP两种方式,SIP首先UDP方式。 ? Step2:解析消息

? 接收到消息后,调用osip_parse函数,来完成对消息包的解析。这个函数完成后,

消息就从普通信令消息分解成了OSIP2自己可以理解的消息事件。osip_parse函数在src\\osipparser2下。

? Step3:将消息送给SIP CORE处理 ? 解析后的消息,系统调用osip_find_transaction_and_add_event函数,把消息发

送给和此消息相关的处理事物(或者说session),如果系统中没有和这个消息相

关的session(也就是说是个新的request),那么此时将新建立一个session(或者说transaction,因为在不同层面有不同理解),用于处理新的事务。实际上,这个session创立的过程也就是一个新的系统状态机的建立过程,根据这个消息的种类,osip_transaction_init负责初始化,建立一个新的和种类对应的状态机(四

种状态机中的一种),然后调用osip_transaction_add_event把消息扔给这个刚建立起来的状态机处理。一个新的状态机也就开始运做。 到此,OSIP就已经正常工作,可以接收网络来的消息。

4.2 一个呼叫过程简要分析

下面通过一对呼叫的连接过程说明OSIP的消息的整个处理过程。假设终端A呼叫终端B,两放都是用的OSIP CORE。

? Stp1:A生成一个Invite消息

这个过程是大家都熟悉的过程,也就是利用本地信息,组建一个SIP包的过程,需

要注意的是:rtp流的本地接收发送端口是在这里就建立的,然后放到SDP中。 ? Step2:A把生成的消息交给核心处理。

首先系统调用osip_transaction_init ,产生一个新的状态机。在发送invite请求的时候,这个状态机是ICT(带invite的client端状态机)。状态机产生后,系统调用函数把消息扔给状态机处理,osip_transaction_add_event负责把消息插到队列中。

? Step3:A的ICT状态机调用ict_snd_invite函数发送invite包给对方,状态机自身

从初始状态跳转到calling状态,等待对方回应,并设置响应的A超时和B超时,当A超时到达的时候,向对方重发一次数据包,并且把A时间的时间增加一倍(最长为4S,如果超过4S,将不再增加)。当B时间到达后,系统认为对方没有响应,则释放资源,结束本次操作。

? Step4:B的信令监听端口接收到此invite请求包,调用osip_parse函数,来完成对

消息包的解析,然后系统调用osip_find_transaction_and_add_event函数来试图把此消息包插入已经存在的session的传输队列(比如系统还有另外一个呼叫),

6

当系统发现当前信令包并不属于已经存在的session的时候,系统认为之是一个新的呼叫过程,因此,系统调用osip_transaction_init函数建立一个信的状态机来处理这个session,这个状态机也就是IST(带invie的server状态机),然后把信令消息插到新状态机的事件列表中,供其处理。

? Step5:B的IST处理A的invite请求,自身的状态机从IST_PRE_PROCEEDING跳转到

IST_PROCEEDING状态,并发送100消息给对方,调用用户设置的回掉函数来完成用户收到请求时候的处理。注意,B应该发两次1XX消息给对方,一个是100,一个是180。下面的状态也一样。

? Step6:A收到1xx的回应,自身从ICT_CALLING状态跳转到ICT_PROCEEDING状态,并

调用用户的回掉函数来完成用户的要求。注意,A会收到B过来的两次1XX消息,参考step5的说明。

? Step7:B的用户认可,可以接收A的此次呼叫,B发送调用ist_snd_2xx函数,发送

200 OK消息给A,B的状态机IST从IST_PROCEEDING IST_TERMINATED。完成一次IST的服务。

? Step8:A接收到200 0K,状态机跳转到ICT_TERMINATED状态,完成一个ICT服务。 ? Step9:信令结束后,RTP流的建立

在Invite信令中,A告诉了B本地的RTP接收地址和端口,B在200 OK中告知了A本地的RTP的接收地址和端口,因此,信令结束后,A和B就可实现流的互通(通常是音频),需要注意的是,RTP并不是OSIP的一部分,从模块上说,它是逻辑上的另外一个部分,RTP流是依靠SIP信令里的信息建立起来的,但和SIP或者SIP信令本身而言并没有任何必然联系。

另外,就RTP要传送的音频数据本身而言(例如音频数据),和SIP更没有必然联系。通常,数据是这样产生的,A采集音频数据,然后交给编码部分编码(例如711,723),压缩完后的数据,由RTP打包,然后发送给B。B接收这些数据,拆RTP包,拿出原始数据,交给解码,解出数据后给播放进行播放。从这里也可以看出,OSIP2和这部分也是没有任何联系的。

关于RTP流的建立的过程请看朱葵阳整理rtp文挡。 4.3 sip消息发送接收详细分析 4.3.1 sip 消息的发送

发送 SIP 消息,需要用到如下三个主要的数据结构:osip_messag_t,保存待发送消息; osip_dialog_t,保存dialog 信息;osip_transaction_t,保存事务信息。

首先,调用osip_malloc 新分配一个dialog 类型的结构体,使用osip_to_init,osip_to_parse,osip_to_free 这类parser 函数按RFC 设置call-id,from,to,local_cseq 等必要字段(原则是:后面生成实际SIP 消息结构体要用到的字段就需要设置)。接着,使用osip_message_init 初始化一个sip msg,并根据dialog 来填充该结构体(不同的消息填充的数据不同,实际应该填充的信息可参考RFC 中的描述)。如果要给SIP 消息添加Body,例如SDP 段,则需要使用osip_message_set_body,osip_message_set_content_type 函数,设置的值是纯文本。另外,如果是SDP,Osip 有提供简单的解析和生成便捷函数, 例如sdp_message_to_str,sdp_message_a_attribute_add,但只是简单的字符操作,要填充合法的字段需要自己参考SDP 的RFC 文档。最后,就是事务的创建和触发,这通过调用

osip_transaction_init 完成。osip_transaction_init 的原型声明如下:

int osip_transaction_init(

osip_transaction_t ** transaction, /*返回的事务结构体指针*/ osip_fsm_type_t ctx_type, /*事务类型ICT/NICT/IST/NIST*/ osip_t * osip, /*前文说的全局变量*/

osip_message_t * request) /*前面生成的sipmsg*/

7

该接口创建了一个新的事务,并自动根据事务类型、dialog 和sipmsg 进行初始化,最重要的是它使用了__osip_add_ict 等函数,将本事务插入到全局的osip_t 结构体的全局FIFO 链表中去了,不同的事务类型对应不同的FIFO。在前面关于osip 结构体的描述可知,有四个FIFO,分别对应ICT,NICT,IST,NIST。事务创建好后,就可以按照状态机的设置,进行状态转换的处理。这步需要事件来触发。应用可以调用osip_new_outgoing_sipmessage 对sip message 进行处理,产生事件,保存到结构体osip_event_t 中。这一步省却了手动去设置。另外, 还调用evt_set_type_outgoing_sipmessage 设置事件的type_t,并将sip message 挂到事件结构体的SIP属性值上。有了根据消息分析出的事件后,使用osip_fifo_add(trn->transactionff, ev)将事件插入到事务的事件FIFO 中。

现在条件都具备了,那么消息是如何发出的呢?实际上,SIP 消息的发送和响应是一个 事务,不能单独隔离开来,所以消息的发送需要事务状态机来控制。我们上面设置了状态机的状态和事件,要触发它,就是要执行状态机了:

osip_ict_execute osip_nict_execute osip_ist_execute osip_nist_execute

上面四个函数分别用来遍历前面提到的osip 全局结构体上的四个事务FIFO。首先取出 事务,再依次取出事务内的事件FIFO 上的事件,使用osip_transaction_execute 依次执行。

最终会调用到osip 结构体的cb_send_message 回调函数。在osip 初始化时,我们为这个函数指针指定了具体的处理函数,此时就会调用该处理函数发送数据。一般我们在实现这个回调函数时,也是按照网络socket 编程,用send 系统调用实现的。如果某个事务不能正常终结怎么办呢?例如发出了Invite 没有收到任何响应,按RFC 定义,不同的事务有不同的超时时间,osip_timers_ict[nict|ist|nist]_execute 这些函数就是来根据取出的事务的时间戳与当前时间取差后与规定的超时时间比对,如果超时,就自动设置超时“事件”,并将事务“状态”设为终结,使用初始化时设定的消息超时事件回调函数处理即可( 如果设置了);如果网络质量不稳定,经常丢失消息,需要使用osip_retransmissions_execute 函数来自动重发消息而不是等待超时。为了即时响应SIP 消息的处理,并推动状态机,上述的九个函数需要不停执行,可以将它放入单独线程中。

4.3.2 sip 消息的接收 有了前面的发送SIP 消息的理解,接收消息的处理就方便理解了,收到SIP 消息,使用osip_parse 进行解析,得到一个osip_message_t 的sip msg ,使用

evt_set_type_incoming_sipmessage 得到事务的“事件”,同上,将sip msg 挂到事件结构体的sip字段,随后立即使用osip_find_transaction_and_add_event 来根据“事件”查找事务,否则新建事务,然后推动状态机执行。

5、osip的使用

5.1 如何解析URI

对于 sip 消息每一部分的解析(头,sip messages,uri),通常都使用如下类似的函数接口:

// allocation/release of memory.

xxxx_init(osip_xxx_t **el); xxxx_free(osip_xxx_t *el);

xxxx_parse(osip_xxx_t *el, char *source);

8

xxxx_to_str(osip_xxx_t *el, char **dest);

如果 buffer 中包含有sip uri,下面的示例代码展示了如何去解析uri: osip_uri_t *uri; int i;

i=osip_uri_init(&uri);

if (i!=0) { fprintf(stderr, \i=osip_uri_parse(uri, buffer);

if (i!=0) { fprintf(stderr, \osip_uri_free(uri);

反过来,需要将osip_uri 结构体中的信息转换到buffer 中,可参考下面的代码: char *dest;

i = osip_uri_to_str(uri, &dest);

if (i!=0) { fprintf(stderr, \fprintf(stdout, \

osip_free(dest);

需要注意的是,dest 所指向的内存是在接口中动态分配的,所以使用完后续用调用 osip_free 进行释放,以免造成内存泄露。 5.2 如何解析sip message

如果 buffer 中包含有sip 请求或者响应消息,下面的示例代码展示了如何将其解析到

osip_message 结构体中:

osip_message_t *sip; int i;

i=osip_message_init(&sip);

if (i!=0) { fprintf(stderr, \i=osip_message_parse(sip, buffer, length_of_buffer);

if (i!=0) { fprintf(stderr, \

osip_message_free(sip);

因为 sip message 中可能包含二进制数据,所以buffer 的长度在调用时必须给出。相反的

过程如下:

char *dest=NULL;

int length=0;

i = osip_message_to_str(sip, &dest, &length);

if (i!=0) { fprintf(stderr, \fprintf(stdout, \osip_free(dest);

类似于上面,dest 指向的内存在使用完后续用释放。

当使用osip 库的事务管理特性时,通常需要创建一个合适的事件。对于收到的sip message,可以使用下面的接口完成该项工作: osip_event_t *evt;

int length = size_of_buffer; evt = osip_parse(buffer, i);

需要注意的是,osip 的解析器不会对message 进行完全的检查,应用层需要对此作出

9

处理。比如,下面的字符串显示一个request-uri 中包含一个奇怪的端口:

INVITE sip:jack@atosc.org:abcd SIP/2.0

但是,osip 的解析器并不会检测到这个错误。它将被提交给应用层去确认。 5.3 如何管理事务

要去“执行”状态机,你需要建立事件(events),并将它提交给正确的事务上下文,如果事件在当前状态中被允许的话,事务的状态将会被更新。

事件可以分为如下三类:

SIP messages Timers

transport errors a. 管理一个新的事务

假设你要实现一个用户端代理,并且开始一个注册事务。首先,你必须使用osip 库构建一个sip 消息(osip 作为一个底层的库,提供构建sip message 的接口,但是需要手动去填充相关必要的域)。一旦构建好sip message,就可以使用下面的代码开始一个新的事务:

osip_t *osip = your_global_osip_context;

osip_transaction_t *transaction;

osip_message_t *sip_register_message; osip_event_t *sipevent;

application_build_register(&sip_register_message); osip_transaction_init(&transaction,

NICT, //a REGISTER is a Non-Invite-Client-Transaction osip,

sip_register_message);

// If you have a special context that you want to associate to that // transaction, you can use a special method that associate your context // to the transaction context.

osip_transaction_set_your_instance(transaction, any_pointer);

// at this point, the transaction context exists in oSIP but you still have // to give the SIP message to the finite state machine. sipevent = osip_new_outgoing_sipmessage (msg);

sipevent->transactionid = transaction->transactionid;

osip_transaction_add_event (transaction, sipevent);

// at this point, the event will be handled by oSIP. (The memory resource will // also be handled by oSIP). Note that no action is taken there. 使用相似的代码,可以添加其他事件到状态机中。 b. 消化事件

之前的步骤展示了如何创建一个事务,并且提供了一种添加新的事件的可行的方式(注 意,一些事件,比如超时事件,是由osip 库来添加的,而不是由应用程序完成)。下面的代码展示了osip 如何消费这个事件。实际上,这非常简单,但是你必须意识到,在任何时间消费一个事件并不总是允许的。状态机必须顺序的消费一个事务上的事件。这也就意味着,当调用 osip_transaction_execute()时,在同一个事务上下文中再次调用该方法将是被禁止的,

知道之前的调用返回。在一个多线程的应用中,如果一个线程捕获一个事务,代码如下:

10

百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库osip2协议栈原理分析以及总结(2)在线全文阅读。

osip2协议栈原理分析以及总结(2).doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.77cn.com.cn/wenku/zonghe/536114.html(转载请注明文章来源)
Copyright © 2008-2022 免费范文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ: 邮箱:tiandhx2@hotmail.com
苏ICP备16052595号-18
× 注册会员免费下载(下载后可以自由复制和排版)
注册会员下载
全站内容免费自由复制
注册会员下载
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: