osip源代码框架详Word格式.docx
- 文档编号:17314996
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:30
- 大小:466.44KB
osip源代码框架详Word格式.docx
《osip源代码框架详Word格式.docx》由会员分享,可在线阅读,更多相关《osip源代码框架详Word格式.docx(30页珍藏版)》请在冰豆网上搜索。
Invite类型的客户端事务
IST
InviteServerTransaction
Invite类型的服务端事务
NICT
NotInviteClientTransaction
非Invite类型的客户端事务
NIST
NotInviteServerTransaction
非Invite类型的服务端事务
IMS
IPMultimediaSubsystem
IP多媒体子系统
PSVT
Packetservicevideotelephony
分组域可视电话
SIP
SessionInitiationProtocol
会话初始协议
UDP
UserDatagramProtocol
用户数据报协议
URL
UniformResourceLocator
统一资源定位器
2整体描述
开源代码的osip协议栈分为两个源代码包,整个协议栈采用lib库的形式,在内部没有使用到任务,采取与TCP/IP协议栈一样的策略,所以在使用上需要上层管理任务直接调用lib库提供的接口。
因为在Lib库内部没有使用到像定时器、发送队列等的任务,而同时需要使用到定时器,所以在lib库的内部采用轮训遍历的方式不停的检查是否有定时器超时,这在某种程度上会浪费CPU的允许时间。
同时整个lib库实现了对call,notify等的管理,为了实现重入,在应用启用多线程的条件下,内部启用的信号量和锁的使用,在下面的分析中不涉及到信号量和锁机制。
Lib库按照sip协议栈的层次关系分为两个lib包,底层的osiplib包实现对单个请求、应答、ACK的处理,包括message的解析、拼装、内容set和get,单个请求形成的transaction相关操作以及通信两端形成的一个dialog的操作。
Lib库上层的exosiplib在底层osiplib库的实现基础上,实现对sip协议整理逻辑上的管理。
Exosip主要关注的是sip协议的业务流程,包括call的整体管理,notify的整体管理,publish的管理,register的管理,option的管理,refer的管理和subscription的管理,其中最主要的为call和register的管理,这两个为sip协议栈必须实现的部分,另几个功能为sip协议栈扩展部分。
从这几个业务的管理流程出发,在业务的底层它们会使用到相似的一些功能,如注册的认证,发送message,接收message,每个请求和应答形成的transaction,多个transaction组合而成的dialog。
在message的处理方面,可以分为两类,一类为发送的message,因为是主动发送,所以上层管理层知道是什么类型的message,lib库直接提供各类接口供使用。
一类为接收到的message,因为不知道是哪种类型,所以需要根据解析出来的message的信息来进行处理,这部分的处理在文件中。
整个lib库的初始化在exOsip中介绍。
3Osip包的源代码框架解析
在osip源代码包中最主要的包括了message的相关操作,其中最重要的为message的解析,即从获取到的一个message中解析生成一个能够被代码直接处理的message数据结构-——osip_message_t。
与message结构相关的操作包括根据message数据结构的信息安装sip协议规范组装成一个message字符串;
message结构的初始化和释放;
message结构的拷贝操作;
以及从message结构中获取各种已经解析的成员变量的值和设置各个成员变量的值。
在message的解析部分,除了message的头之外,还包括了body的解析,涉及到sdp协议,包括对每个sdp字段的解析。
在osip源代码包中,设计了一个与同一个请求相关的所有message的集合——transaction,在发送或接收到一个新的请求的时候就会生成一个transaction,其中ACK和CANCEL请求是比较特殊的,对于非2xx应答的ACK和初始INVITE请求是属于同一个transaction的,而对于2xx的请求是属于单独的transaction的,所以其重传操作由UAC来控制,而不在INVITE的transaction内部进行控制。
CANCEL的请求除了本身建立一个transaction外,根据协议它还会去匹配要CANCEL掉的请求的transaction,如果匹配成功会CANCEL掉相应的transaction。
在osip包中同样设计了dialog相关操作,包括dialog的建立,dialog信息的保存,dialog的匹配及删除等操作。
其它方面,包括多线程中使用到的锁和信号量及信号,内部使用到的链表,用于事件的队列(需要先进先出策略),一些平台无关的封装,定时器以及常量等的定义。
这部分比较简单,而且都是最底层函数,直接封装了系统调用层。
3.1osip的transaction的event的产生
transaction的状态变化是由事件来驱动的,当transaction上有事件产生时,根据事件的类型和当前transaction的状态来处理该event。
Transaction上的事件分为两类:
一为定时器事件,在设定的定时器超时时会产生相应的定时器事件;
另一类为事件驱动事件,如发送一个请求、应答或接收到一个请求、应答,发送一个ACK和接收到一个ACK,即是由报文产生的事件。
3.1.1定时器事件的产生过程
ICT、IST、NICT和NIST的定时器的事件产生流程都一样,对于每一个transaction,其定时器是有顺序的,ICT流程中TIMEOUT_B的优先级最高,TIMEOUT_B定时器触发后,会触发killtransaction的操作。
当transactionff队列中有未处理的事件时,不处理定时器,直接返回,所以在transactionff队列中总的事件的数量是不多的。
所有的定时器函数调用底层同一个定时器检查函数__osip_transaction_need_timer_x_event。
该函数会先检查该定时器是否启动,判断条件为(timer->
tv_sec==-1),如果启动,检查当前时间是否超过定时器中设定的时间,如果是,则产生新的定时器事件。
因为定时器没有一个单独的任务,所以是采样轮训的方式检查是否有新的定时器事件产生,而不是根据系统时钟中断进行检测,因此会比较占用系统资源。
定时器的启动和修改使用接口osip_gettimeofday和add_gettimeofday。
只需要设定定时器的超时时间,即设定了一个新的定时器。
取消一个定时器,只需要修改定时器的timer->
tv_sev为-1。
3.1.2报文触发的事件
包括一个新的invite、response、ack的发送或接收,除了对非2xx的应答ack外,其他的请求和应答都会产生一个新的transaction,并且产生一个新的sipevent事件。
3.2osip的transaction的event处理流程
在sip协议栈中为了更快更好的处理transaction,根据协议栈的描述,划分为四种不同的transaction,分别为ICT、IST、NICT和NIST。
四种不同的transaction会有不同的处理流程和状态转换表,以及使用到不同的定时器。
ICT、IST、NICT和NIST的状态转换采样注册函数处理方式,为便于管理和使用注册函数,源码中使用了四个全局变量管理四种不同类型transaction的转换表:
ict_fsm、ist_fsm、nist_fsm和nist_fsm。
osip结构如下:
structosip
{
void*application_context;
/**<
UserdefinedPointer*/
/*listoftransactionsforict,ist,nict,nist*/
osip_list_tosip_ict_transactions;
listoficttransactions*/
osip_list_tosip_ist_transactions;
listofisttransactions*/
osip_list_tosip_nict_transactions;
listofnicttransactions*/
osip_list_tosip_nist_transactions;
listofnisttransactions*/
……
}
整体简单处理流程如下图:
图51:
transaction的event处理流程
3.2.1ICT的处理流程
如上图,ICT事件处理时:
1)检查osip管理结构中的osip_ict_transactions链表,如果没有链表元素,直接返回OSIP_SUCCESS
2)获取链表中元素个数,并保存transaction到临时局部数组
3)遍历所有transaction,osip_fifo_tryget顺序获取每个transaction中的事件,调用osip_transaction_execute处理每个事件,直到所有transaction中的所有事件被处理完毕,然后返回。
Osip_transacton_execute执行时,根据传入的参数osip_transaction_t*transaction中的transactionde类型获取到状态转移表的全局管理变量ict_fsm,并且根据event的type和transaction的状态调用fsm_callmethod——在文件,是状态转移注册函数的总入口——查询找到event的处理函数,并调用处理函数进行event的处理。
ICT的相关event的注册处理函数在文件和文件。
ICT使用到了3个定时器:
TIMEOUT_A、TIMEOUT_B和TIMEOUT_D。
在client端发送Invite而需要创建新的ICT的transaction时,TIMEOUT_B被启动,时长为64*DEFAULT_T1(DEFAULT_TI为500ms),TIMEOUT_B为整个transaction的生命周期时长,如果超过这个时间,transaction会被结束。
如同传输层使用的是没有传输保证的UDP,则设置TIMEOUT_A,TIMEOUT_D的间隔时间为DEFAULT_T1和64*DEFAULT_T1。
如果传输层使用的是面向连接的TCP及相关协议,则直接使用TCP内部的重传机制,不在SIP协议层提供传输的保护机制,所以不启动TIMEOUT_A和TIMEOUT_D。
TIMEOUT_A管理Invite的传送,在Invite被发送时,启动定时器TIMEOUT_A,并且在超时时间内还没接收到response的时候,重发该Invite。
TIMEOUT_D用于管理ACK,当接收到的response不是>
=300时,client端发送ACK,当重复接收到该invite的response时,重发该ACK,确保server端在killtranction前能接收到ACK。
3.2.2IST的处理流程
同ICT的处理流程,处理osip中的osip_ist_transaction链表。
IST的相关event的注册处理函数在文件和文件。
IST使用了定时器TIMEOUT_G、TIMEOUT_H和TIMEOUT_I。
使用方式与ICTL类似,详细见协议栈说明。
3.2.3NICT的处理流程
同ICT的处理流程,处理osip中的osip_nict_transaction链表。
NICT的相关event的注册处理函数在文件和文件。
NICT使用了定时器TIMEOUT_E、TIMEOUT_F和TIMEOUT_K。
3.2.4NIST的处理流程
同ICT的处理流程,处理osip中的osip_nist_transaction链表。
NIST的相关event的注册处理函数在文件和文件。
NIST使用了定时器TIMEOUT_J。
3.3Osip报文的解析
3.3.1sip协议报文的解析整理流程
当接收到一个message的时候,需要解析该message,生成一个代码能够处理的数据结构,该结构定义为structosip_message,该结构定义的一个message的全部相关信息,这些信息主要是供transaction和dialog及dialog的更上一层如call,notify等的使用。
对一个message的解析流程如下图所示:
在接收到一个message时,调用函数osip_message_parse进行message的解析。
首先调用函数osip_util_replace_all_lws替换掉message中的连续出现的‘\r\n\t’、‘\r\t’、‘\n\t’、‘\r\n’、‘\r’、‘\n’为空格,message是以‘\0’为结束标志的,message的headers和body之间的分界是以’\r\n\r\n’为标志的,替换只替换到’\r\n\r\n’为止,即只替换headers部分出现的\t、\r、\n。
由于sip协议栈规定,每个headers都是起新行,而且新行的头一个字符不为空格或\t,所以两个header之间的\r\n不会被替换掉,替换的只是一个允许multi合并项的header的内部多个值之间的“\r\n\t”或“\r\n”。
举例如下:
有两个header,其中Subject只允许单个值出现,Route允许有多个值出现,而且允许分行,但是分行必须以空格或\t开头,而Subject和Route行必需顶格开始,前面是没有空格或\t的,osip_util_replace_all_lws函数将Routeheadervalue中的两行间的\r\n\t转化为空格,即在逻辑上就成为一行了。
Subject:
Lunch
Route>
>
>
一个message由三部分组成,首先是message的startline部分,该行指明这是一个sip的message,包括sip标志,请求或应答说明,状态值,然后以\r\n做为和headers的分隔符。
该\r\n不会被osip_util_replace_all_lws替换为空格,如请求的INVITESIP/或应答的SIP/200OK,在三个属性之间有且仅有一个空格。
起始行的解析由__osip_message_startline_parse进行解析,解析得到message的类型,message的sipversion以及message的status_code,当status_code为初始化值0时,该message为一个请求,否则为应答。
请求的startline由__osip_message_startline_parsereq进行解析,得到请求的request_uri;
应答的startline由__osip_message_startline_parseresp进行解析。
Startline部分的解析是严格安装出现的三个属性的顺序进行解析的,并将解析结果保存在osip_message的结构成员变量中。
然后解析messge的headers部分,调用函数msg_headers_parse。
说明见osip的header报文头解析。
如果message中在headers之后不是结束符’\0’,则继续解析message的负载部分,调用函数msg_osip_body_parse进行解析。
Message的body解析首先查询headers头解析中保存的content——即body――的属性:
content_type,如果content_type中的type不为multipart,即不支持多种mime方式的content,说明body中就一个编码方式,直接将整个body解析为一个内容;
如果type为multitype,说明有多个编码方式的body组合在一起形成一个整体的body,则以”--”为分隔符解析body,将body分为多个mime编码方式的字符串,每个解析后的body内容保存在osip_message结构中的bodies结构成员中。
3.3.2Osip报文头的解析
在解析message的header的时候,因为前面的osip_util_replace_all_lws已经转化了单个header内部出现的\r、\n和\t为空格,所以每个header之间可以使用\r\n做为分隔符进行分隔。
如果字符串开头start_of_header已经到达结束符”\0”,则全部header解析完毕,返回成功;
调用__osip_find_next_crlf找到这个header的结束字符并保存在end_of_header中;
如果start_of_header为\r或\n,则已经解析到\r\n\r\n即headers的结束字符串,则返回成功,并且保存start_of_header到body中,即body是从\r\n字符串开始解析的,所以在body解析时,需要跳过\r\n及之后的空格部分;
根据header内部分隔符“:
”,取出header的hname和hvalue,其中hvalue在某些hname的情况下是允许为空的,然后调用osip_message_set_multiple_header来解析该header的hvalue字符串;
解析成功后,置start_of_header为已经解析完的header的end_of_header,开始解析下一个header。
在osip_message_set_multiple_header中,将headers分为两类,一类如上面例子中的Subject,只允许一个值,则直接调用osip_message_set__header进行解析;
一类如上面例子中的Router,允许多个值,根据sip协议,每个值之间以“,”进行分隔,所以需要查询整个hvalue字符串,根据”,”将hvalue分隔成多个值,每个值调用osip_message_set__header进行解析并保存解析结果到osip_message的数据成员变量中。
因为hvalue允许使用引号将值引起来,所以需要特别处理“,”是否出现在引号内部的问题。
只有在引号外部的“,”才是header值的分隔符,而内部的“,”只是一个header值的一部分。
osip源码中osip_message_set__header对于messageheaders的解析采用注册函数的方式实现,采用这种方式能够在后继版本很方便的进行新的header的添加,并且不会影响到整个源代码的框架流程。
文件中定义了header头解析所使用到的全局管理变量:
static__osip_message_config_tpconfig[NUMBER_OF_HEADERS];
__osip_message_config_t的结构定义如下:
typedefstruct___osip_message_config_t
char*hname;
int(*setheader)(osip_message_t*,constchar*);
intignored_when_invalid;
}__osip_message_config_t;
hname为sip协议定义的头字段的字符串,这些字符串定义在文件中;
函数指针setheader为该协议header的对应的解析函数;
ignored_when_invalid为是否忽略该header解析错误的标志,该标志值为1时,在解析该协议header发送错误时,忽略该错误,除sip协议规定的几个必要header之外,其他头应该采用忽略方式。
为了更快的根据header的hname,找到对应的setheader解析函数,采用了hash表的查询方式,根据hname生成一个hash值,并且需要保证没有两个不同的hname对应到同一个hash值中,以提高查询的速度。
调用__osip_message_is_known_header(hname)获取到在数组中的index,调用__osip_message_call_method(my_index,sip,hvalue)解析协议header,并且解析的结果保存在结构osip_message_t*dest,中。
每一个header都包含几个通用的操作:
header字符串的解析函数,即上段讲到的osip_message_set_xxx解析函数;
header解析后的结构的获取函数,osip_message_get_xxx函数;
根据header解析后的结构生成字符串的函数:
osip_xxx_str;
header解析后的结构的copy函数osip_xxx_clone;
header解析后的结构的是否函数:
osip_xxx_free;
以及header解析结构的初始化函数:
osip_xxx_init。
对每个header的几个相关操作最终目的是提供协议的整个header的整体操作,包括osip_message_init,osip_message_free,osip_message_clone和osip_message_parse。
3.3.3uri的解析
绝大部分的header的解析都是相识的,只有其中有参数的部分的header的解析会比较复杂,最主要的有from、to、contact等,因为除了本身就有参数之外,其值中的request_uri本身也可以包含有参数,而这两种参数之间是有区别的。
Sip协议栈规定header的表示分为header’sname,header’svalue和header’sparameter。
其中name和value之间用“:
”分隔,value与parameter之间用“;
”分隔,parameter之间也使用“;
”相分隔。
在结构定义中header的value根据具体header包含的信息进行结构变量的定义,而如果包含parameter则直接定义一个gen_params的链表,所有的parameter都保存在这个链表中。
如下面from的定义,包含有from的名称及一个url,及相关的parameter:
structosip_from
{
char*displayname;
DisplayName*/
osip_uri_t*url;
url*/
osip_list_tgen_params;
otherFromparameters*/
};
对应parameter的解析直接调用__osip_generic_param_parseall,该函数解析header的单个hvalue字符串中包含的所有parameter,在函数内部会根据“;
”将字符串划分为几个parameter,然后解析每个parameter,将解析结
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- osip 源代码 框架