osip源代码框架详解 下载本文

Q/CT XXXX.1-2008

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对于message headers的解析采用注册函数的方式实现,采用这种方式能够在后继版本很方便的进行新的header的添加,并且不会影响到整个源代码的框架流程。

Osip_parser_cfg.c文件中定义了header头解析所使用到的全局管理变量:static __osip_message_config_t pconfig[NUMBER_OF_HEADERS];

__osip_message_config_t的结构定义如下: typedef struct ___osip_message_config_t {

char *hname;

int (*setheader) (osip_message_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解析函数,采用了hash表的查询方式,根据hname生成一个hash值,并且需要保证没有两个不同的hname对应到同一个hash值中,以提高查询的速度。调用__osip_message_is_known_header (hname)获取到在数组中的index, 调用__osip_message_call_method (my_index, sip, hvalue)解析协议header,并且解

中国IMS网络SIP协议规范总体技术要求 - 13 -

Q/CT XXXX.1-2008

析的结果保存在结构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.3

uri的解析

绝大部分的header的解析都是相识的,只有其中有参数的部分的header的解析会比较复杂,最主要的有from、to、contact等,因为除了本身就有参数之外,其值中的request_uri本身也可以包含有参数,而这两种参数之间是有区别的。

Sip协议栈规定header的表示分为 header’s name, header’s value和header’s parameter。其中name和value之间用“:”分隔,value与parameter之间用“;”分隔,parameter之间也使用“;”相分隔。

在结构定义中header的value根据具体header包含的信息进行结构变量的定义,而如果包含parameter则直接定义一个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 */

中国IMS网络SIP协议规范总体技术要求 - 14 -

Q/CT XXXX.1-2008

};

对应parameter的解析直接调用__osip_generic_param_parseall,该函数解析header的单个hvalue字符串中包含的所有parameter,在函数内部会根据“;”将字符串划分为几个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头部分与参数部分用”;”进行分隔,参数之间也使用“;”进行分隔。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 1)

添加一个新的协议header字段

需要添加多个一个对该字段进行解析的文件,包含一个header常用到的几个基本通用操作,如果该header有特殊的地方需要处理,需要增加相关的处理函数,文件名一般定义为osip_xxx.c和osip_xxx.h

2) 需要在parser_init中注册新的header的解析函数,需要修改static __osip_message_config_t

pconfig[NUMBER_OF_HEADERS]

NUMBER_OF_HEADERS宏值。

3)

在osip_const.h中添加新的header的宏定义,osip的相关的常量宏定义都定义在该文件

4) 在osip_message.c文件额osip_message_init函数中添加对该header相关结构的初始化操作。在osip_message_free函数中同样添加对该header的相关释放操作,在osip_message_clone中添加对该header的clone相关操作。

中国IMS网络SIP协议规范总体技术要求 - 15 -

Q/CT XXXX.1-2008

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函数中添加对该header的处理。

7) 8)

在osip_message.h的头文件中的osip_message结构中添加对该header字段的结构。 在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个部分一起识别某一个transaction,如果缺少任何一部分,该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的标识值,该值是随机生成的,算法保证很长一段时间内生成的cal_id是不相同的,__osip_transaction_set_cseq用于设置cseq值,该值在同一个dialog内部是一直保持增长的,即同一个dialog的后面的transaction的cseq会比前面的transaction的值大,按照sip协议其初始值可以是随机数,代码实现中如果是非register请求,从1开始,如果是register请求的dialog,从20开始。

Transaction的初始化发生在接收到一个新的请求或发送一个请求的时候,该请求以及经过解析成为一个可以直接使用请求信息的结构osip_message_t。其初始化具体过程如上面所述,在设置完那5个部分后,还需要初始化event的队列,以及根据osip_message_t的type初始化使用到的定时器结构,如ICT的ict_context。其它部分的初始化在exosip源代码中实现,相关的如your_instance、in_socket、out_socket和record都是未了方便exosip中对transaction的管理而设置的。

Transaction中的event的相关操作在如前面所述。

中国IMS网络SIP协议规范总体技术要求 - 16 -