一种新的面向IMS网络的SIP协议栈*

2012-10-08 01:58季光献
电信科学 2012年4期
关键词:状态机事务消息

季光献

(丽水职业技术学院 丽水 323000)

1 引言

IMS(IP multimedia subsystem,IP 多媒体子系统)是第三代移动通信伙伴组织(3GPP)在R5版本标准中提出的支持IP多媒体业务的子系统。它基于SIP(session initiation protocol,会话初始化协议)的体系,使用SIP呼叫控制机制来创建、管理和终结各种类型的多媒体业务。各种类型的客户端通过IMS都可以建立起端到端的IP通信,并可获得所需要的服务质量。在网络融合的发展趋势下,IMS技术为基于IP的移动和固定通信融合提供了基础,并被业界认为是网络演进的一个重要阶段[1]。

SIP是由IETF制定的面向Internet会议和电话的应用层控制协议,用于建立、修改和终止多媒体会话。最初版本是1999年形成的RFC2543,之后不断更新,最新的版本是2002年6月提出来的RFC3261。所谓多媒体会话是指多媒体发送者、接收者和从发送者到接收者的数据流的集合。在基于SIP的应用中,每一个会话可以是各种不同的数据,如普通的文本、经过数字化处理的音频、视频数据等,应用具有很大的灵活性[2,3]。

SIP是一个基于ASCII码的端到端的协议,参与会话的成员可以通过多播方式、单播连网或者两者结合的形式进行通信。作为一个应用层的控制协议,SIP可以用来建立、修改和终止多媒体会话(或者会议),如 Internet电话;也可以邀请参与者参加已经存在的会话,如多方会议。媒体可以在一个已经存在的会话中方便地增加(或者删除)。SIP支持名字映射和重定向服务,可用于支持个人移动业务——用户可以使用一个唯一的外部标志而不用关心他们的实际网络地点。

SIP在建立和维持终止多媒体会话协议上,支持以下5个方面的功能。

·用户定位:检查终端用户的位置,用于通信。

·用户有效性:检查用户参与会话的意愿程度。

·用户能力:检查媒体和媒体的参数。

·建立会话:在呼叫方和被叫方间建立会话参数。

·会话管理:包括发送和终止会话,修改会话参数,激活服务等[4]。

SIP是IETF多媒体数据和控制体系结构的一部分,该协议大量借鉴了成熟的HTTP协议,并且具有易扩展、易实现等特点。SIP信令的特点如下[6]。

·基于文本,便于用Java、Perl等面向对象语言实现,易于调测排错,结构灵活,便于扩展。

·中性的底层传输协议:可用TCP或UDP,推荐首选UDP。TCP是通过证实机制保证可靠传送的,在网络负载较大的情况下,常会发生超时,导致建立信令通道时延较大,采用UDP后,可以用应用层控制协议消息的定时和重发,并可方便地利用多播机制并行搜索目的用户,无需为每一次搜索建立一个TCP连接。

·呼叫和媒体信息同时发送:SIP在传送呼叫控制信令的同时,还可以在消息本体中传送呼叫的媒体类型和格式等信息,以加快呼叫的建立速度。

·充分利用和组合Internet已有的协议:SIP容易与其他协议组合起来提供服务,如DNS用于地址解析、SDP用于会话和媒体流描述、RTP用于实时多媒体传送、RSVP和RTCP用于QoS质量保证等。随着网络技术的发展,只需更新相关的协议,有利于系统的优化和对新业务的灵活、快速反应。

·SIP使用统一资源定位器给出SIP资源的地址:SIP URI的格式和Web及E-mail系统中使用的格式是相同的,这给SIP重定向以巨大的灵活性,并且能将多种通信格式整合起来。

SIP的消息机制[7]使用ISO0646字符集UTF-8格式,除了字符集的区别以外,SIP的许多消息语法都与HTTP/1.1相同,也是一个请求/应答协议。需要注意的是,SIP并不是HTTP的扩展。SIP消息可以是客户端发给服务器的请求或服务器对客户端的响应。SIP客户端是指产生请求的SIP实体,而SIP服务器是指接收请求和返回应答的SIP实体,按照这个定义,当两个用户代理交换SIP消息的时候,发送请求的用户代理就是用户代理客户端(UAC),而返回应答的用户代理就是用户代理服务器 (UAS)。一个SIP请求连同它所出发的所有应答称为一个SIP事务。

SIP消息分为两种:从客户端到服务器的请求;从服务器返回网络客户端的响应。SIP请求和响应消息都使用RFC2822规定的通用消息格式,包括开始行、一个或多个消息头、一个空行(CRLF,表示消息头结束)以及一个可选消息体。

SIP消息=开始行

*消息头

空行(CRLF)

[消息体]

开始行=请求行|状态行

消 息 头=(通 用 头 (general-header)|请 求 头 (requestheader)|响应头(response-header)|实体头(entity-header))

SIP协议中的请求消息提供了6种方法,见表1。

表1 SIP请求消息

SIP的响应消息和请求消息结构类似,但格式中第一行由状态码构成,代表服务器不同的响应状态。RFC3261中使用nXX(n从1到6)的格式对状态码进行定义,n用来表示不同的响应类型,XX用来对响应类型进行进一步的描述。响应消息中的相关应答码及其含义见表2。

SIP的协议结构如图1所示。SIP是一个分层的协议,由多个处理层次组成。协议分成不同层次来描述是为了能够更清晰地表达。

最底层的是语法和编码层。编码方式是采用扩展的Backus-Naur Form Grammar(BNF 范式)。

第二层是传输层。它定义了一个客户端如何发送请求和接收应答以及一个服务器如何接收请求和发送应答。所有的SIP要素都包含一个通信层。

表2 SIP响应消息

第3层是事务层。事务是SIP的基本组成部分。一个事务是客户发送一个请求事务(通过通信层)到一个服务器事务,连同服务器事务的所有该请求的应答发送回客户端事务。事务层处理应用服务层的重发,匹配请求的应答以及应用服务层的超时。任何一个用户代理客户端完成的事情都是由一组事务构成的。用户代理包含一个事务层来实现有状态的代理服务器。无状态的代理服务器并不包含事务层。事务层包含一个客户元素(可以认为是一个客户事务)和一个服务器元素(可以认为是一个服务器事务),它们都可以用一个有限状态机来处理特定的请求。

在事务层之上是事务用户(TU)。每一个SIP实体,除了无状态代理,都是一个事务用户。当一个TU发出一个请求,它首先创建一个客户事务实例 (client transaction instance)并且和请求一起发送,这包括了目标IP地址、端口号以及发送请求的设备。TU可以创建客户事务,也可以取消客户事务。当客户取消一个事务,它请求服务器终止正在处理的事务,并且回滚状态到该事务开始前的状态,并且产生指定的该事务的错误报告。这是由cancel请求完成的,这个请求有自己的事务,并且包含一个被取消的事务[3]。

在本文中,设计了一个稳定、高效的SIP协议栈,其实现方式主要通过提供SIP操作所需的基本数据结构和应用程序编程接口(API),包括用于表示SIP中的各类对象(如SIP消息、SDP消息体以及各种头域、计时器等)的数据结构以及对消息、消息体进行解析的API和实现4类有限状态机的API。为验证信令协议栈的可靠性和SIP软终端的通信功能,本文对局域网内SIP软终端的信令流程进行测试,采用Wireshark软件抓取分组,并分析所捕获数据分组的内容,结果表明本文提出的SIP协议栈是有效的。

2 提出的SIP协议栈

oSIP是按照RFC3261和RFC2327标准,使用ANSIC编写的开源协议栈。它结构简单小巧,支持线程安全,可用于多线程及单线程的编程模式,eXosip是oSIP的一个扩展协议集,它在oSIP基础上对SIP消息的API做了较高级的封装。eXosip可方便地创建一个完整的SIP程序,适用于SIP终端开发。

鉴于上述特性,本终端的SIP协议栈在oSIP/eXosip协议栈基础上,通过引入有限状态机进行修改和二次开发来实现,包括4大模块:状态机模块、解析器模块、工具模块和上层封装接口层。其模块结构如图2所示。

解析器模块主要完成对SIP消息的语法解析,SIP中以事务为单位来描述各种请求和响应的交互过程。状态机模块的功能就是完成UAS或UAC对接收到的某个事务的响应,完成对该事务(注册过程、呼叫过程等)的状态记录,并在特定状态下触发相应的事件或回调函数。工具模块主要是提供一些进行SDP协商和对话管理的API。上层封装接口层根据MVC模式中的Model层的调用方式,提供了面向Model层简便易用的操作协议栈接口。

2.1 状态机

2.1.1 事务

事务是SIP最基本的元素,事务是指SIP客户端向SIP服务器发起的一次请求以及针对此次请求产生的所有应答的处理过程。

事务分为客户事务和服务器事务两大类。客户事务是指发起请求一端(即客户端)的处理过程,服务器事务是指接收请求一端(即服务器端)的处理过程。事务还可以根据发起事务的请求是否为invite分为invite事务和non-invite事务。因此,事务可以分为4类:invite客户事务、non-invite客户事务、invite服务器事务和non-invite服务器事务。

结构体transaction_t主要用于管理事务,同时在这个结构中记录事务的相关信息。协议栈在开始一个对话时(如创建一个invite transaction来发送invite请求)分配该数据结构。在transaction_t的数据结构中,transactionid是事务处理链表中每个个体的唯一标识,transactionff是一个FIFO结构,用以标识此事务处理的事件,事务的状态则由state来说明。

2.1.2 有限状态机

SIP UA的核心就是事务处理,UA中事务的处理可以用有限状态机来表示。

一个事务和一个状态机有关。每一时刻状态机(发送方或接收方)总处于一个特定的状态,其状态是由所有变量值组成的,包括计数器在内,其执行于事务层。每个状态机都有一个初始状态,当有消息到来时,判断是哪种状态机的事件,根据消息的类型和状态机的状态,在状态机的链表中查找需要执行的操作函数的地址进行处理,并设置事件完成后的状态。状态机使用链表结构而不是单一对象,是为了在多事务同时处理环境下的应用(SIP服务器以及支持多方会议的SIP电话)。

事务有4大类,因此对事务的处理就由4种有限状态机来表示,分别为ICT(请求客户端事务的状态)、IST(请求服务器端事务的状态)、NICT(非请求客户端事务的状态)和NIST(非请求服务器端事务的状态)。其执行函数分别为 osip_ict_execute (manager→config)、 osip_nist_execute(manager→config)、osip_ist_execute(manager→config)、osip_nist_execute(manager→config)。

2.1.3 事件

状态机内部的状态跳转是由事件触发的。事件是应用程序与状态机通信的手段。所有的从网络上收取的数据分组都视为状态机的事件,这些事件将被存储在状态机结构相关的事件队列里。

一个事件主要包含事件类型和关联的事务两部分内容,事件类型指导致状态机状态跳转的各类事件的具体类型,如超时事件、收到invite请求等。可以说,外界与SIP模块通信的载体是SIP消息和程序指令;在SIP模块内,协议栈外围程序与内核状态机通信的载体则是事件。

在有限状态机中有3种事件:发送SIP消息(请求和应答)、接收SIP消息(请求和应答)、计时器事件(重传和上下文删除或结束)。

事件的结构定义如下:

struct sipevent_t

{

type_t type; //事件的类型

int transactionid; //关联的事务的标识号

sip_t*sip; //SIP消息结构

};

2.1.4 回调函数

在SIP协议栈中,对各类事件的响应都是以回调函数的方式实现的。回调函数本身是函数指针的形式,它在状态机内部状态跳转时被事务处理函数调用,事务处理函数的其余部分完成对该事件的默认响应行为。所以说回调函数是SIP协议栈留给外界的用户接口,用户需要定义自己UA相关的处理内容。

本协议栈定义了osip_t对象作为所有回调函数的管理对象,外围UA应用程序必须通过该对象实现对协议栈回调函数的使用。osip_t除了管理所有的回调函数,也包含了4个状态机事务对象的相关信息。在使用协议栈前必须调用函数osip_init()分配该结构并进行初始化。在系统运行期间,该结构存储的内容是动态变化的,而这些变化主要是基于事务的建立或结束。

2.2 解析器模块

解析器模块可以分为3个部分:URI解析器、SIP解析器和SDP解析器。它主要实现将收到的SIP消息从文本解析成一个SIP消息结构体(sip_t),处理完毕后将待发送的sip_t结构还原成SIP文本消息然后发送的功能。在使用语法解析器之前必须先对它进行初始化:int parser_init()。

sip_t中存储着发送或接收到的SIP消息的详细结构,包含SIP协议定义的各个头域以及SIP消息体,而这些解析后的头域本身也是一些结构体,解析器在解析整个消息的同时也将消息中的头域分别解析成对应的结构。解析的作用在于方便应用程序内部对消息及各个头域进行操作。下面给出sip_t结构的部分内容:

struct sip_t

{

startline_t*strtline;

from_t*from;

to_t*to;

call_id_t*call_id;

list_t*contacts;

content_type_t*content_type;

......

}

sip_t的数据结构定义分3部分。第一部分是起始行,其结构单独定义为startline_t,当此消息是SIP请求时,其为请求的方法和请求源的URI;当此消息是SIP应答时,它为应答状态码。第二部分是一些SIP消息头域的结构列表,这是由于头域的个数是可变的原因,故采用列表来存放。最后一部分是一些其他头域字段、消息体(list_t*bodies)以及对消息的描述字段。

sip_t中的一些成员(不包括char*message)为null时表示该SIP消息不含该字段。协议栈在要发送SIP消息或接收到SIP消息时创建sip_t,并填写好相应的信息,发送完后或处理完之后释放该结构。

sip_t结构中各个变量的值是从界面的用户输入或系统配置中读取的,然后通过函数将读取的值存放到sip_t结构中。如int msg_setbody(sip_t*sip,char*buf)就是设定sip_t结构中body的值。相应地,也可以从结构中根据名字获取各个参数,实现函数的名称类似对应的函数中的set改为 get,如 int msg_getbody(sip_t*sip,char*buf)就是获得body的值。

对于消息结构体sip_t的操作包括以下5种操作。

(1)初始化结构体

利用msg_init函数对结构体进行初始化,目的是为结构体分配存储空间。

(2)释放结构体

利用msg_free函数释放初始化时分配给结构体的存储空间。

(3)将结构体变成字符串的形式

利用msg_2char函数将结构体转化为符合SIP消息规范的字符串的形式。

(4)将消息的字符串格式转化为结构体的存储形式

利用msg_parse函数分析消息的字符串,将相应的字符存储到结构体实例的相应字段中。

(5)拷贝结构体

利用msg_clone函数创建结构体实例的副本。

2.2.1 SIP消息的解析

SIP消息的解析流程如图3所示。

(1)解析起始行

对起始行的分析首先是判断第一个参数,如果是sipversion(字符是SIP/2.0),则该消息是响应消息,这时从起始行中获得状态码和原因短语,并将结构体中的成员sipmethod 和 rquri设为 null;如果是 sipmehtod(invite、Ack、bye、register、cancel、options共 6 种方法),则该消息是请求消息,这时从起始行中获得请求方法、请求URI和版本号,并将statuscode和reasonphrase设为 null。

(2)解析 SIP 头域

头域采用通用格式,其结构体定义如下:

typedef struct_header_t{

char*hname;

char*hvalue;

}header_t;

字段的值可以有多个参数,参数之间用分号";"来分隔。对头域的分析可有以下两种情况:

·对于仅仅为单个参数的成员,根据头域字段的名字调用相应字段的分析函数,分析字符串来获得该头域字段的值;

·对于可以有多个参数的成员,由于是采用链表的形式存储,直接将字段名字和字段的值相分离,根据字段名字的属性将字段的值赋给相应的成员。

(2)解析 SIP 消息体

根据content type(编码类型)和 content length(编码长度)两个标题头的值来判断消息体部分是否有值,这两个标题头的参数表明消息体中是否存在消息体,如果有,则把这些数据拷贝到消息体的结构体中。

2.2.2 SIP消息的构造

相对于SIP消息的解析过程,SIP消息的构造也是通过调用解析器模块的相关函数和工具模块的相关函数来完成的。

当SIP服务器想发送一个消息时,通知解析器模块开始操作。首先对起始行、头域等结构体进行初始化;随后调用各个功能函数对SIP消息结构体中的各项内容分别进行添加和设定;然后调用sipmsg_2char函数将SIP消息结构体中的信息转化为可以发送的字符串,调用sipmsg_clone函数为sipmsg_t结构创建副本 (以备重发);最后对各结构体的信息进行释放。

2.3 工具模块

工具模块提供了比较完善的SDP协商机制,包括SDP结构体的定义、各类SDP字段的添加设置以及根据预定义的本地SDP环境产生针对某个SDP结构体的应答。SDP协商指主被叫用户交换关于呼叫的一些相关媒体信息(如媒体编解码方式、媒体流传输所用的端口号等)的行为。SDP协商主要采用offer/answer的模式,而协议栈中的SDP协商工具(SDP negotiator)主要提供了一种从SDP offer去构建SDP answer的方法,如通过分析invite请求消息中消息体SDP部分的媒体参数描述去构造对于invite请求的响应消息200OK中的SDP消息体部分。

此外,工具模块还提供了基本的对话(dialog)处理机制。对话就是指持续一段时间的两个UA之间对等的一种SIP会话关系。对话可以帮助管理UA的消息排序和UA之间正确的路由。在dialog中,可以动态地创建新的事务来开始端点之间的SIP通信过程。在UA中,对话用dialog ID标识。一个dialog ID由SIP消息中的Call-ID、一个本地tag(local tag)和一个远程 tag(remote tag)组成。在同一个对话中,UA的本地tag就是对等 UA的远程tag,反之,远程tag就是对等UA的本地tag。基本的dialog处理机制包括dialog结构体的定义、按照两种方式建立的dialog(被叫方callee和主叫方caller)、对话的更新维护、对话的拆除。本协议栈中的对话管理工具主要用来创建dialog并对dialog信息进行管理。

2.4 上层封装接口层

eXosip封装了大部分的SIP协议调用接口,一般的应用都不需要直接调用oSIP的接口函数。上层封装接口层在其基础上进一步封装,供上层Model层调用,使用几行代码就可以实现一个具有音视频功能的呼叫。下面对其处理呼叫的关键接口进行定义。

(1)OWPL_RESULT owplLineAdd (const char *displayname,constchar* sipUsername,constchar*sipServer,const char*sipProxy,OWPL_TRANSPORT_PROTOCOL sipTransport,int regTimeout,OWPL_LINE*phLine)

方法功能描述:添加一条虚拟线路,即向服务器注册。

参数说明:displayname:SIP实体要显示的名字,对应于“displayname”;sipUsername 和sipServer对应于上述格式;sipProxy是代理服务器地址;sipTransport为传输层协议;regTimeout为注册超时时间;phLine指向新建立的虚拟线路。

(2)OWPL_RESULT owplLineDelete(OWPL_LINE hLine,unsigned int skipUnregister)

方法功能描述:删除一条虚拟线路。

参数说明:hLine代表要删除的虚拟线路;skipUnregister值为1时表示在删除虚拟线路时跳过注销,为0时强制删除虚拟线路,无需注销。

(3)OWPL_RESULT owplLineRegister(const OWPL_LINE hLine,const int bRegister)

方法功能描述:注册一条虚拟线路。

参数说明:hLine代表要注册的虚拟线路;bRegister值为1时注册该虚拟线路,为0时注销该虚拟线路。

(4)OWPL_RESULT owplCallCreate(const OWPL_LINE hLine,OWPL_CALL*hCall)

方法功能描述:建立一个呼叫对象。

参数说明:hLine代表要建立呼叫对象的虚拟线路;hCall指向建立好的呼叫对象。

(5)OWPL_RESULT owplCallConnect(const OWPL_CALL hCall,const char*szAddress,int mediaStreams)

方法功能描述:呼叫连接。

参数说明:hCall代表要进行连接的呼叫对象;szAddress呼叫对端的SIP地址;mediaStreams表示媒体流种类。

(6)OWPL_RESULT owplCallAccept(constOWPL_CALL hCall,int mediaStreams)

方法功能描述:接收一个呼叫。

参数说明:hCall代表要接收的呼叫对象;mediaStreams表示媒体流种类。

(7)OWPL_RESULT owplCallAnswer(const OWPL_CALL hCall,int mediaStreams)

方法功能描述:对到来的一个呼叫应答。

参数说明:hCall代表要应答的呼叫对象;mediaStreams表示媒体流种类。

(8)OWPL_RESULT owplCallReject(const OWPL_CALL hCall,const int errorCode,const char*szErrorText)

方法功能描述:拒绝到来的一个呼叫。

参数说明:hCall代表要拒绝的呼叫对象;errorCode指SIP消息的错误码;szErrorText是对应错误码的文本信息。

(9)OWPL_RESULT owplCallHold(const OWPL_CALL hCall)

方法功能描述:挂起一个呼叫。

参数说明:hCall代表要挂起的呼叫对象。

(10)OWPL_RESULT owplCallUnhold(constOWPL_CALL hCall)

方法功能描述:恢复一个呼叫。

参数说明:hCall代表要恢复的呼叫对象。

(11)OWPL_RESULT owplCallDisconnect(OWPL_CALL hCall)

方法功能描述:结束一个呼叫。

参数说明:hCall代表要结束的呼叫对象。

3 仿真实验

为验证信令协议栈的设计实现的可靠性和SIP软终端的通信功能,本文对局域网内SIP软终端的信令流程进行测试,采用Wireshark软件抓取分组,并分析所捕获数据分组的内容。实验的目的是为了验证提出的协议栈的有效性,对其中呼叫建立的基本交互流程不做详细说明,且由于版面的限制,有关SIP协议交互流程的更多交互信息见参考文献[3]。

3.1 实验建立

如图4所示,测试环境包括分别部署在两台PC(IP地址分别为***.***.156.225和***.***.158.730)上的两个SIP软终端以及一台IP地址为***.***.158.230的SIP服务器。

3.2 注册功能

注册功能测试用例见表3。

表3 注册功能测试用例

3.3 通话功能

通话功能测试用例见表4。

表4 通话功能测试用例

图5展示了本SIP软终端通话功能的实际效果。大的视频窗口显示对方的影像,右下角的视频窗口显示本地摄像头采集的影像。

3.4 呼叫建立时间

呼叫建立时间测试用例见表5。

3.5 长时通话

长时通话测试用例见表6。

表5 呼叫建立时间测试用例

表6 长时通话测试用例

由表3~表6及图5,验证了本文所设计的软终端能够使用SIP信令建立连接,可以完成实时视音频通信功能,并且具备一定的可靠性,表明本文提出的SIP协议栈的设计思路和实现方法是合理的、切实可行的。

4 结束语

IMS网络使用SIP呼叫控制机制来创建、管理和终结各种类型的多媒体业务。各种类型的客户端通过SIP都可以建立起端到端的通信,并可获得所需要的服务质量。本文提出了一种新的SIP协议栈,并依照该协议栈实现了SIP软终端,具备基于SIP的视频和音频通话功能。经过验证,该软终端具有良好的稳定性和实用性,能较好地运行于IMS网络环境下,实现双方通信。

1 王尚广,孙其博,杨放春.IMS网络中的SIP洪泛攻击检测.软件学报,2011,22(4):761~772

2 胡成喆.一种基于MVC架构的SIP软终端的设计与实现.北京邮电大学硕士学位论文,2010

3 孙建勇.基于SIP协议的软终端的研究与实现.北京邮电大学硕士学位论文,2004

4 邓挺,李小兵.SIP在视频监控系统中的应用.安防科技,2007(8)

5 Gonzalo Camarillo著.白建军,彭晖,田敏等译.SIP揭密.北京:人民邮电出版社,2003

6 赵慧玲,叶华.以软交换为核心的下一代网络技术.北京:人民邮电出版社,2002

7 Session Initiation Protocol RFC3261.IETF Network Working Group,2002

猜你喜欢
状态机事务消息
基于分布式事务的门架数据处理系统设计与实现
河湖事务
一张图看5G消息
基于有限状态机的交会对接飞行任务规划方法
基于OCC-DA-MCP算法的Redis并发控制
双口RAM读写正确性自动测试的有限状态机控制器设计方法
消息
消息
消息
移动实时环境下的数据一致性研究