osip源代码框架详解.doc

上传人:豆**** 文档编号:17418943 上传时间:2022-05-24 格式:DOC 页数:28 大小:369KB
返回 下载 相关 举报
osip源代码框架详解.doc_第1页
第1页 / 共28页
osip源代码框架详解.doc_第2页
第2页 / 共28页
点击查看更多>>
资源描述

《osip源代码框架详解.doc》由会员分享,可在线阅读,更多相关《osip源代码框架详解.doc(28页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、【精品文档】如有侵权,请联系网站删除,仅供学习与交流osip源代码框架详解.精品文档.Osip协议源代码框架详解Prepared byMao minghuaDate2009.09.25Reviewed by DateApproved byDateRevision HistoryVersionAuthorReviewed ByCommentsIssued Date0.1Mao minghua描述osip协议栈的源代码框架目录1符号及缩写42整体描述43OSIP包的源代码框架解析53.1osip的transaction的event的产生53.1.1定时器事件的产生过程63.1.2报文触发的事件73

2、.2osip 的transaction的event处理流程73.2.1ICT的处理流程83.2.2IST的处理流程93.2.3NICT的处理流程93.2.4NIST的处理流程93.3Osip报文的解析103.3.1sip协议报文的解析整理流程103.3.2Osip报文头的解析123.3.3uri的解析143.3.4添加一个新的协议header字段153.4osip的transaction的管理163.5osip中dialog的管理184EXOSIP包的源代码框架解析194.1Lib库的初始化和销毁204.2Lib库的主处理线程234.2.12xx应答的重发处理机制244.2.2Exosip_e

3、xecute执行流程244.2.2.1Exosip_read_message的处理264.2.2.2eXosip_process_response_out_of_transaction的处理流程:294.2.3eXosip_automatic_action处理流程294.3Call的处理304.3.1创建Call的第一个INVITE304.3.2INVITE的ACK应答的创建和发送324.3.3dialog内的请求的创建和发送334.3.4Dialog内answer的创建和发送334.4Register的处理344.4.1向一个服务器第一次注册354.4.2调整一个注册的注册超时时间354.4

4、.3发送一个register注册35Osip源代码框架详解1 符号及缩写缩写英文全称中文名称ICTInvite Client Transaction Invite类型的客户端事务ISTInvite Server TransactionInvite类型的服务端事务NICTNot Invite Client Transaction 非Invite类型的客户端事务NISTNot Invite Server Transaction非Invite类型的服务端事务IMSIP Multimedia SubsystemIP多媒体子系统PSVTPacket service video telephony分组域可

5、视电话SIPSession Initiation Protocol会话初始协议UDPUser Datagram Protocol用户数据报协议URLUniform Resource Locator统一资源定位器2 整体描述开源代码的osip协议栈分为两个源代码包,整个协议栈采用lib库的形式,在内部没有使用到任务,采取与TCP/IP协议栈一样的策略,所以在使用上需要上层管理任务直接调用lib库提供的接口。因为在Lib库内部没有使用到像定时器、发送队列等的任务,而同时需要使用到定时器,所以在lib库的内部采用轮训遍历的方式不停的检查是否有定时器超时,这在某种程度上会浪费CPU的允许时间。同时整个

6、lib库实现了对call, notify等的管理,为了实现重入,在应用启用多线程的条件下,内部启用的信号量和锁的使用,在下面的分析中不涉及到信号量和锁机制。Lib库按照sip协议栈的层次关系分为两个lib包,底层的osip lib包实现对单个请求、应答、ACK的处理,包括message的解析、拼装、内容set和get,单个请求形成的transaction相关操作以及通信两端形成的一个dialog的操作。Lib库上层的exosip lib在底层osip lib库的实现基础上,实现对sip协议整理逻辑上的管理。Exosip主要关注的是sip协议的业务流程,包括call的整体管理,notify的整体

7、管理, publish的管理,register的管理,option的管理,refer的管理和subscription的管理,其中最主要的为call和register的管理,这两个为sip协议栈必须实现的部分,另几个功能为sip协议栈扩展部分。从这几个业务的管理流程出发,在业务的底层它们会使用到相似的一些功能,如注册的认证,发送message,接收message,每个请求和应答形成的transaction,多个transaction组合而成的dialog。在message的处理方面,可以分为两类,一类为发送的message,因为是主动发送,所以上层管理层知道是什么类型的message,lib库直

8、接提供各类接口供使用。一类为接收到的message,因为不知道是哪种类型,所以需要根据解析出来的message的信息来进行处理,这部分的处理在udp.c文件中。整个lib库的初始化在exOsip中介绍。3 Osip包的源代码框架解析在osip源代码包中最主要的包括了message的相关操作,其中最重要的为message的解析,即从获取到的一个message中解析生成一个能够被代码直接处理的message数据结构osip_message_t。与message结构相关的操作包括根据message数据结构的信息安装sip协议规范组装成一个message字符串;message结构的初始化和释放;mes

9、sage结构的拷贝操作;以及从message结构中获取各种已经解析的成员变量的值和设置各个成员变量的值。在message的解析部分,除了message的头之外,还包括了body的解析,涉及到sdp协议,包括对每个sdp字段的解析。在osip源代码包中,设计了一个与同一个请求相关的所有message的集合transaction,在发送或接收到一个新的请求的时候就会生成一个transaction,其中ACK和CANCEL请求是比较特殊的,对于非2xx应答的ACK和初始INVITE请求是属于同一个transaction的,而对于2xx的请求是属于单独的transaction的,所以其重传操作由UAC

10、来控制,而不在INVITE的transaction内部进行控制。CANCEL的请求除了本身建立一个transaction外,根据协议它还会去匹配要CANCEL掉的请求的transaction,如果匹配成功会CANCEL掉相应的transaction。在osip包中同样设计了dialog相关操作,包括dialog的建立,dialog信息的保存,dialog的匹配及删除等操作。其它方面,包括多线程中使用到的锁和信号量及信号,内部使用到的链表,用于事件的队列(需要先进先出策略),一些平台无关的封装,定时器以及常量等的定义。这部分比较简单,而且都是最底层函数,直接封装了系统调用层。3.1 osip的t

11、ransaction的event的产生transaction的状态变化是由事件来驱动的,当transaction上有事件产生时,根据事件的类型和当前transaction的状态来处理该event。Transaction上的事件分为两类:一为定时器事件,在设定的定时器超时时会产生相应的定时器事件;另一类为事件驱动事件,如发送一个请求、应答或接收到一个请求、应答,发送一个ACK和接收到一个ACK,即是由报文产生的事件。3.1.1 定时器事件的产生过程ICT、IST、NICT和NIST的定时器的事件产生流程都一样,对于每一个transaction,其定时器是有顺序的,ICT流程中TIMEOUT_B的

12、优先级最高,TIMEOUT_B定时器触发后,会触发kill transaction的操作。当transactionff队列中有未处理的事件时,不处理定时器,直接返回,所以在transactionff队列中总的事件的数量是不多的。所有的定时器函数调用底层同一个定时器检查函数_osip_transaction_need_timer_x_event。该函数会先检查该定时器是否启动,判断条件为(timer-tv_sec = -1),如果启动,检查当前时间是否超过定时器中设定的时间,如果是,则产生新的定时器事件。因为定时器没有一个单独的任务,所以是采样轮训的方式检查是否有新的定时器事件产生,而不是根据系

13、统时钟中断进行检测,因此会比较占用系统资源。定时器的启动和修改使用接口osip_gettimeofday和add_gettimeofday。只需要设定定时器的超时时间,即设定了一个新的定时器。取消一个定时器,只需要修改定时器的timer-tv_sev为-1。3.1.2 报文触发的事件包括一个新的invite、response、ack的发送或接收,除了对非2xx的应答ack外,其他的请求和应答都会产生一个新的transaction,并且产生一个新的sipevent事件。3.2 osip 的transaction的event处理流程在sip协议栈中为了更快更好的处理transaction,根据协议

14、栈的描述,划分为四种不同的transaction,分别为ICT、IST、NICT和NIST。四种不同的transaction会有不同的处理流程和状态转换表,以及使用到不同的定时器。ICT、IST、NICT和NIST的状态转换采样注册函数处理方式,为便于管理和使用注册函数,源码中使用了四个全局变量管理四种不同类型transaction的转换表:ict_fsm、ist_fsm、nist_fsm和nist_fsm。osip结构如下:struct osipvoid *application_context;/* User defined Pointer */* list of transactions

15、 for ict, ist, nict, nist */osip_list_t osip_ict_transactions;/* list of ict transactions */osip_list_t osip_ist_transactions;/* list of ist transactions */osip_list_t osip_nict_transactions;/* list of nict transactions */osip_list_t osip_nist_transactions;/*300时,client端发送ACK,当重复接收到该invite的response时

16、,重发该ACK,确保server端在kill tranction前能接收到ACK。3.2.2 IST的处理流程同ICT的处理流程,处理osip中的osip_ist_transaction链表。IST的相关event的注册处理函数在ist_fsm.c文件和ist.c文件。IST使用了定时器TIMEOUT_G、TIMEOUT_H和TIMEOUT_I。使用方式与ICTL类似,详细见协议栈说明。3.2.3 NICT的处理流程同ICT的处理流程,处理osip中的osip_nict_transaction链表。NICT的相关event的注册处理函数在nict_fsm.c文件和nict.c文件。NICT使用

17、了定时器TIMEOUT_E、TIMEOUT_F和TIMEOUT_K。3.2.4 NIST的处理流程同ICT的处理流程,处理osip中的osip_nist_transaction链表。NIST的相关event的注册处理函数在nist_fsm.c文件和nist.c文件。NIST使用了定时器TIMEOUT_J。3.3 Osip报文的解析3.3.1 sip协议报文的解析整理流程当接收到一个message的时候,需要解析该message,生成一个代码能够处理的数据结构,该结构定义为struct osip_message,该结构定义的一个message的全部相关信息,这些信息主要是供transaction

18、和dialog及dialog的更上一层如call,notify等的使用。对一个message的解析流程如下图所示:在接收到一个message时,调用函数osip_message_parse进行message的解析。首先调用函数osip_util_replace_all_lws替换掉message中的连续出现的 rnt、rt、nt、rn 、r 、n 为空格,message是以0为结束标志的,message的headers和body之间的分界是以rnrn为标志的,替换只替换到rnrn为止,即只替换headers部分出现的t、r、n。由于sip协议栈规定,每个headers都是起新行,而且新行的头一

19、个字符不为空格或t,所以两个header之间的rn不会被替换掉,替换的只是一个允许multi合并项的header的内部多个值之间的“rnt”或“rn ”。举例如下:有两个header,其中Subject只允许单个值出现, Route允许有多个值出现,而且允许分行,但是分行必须以空格或t开头,而Subject和Route行必需顶格开始,前面是没有空格或t的,osip_util_replace_all_lws函数将Route header value中的两行间的rnt转化为空格,即在逻辑上就成为一行了。Subject: Lunch Route: , 一个message由三部分组成,首先是messa

20、ge的startline部分,该行指明这是一个sip的message,包括sip标志,请求或应答说明,状态值,然后以rn做为和headers的分隔符。该rn不会被osip_util_replace_all_lws替换为空格,如请求的INVITE sip:bob SIP/2.0或应答的SIP/2.0 200 OK,在三个属性之间有且仅有一个空格。起始行的解析由_osip_message_startline_parse进行解析,解析得到message的类型,message的sipversion以及message的status_code,当status_code为初始化值0时,该message为一个

21、请求,否则为应答。请求的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的负载部分

22、,调用函数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结构

23、成员中。3.3.2 Osip报文头的解析在解析message的header的时候,因为前面的osip_util_replace_all_lws已经转化了单个header内部出现的r、n和t为空格,所以每个header之间可以使用rn做为分隔符进行分隔。如果字符串开头start_of_header已经到达结束符”0”,则全部header解析完毕,返回成功;调用_osip_find_next_crlf找到这个header的结束字符并保存在end_of_header中;如果start_of_header为r或n,则已经解析到rnrn即headers的结束字符串,则返回成功,并且保存start_of_

24、header到body中,即body是从rn字符串开始解析的,所以在body解析时,需要跳过rn及之后的空格部分;根据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分为两类,一类如上面例子中

25、的Subject,只允许一个值,则直接调用osip_message_set_header进行解析;一类如上面例子中的Router,允许多个值,根据sip协议,每个值之间以“,”进行分隔,所以需要查询整个hvalue字符串,根据”,”将hvalue分隔成多个值,每个值调用osip_message_set_header进行解析并保存解析结果到osip_message的数据成员变量中。因为hvalue允许使用引号将值引起来,所以需要特别处理“,”是否出现在引号内部的问题。只有在引号外部的“,”才是header值的分隔符,而内部的“,”只是一个header值的一部分。osip源码中osip_messa

26、ge_set_header对于message headers的解析采用注册函数的方式实现,采用这种方式能够在后继版本很方便的进行新的header的添加,并且不会影响到整个源代码的框架流程。Osip_parser_cfg.c文件中定义了header头解析所使用到的全局管理变量:static _osip_message_config_t pconfigNUMBER_OF_HEADERS;_osip_message_config_t的结构定义如下:typedef struct _osip_message_config_t char *hname; int (*setheader) (osip_mes

27、sage_t *, const char *); int ignored_when_invalid;_osip_message_config_t;hname为sip协议定义的头字段的字符串,这些字符串定义在osip_const.h文件中;函数指针setheader为该协议header的对应的解析函数;ignored_when_invalid为是否忽略该header解析错误的标志,该标志值为1时,在解析该协议header发送错误时,忽略该错误,除sip协议规定的几个必要header之外,其他头应该采用忽略方式。为了更快的根据header的hname,找到对应的setheader解析函数,采用了h

28、ash表的查询方式,根据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解析后的结构的获取

29、函数,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.3 uri的解析绝大部分的header

30、的解析都是相识的,只有其中有参数的部分的header的解析会比较复杂,最主要的有from、to、contact等,因为除了本身就有参数之外,其值中的request_uri本身也可以包含有参数,而这两种参数之间是有区别的。Sip协议栈规定header的表示分为 headers name, headers value和headers parameter。其中name和value之间用“:”分隔,value与parameter之间用“;”分隔,parameter之间也使用“;”相分隔。在结构定义中header的value根据具体header包含的信息进行结构变量的定义,而如果包含parameter则

31、直接定义一个gen_params的链表,所有的parameter都保存在这个链表中。如下面from的定义,包含有from的名称及一个url,及相关的parameter: struct osip_from char *displayname; /* Display Name */ osip_uri_t *url; /* url */ osip_list_t gen_params; /* other From parameters */对应parameter的解析直接调用_osip_generic_param_parseall,该函数解析header的单个hvalue字符串中包含的所有parame

32、ter,在函数内部会根据“;”将字符串划分为几个parameter,然后解析每个parameter,将解析结果保存在gen_params链表中。Parameter的格式为pname=pvalue类型,等号两边允许空格。From、to、contact以及via中间都可能出现url。url的解析接口为osip_uri_parse,输入为url的字符串,解析的结构保存在结构osip_uri_t之中。url包含有三部分内容:url的基本信息,url的header头部分和url的参数部分。开始部分与header头部分用“?”进行分隔,header头之间用”&”进行分隔,header头部分与参数部分用”;

33、”进行分隔,参数之间也使用“;”进行分隔。Header部分调用函数osip_uri_parse_headers进行解析,结果保存在osip_uri_t结构中的url_headers成员变量中;parameter部分调用函数osip_uri_parse_params进行解析,其结果保存在osip_uri_t的url_params成员变量中。在from、to、contact等包含url的header中,如果url中包含parameter,则整个url必需使用“”括起来,以表示一个完整url部分。所以解析from等header时需要检查是否包含”字符。3.3.4 添加一个新的协议header字段1)

34、 需要添加多个一个对该字段进行解析的文件,包含一个header常用到的几个基本通用操作,如果该header有特殊的地方需要处理,需要增加相关的处理函数,文件名一般定义为osip_xxx.c和osip_xxx.h2) 需要在parser_init中注册新的header的解析函数,需要修改static _osip_message_config_t pconfigNUMBER_OF_HEADERS中的NUMBER_OF_HEADERS宏值。3) 在osip_const.h中添加新的header的宏定义,osip的相关的常量宏定义都定义在该文件4) 在osip_message.c文件额osip_mes

35、sage_init函数中添加对该header相关结构的初始化操作。在osip_message_free函数中同样添加对该header的相关释放操作,在osip_message_clone中添加对该header的clone相关操作。5) 在osip_message_to_str.c文件中的_osip_message_to_str函数中添加该header转化为string的函数注册。6) 如果该header不允许重复多个出现,即不允许multiple header,则在osip_message_parse.c文件的 osip_message_set_multiple_header函数中添加对该he

36、ader的处理。7) 在osip_message.h的头文件中的osip_message结构中添加对该header字段的结构。8) 在osip_headers.h文件中添加新的header的头文件引用。3.4 osip的transaction的管理transaction的操作主要包括transaction的初始化、transaction的free、transaction的匹配、从transaction中获取信息和设置transaction信息。根据sip协议描述一个transaction由5个必要部分组成:from、to、topvia、call-id和cseq,这5个部分一起识别某一个tran

37、saction,如果缺少任何一部分,该transaction就会设置失败。所以对每个部分的设置都会有一个设置函数:_osip_transaction_set_topvia用于设置topvia,对于发送端topvia为自己的via,对于接收端topvia为将message转发到自己的最后一个sip-proxy服务器,_osip_transaction_set_from用于设置message的发送端,_osip_transaction_set_to用于设置message的接收端,_osip_transaction_set_call_id用于设置一个dialog的标识值,该值是随机生成的,算法保证很

38、长一段时间内生成的cal_id是不相同的,_osip_transaction_set_cseq用于设置cseq值,该值在同一个dialog内部是一直保持增长的,即同一个dialog的后面的transaction的cseq会比前面的transaction的值大,按照sip协议其初始值可以是随机数,代码实现中如果是非register请求,从1开始,如果是register请求的dialog,从20开始。Transaction的初始化发生在接收到一个新的请求或发送一个请求的时候,该请求以及经过解析成为一个可以直接使用请求信息的结构osip_message_t。其初始化具体过程如上面所述,在设置完那5个

39、部分后,还需要初始化event的队列,以及根据osip_message_t的type初始化使用到的定时器结构,如ICT的ict_context。其它部分的初始化在exosip源代码中实现,相关的如your_instance、in_socket、out_socket和record都是未了方便exosip中对transaction的管理而设置的。Transaction中的event的相关操作在如前面所述。在transaction的匹配中,根据RFC3261的最新sip协议的描述,由topvia的branch_id是否相同来匹配,如果相同,就是同一个transaction的请求和应答及ACK,为兼容

40、旧版本的transaction的匹配规则,同时支持根据call_id, cseq, from_tag, to_tag来匹配transaction。如下图,为便于管理的transaction,所有的transaction保持在osip_t结构的四条链表中,按照处理流程的不同分为发送出去的INVITE类型请求和应答、其它类型请求和应答,接收到的INVITE请求和应答、其它请求和应答。struct osipvoid *application_context; /* User defined Pointer */ /* list of transactions for ict, ist, nict,

41、nist */ osip_list_t osip_ict_transactions; /* list of ict transactions */ osip_list_t osip_ist_transactions; /* list of ist transactions */ osip_list_t osip_nict_transactions; /* list of nict transactions */ osip_list_t osip_nist_transactions; /* list of nist transactions */#if defined(HAVE_DICT_DIC

42、T_H) dict *osip_ict_hastable; /* htable of ict transactions */ dict *osip_ist_hastable; /* htable of ist transactions */ dict *osip_nict_hastable; /* htable of nict transactions */ dict *osip_nist_hastable; /* htable of nist transactions */#endif在transaction的匹配过程中,如果是发出的请求,因为本地的transaction都会分配一个不重复的

43、transaction_id,所以只需要比配transaction_id即可;对于incoming的message,如果是request,则匹配branch_id或者为兼容前面版本进行transaction的比配,按照协议RFC3261的17-2-3节的方式进行匹配;如果incoming的message是response,则匹配branch_id或根据RFC3261的17-1-3节的规则进行匹配。3.5 osip中dialog的管理dialog的相关的管理操作包括dialog的初始化建立过程,dialog的销毁free过程,以及dialog的匹配。此外dialog中保存了相关的路由信息和cseq信息。Dialog结构如下,由call_id、local_tag和remote_tag唯一确定一个dialog: struct osip_dialog char *call_id; /* Call-ID*/ char *local_tag; /*

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 小学资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com