SIP协议整理

  本文记录开发、实现IMS项目时,整理的SIP协议基础知识;若有侵权,请告之。

SIP协议

  1. 1.      SIP协议简介

SIP是一个应用层的控制协议,可以用来建立、修改、和终止多媒体会话(或者会议)例如Internet电话。SIP也可以邀请参与者参加已经存在的会话,比如多方会议。媒体可以在一个已经存在的会话中方便的增加(或者删除)。SIP显示的支持名字映射和重定向服务,这个用于支持个人移动业务-用户可以使用一个唯一的外部标志而不用关系他们的实际网络地点。SIP在建立和维持终止多媒体会话协议上,支持5个方面:

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

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

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

建立会话:”ringing”,建立会话参数在呼叫方和被叫方。

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

SIP不是一个垂直集成的通讯系统。SIP可能叫做是一个部件更合适,它可以用作其他IETF协议的一个部分,用来构造完整的多媒体架构。比如,这些架构将会包含实时数据传输协议(RTP)(RFC1889)用来传输实时的数据并且提供QoS反馈,实时流协议(RSTP)(RFC2326)用于控制流媒体的的传输,媒体网关控制协议(MEGACO)(RFC3015)用来控制到公共电话交换网(PSTN)的网关,还有会话描述协议(SDP)(RFC2327)用于描述多媒体会话。因此,SIP应该和其他的协议一起工作,才能提供完整的对终端用户的服务。虽然基本的SIP协议的功能组件并不依赖于这些协议。

SIP本身并不提供服务。但是,SIP提供了一个基础,可以用来实现不同的服务。比如,SIP可以定位用户和传输一个封装好的对象到对方的当前位置。并且如果我们利用这点来通过SDP传输会话的描述,对方的用户代理立刻可以得到这个会话的参数。如果我们用这个像传输会话描述(SESSIONDESCRIPTIONSD)一样呼叫方的照片,一个”呼叫ID”服务很容易就建立了。这个简单的例子说明了,SIP作为一个基础,可以在其上提供很多不同的服务。

SIP并不提供会议控制服务(比如议席控制或者投票系统),并且并没有建议会议应该则那样管理。可以通过在SIP上建立其他的会议控制协议来发起一个会议。由于SIP可以管理参与会议的各方的会话,所以会议可以跨异构的网络,SIP并不能,也不打算提供任何形式的网络资源预留管理。

安全对于提供的服务来说特别重要。要达到理想的安全程度,SIP提供了一套安全服务,包括防止拒绝服务,认证服务(用户到用户,代理到用户),完整性保证,加密和隐私服务。

SIP可以基于IPV4也可以基于IPV6

  1. 2.      SIP协议常用术语说明

Address-of-RecordAddress-of-Record(AOR)是一个SIP或SIPS URI,它指向带位置服务的一个域,位置服务可以将一个URI与另一个URI(可能找到用户的URI)映射。典型的,通过注册来填写位置服务。通常认为AOR是用户的“公开地址”。

Back-to-Back User Agent背对背用户代理(B2BUA)是一个逻辑实体,它接收请求,并作为用户代理服务器(UAS)处理该请求。为确定如何应答一个请求,它作为用户代理客户端(UAC)并生成请求。与代理服务器不同,B2BUA保持对话状态,并参与其建立的对话中发送的所有请求。由于B2BUA是UAC和UAS间的连接,所以不需要明确定义其行为。

Call呼叫是一个非正式术语,它是指对等实体间的通信,通常是建立多媒体对话。

Call Leg对话[31]的另一个名称,本规范中没有使用。

Call Stateful如果一个代理从初始INVITE到终止BYE请求都保留了对话的状态,那么该代理有呼叫状态。有呼叫状态代理通常是有状态事务。但反之则不一定成立。

Client代理是发送SIP请求和接收SIP响应的任何网络元素。客户端可以与也可以不与用户直接交互。用户代理客户端和代理都是客户端。

Conference包含多个参与者的多媒体会话。

Core核心指明特殊SIP实体类型特有的功能,即有状态或无状态代理、用户代理和注册员特有的。所有核心,除无状态代理的核心外,都是事务用户。

Dialog对话是两个UA间持续一段时间的对等SIP关系。对话由SIP消息建立,如INVITE请求的2xx响应。用呼叫标识符、本地标签和远程标签标识对话。对话即RFC2543中的呼叫腿。

Downstream在一个事务中转发消息的方向,它是指请求从用户代理客户端流向用户代理服务器的方向。

Final Response终止SIP事务的响应,与不终止SIP事务的临时响应相反,所有2xx、3xx、4xx、5xx和6xx响应都是最终响应。

Header头是SIP消息的一个组件,它传递消息的信息。构造头字段作为头字段序列。

Header Field头字段是SIP消息头的一个组件。一个头字段可以是一个或多个头字段行。头字段行由一个头字段名和零或多个头字段值组成。给定的头字段行中的多个头字段值用逗号隔开。某些头字段只能有一个头字段值,因此,它们通常只有一个头字段行。

Header Field Value头字段值是一个值,头字段由零或多个都字段值组成。

Home Domain此域为SIP用户提供服务。典型的,它通常是注册的记录地址中URI中出现的域。

Informational Response与临时响应相同。

Initiator, Calling Party, Caller用INVITE请求发起会话(和对话)的一方。从发送建立对话的初始INVITE请求到该对话终止,呼叫者保持此角色。

Invitation一个INVITE请求。

Invitee, Invited User, Called Party, Callee接收用于建立新会话的INVITE请求的一方。从接收用于建立对话的初始INVITE请求到该对话终止,被呼叫者保持此角色。

Location ServiceSIP重定向或代理服务器使用位置服务,以获得被呼叫者可能位置的信息。它包含记录地址与零或多个联系地址的绑定列表。有多种创建和删除这种绑定的方法。本规范定义了更新这种绑定的REGISTER方法。

Loop一个请求到达代理,然后被转发,最后又返回到同一个代理。当请求第二次到达代理时,Request-URI与第一次相同,其它影响代理操作的头字段也不变,因此代理能对该请求作出与第一次相同的处理决定。循环的请求是错误的,由协议描述检测和处理循环请求的程序。

Loose Routing如果代理遵循本规范定义的处理路由头字段的程序,那么我们就称其为松散路由选择。该程序将请求的目的地址(在Request-URI中)与请求在路由中要访问的代理(在路由头字段中)相分离。符合此机制的代理即是松散路由器。

Message协议中SIP元素间发送的数据。SIP消息是请求或响应。

Method方法是请求调用服务器上的基本功能。方法在请求消息中。方法的实例有INVITE和BYE等。

Outbound Proxy从客户端接收请求的代理,尽管它可能不是Request-URI解析的服务器。一般手动为UA配置一个出站代理,或通过自动配置协议获知一个代理。

Parallel Search在并行搜索中,代理在接收到入站请求后,向可能的用户位置发布几个请求。在顺序搜索中,发送一个请求后,代理等待最终响应,而不是立即发送下一个请求;并行搜索在发送请求时,不等待先前请求的结果。

Provisional Response服务器使用该响应指示进行的响应,该响应不终止SIP事务。1xx响应是临时响应,其它响应都认为是最终响应。

Proxy, Proxy Server一个媒介(中间)实体,它既作为服务器,也作为客户端(代替其它客户端发送请求)。代理服务器主要执行路由选择,即其职责是确保请求发送到一个离目标用户“更近”的实体。代理也可用于执行策略(例如,确定一个用户可以发起呼叫)。代理负责解释,如果需要的话,在转发请求前重写请求消息的特定部分。

Recursion当客户端在响应的Contact头字段中产生一个或多个URI的请求时,客户端递归一个3xx响应。

Redirect Server重定向服务器是用户代理服务器,它为接收到的请求生成3xx响应,告诉客户端联系一个可能的URI集。

Registrar注册员是服务器,它接收REGISTER请求,并把从请求中接收的信息放入其所在的域的位置服务中。

Regular Transaction正常事务是方法非INVITE、ACK和CANCEL的事务。

Request为调用一个特殊的操作。客户端向服务器发送的SIP消息。

Response为指明客户端向服务器发送的请求的状态,服务器向客户端发送的SIP消息。

Ringback回铃是呼叫者的应用产生的信令音调(signalingtone),表明被呼叫者正在响铃。

RouteSet路由集是按顺序的SIP或SIPSURI的集合,它是发送特殊请求时必须遍历的代理的列表。路由集是可通过头如Record-Route识别的,或是可配置的。

Server服务器是一个网络元素,它接收请求,并为这些请求发送响应。服务器的实例有代理、用户代理服务器、重定向服务器和注册员。

Sequential Search在顺序搜索中,代理服务器按顺序尝试每个联系地址,在前一个产生最终响应后再开始尝试下一个。通常用2xx或6xx最终响应终止一个顺序搜索。

Session在SDP规范中这样描述:“多媒体会话是多媒体发送者、接收者以及发送者和接收者间数据流的集合。多媒体会议是多媒体会话的实例。”(RFC2327[1])(定义的SDP会话包含一个或多个RTP会话。)正如所定义的,在同一会话中,被呼叫者可以被不同的呼叫邀请多次。如果使用SDP,会话由源字段中的SDP用户名、会话ID、网络类型、地址类型和地址元素的串接定义。

SIPTransactionSIP事务在客户端和服务器之间发生,包含从客户端向服务器端发送的第一个请求到服务器端向客户端发送的最后一个响应(非1xx)间的所有消息。如果请求是INVITE而最后的响应不是2xx,那么事务也包含响应的ACK。INVITE请求的2xx响应的ACK是一个独立的事务。

Spiral螺旋是发送到代理,继续转发,再次回到该代理的SIP请求,但是这次将做出不同于原始请求的处理决定,通常表示请求的Request-URI与先前的不同。螺旋不是一个错误情况,与循环不同。典型的原因是呼叫转发。一个用户呼叫joe@example.com.com,代理将其转发到Joe的PC,PC反之将其转发给bob@example.com。该请求再次转发到.com代理。但是,这不是循环。因为此时该请求的目标用户不同于上次,它被称为螺旋,这是一种有效的情况。

Stateful Proxy本规范定义的在处理请求过程中,维持客户端和服务器事务状态机的逻辑实体,也称为事务有状态代理。有状态代理行为的详细定义见第16节。(事务)有状态代理不同于呼叫有状态代理。

Stateless Proxy本规范定义的在处理请求过程中,不维持客户端和服务器事务状态机的逻辑实体。无状态代理转发它从下游接收到的每个请求和从上游接收的每个响应。

Strict Routing如果代理遵循RFC2543以及本版本的先前工作中的路由处理规则,则称代理为严格路由。使用严格路由规则时,当出现Route头字段时,代理会损坏Request-URI的内容。本规范没有使用严格路由行为,而是使用松散路由行为。实现严格路由的代理称为严格路由器。

Target Refresh Request将在对话中发送的目标更新请求定义为请求,它能修改对话的远程目标。

Transaction User(TU):传输层上的协议处理层。事务用户包括UAC核心、UAS核心和代理核心。

Upstream事务中消息的转发方向,它是指响应从用户代理服务器流向用户代理客户端的方向。

URL-encoded根据RFC2396编码的字符串,见第2.4[5]节。

User Agent Client(UAC)用户代理客户端是创建新请求,然后使用客户端事务状态机发送请求的逻辑实体。UAC角色仅存在事务的持续时间内。换言之,如果软件发起一个请求,它仅在该事务的持续时间内是一个UAC。如果随后它接收到一个请求,在处理此事务时,它被假想成一个用户代理服务器角色。

UAC Core事务和传输层上的UAC的处理功能集。

User Agent Server(UAS)用户代理服务器是一个逻辑实体,它产生SIP请求的响应。响应接收、拒绝和重定向请求。该角色仅存在于事务期间。换言之,如果软件对请求作出响应,那么它在事务期间就是UAS。如果随后它产生一个请求,那么在处理事务的期间我们就把它假想成用户代理客户端。

UASCore事务和传输层上UAS的处理功能集。

User Agent(UA)既能作为用户代理客户端又能作为用户代理服务器的逻辑实体。角色UAC和UAS,以及代理和重定向服务器都是定义在事务的基础上的。例如,当用户发起一个呼叫发送初始INVITE请求时,它作为UAC;当它从被呼叫者接收BYE请求时,作为UAS。类似的,同一软件能作为一个请求的代理服务器和下一个请求的重定向服务器。以上定义的代理、位置和注册服务器都是逻辑实体。实现时可能将它们结合到一个应用中。

  1. 3.      SIP协议结构

SIP是一个分层协议,这就意味着其行为用相对独立的处理阶段集来描述,每个阶段间松耦合。为便于表述,协议的行为用层来描述,允许对功能的描述跨越元素。但是它没有规定实现。当我们说一个元素“包含”一层,我们的意思是说元素遵从该层定义的规则。并非协议指定的每个元素都包含每一层。而且,SIP所指的元素都是逻辑元素,而非物理元素。物理实现可作为不同逻辑元素,甚至是基于事务(transaction-by-transaction)的。

SIP的最低层是语法和编码。其编码指定使用巴科斯范式(BNF)

第二层是传输层。它定义在网络上客户端如何发送请求和接收响应,服务器如何接收请求和发送响应。所有SIP元素都包含传输层。

第三层是事务层。事务是SIP的基础组件。事务是客户端事务(使用传输层)向服务器事务发送的请求,以及服务器事务向客户端发回的该请求的响应。事务层处理应用层转播、响应与请求的匹配以及应用层超时。用户代理客户端(UAC)完成任何任务都使用一系列事务。用户代理包含一个事务层,如有状态代理。无状态代理不包含事务层。事务层有一个客户端组件(称为客户端事务)和服务器组件(称为服务器事务),它们都用有限状态机表示,用来处理特殊请求。

事务层之上的层称为事务用户(TU)。每个SIP实体,除无状态代理外,都是事务用户。当事务用户想发送请求时,它就创建一个客户端事务实例,并将请求与目的IP 地址、端口一起发送。创建客户端事务的TU 也可以取消事务。客户端取消事务的时候,就要求服务器停止进一步处理,并恢复到初始化事务前的状态,然后返回该事务的一个错误响应。可通过CANCEL请求完成取消事务,CANCEL请求包含自己的事务,同时也提及需要取消的事务。

SIP元素即用户代理客户端和服务器、无状态和有状态代理、注册服务器,包含区分这些元素的核心(Core)。除无状态代理外,核心是事务用户。UAC 和UAS核心的行为依赖于方法,所有方法有一些通用规则(见第8 章)。对UAC 而言,规则支配请求的结构;对UAS而言,规则管理请求的处理和响应的生成。由于注册在SIP中扮演很重要的角色,处理REGISTER 的UAS有一个特殊的名称“注册员”。第10 章描述了REGISTER 方法的UAC、UAS核心行为。

其它的请求都在对话中发送。对话是在两个用户代理间持续一定时间的对等SIP关系。对话促成两个代理间消息顺序和请求的正确路由。INVITE方法是本规范中定义的用于建立对话的唯一方法。当UAC 在对话的连接中发送一个请求时,它遵通用UAC规则以及对话中请求规则。

SIP中最重要的方法是INVITE方法,它用于在参与者间建立会话。会话是参与者和参与者间通信的媒体流的集合。

  1. 4.      SIP消息结构

SIP消息是从客户端到服务器的请求,或从服务器到客户端的响应。

尽管语法在字符集和语法细节上不同,请求和响应都使用基本的RFC 2822格式。(SIP允许头字段不是有效的RFC 2822头字段。)两种类型的消息都由一个起始行、一个或多个头字段、一个标识头字段结束的空行和一个可选消息体组成。

generic-message=start-line

*message-header

CRLF

[message-body]

start-line=Request-Line/Status-Line

起始行、每个消息头行和空行必须以回车换行序列(CRLF)终止。注意:即使没有消息体,也必须有空行。

除了上面所述的字符集不同外,SIP消息和头字段语法大部分与HTTP/1.1相同。

4.1.   请求

SIP请求的起始行有Request-Line,作为与其它消息的区分。Request-Line包含一个方法名、一个Request-URI和由空格(SP)字符分开的协议版本。

Request-Line以CRLF结束。除在终止行CRLF序列中外,其它的地方都不允许CR或LF。在元素中不允许任意数量的空格(LWS)。

Request-Line=Method SP Request-URI SP SIP-Version CRLF

Method:用于注册Contact信息的REGISTER;用于建立会话的INVITE、ACK和CANCEL;用于终止会话的BYE和用于查询服务器能力的OPTIONS。用于即时消息的MESSAGE;SIP扩展在RFC中可能有附加方法。

Request-URI:Request-URI是SIP或SIPS URI,描述见第17.1节,或是普通URI(RFC 2396)。它指明请求的目的用户或服务。Request-URI不能包含未保留空间(unescaped spaces)或控制字符,也不能包围在“<>”中。

SIP元素可能支持“SIP”和“SIPS”以外的Request-URI模式,如RFC 2806中的“tel”URI模式。SIP元素可使用任何机制将非SIPURI转换成SIPURI、SIPS URI或其它模式。

SIP-Version:请求和响应消息都包含所使用的SIP版本号,遵循[H3.1](用SIP替换HTTP、SIP/2.0替换HTTP/1.1)中关于版本次序、规范要求和版本号更新的描述。为遵从本规范,发送SIP消息的应用必须包含SIP-Version“SIP/2.0”。SIP-Version字符串区分大小写,实现时必须发送大写形式的字符串。

与HTTP/1.1不同,SIP将版本号视为字符串。而实际上,这是没有区别的。

例如:

 

4.2.   应答

SIP响应在起始行中有一个Status-Line,作为与请求的区分。Status-Line依次由协议版本号、数字Status-Code和以及相关的文本分析(textual phrase)组成,它们之间用字符SP隔开。

除在最后的CRLF序列中,其他地方不允许有CR或LF。

Status-Line=SIP-Version SP Status-Code SP Reason-Phrase CRLF

Status-Code是一个三位整数的结果代码,它指明尝试理解和满足请求的结果。Reason-Phrase是Status-Code的简短的文本描述。Status-Code用于自动控制,Reason-Phrase便于人理解。客户端不需要检查或显示Reason-Phrase。

建议这些原因分析的一些特定用语,实现可以先用其它的文本,例如,在请求的Accept-Language头字段中指明的语言。

Status-Code的第一个数字定义响应类型。后面的两位数字没有类别的意义。因此,状态代码在100到199之间的响应成为“1xx”响应,状态代码在200到299之间的响应成为“2xx”响应,依此类推。SIP/2.0中第一个数字有六种值:

1xx:informational-已经收到请求、继续处理请求。

2xx:success-已经成功收到,理解和介绍行动。

3xx:Redirection-为完成呼叫请求,还须采取进一步地动作。

4xx:ClientError-请求有语法错误或服务器不能执行请求。

5xx:ServerError-服务器出错,不能执行合法请求。

6xx:GLOBALFAILURE-任何服务器都不能执行请求。

例如:

 

4.3.   头字段

在语法和语义方面,SIP头字段和HTTP头字段很相似。特别的,SIP头字段遵循HTTP/1.1中消息头语法的定义,以及扩展多行头字段的规则。但是,后者在HTTP中有隐含的空白和折叠(white space and folding)。本规范遵从RFC 2234,使用明确的空白和折叠作为语法的完整部分。

HTTP/1.1中指出其值用逗号分隔的、具有相同字段名的多个头字段能组合成一个头字段。这同样适用于SIP,但对不同的语法有特殊的规则。特别的,SIP头的语法格式如下:

header=header-name HCOLON header-value *(COMMA header-value)

它允许将名称相同的头字段组合成用逗号分隔的一列。除非头字段值为“*”,Contact头字段允许用逗号分隔。

4.3.1. 头字段格式

头字段遵循RFC 2822的第2.2节中的通用头格式。每个头字段依次由:字段名、冒号“:”和字段值组成。

field-name:field-value

消息头的正式语法允许冒号的两边有任意多个空格;但是,实现时应避免字段名和冒号间的空白,在冒号和字段值间使用一个空格(SP)。

Subject:         lunch

Subject    :     lunch

Subject         :lunch

Subject: lunch

因此,以上格式都是有效格式,且意义相同,但最后一个是首选格式。

头字段可扩展为多行,方法是在每个附加行前添加一个空格(SP)或横向制表(HT)。一行的结束以及下一行开始的空格都看作一个空格(SP)字符。因此,以下两种方式意义相同:

Subject: I know you’re there,pick up the phone and talk to me!

Subject: I know you’re there,

pick up the phone

and talk to me!

不同字段名的头字段的相对顺序并不重要。但推荐需要代理处理的头字段(例如,Via、Route、Record-Route、Proxy-Require、Max-Forwards和Proxy-Authorization)放在消息的头部,以便于快速解析。相同字段名的头字段行的相对顺序非常重要。带相同字段名的多个头字段行仅出现在这样的消息中:头字段的整个字段值的定义是用冒号分隔的一列。我们可以将多个头字段行组合成一个“field-name:fieldvalue”对,而不改变消息的语义,方法是依次将每个字段值添加到第一个后,它们之间用逗号分隔。WWW-Authenticate、Authorization、Proxy-Authenticate和Proxy-Authorization不符合本规则,字段名为上述项的多个头字段行可能在一个消息中同时出现,因此不能将它们组合成一个头字段行。

实现应能以每行一值或逗号分隔值的格式处理相同名称的多个头字段行。

以下几组头字段行是合法的并且意义相同:

Route: <sip:alice@atlanta.com>

Subject: Lunch

Route: <sip:bob@biloxi.com>

Route: <sip:carol@chicago.com>

Route: <sip:alice@atlanta.com>, <sip:bob@biloxi.com>

Route: <sip:carol@chicago.com>

Subject: Lunch

Subject: Lunch

Route: <sip:alice@atlanta.com>, <sip:bob@biloxi.com>, <sip:carol@chicago.com>

以下几组是合法的,但意义不同:

Route: <sip:alice@atlanta.com>

Route: <sip:bob@biloxi.com>

Route: <sip:carol@chicago.com>

 

Route: <sip:bob@biloxi.com>

Route:<sip:alice@atlanta.com>

Route: <sip:carol@chicago.com>

 

Route: <sip:alice@atlanta.com>, <sip:carol@chicago.com>, <sip:bob@biloxi.com>

头字段值的格式按头名定义。它通常是一个TEXT-UTF8八位位组序列,或一个空格、标记、分隔符和引用串的组合。许多现用的头字段遵循这样的通用格式:字段值,随后是分号分隔的参数名、参数值对:

field-name: field-value*(;parameter-name=parameter-value)

尽管在头字段值后可附加任意多个参数对,但任何给定的参数名不能出现多次。比较头字段时,字段名是不区分大小写的。除非在特定头字段的定义中有说明外,字段值、参数名和参数值都是不分大小写的。标记通常不区分大小写。除非特殊说明,引用串值要区分大小写。例如:

Contact:<sip:alice@atlanta.com>;expires=3600

与CONTACT: <sip:alice@atlanta.com>;ExPiReS=3600意义相同;

且Content-Disposition: session;handling=optional与

content-disposition: Session;HANDLING=OPTIONAL意义相同。

以下两个头字段意义不同:

Warning: 370 dev null "Choose a bigger pipe"

Warning:370 dev null "CHOOSE A BIGGER PIPE"

 

4.4.   消息体

4.4.1. 消息体类型

消息体的Internet媒体类型由Content-Type头字段指定。如果对体进行了任何编码,如压缩,那么必须在Content-Encoding头字段中指出。否则,必须省略Content-Encoding。如果可行,消息体的字符集作为Content-Type头字段值的一部分。

可以在消息体中使用RFC2046 [10]中定义的“多方”MIME 类型。如果远程实现请求,通过不包含多方的Accept头字段请求非多方消息体,那么发送包含多方消息体的请求的实现,必须发送一个会话描述,作为非多方消息体。

SIP消息可能包含二进制体或体部分。如果发送者没有明确指定字符集参数,定义“文本”类型的媒体子类型有默认的字符集值“UTF-8”。

4.4.2. 消息体长度

在Content-Length 头字段中指定以字节计算的体长度。第20.14 节详细描述了头字段的必须内容。

HTTP/1.1 的“分块”传输编码不能用于SIP。(注意,为以分块序列传输消息,“分块”编码修改消息体,每一个都有大小指示器)

  1. 5.      通用用户代理行为

用户代理表示终端系统。它包括用户代理客户端 (UAC)和用户代理服务器(UAS),UAC生成请求,UAS响应请求。外部因素(用户点击按钮或PSTN线信号)促使UAC生成请求,并处理响应。UAS接收请求,并且根据用户输入、外部因素、程序执行结果或者其它机制,生成响应。

当UAC发送请求时,请求通过代理服务器,可以将这些请求转发给UAS。当UAS生成响应,响应将转发给UAC。

UAC和UAS过程取决于两个因素。第一个是,请求或响应是在对话的内部还是外部;第二个是,请求的方法。

在本章,我们讨论了处理对话外的请求时,UAC和UAS行为独立于方法的规则。这当然包括自己建立对话的请求。

5.1.    UAC行为

介绍对话外的UAC 行为。

5.1.1. 生成请求

UAC 制定的有效SIP请求,至少必须包括以下头字段:To、From、Cseq、Call-ID、Max-Forwards 和Via。在所有的SIP请求中,这些头字段都是必需的。这六个头字段是SIP消息基本的构件块,它们共同提供大部分关键性消息路由服务,包括消息的寻址、响应的路由、限制消息的传播、消息的排序和事务的唯一标识符。UAC 制定的有效SIP请求除了包含这些头字段外,还有必需的请求行。这个请求行包含了方法、Request-URI和SIP版本。

Request-URI消息初始Request-URI应该设置成To字段的URI值。但应注意,REGISTER方法例外。保密性原因或者便于将这些字段设置成相同的值(特别是在传输过程中,原始UA期望改变Request-URI),可能不符合需要。

在一些特殊的情况中,预有的路由集合的存在可能影响消息的Request-URI。预有的路由集合可能是用来识别一系列服务器的URI有序集合,UAC将对话外的出站请求发送到其中一个服务器上。通常,预有的路由集合由用户或者服务提供商在UA上手动配置,或者通过一些其它的非SIP机制配置。当提供商希望用带外代理配置UA时,推荐通过为UA提供一个带外代理预有的带单一URI的路由集合来配置UA。

To To头字段首先指明了想要的请求的“逻辑”接收者或者用户的记录地址或者作为请求目标的资源。这不一定是请求的最终接收者。To字段可能包含SIP或者SIPS URI,在适当的时候,它也可以使用其它URI模式(例如,tel URL (RFC 2806 [8]))。所有SIP执行必须支持SIPS URI模式。任何支持TLS的执行必须支持SIPS URI模式。

UAC可以知道怎样以多种方法为特定的请求填充To头字段。通常,用户建议To头字段通过用户界面填充——可能是手动输入URI或者从地址本中选择。通常,用户不必键入完整的URI,而是键入数字或字符串(如,“bob”)。这由UA来选择怎样解释此输入。使用字符串来形成用户SIPS URI的一部分,意味着UA希望此名字可以在SIPS URI注册的右边(RHS)进行域名解析(如,sip:bob@example.com)。使用字符串来形成用户SIPS URI的一部分,意味着UA 希望可以安全地通信,同时,此名字可以在[@]的右边进行域名解析。右边通常是请求者的归属域,这考虑了处理出站请求的归属域。这种像“快速拨号”的特征很有用,它需要归属域的用户部分的解释。

当UA 不希望指明应该解释用户输入的电话号码的域时,可以使用tel URL。相反,UA希望指明请求通过的每个域。例如,在飞机场的用户可能已经登机,通过飞机场的带外代理发送请求。如果键入“411”(美国本地目录帮助的电话号码),这需要通过飞机场——而不是用户归属域的带外代理解释并处理它。在这种情况中,tel:411 将是正确的选择。

对话外的请求不能包含To 标签,请求中的To 字段标签表示对等对话。因为没有建立对话,所以不存在标签。

From  From头字段表示请求发起者的逻辑身份,有可能是用户的记录地址。和To字段一样,它包含了URI和显示名称,显示名称是可选的。SIP元素用它来确定应用于请求的处理规则(如,自动呼叫拒绝)。同样地,因为没有逻辑名字,不包含IP地址或者UA运行主机的正式域名的From URI很重要。

From头字段考虑了显示名称。如果客户端的身份是隐藏时,UAC应该使用显示语法正确的名字“匿名的(anonymous)”,而不是无意义的URI(像sip:thisis@anonymous.invalid)。

通常,特殊UA产生的、在请求中填充到From头字段的值是用户或者用户本地域的管理员预先提供的。如果多个用户使用特殊UA,那么,它具有可交换的描述,包括对应于描述用户身份的URI。为了确定它们是From 头字段所声称的人,请求的接收者可以认证请求的发起者。

From 字段必须包含UAC选择的新标签参数。

Call-ID  Call-ID头字段作为集合一系列消息的唯一标识符。在对话中,每个UA 发送的所有请求和响应中,Call-ID 必须是一样的。UA 的每个注册中,它应该是一样的。

在UAC 创建的对话外的新请求中,如果不是特定方法行为覆盖的,UAC选择的Call-ID头字段必须是在时间和空间上全球唯一的标识符。所有的SIPUA必须有一种方法来保证其他UA 不会产生它们产生的Call-ID头字段。注意,当在特定的失效响应后,重发请求以修正请求时(如,认证挑战),重的请求将不作为新的请求,因此不需要新的Call-ID 头字段;

推荐在生成Call-ID 时,使用密码学上的随机标识符(RFC 1750 [11])。执行时可以使用这种格式“localid@host”。Call-ID 是区分大小写的,并且逐字节比较的。

使用密码学上的随机标识符提供了会话截获保护,并减少了Call-ID 冲突的可能性。

对于选择请求的Call-ID 头字段的值,不需要规章界面或用户界面。

CSeq  CSeq头字段是用作识别和指示事务的。它由序列号和方法组成。此方法必须和请求相匹配。对于对话外的非REGISTER 请求,此序列号是任意的。此序列号的值必须是值小于2~31 的32 位的无符号整数。只要遵循上述原则,客户端就可以随意地使用一种机制来选择CSeq 头字段值。

Max-Forwards  Max-Forwards头字段是用作限制请求传输到其目的地跳跃的点数。它是一个整数,在每个跳跃点上减一。如果请求在到达其目的地之前,Max- Forwards 值到0,将返回483(太多跳跃点)错误响应,拒绝其请求。

UAC必须在每个请求中插入Max-Forwards头字段,并赋初始值为70。此数字足够长,可保证在没有环路时,请求不会在SIP网络中丢失;当存在环路时,此数字不会消耗代理太多的资源。要谨慎地使用更小的值,只有在UA知道网络拓扑时,才可以使用更小的值。

Via  Via头字段表示事务中使用的传输,并标识了响应发送的位置。仅在选择了要到达的下一个跳跃点后(这可能包括[4]中过程的使用),才在传输中加上Via 头字段的值。

当UAC创建请求时,它必须在请求中插入Via。在头字段中的协议名和协议版本必须分别是SIP和2.0。Via头字段值必须包含分支参数(branch parameter)。此参数用来识别请求创建的事务。此参数同时用于客户端和服务器。

对于UA发送的所有请求,其分支参数的值必须在时间和空间上是唯一的。此规则的异常是CANCEL和非2xx 响应的ACK。CANCEL请求有与它取消的请求相同的分支值。非2xx 响应的ACK也有与它所应答的INVITE响应相同的分支ID。

分支ID 参数唯一的特性,有助于其作为事务ID使用,和本规范一致的元素插入的分支ID 必须是以“z9hG4bk”字符开头。这七个字符用作magic cookie(7 认为是足以确保旧RFC 2543 执行不会选择这个值),以便于接收请求的服务器可以确定以本规范描述的格式(即全球唯一)构造分支ID。在本规范内,分支标签的精确格式是执行定义的(implementation-defined)。

当请求是通过传输层处理的,那么将发送Via头的maddr、ttl 和sent-by组件。

Contact  Contact头字段提供了SIP或者SIPS URI,可用于为随后请求联系UA的具体实例。必须正确地表示Contact头字段,并包含任何请求中的SIP或者SIPS URI,这将导致建立对话。Contact的范围是全局的。即Contact头字段值包括UA要接收请求的URI,即使是在任何对话外的随后请求中使用,此URI都必须是有效的。

如果Request-URI或top Route头字段值包含SIPS URI,Contact头字段也必须包含SIPS URI。

Supported and Require 如果UAC支持SIP扩展,服务器可将此扩展用于响应,UAC应该在请求中引用Supported头字段,

列出的可选标签必须引用标准协议栈RFC中定义的扩展。这就防止了服务器为了接收

服务而坚持客户端执行非标准的、供应商定义的特性。因为,供应商也经常参考实验和情报的RFC 中定义的扩展,定义自己的扩展,所以,它们显然不能用在请求中的Supported头字段。

如果UAC坚持要UAS理解,UAC为处理请求而用于请求的扩展,它必须在请求中插入Require头字段,列出这些扩展的可选标签。如果UAC希望将扩展用于请求中,并坚持它所要经历的任何代理都可以理解这些扩展,它必须在请求中插入Proxy-Require头字段,列出这些扩展的可选标签。

和Supported 头字段一起,Require 和Proxy-Require 中头字段可选的标签必须仅仅引用标准协议栈RFC中定义的扩展。

Additional Message Components 在创建了新请求,并合理地构造上面所介绍的头字段后,可以添加任何其他的可选头字段,作为具体方法的头字段。

SIP请求可能包含MIME编码的消息体。不管请求包含的消息体是什么类型,必须阐明特定的头字段来说明主题内容的特征。

5.1.2. 发送请求

 

请求的目的地是可计算的。除非有本地的策略指明,目的地必须通过[4]中介绍的DNS过程才可以确定。如果路由集合中的第一个元素指示了严格的路由器,那么必须将DNS过程用于请求的Request-URI。否则,必须将DNS过程用于请求中的第一个Route头字段(如果存在),如果没有Route 头字段,将DNS过程用于请求的Request-URI。这些过程产生有序的地址集合、端口和传输。如果Request-URI指定SIP源,那么与过程[4]使用哪个URI无关;如果输入的URI是SIPS URI,那么UAC必须遵循过程[4]。

本地策略可以指定可选的目的地。如果Request-URI包含SIPS URI,那么,任何可选的目的地必须和TLS 联系。除此以外,如果请求中没有包含Route头字段,那么,就不约束可选的目的地。这提供了简单的可选机制——为预有的路由集合指定带外代理。然而,不推荐配置带外代理,反而应该使用单一URI 的预有的路由集合。如果请求包括路由头字段,那么请求应该发送到来自其最上面值的位置;但是也可以遵循本文档指定的路由和Request-URI策略发送至任何UA信任的服务器(与RFC 2543中相反)。特别的是,带外代理配置的UAC 应该试图发送请求给第一个Route头字段值指明的位置,而不是采用策略发送所有消息给带外代理。

这确保了没有添加Record-Route头字段值的带外代理将不参与随后请求的路径。它也允许不能解析第一个Route URI的终端,将此任务委派给带外代理。

对于有状态元素,UAC应该遵循[4]中定义的过程——尝试每个地址,直到联系到服务器。每次尝试构成新的事务,因此,每次用新的分支参数携带不同的最上面的Via头字段值。此外,在Via 头字段的传输值设置成每个目标服务器确定的传输。

5.1.3. 处理应答

 

响应最初是在传输层处理,然后传输到处理层。处理层完成其处理,然后将响应传输到TU。TU的大多数响应处理是指定方法的。但是,还有一些通用的行为与方法无关。

Transaction Layer Errors 在很多情况中,处理层返回的响应不是SIP消息,而是处理层错误。当从处理层接收到超时错误时,必须视为接收到了408(请求超时)状态代码。如果传输层报告了重大的传输错误(通常,由于UDP 的重大ICMP错误或者TCP连接错误),这种情况必须视为503(服务不可用)状态代码。

Unrecognized Responses UAC必须将其不识别的最终响应视为对等于x00类的响应代码,并且,UAC必须能够处理所有的x00响应代码。

例如,UAC接收到了不识别的响应代码431,它可以安全地设想此请求有问题,并将响应处理为接收到了400(错误请求)响应代码。UAC必须将不同于100 的、不识别的临时响应视为183(会话进行)。UAC 必须能够处理100和183 响应。

Vias 如果在响应中存在不止一个Via头字段,那么UAC应该丢弃这些信息。在请求发起者之前的其他Via 头字段值的状态,暗示消息是错误指向的或者是不可靠的。

Processing 3xx Responses 在接收到重定向响应后(如,301响应状态代码),客户端应该使用Contact头字段的URI来说明一个或者多个基于重定向请求的新请求。客户端从正确包含URI和原始请求Request-URI的初始目标集合开始。如果客户端希望阐明此请求的基于3xx类响应的新请求,它将此URI放在目标集合中。服从本规范的约束,客户端可以选择将哪个Contact URI放在目标集合中。随着代理递归,处理3xx 类响应的客户端不能够再在目标集合中添加任何给定的URI。如果原始请求有Request-URI中的SIPS URI,那么客户端可以选择换成非SIPS URI,但是应该通知用户不安全URI的重定向。

任何新请求都可能接收到包含其自己原始URI的3xx响应作为联系。两个位置可以互相配置成重定向。将任何给定的URI 仅在目标集合放置一次可以防止无穷的重定向环路。

随着目标集合的增长,客户端可以以任何顺序生成URI 新请求。通用的机制是按照Contact头字段值的‘q’参数值排序。URI请求可以是连续的,也可以是并行的。其中一种方法是,连续地处理递减的q 值排序,并行地处理URI 的每个q值。另一种方法是,仅仅连续地处理递减的q值排序,任意选择相等q值之间的联系。

如果联系列表中的地址造成错误,与在下一章所定义的一样,元素移到列表中的下一地址,直到列表用完为止。如果列表已经用完,那么此请求错误。

错误应该通过错误响应代码(比399大的代码)来检测;如果是网络错误,那么客户端事务将向事务用户报告传输层错误。注意,有些响应代码说明了重试的请求,重试的请求不应该认为是错误。

当接收到具体联系地址失败时,客户端应该尝试下一个连接地址。这包括创建新的客户端事务来传递新的请求。

为了在3xx 响应中创建基于联系地址的请求,UAC必须将目标集合中的整个URI复制到Request-URI,除了method-param和header URI参数。它使用头参数来创建新请求的头字段值。

注意,在一些实例中,在联系地址中通信的头字段可以改为添加到原始重定向请求的现有请求的头字段中。作为通用规则,如果头字段接受了逗号分隔的列标值,那么新的头字段可以添加到原始重定向请求的现有值中。如果头字段不能接受多个值,那么,可以用联系地址中通信的头字段值重写原始重定向请求。例如,如果与下列值一起返回联系地址:

sip:user@host?Subject=foo&Call-Info=<http://www.foo.com>

那么,将重写原始重定向请求的Subject 头字段,HTTP URI 不过是附加在现有的Call-Info 头字段值后面。

推荐UAC重用原始重定向请求中相同的To、From和Call-ID,但是UAC可以选择更新新请求的Call-ID 头字段值。

最后,一旦构造了新请求,那么,使用新的客户端事务来发送新请求,因此,必须在最上面Via字段中有新的分支ID。

无论从其他哪个方面来看,在接收重定向响应基础上发送的请求应该重用原始请求的头字段和消息体。

在一些实例中,与接收到的状态代码和逾时间隔的状态有关,可以在UAC中临时或者永久地缓存Contact头字段值。

Processing 4xx Responses 具体的4xx响应代码与方法无关,需要具体的UA处理。

如果接收到401(未经许可)或407(需要代理认证)响应,那么UAC应该遵循认证过程,使用凭证来重试请求。

如果接收到413(请求实体太大)响应,请求包含的消息体比UAS愿意接受的消息体长,如果可能的话,UAC应该忽略消息体或者使用较短的消息体重试请求。

如果接收到415(不支持的媒体类型)响应,UAS不支持请求中包含的媒体类型。UAC应该重试请求,此时仅使用响应中Accept头字段列出的类型,响应中Accept-Encoding头字段列出的编码和响应中Accept-Language头字段列出的语言。

如果接收到 416(不支持的URI 模式)响应,服务器不支持Request-URI使用的URI模式。客户端应该重试请求,此时使用SIPS URI。

如果接收到420(错误的扩展)响应,此请求包含Require 或者Proxy- Require头字段,列出了代理或者UAS不支持的可选标签特征。UAC应该重试请求,此时,忽略响应中扩展列出的Unsupported头字段。

在上面所有的情况中,通过适当的修改创建新请求,重试请求。新请求组成新事务,应该有与原来请求相同的Call-ID、To 和From 值,但是Cseq应该包含比原来高的新序列号。

其它的4xx响应,包括仍然在定义的,重试可以与也可以不与方法和使用案例有关。

5.2.    UAS行为

当UAS处理对话外的请求时,与方法无关,要遵循一套处理规则。

注意,请求处理是基本的。如果接受请求,所有与其相关的状态改变必须执行。如果拒绝请求,所有的状态改变都不能执行。

5.2.1. 方法检查

一旦请求通过了认证(或者跳过认证),UAS必须检查请求的方法。如果UAS识别但是不支持请求的方法,它必须生成405(方法不允许)响应。UAS必须为405(方法不允许)响应添加Allow头字段。Allow头字段必须列出UAS生成消息支持的方法集合。

如果方法是服务器支持的一种,那么,将继续处理。

5.2.2. 包头检查

如果UAS不能理解请求中的头字段(即是没有在本规范或者其它支持的扩展中定义此头字段),那么服务器必须忽略此头字段,并继续处理消息。UAS应该忽略任何在处理请求中非必需的、非格式化的头字段。

To and Request-URI To头字段标识了原始请求中From字段中标识的用户。由于呼叫转移或者其它代理操作,原始接收者可以是也可以不是UAS处理此请求。当To头字段不是UAS身份时,UAS可以应用任何策略来确定是否接受请求。然而,即使在To头字段中有它们不识别的URI模式(如,tel:URI),或者To头字段没有指明UAS已知的或者当前用户,推荐UAS接受请求。另一方面,如果UAS决定拒绝此请求,它应该生成响应403(Forbidden)状态代码,并将其传送给服务器事务发送。

然而,Request-URI识别处理请求的UAS。如果Request-URI使用了UAS不支持的模式,它应该拒绝此请求,返回416(不支持URI 模式)响应。如果Request-URI不识别UAS将要接受请求的地址,它应该拒绝此请求,返回404(没找到)响应。典型地,使用REGISTER方法来为具体的联系地址绑定其记录地址的UA,将查找Request-URI与联系地址相等的请求。接收Request-URI的其它潜在资源包括,UA发送的、建立或者更新对话的请求和响应的Contact 头字段。

Merged Requests 如果请求在To头字段中没有标签,那么UAS核心必须检查正在进行事务的请求。如果From标签、Call-ID和Cseq和事务精确匹配,那么UAS核心应该生成482(发现环路)响应,并将其发送到服务器事务。

由于分发,相同的请求从不同的路径多次发送到UAS。UAS处理第一个接收到的这样的请求,对于第一个以外的请求,生成482(发现环路)响应。

Require 假定UAS认为Require是处理请求的要素,那么,如果存在Require的话,它将检查Require 头字段。

UAC使用Require头字段告诉UAS——为了正确地处理请求,UAC希望UAS支持的SIP扩展。如果UAS不理解Require 头字段中列出的可选标签,它必须返回状态代码420(错误的扩展)。UAS必须添加Unsupported头字段,并列出请求的Require 头字段中它所不理解选项。

注意,在SIPCANCEL中不能使用Require和Proxy-Require,或者发送ACK请求非2xx响应。如果在请求中出现了这些头字段,必须忽略它们。

ACK 请求2xx 响应必须仅包含在初始请求中出现的Require和Proxy-Require值。

以下是Require 的实例:

UAC -> AS: INVITEsip:watson@bell-telephone.com SIP/2.0

Require: 100rel

UAS-> UAC: SIP/2.0 420 Bad Extension

Unsupported: 100rel

当两边都理解了所有选项时,此行为确保了无延时地进行客户端-服务器交互;如果不理解选项,将减慢速度(如上例)。对于完好匹配的客户端-服务器对,节省了协商机制经常需要的来回路程,交互处理很快。

此外,当服务器不理解客户端请求的特征时,它可以模糊地移动。有些特征,如呼叫处理字段,仅是终端系统感兴趣的。

5.2.3. 内容处理

假定UAS理解客户端需要的任何扩展,UAS检查了消息体和描述它的头字段。如果不理解某一消息体的类型(Content-Type指明的)、语言(Content-Language指明的)或者编码(Content-Encoding指明的),并且此消息体部分不是可选(Content-Disposition字段指明的),那么UAS必须拒绝此请求,返回415(不支持的媒体类型)响应。如果请求中包含了UAS不支持的消息体类型,响应必须包括Accept头字段,列出它所理解的所有消息体。如果请求中包含了UAS不理解的编码,响应必须包括Accept-Encoding头字段,列出UAS所理解的编码。如果请求中包含了UAS不理解的语言,响应必须包括Accept-Language头字段,列出UAS所理解的语言。除了这些检查外,消息体处理还与方法及类型有关。

5.2.4. 应用扩展

除非是请求的Supported头字段中指明了支持的扩展,不允许UAS生成响应时应用扩展。如果不支持想要的扩展,那么服务器应该依靠基准SIP和客户端支持的扩展。在少数情况中,没有扩展,服务器不处理请求,服务器可能发送421(必需扩展)响应。此响应表示,没有支持指定的扩展,不能生成响应。此必需的扩展必须包含在响应的Require头字段中。不推荐使用此行为,因为它将破坏互操作性。

适用于非421响应的任何扩展必须在响应的Require头字段中列出来。当然,服务器不能应用响应的Require头字段没有列出来的扩展。结果,响应的Require头字段仅包含标准协议栈RFC中定义的可选标签。

5.2.5. 处理请求

假定通过了前面子章节的所有检查,UAS处理就成为面向具体方法的。后面章节分别介绍了REGISTER、OPTIONS 、INVITE、BYE、MESSAGE等请求处理。

5.2.6. 生成响应

当UAS希望为请求构造响应时,那么它遵循后面章节介绍的通用过程。在本节没有详细介绍的,正在讨论的响应代码的其他行为,也是必需的。

一旦与创建响应相关的所有过程完成,UAS就将这些响应发送给它所接收请求的服务器事务。

Sending a Provisional Response 生成响应大的、非面向具体方法的原则是,UAS不应该发布非INVITE请求的临时响应;而是,应该尽可能地生成非INVITE请求的最终响应。

当生成100(Trying)响应时,请求中的Timestamp头字段必须复制到100(Trying)响应中。如果在生成响应时有延时,那么UAS应该将延时加到响应的Timestamp 值中。此值必须包含以秒计算的、发送响应和接收请求的时间差。

Headers and Tags 响应的From 字段必须和请求的From 头字段相同,响应的Call-ID字段必须和请求的Call-ID 头字段相同,响应的CSeq 字段必须和请求的CSeq 头字段相同,

响应的Via字段必须和请求的Via头字段相同,并且必须保持相同的顺序。如果请求中包含请求的To标签,那么,响应中的To头字段必须和请求中的相同。然而,如果请求的To字段没有包含标签,那么,响应中的To头字段的URI必须和请求中的To头字段的URI 相同,此外,UAS必须在响应的To头字段中添加标签(除了100Trying)响应外,其中可能有标签)。这用于识别正在响应的UAS,可能会生成对话ID的组件。相同的标签必须用于该请求的所有响应,包括最终和临时的(也包括100(Trying))响应。

5.2.7. 无状态UAC行为

无状态UAS是不能保持事务状态UAS。它正常地回复请求,但是丢弃响应发送后的状态——通常UAS会保留其状态的。如果无状态UAS接收转发的请求,它将重新生成响应,并重新发送响应,就像它第一次收到请求一样。如果请求是一样的,除非请求处理的方法总是导致相同的结果,否则UAS不能是无状态的。例如,此规则输出无状态注册服务器。无状态代理不使用处理层,它们直接从传输层接收到请求,并直接将响应发送给传输层。

无状态UAS角色主要是处理发布挑战响应的不需认证的请求。如果对不需认证的请求进行有状态的处理,那么,恶意的不需认证的请求可以创建大量的事务状态,可能会减慢或者挂掉UAS的呼叫处理,实际上,将造成拒绝服务。

无状态UAS的大多数重要的行为如下:

²  无状态UAS不能够发送临时(1xx)响应。

²  无状态UAS不能够转发响应。

²  无状态UAS必须忽略ACK请求。

²  无状态UAS必须忽略CANCEL请求。

²  必须以无状态方式生成To 头字段——为相同请求一贯地生成相同标签的方式。

在其它各个方面,无状态UAS和有状态UAS是一样的。对于每个新请求,UAS可以以有状态或无状态的方式来操作

  1. 6.      注册(REGISTER

SIP提供了发现机制。如果用户要发起和另一个用户的会话,SIP必须发现可到达目的用户的当前主机。发现处理经常是SIP网络元素完成,比如代理服务器和重定向服务器——它们负责接收请求,决定要发送请求的用户位置,然后将它发送到相应的位置。为了完成这些,SIP网络元素查询了抽象服务——定位服务,这提供了特定域的地址绑定。这些地址绑定将输入的SIP和SIPS URI(如,sip:bob@biloxi.com)映射到想要的用户“更近”的一个或多个URI(如,sip:bob@engineering.biloxi.com)。最后,代理将查询定位服务,将接收到的URI映射到想要的接收者常驻的用户代理。

注册创建了特定域中定位服务的绑定,它将记录地址 URI和一个或者多个联系地址相关联。因此,当域中的代理接收Request-URI和记录地址匹配的请求时,代理将请求转发给记录地址已注册的地址。通常,当请求记录地址路由到域中时,在域定位服务注册记录地址才有意义。在大多数情况中,这意味着注册的域需要与记录地址的URI域匹配。

建立定位服务内容有很多种方法。其中之一是管理。在上面的实例中,通过访问公司数据库可以知道Bob是工程部门的一员。但是,SIP为UA提供了一种机制明确地创建绑定。这种机制就是注册。

注册必须发送REGISTER请求给特定类型的UAS——即是注册服务器。注册服务器作为域中定位服务的前端,发送和写基于REGISTER内容的映射。随后主要是负责此域路由请求的代理服务器查询此定位服务。

SIP不强制执行定位服务的具体机制。唯一的要求是域中的注册服务器必须能够在定位服务中读和写数据,域中的代理和重定向服务必须能够读取相同的数据。在同一域内,注册服务器与特定的SIP代理服务器可以在同一接点。

6.1.    构造REGISTER请求

REGISTER请求添加、删除和查询绑定。REGISTER请求可以在记录地址和一个或多个联系地址之间添加新绑定。合适地通过认证的第三方可以完成代表特定记录地址的注册。客户端也可以删除以前的绑定或者查询绑定,确定记录地址绑定当前所在的位置。

除非另有说明,REGISTER请求的构造和客户端发送REGISTER请求的行为与第5.1节中介绍的通用UAC行为是一样。

REGISTER请求不建立对话。UAC可以在REGISTER请求中包括基于第5.1节介绍的预有的路由集合的Route头字段。在REGISTER请求和响应中的Record-Route头字段没有意义,如果存在,必须忽略。特别的,UAC不能根据REGISTER请求的任何响应中存在和缺少的Record-Route头字段创建新的路由集合。

下列头字段,除了Contact外,必须包含在REGISTER请求中。当然,也可以包括Contact头字段。

Request-URI: Request-URI指定了注册服务器指明的定位服务域。( 如sip:chicago.com)。不能出现SIPS URI的userinfo和@组件。

To: To头字段包括记录地址,可以创建、查询和修改其注册。To头字段和Request-URI字段主要的不同是,前者包含用户名。此记录地址必须是SIP或者SIPS URI。

From: From头字段包含负责注册的人的记录地址。除非是第三方注册,此值和To头字段的值是一样的。

Call-ID: UAC所有的注册应该使用与发送到注册服务器的注册相同的Call-ID头字段值。

如果相同的客户端使用不同的Call-ID值,那么注册服务器不能检测延时的REGISTER请求是否没有排序到达。

CSeq:CSeq值保证REGISTER请求适当的排序。对于每个使用相同的Call-ID的REGISTER请求,UA必须逐一增加Cseq值。

Contact: REGISTER请求可能包括有一个或多个地址绑定值的Contact头字段。直到它们接收到来自注册服务器的前一请求的最终响应,或之前的REGISTER请求超时,UA才能发送新的注册(即是包含与转发相对的新Contact头字段值)。

在REGISTER请求中,下面的Contact头参数有特定的意义。

action:RFC 2543 不赞成action 参数。UAC 不应该使用action 参数。

expires:expires参数表示了UA绑定的有效时间。此参数值是表示秒的数字。如果不提供此参数,那么将使用expires头字段的值代替。不规范的值应该视为等于3600。

6.1.1. 添加绑定

发送给注册服务器的REGISTER请求包括SIP请求应该转发给记录地址的地址。记录地址包括在REGISTER请求的To头字段中。

请求的Contact头字段值主要是由SIP和SIPS URI组成的,它确定具体的SIP终端(如,“sip:carol@cube2214a.chicago.com”),同时,也可以使用其它的URI模式。例如,SIPUA可以选择注册电话号码(使用tel URL,RFC 2806)和email 地址(使用mail to URL,RFC 2368 )作为的记录地址的联系人。

例如, Carol,使用记录地址“ sip:carol@chicago.com ”在SIP注册服务器的chicago.com 域注册。chicago.com 域的代理服务器将使用Carol 的注册,将Carol 的记录地址请求路由到其SIP终端。

一旦客户端在注册服务器上建立了绑定,如果需要,它可以发送包含新绑定和修订现有绑定的随后注册。REGISTER 请求的2xx 响应,将在Contact 头字段中包含完整的、在此注册服务器上注册记录地址的绑定列表。

如果REGISTER请求To头字段的记录地址是SIPS URI,那么,请求的Contact头字段值也应该是SIPS URI。当以其它方式来保证联系地址 表示的资源的安全时,客户端仅注册SIP记录地址下的非SIPS URI。这可适用于调用不是SIP协议的URI和不是TLS协议保证其安全性的SIP设备。

注册不需要更新绑定。典型的是,UA仅更新其自己的联系地址。Setting the Expiration Interval of Contact Addresses 当客户端发送REGISTER请求时,它可以建议逾时间隔的状态,表示客户端注册有效的时间。(注册服务器基于其本地策略选择实际的时间间隔。)

有两种方法可用于客户端建议绑定的逾时间隔:通过Expires 头字段或者expiresContact 头参数。当在单个REGISTER 请求中给出多个绑定时,后者允许在预先绑定的基础上建议逾时间隔,但是前者建议的逾时间隔适用于不包含expires 参数的所有Contact 头字段值。

如果在REGISTER中,表示建议到期时间的两种机制都不存在,那么,客户端表示,它要服务进行选择。

Preferences among Contact Addresses 如果REGISTER 请求发送多个Contact,那么,注册UA要将所有的Contact头字段值的URI和To字段的记录地址相关联。此列表可以使用Contact头字段的‘q’参数排出优先级。Q参数表示具体Contact头字段值与记录地址其它绑定的相关优先级。

6.1.2. 删除绑定

注册是软状态,除非是更新才到期,但是也可以明确地删除。客户端可以影响注册服务器选择的逾时间隔。通过在REGISTER 请求的联系地址指定“0”逾时间隔,UA请求立即删除绑定。UA应该支持这种机制,以便于可以在逾时间隔到期之前删除绑定。

REGISTER-specific Contact头字段值“*”用于所有的注册,但是,如果Expires头字段不用值“0”表示,不能使用“*”。

使用“*”Contact 头字段值允许注册——在不知道精确值时,删除与记录地址相关的所有绑定。

6.1.3. 提取绑定

不管请求是否包含有Contact 头字段,REGISTER 请求成功的响应包含全部的现有绑定。如果REGISTER 请求中没有Contact 头字段,那么绑定列表左边不改变。

6.1.4. 更新绑定

每个UA负责更新它之前建立的绑定。UA不应该更新其它UA建立的绑定。注册服务器的200(OK)响应包含一系列的Contact头,列举了所有的当前绑定。UA 比较每个联系地址,检查它是否创建了联系地址。如果是,根据expires参数——如果没有,就根据Expires 字段值更新逾时间隔。UA随后在逾时间隔结束之前,为其每个绑定发布REGISTER请求。它也可以在REGISTER请求中,组合几个更新。

在单个引导周期,UA应该为所有的注册使用相同的Call-ID。除非有重定向,注册更新应该发送到与原始注册相同的网络地址。

6.1.5. 设置内部时钟

如果REGISTER 请求的响应包含有Data 头字段,那么客户端可以使用此头字段获取当前的时间,设置内部时钟。

6.1.6. 发现注册服务器

UA可以使用三种方法来确定发送注册的地址:通过配置、使用记录地址和多播。可以用注册服务器地址配置UA,这种方法超出了本规范的范围。如果没有可配置的注册服务器地址,那么,UA应该使用通用的SIP服务器定位机制,将主机部分的记录地址作为请求的Request-URI和地址。例如,UA为用户“sip:carol@chicago.com”将REGISTER请求寻址到“sip:chicago.com”。

最后,UA可以配置成多播。多播注册都编址为已知的“所有SIP服务器”多播地址“sip.mcast.net”(224.0.1.75 for IPv4)。现在没有分配已知的Ipv6的多播地址;当需要时,将单独说明这种分配。SIPUA可以侦听此地址,并使用它来知道其它本地用户的当前位置;但是,它们并不响应请求。

在有些情况中,多播注册可能不适用,例如,如果多播事务共享相同的本地网络。

6.1.7. 发送请求

一旦构造了REGISTER方法,并确定了消息的目的地,那么,UAS遵循第5.1.2节介绍的过程,将REGISTER请求发送给处理层。如果因为REGISTER没有响应,处理层返回超时错误,UAS不应该立即向相同的注册服务器再尝试注册。

立即再尝试有可能也超时。为造成超时的条件等待合理的时间间隔,可以减少不必要的网络负载。没有强制具体的时间间隔。

6.1.8. 错误响应

如果UA 接收到423(Interval Too Brief)响应,在使得REGISTER 请求中的所有联系地址逾时间隔等于或大于423(Interval Too Brief)响应Min-Expires 头字段的逾时间隔后,它可以再注册。

6.2.    处理REGISTER请求

注册服务器是UAS,在其管理域内,它响应REGISTER请求,并保留可以访问代理服务器和重定向服务器的一系列绑定。注册服务器遵循第5.2节处理响应,但是它只接受REGISTER请求。注册服务器不能生成6xx响应。

在适当的时候,注册服务器可以重定向REGISTER请求。通用的用法是,注册服务器侦听多播接口,用302(暂时清除)响应将多播REGISTER请求重定向到其自己单播接口。

如果Record-Route包含在REGISTER请求中,那么,注册服务器必须忽略Record-Route头字段。注册服务器不能在REGISTER 请求的响应中包含Record-Route 头字段。

注册服务器可能接收到穿越代理的请求,它认为REGISTER是未知的请求,并添加Record-Route头字段值。

注册服务器必须知道(例如,通过配置)它所保留绑定的域。注册服务器必须按照其接收的顺序处理REGISTER请求。必须能够基本处理REGISTER 请求,意味着具体的REGISTER请求可以完全处理,也可以一点都不处理。必须独立于其它注册和绑定改变,处理每个REGISTER 请求。

当接收到REGISTER请求,注册服务器遵循以下步骤:

1. 注册服务器检查Request-URI,确定它是否可以访问Request-URI指定域的绑定。如果不能,并且,如果服务器也当作代理服务器,那么,服务器应该遵循第14章介绍的代理消息的通用行为,将请求转发给寻址域。

2. 为了保证注册服务器支持任何必要的扩展,注册服务器必须像第5.2.2节介绍的UAS一样处理Require 头字段。

3. 注册服务器应该认证UAC。注册服务器的行为绝对不会不考虑SIP通用认证框架。如果认证机制不可用,那么注册服务器可以将From地址作为请求发起者声明的身份。

4. 注册服务器应该确定,认证用户是否有权修改记录地址的注册。例如,注册服务器可能查询授权数据库——它映射了用户名和用户有权修改的一系列记录地址。如果认证用户无权修改绑定,注册服务器必须返回403(Forbidden),并跳过剩下的步骤。

在支持第三方注册的架构中,实体可以负责更新多个记录地址相关的注册。

5. 注册服务器从请求的To头字段取出记录地址。如果记录地址不可用于Request-URI域,那么注册服务器发送404(Not Found)响应,并跳过剩下的步骤。URI必须转换成规范的格式。为了实现这一点,必须删除所有的URI 参数(包括user-param),同时将所有的转义字符串转换成保留格式。此结果用作一系列绑定的索引。

6. 注册服务器检查请求是否包含Contact头字段。如果没有,跳到最后一步。如果有Contact头字段,注册服务器检查,Contact头字段是否包含了特殊值“*”和Expires字段。

如果请求有其他的Contact头或者非零的到期时间,那么,请求是无效的,服务器返回400(Bad Request)响应,并跳过剩下的步骤。如果没有,注册服务器检查,Call-ID是否和每个绑定的存储值一致。如果没有,它必须删除这些绑定。如果一致,仅在请求的Cseq高于绑定的存储值时,删除绑定。否则,必须放弃更新,同时请求失败。

7. 注册服务器现在依次处理Contact头字段的每个联系地址。对于每个地址,它按照下面的方法确定逾时间隔:

²  如果字段值有expires参数,此值必须当作请求的到期时间。

²  如果没有这样的参数,但是请求有Expires头字段,此值必须当作请求的到期时间。

²  如果都没有,本地配置的默认值必须当作请求的到期时间。

注册服务器可以选择小于请求的逾时间隔的到期时间。当且仅当请求的到期时间大于零,并且小于一个小时,同时小于注册服务器配置的最小值,注册服务器可以拒绝注册,并返回423(Interval Too Brief)响应。此响应必须包含Min-Expires 头字段——说明注册服务器想要的最小逾时间隔。然后,它跳过剩下的步骤。

在限制需要保持的状态和减少可能的注册停滞的同时,允许注册服务器设置注册时间间隔,防止过于频繁的注册更新。注册的逾时间隔频繁地用于创建服务上。其中一个实例是,follow-me服务,在这里,终端用户可能仅在一个很短的周期内可用。因此,注册服务器应该接受简短注册,如果时间间隔很短以至于更新会降低注册服务器的性能,那么,应该拒绝该请求。

对于每个地址,注册服务器随后使用URI 比较规则搜索当前的绑定列表。如果绑定不存在,将暂时添加它。如果绑定存在,注册服务器检查Call-ID 值。如果现有绑定的Call-ID值与请求中的Call-ID 值不同,如果逾时间隔为零或者有其它更新,必须删除绑定。如果它们是相同的,那么注册服务器比较CSeq 值。如果此值高于现有绑定的值,它必须更新或者删除绑定。否则,必须放弃更新,同时请求失败。

此算法确保了忽略相同UA 无序的请求。

每个绑定记录记录了请求的Call-ID 和Cseq 值。

当且仅当,绑定更新和添加成功,必须提交绑定更新(即是使得代理和重定向服务器可见)。如果其中之一失败了(例如,因为后台数据库提交失败),那么,请求必须失败,返回500(Server Internal Error)响应,同时必须删除所有尝试的绑定更新。

8. 注册服务器返回200(OK)响应。响应必须包含列出了所有当前绑定的Contact 头字段值。每个Contact 值必须对注册服务器选择的、说明其逾时间隔的“expires”参数起作用。此响应应该包含Date 头字段。

  1. 7.      查询(OPTIONS

SIP方法OPTIONS允许UA 查询其它UA 和代理服务器的能力。这就允许客户端不必“Ringing”另一方,发现关于支持的方法、内容类型、扩展和编码等等的信息。例如,在客户端将Require 头字段插入到INVITE 列出的它所不确定目的UAS 支持的选项时,客户端可以使用OPTIONS查询目的UAS,检查Supported头字段是否返回此选项。所有的UA必须支持OPTIONS 方法。

Request-URI确定OPTIONS请求的目标,它可以识别其它的UA和SIP服务器。如果OPTIONS寻址到代理服务器,那么Request-URI设置为没有用户部分,和REGISTER请求的Request-URI 设置一样。

换言之,服务器接收到Max-Forwards头字段为0的OPTIONS请求,可能不管Request-URI而直接响应请求。

此行为和HTTP/1.1相同。通过发送一系列有递增Max-Forwards值的OPTIONS请求,此行为可以用作“路由跟踪”功能,检查单个跳跃点服务器的能力。

作为通用UA的行为,如果OPTIONS没有响应,处理层可以返回超时错误。这可以说明目标不可到达,因此是无效的。

OPTIONS请求可以作为建立对话的一部分发送,查询在对话中以后可能使用的对等物的能力。

7.1.    构造OPTIONS请求

使用第5.1.1节讨论的SIP请求的标准规则来构造OPTIONS请求。

Contact头字段可能出现在OPTIONS中。

应该包括Accept头字段,说明在响应中UAC想要接收到的消息体的类型。这主要用来设置一种用于描述UA媒体能力的格式,如SDP(application/sdp)。

OPTIONS请求的响应假定为是在原始请求Request-URI的范围内的。然而,仅当OPTIONS作为建立对话的一部分发送时,它才能保证生成OPTIONS响应的服务器可以接收到将来的请求。

以下是OPTIONS请求的实例:

OPTIONS sip:carol@chicago.com SIP/2.0

Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877

Max-Forwards: 70

To: <sip:carol@chicago.com>

From: Alice <sip:alice@atlanta.com>;tag=1928301774

Call-ID: a84b4c76e66710

CSeq: 63104 OPTIONS

Contact: <sip:alice@pc33.atlanta.com>

Accept: application/sdp

Content-Length: 0

7.2.    处理OPTIONS请求

使用第5.2.6 节讨论的SIP响应的标准规则来构造OPTIONS响应。选择的响应代码必须和INVITE请求已经选择的一样。即使,如果准备接受呼叫,返回200 (OK);如果UAS 忙,返回486(这儿正忙)等等。这允许OPTIONS请求用作确定UAS 的基本状态,这可以是UAS是否接受INVITE 请求的指示。

在对话中接收到OPTIONS请求生成200 (OK)响应,和对话外构造的一样,对对话没有任何影响。

因为代理处理OPTIONS和INVITE请求的不同,OPTIONS的使用有局限性。分发的INVITE可能返回多个200(OK)响应,而分发的OPTIONS可能只返回一个200(OK)响应,因为代理使用非INVITE 处理机制处理的。

如果代理服务器生成OPTIONS响应,那么,代理返回200(OK),列出服务器的能力。此响应不包括消息体。

Allow、Accept、Accept-Encoding、Accept-Language和Supported头字段应该出现在OPTIONS请求的200 (OK)响应中。如果代理产生此响应,因为代理不知道方法,Allow是模糊的,所以代理应该忽略Allow头字段。Contact头字段可能出现在200 (OK)响应中,并和3xx 响应有相同的语义。即是它们可能列出到达用户的一系列可选名字和方法。Warning头字段也可能出现。

消息体可能发送,其类型由OPTIONS请求的Accept头字段确定(如果Accept头字段不存在,默认值为application/sdp)。如果此类型包括可以描述媒体能力的类型,那么,UAS应该为此目的在响应中包括消息体。在[12]中介绍了在application/sdp情况下,构造此消息体的详情。

以下是UAS创建的OPTIONS响应实例(和第11.1 节的请求相对应):

SIP/2.0 200 OK

Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877 ;received=192.0.2.4

To: <sip:carol@chicago.com>;tag=93810874

From: Alice <sip:alice@atlanta.com>;tag=1928301774

Call-ID: a84b4c76e66710

CSeq: 63104 OPTIONS

Contact: <sip:carol@chicago.com>

Contact: <mailto:carol@chicago.com>

Allow: INVITE, ACK, CANCEL, OPTIONS, BYE

Accept: application/sdp

Accept-Encoding: gzip

Accept-Language: en

Supported: foo

Content-Type: application/sdp

Content-Length: 274

(SDP not shown)

  1. 8.      对话

一个UA的核心概念就是对话。对话是表现为两个用户代理(UA)之间的持续一段时间的点对点的SIP关系。对话(Dialog)使得用户代理之间的消息顺序传递和两个用户代理之间的请求正确路由更加容易。对话(Dialog)可以认为是对SIP消息解释的上下文关系。第8节讲述了方法无关的UA处理和响应对话(Dialog)外的请求。本节将讨论如何通过请求和应答来创建一个对话(Dialog),并且在对话(Dialog)中如何发起和响应后续的请求。

一个对话在参与对话的UA中都有一个dialog ID作为标记,这个ID由Call-ID,和一个本地tag和远程tag组成。各个UA的dialog ID在对话中是不一样的。特别是,在一边UA的本地tag,在另外一方就是远程tag。这些tag都是互相不透明的,并且使得整个dialog ID是唯一的。

dialog ID同样是和所有的To头域中包含了tag参数的请求及应答相关。

填写一个消息中的dialog ID的规则依赖于SIP元素是UAC还是UAS。对于UAC来说,dialog ID中的Call-ID的值会填写到消息中的Call-ID域中,远程tag放在消息中的To的tag参数中,本地tag放在From的tag参数中。(这些规则对请求和应答都适用)。对于UAS来说,dialog ID的Call-ID值放在消息的Call-ID头域中,远程tag放在From头域的tag中,本地tag放在To头域的tag参数中。

一个对话包含一些特定的状态用于以后的对话中的消息传送。这个状态由dialog ID,本地序列号(用来排序UA到对方的请求的序列),远程序列号(用来排序请求从远端到本UA),本地URI,远端URI,remote target,一个布尔类型的标记”secure”,路由集合(一组有序的URI)组成。

路由集合是由发送请求到对方需要途径的一组服务器列表组成。一个对话可以处于”early”状态,这是由于当这个对话收到了临时应答而创建,并且当收到了2xx终结应答的时候转换到”confirmed”状态。对于其他应答,或者没有应答,”early”对话将会终结。

 

8.1.    创建一个对话

对话是由对一组特定请求的没有失败的应答来创建的。在本规范中,只有包含To tag的2xx和101-199应答,并且请求是INVITE的,会建立一个对话。当收到一个非终结应答的时候,对话会建立成”early”状态,并且成为early dailog。创建对话的时候可以使用Extension来定义扩展。13节描述了INVITE请求的更多细节。在这里,我们描述与方法无关的对创建对话状态的处理。

UA必须按照下边描述的方法对dialog ID进行赋值。

8.1.1. UAS行为

当UAS响应一个请求给出一个应答,并且这个应答会建立一个对话的时候(比如对INVITE的2xx应答),UAS必须拷贝所有的请求中的Record-Route头域到应答中去(包括URI,URI参数,和其他任何Record-Route头域的参数,无论UAS是不是认识的参数都需要原样拷贝),并且必须维持这些参数的顺序。UAS必须增加一个Contact头域给应答。这个Contact头域包含一个UAS在后续对话请求中接收请求的地址(这个包含了给INVITE请求的2xx应答的ACK请求处理的地址)。通常情况下,UAS会用IP地址或者FQDN形式来发布自己的这个Contact地址。这个在Contact头域中的URI必须是一个SIP或者SIPS URI。如果创建对话的请求在Request-URI中包含的是SIPS URI,或者在Record-Route头域的最上的一个值是SIPS URI,或者如果请求中没有Record-Route头域但是请求中的Contact头域是SIPS URI,那么给出的应答中的Contact头域必须是一个SIPS URI。 这个URI应该是全局有效的(就是说,这个URI可以用于对话外的消息)。同样的,在请求INVITE中的Contact头域的URI也不应当仅限于这个对话中使用。因此它可以用于对话外的消息中。

UAS接着创建这个对话的状态。对话状态必须维持直到对话结束。

如果请求是通过TLS过来的,并且Request-URI包含一个SIPS URI,”secure”标志将被赋值成为TRUE。

路由集合必须设置成为请求中的Record-Route的URI列表,保留所有的URI参数和顺序。如果请求中没有Record-Route头域,那么路由集合必须设置成为空。这个路由集合,即便是空的,为了以后的对话中的请求,也要覆盖任何预先存在(pre-existing)的路由集合。remote taget必须设置成为请求的Contact头域中的URI。

远程序列号必须设置成为请求中的Cseq头域的序列号。本地序列号必须设置成为空。dialog ID中的呼叫标志应该设置成为请求的Call-ID头域的值。dialog ID的本地tag必须设置成为对请求的应答包中的To头域的tag,并且dialog ID的远程tag必须设置成为请求中的From 头域中的tag。UAS必须能够处理接收到的请求中的From头域没有tag标志,在这种情况下,这个tag就是空值。这是为了兼容RFC2543协议,它并没有定义From tag。

远程URI(remote URI)必须设置成为From头域中的URI,并且本地URI必须设置成为TO头域中的URI。

8.1.2. UAC行为

当一个UAC发出一个请求,这个请求能够建立一个对话(比如这个请求是INVITE),它必须在Contact头域中提供一个基于全局的SIP或者SIPS URI(例如,可以在对话外使用的SIP URI)。如果请求包含一个Request-URI或者最上的Route头域是SIPS URI,Contact头域也必须包含的是SIPS URI。

当一个UAC接收到应答,并且这个应答建立对话的时候,它也同样构造这个对话的状态。这个状态必须维持到对话的结束。

如果这个请求是基于TLS发送的,并且Request-URI包含一个SIPS URI,那么”secure”标志被设置成为TRUE。

路由集合必须设置成为应答中的Record-Route头域的URI列表,保留所有的URI参数和顺序。如果在应答中没有Record-Route头域,那么这个路由集合必须设置成为空集合。这个路由集合即便是空的,为了以后的对话中的请求,也要覆盖任何预先存在(pre-existing)的路由集合。remote taget必须设置成为应答中的Contact头域的URI。

本地序列号必须设置成为请求中的Cseq头域的序列号。远程序列号必须设置成为空(他会由远端的UA在对话中发送请求而建立)。dialog ID中的呼叫标志必须设置成为请求的Call-ID头域的值。dialog ID的本地tag必须设置成为请求中的From头域的tag,dialog ID的远程tag必须设置成为应答中的To头域的tag。UAC必须能够处理接收到的应答的To头域中没有tag的情况,在这个情况下,tag值取值成为空。这是为了能够向下兼容RFC2543,它没有规定To的tag。

remote URI必须设置成为To头域的URI,local URI必须设置成为From头域的URI。

 

8.2.    对话中的请求

当两个UA之间的对话建立以后,他们都可以在对话中初始化一个新的事务(transaction)。如果UA发送请求,将遵循UAC的事务规则。UA接收请求将遵循UAS的规则。在建立对话的事务过程中,UA扮演的角色可能是不一样的。

在对话中的请求可以包含Record-Route和Contact头域。不过,虽然他们会修改remote target的URI,但是这些请求也不会导致对话的路由集被改变。明确说,如果请求不是刷新target的请求,那么这个请求不会更改对话的remote target URI,如果请求是刷新target的请求,那么这个请求才会更改对话的remote target URI。对于用INVITE建立的对话来说,唯一的能够刷新target的请求就是re-INVITE(见14节说明)。可能会有其他扩展定义通过其他方法来刷新target的请求。

注意ACK不是一个刷新target的请求。

刷新target请求只会更改对话的remote target URI,并且更改由Record-Route指定的路由集合。如果更新路由集合会带来严重的和RFC2543向后兼容问题。

 

8.2.1. UAC行为

8.2.1.1.     产生请求

在对话中的请求是通过用许多对话的状态部分来构造的。在TO头域中的URI部分必须设置成为对话状态中的remote URI。To头域的tag参数必须设置成为dialog ID中的remote tag部分。请求的From URI必须设置成为对话状态中的local URI。From头域的tag参数必须设置成为dialog ID的local tag部分。如果remote或者local tag是空值,那么tag参数必须分别从From或者To头域中去除。

在请求序列中的原始请求的To和From头域的URI的使用方法是为了向下兼容RFC2543协议的,在RFC2543协议中,使用URI作为对话的标志。在这个规范中,只有tags用于区分对话。有可能在本协议的后续版本中,在对话中的请求必须强制反应原始请求的To和From头域的URI将会去除。

请求的Call-ID必须设置成为对话的Call-ID。在对话中的请求必须严格遵循单个递增的Cseq序列号(每次增加1)(当然要除了ACK和CANCEL,这两个请求中的Cseq必须和原始的请求或者确认请求一样)。因此,如果本地序列号(local sequence number)不为空,那么本地序列号码必须依次增加1,并且这个数值要存放到Cseq头域中。如果本地序列号码是空的,那么在8.1.1.5节约定的初始值必须填写进去。在Cseq头域中的method字段必须和请求的方法(method)一致。

通过使用32位的长整数,使得即使每秒种产生1笔请求,也会要136年才会用完这个整数出现重复。这个序列号的初始值的选取是为了让对话中后续的请求序列号不会重复。非0的初始值可以考虑采用时间来作为初始的序列号。一个客户端可以用31位有符号整数或者32位无符号整数来存放时间作为初始化的序列号。

UAC使用remote target和路由集合来构造请求中的Request-URI和Route头域。如果路由集合是空的,那么UAC必须把remote target URI放到Request-URI中,并且UAC不能添加Route头域到请求中。

如果路由集合不为空,并且路由集合的第一个URI包含lr参数(见19.1.1),那么UAC必须填写remote target URI到Request-URI,并且必须包含Route头域,这个Route头域按照顺序填写路由集合和路由集合的参数。

如果路由集合不为空,并且路由集合的第一个URI没有包含lr参数,那么UAC必须把第一个URI放在Request-URI中,并且拆去所有不被Request-URI允许的参数。UAC必须增加一个Route头域顺序包含所有剩下的路由集合元素,及其参数。UAC接着必须把remote target URI放在Route头域的最后一项。

例如,如果remote targe是: sip:user@remoteua 并且路由集合包括:

<sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>

那么请求应该有下列的Request-URI和Route头域

METHOD sip:proxy1

Route: <sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>,<sip:user@remoteua>

如果路由集合的第一个URI不包含lr参数,那么对应的说明proxy并不能支持本文档所约定的路由机制,而是支持RFC2543文档所约定的路由机制,那么在发送信息的时候需要通过替换Request-URI为接收到的第一个Route头域的值。将Request-URI的值放在Route头域的目的是为了保护Request-URI,使得它经过严格路由的时候不丢失(当请求遇到一个松散路由的时候会返回到Request-URI中?????。)

在对话内的任何一个刷新target的请求中,都应当包含一个Contact头域,并且这个URI除非有必要,否则都应当是和对话内上次请求的URI值一样。如果”secure”标志设置成为TRUE,那么URI也应当是SIPS URI。

如果在12.2.2节讨论的那样,在刷新target请求中的Contact头域会更新remote target URI。这个允许UA提供一个新的联系地址(Contact address),表明它在对话中改变了自己的地址。不过,如果请求不是刷新target的请求,那么不会影响对话中的remote target URI。请求中的剩下的部分请按照8.1.1节描述的填写。一旦请求被创建了,请求将按照对话外请求发送标准步骤(8.1.2节)来解析服务器的地址并且发送请求。

8.1.2节中的步骤一般把请求发送到Route头域的最上一个地址,或者如果没有Route头域,那么就发送到Request-URI地址。由于受到特定的限制,这些步骤也允许把请求发送到另外一个地址(比如在route set中没有的缺省的外发proxy)

8.2.1.2.     处理应答

UAC将会从transaction层收到请求的应答。如果客户端的事务层返回一个超时,这会等同于一个408(请求超时)的应答。UAC处理3xx应答的时候,在这个应答是在对话内的请求的应答的处理方法和在对话外的处理方法是一样的。这个方法在8.1.3.4节中描述。需要注意的是,虽然UAC会尝试新的地址(处理3xx应答的时候),但是它依旧使用对话内的路由集合来构造请求的Route头域。

当UAC收到一个刷新target请求的2xx应答的时候,如果对话的remote target URI存在,那么它必须用这个应答的Contact头域的值来替换对话的remote target URI。

如果对话那的请求的应答是481应答(呼叫/事务不存在Call/Transaction Does Not Exits)或者一个408(请求超时),那么UAC应当终止这个对话。并且UAC应当在请求完全没有应答的时候(客户端transaciton将会通知TU这个超时)客户端transaction终止这个对话。

对于INVITE初始化的对话,终止对话需要发送一个BYE。

8.2.2. UAS行为

在对话中发送的请求,就像其他请求一样,是原子请求。如果UAS收到某个请求,所有的相关状态要么一起改变,要么就一起不变。在某些请求中,请求会影响好几个状态(比如INVITE请求)。

UAS从transaction层收到请求。如果请求的To头域有tag字段,UAS的处理核心需要校验对话的ID,拿请求中的tag和现存的对话相比较。如果匹配成功,那么就是一个在对话中的请求。在这种情况下,UAS首先使用8.2节中的对话外请求处理的步骤。如果请求To头域包括了一个tag字段,但是对话的ID并不匹配现存的对话,UAS可能是因为崩溃而重新启动,或者收到了一个另外(可能是错误的)UAS(UAS可以构造To的tags,这样UAS在灾备恢复下,可以把这个tag看成它自己的)。还有一种简单的可能是请求发送错误了。在这个基础上,UAS可以选择接受或者拒绝请求。在允许的情况下,尽量处理这些请求会提供灾难恢复的机制。UAS如果希望支持这样的特性就必须遵循一些原则,比如用始终使用单调递增的Cseq序列号,甚至是在重新启动之后也这样,在重启动后重建路由集合,处理越界的RTP时间戳和序列号等等。

如果UAS由于不希望重构对话而拒绝这个请求,它必须应答对方一个481(呼叫/事务不存在。Call / Transaction不存在)应答。

对于在对话中接收到的,那些不会用任何形式更改对话状态的请求,比如OPTIONS请求,他们等同于在对话外的处理请求。

如果远端的序列号(remote sequence number)是空的,它必须设置成为请求中的Cseq头域的序列号(sequence number)。如果remote sequence number不是空的,但是请求中的sequence number小于这个remote sequence number,请求就是非顺序的,并且必须通过应答500(服务器内部错误)打回去。如果remote sequence number不是空的,并且请求中的序列号大于这个remote sequence number,请求就是按照顺序的。这个请求中的Cseq的序列号可以比remote sequence number大不止1。在这种情况下,并非是错误的,并且UAS应当准备接收和处理比上次处理的请求Cseq值大于1 的请求。UAS必须设置remote sequence number成为请求中的Cseq头域中的序列号。

如果一个proxy废弃掉一个UAC产生的请求,并且UAC重新递交这个请求的时候。这个请求是会具有一个全新的Cseq序列号。UAS是不会收到第一个请求的,这样,Cseq序列号就会出现间隔,这样的间隔并非是一种错误的情况。

当UAS接收到一个target刷新请求的时候,如果请求中存在Contact头域,它必须用Contact头域中的URI来替换对话的remote target URI。

8.3.    终止对话

在建立对话中的终结对话,跟请求方法无关,如果对话外的请求产生了一个非2xx终结应答,任何前边请求创建的”早期对话”(early dialogs)将会终止。在已经建立的对话中,终结对话就是请求方法相关的。在这个定义中,BYE方法将会终结一个对话。15节有细致的讨论。

 

 

  1. 9.      初始化一个会话(INVITE

当UAC希望初始化一个会话(比如,audio,video或者游戏),它首先构造一个INVITE请求。这个INVITE请求一个服务器来建立一个会话。这个请求可能会由proxy层层转发,最后到达一个或者多个可能能够处理这个邀请的UAS。这些UAS需要看看是否用户接收这个邀请。然后UAS可以接收这个请求(也就是会话建立了),通过发送2xx应答。如果邀请被拒绝,根据拒绝的原因,3xx,4xx,5xx或者6xx应答将会发送。在发送终结应答之前,UAS可以发送一些临时应答(1xx)应答给UAC,以便UAC能够掌握建立会话的进度。

当收到了一个或者多个临时应答,UAC可能收到一个或者多个2xx应答或者一个非2xx终结应答。由于在INVITE终结应答之前,可能有不少时间,在INVITE事务的可靠性机制和其他的请求不同(比如OPTIONS)。当UAC收到了终结应答,UAC需要给每一个INVITE的终结应答,发送一个ACK请求。发送ACK请求的步骤依赖于应答的类别。对于在300到699的终结应答,ACK是在transaction层处理的,并且遵循一系列规则(17节)。对于2xx应答,ACK是由UAC处理核心产生的。

INVITE的一个2xx应答会建立一个会话,同时也建立了一个基于发送INVITE请求的UA和产生2xx应答的UA之间的对话。因此,当从多个远程UA收到了多个2xx应答(可能由于INVITE的分支),每一个2xx建立一个不同的对话(dialog)。所有这些对话都是同一个呼叫的组成部分。

本节介绍了INVITE请求建立会话的详细过程。支持INVITE的UA也一定同时支持ACK,CANCEL和BYE。

9.1.    UAC处理

9.1.1. 创建一个初始化的INVITE

由于初始化的INVITE请求是一个对话外的请求,它遵循8.1.1节的步骤创建。除此之外还有专门针对INVITE的附加处理步骤。

在INVITE中应当包括一个Allow头域(20.5节)。它用来标志在这个INVITE建立的这个对话(dialog)中什么样的方法可以接受。比如,一个UA可以在对话中接收和处理INFO请求[34],那么在INVITE请求的Allow头域中应当列出这个INFO方法。在INVITE请求中,Supported头域应当包含。这个头域包含了所有这个UAC支持的扩展部分。

在INVITE中可以包含一个Accept头域(20.1节)。这个标志了UA在后续建立的对话中,能兼容的接收和发送的Content-Type。Accept头域支持不同会话描述格式(session descrioption format)的时候特别有用。

UAC可以通过包含一个Expire头域(20.19节)来限制邀请的有效期限。如果Expire头域的时间到了还没有接收到INVITE的终结应答,UAC处理核心应当像9节描述的那样产生一个对INVITE请求的CANCEL请求,

UAC还可以根据需要增加Subject(20.36节),Organization(20.25节)和User-Agent(20.41节)头域。这些头域都包含了INVITE的相关资料。UAC可以给INVITE增加一个消息体。8.1.1.10节讲述了如何构造Content-Type头域来描述消息体。

对于消息体,有一些特别的规定――他们是基于某种磋商机制的,他们对应的Content-Disposition 是”session”(会话的)。SIP使用一个请求/应答模型,UA发出一个会话描述,称作是请求,里边包含了会话的描述。这个请求标志了特定的联系内涵(比如audio,vidio,game),这些内涵的参数(比如解码器等等),并且从应答方接收媒体信息的地址。对方UA会回应另外一个会话的描述,称之为应答,标志了能接受的联系内涵,这些内涵的参数。这个请求/应答的交换实在对话的上下文进行中的,所以如果一个SIP INVITE请求导致了多个对话,每一个对话都包含自己独立的请求/应答的交换。请求/应答模型定义了对于请求和应答的限制。(比如在上一个请求尚未处理完成情况下不能发起下一个请求)。这也导致了请求/应答在SIP消息中出现的位置限制。在这个规范中,请求和应答只能出现在INVITE、ACK请求和其应答中。请求和应答的使用中更进一步被限制。在初始化一个INVITE事务中,规则如下:

o 初始化请求必须在INVITE中,如果不在INVITE请求中,就必须在UAS回送给UAC的第一个非失败的可靠消息中。在这个规范中,这个应答就是2xx应答。

o 如果初始的请求是一个INVITE,那么应答必须是由UAS发送回给对应发出INVITE请求的UAC的可靠的非失败的消息。在本规范中,只有2xx应答对应这个INVITE请求。同样相同的应答可能在之前发送的零食应答中存在。UAC必须把它接收到的第一个会话描述当作是应答,并且必须忽略任何在初始INVITE请求中后续的会话描述应答描述。

o 如果初始请求是在第一个可靠的非失败的UAS回送给UAC的消息中,那么应答必须在这个消息的确认消息中(在本规范中,就是给2xx应答的ACK确认消息)

o 在发送或者接收到第一个请求的应答之后,UAC可以同样依据这样的问答方法产生后续的请求。但是只能在收到每一个请求的应答之后才能发起下一个请求。不能在上一个请求尚未收到应答的时候发起下一个请求。

o 当UAS发送或者接收到初始化的请求的时候,禁止在它给初始的INVITE请求的应答中产生后续的请求(协商会话描述请求)。这就意味着基于本规范的UAS在完成初始化的事务之前,不会产生任何会话描述请求。

 

具体来说,根据本规范,上边的规则分别定义了两种UA之间交换信息的方法。请求实在INVITE中,应答是在2xx(可能在1xx中也存在,具备相同的值)中,或者请求在2xx中,应答在ACK中。(这个意思是说,两个UA之间建立连接的时候,首先需要协商一下两个UA能够支持的消息体正文,那么这个协商关系也是通过问答形式的,也就是通过请求/应答的,这个媒体磋商的请求既可以在UAC发起的INVITE请求中,也可以在UAS回应的2xx应答中。同样的,媒体磋商的应答既可以在UAS的2xx应答或者1xx应答中,也可以在ACK确认请求中)。所有的支持INVITE请求的UA都必须支持两种交换方式。会话描述协议(session description protocol sdp)(RFC 2327[1])在所有的UA中都必须得到支持,并且它的用法和请求/应答的构造必须遵循[13]中定义的步骤。

在上边讲述的请求/应答模型中,只能适用于在包头域Content-Disposition中的值是”session”的包体情况。因此,有可能会INVITE和ACK请求中都包含一个包体信息(比如,INVITE包含一个相片(Content-Disposition:render)并且ACK包含一个会话描述(Content-Disposition:session))。

如果Content-Disposition头域不存在,Content-Type 是application/sdp的包体实现就等同于Content-Disposition”session”,其他Content-Type的情况就是实现”render”。

当INVITE请求创建以后,UAC遵循对话外请求发送的步骤进行发送(8节)。这也就是创建一个客户事务并且由这个客户事务发送请求并且处理应答。

9.1.2. 处理INVITE应答

当INVITE请求被传送给INVITE的客户事务层进行处理,UAS等待INVITE的应答。如果INVITE客户事务层返回一个超时而不是收到一个应答,那么这个TU就应当像收到一个408(请求超时)应答(8.1.3节)那样进行处理。

9.1.2.1.     1xx应答

有可能在收到一个或者多个终结应答之前,UAC会收到0个或者1个或者多个临时应答。INVITE的临时应答会建立”early dialogs”(早期对话)。如果一个临时应答在To头域中有一个tag子顿,并且应答的dialog ID并不是已经存在的对话的ID,那么就应当遵循12.1.2节定义的步骤创建一个对话(早期对话)。

early dialog只会在下边这个情况中需要:如果一个UAC需要在完成初始的INVITE事务之前,给对方发送一个对话内的请求的时候,就需要early dialog。在临时应答中的头域可以在当对话是early state的时候都有效(也就是说,比如一个临时应答的Allow 头域包含的方法,在对话状态是early state的时候都是有效的。[由于Allow是允许的方法集合,所以,当对话状态是早期对话的时候,这个Allow的集合是不会改变的,但是当创建正式的dialog之后,Allow的集合可能会改变哦]。)

9.1.2.2.     3xx应答

一个3xx应答可能包含一个或者多个Contact头域值,这个头域值提供了被叫方可能存在的地点。UAC可以根据3xx应答的状态码(21.3节)来决定是否尝试这些新的地址。

9.1.2.3.     4xx,5xx,6xx应答

在INVITE请求中,可能会收到单个非2xx终结应答。4xx,5xx,6xx应答如果包含了Contact头域,那么这个头域值指示了错误的详细信息的解释地点。后续的终结应答(只有可能在发生错误的情况下),必须被忽略掉。

所有的早期对话都会由于接收到非2xx终结应答而结束。

一旦接收到了非2xx终结应答,UAC处理核心就认为INVITE事务结束了。INVITE客户事务处理生成对这个应答的ACK(参见17节)。

9.1.2.4.     2xx 应答

单个INVITE请求可能会导致多个2xx应答返回给UAC,这是因为proxy可以分支。每一个应答都是由To中的tag参数来进行区分的,并且每一个应答都代表了一个独立的对话,具备单独的对话ID。

如果在2xx应答中的对话ID和一个现存的对话匹配,那么这个对话必须切换到”confirmed”状态,并且对话的路由集合必须基于2xx的应答进行重新计算(参见12.2.1.2)。如果不匹配,那么必须创建一个新的对话,这个对话具备”confirmed”状态,参见12.1.2的步骤进行创建。

注意在对话状态中,只有路由集合不需要重新计算。其他部分比如对话内的最大的序列号(远程的和本地的)等都不需要重新计算。路由集合只是由于需要向后兼容而需要重新计算。RFC 2543并没有要求在1xx应答中反射Record-Route头域回来,只在2xx请求中要求了。我们不能更新对话状态的全部部分,因为在早期对话(early dialog)中可能会存在对话中的请求,比如更改序列号等等。UAC核心必须为每一个2xx应答,产生一个ACK请求。除了在Cseq和身份认证相关的头域之外,ACK请求的头域的创建和在对话中的请求创建的方法一样(12节)。Cseq头域的序列号部分必须和需要确认的INVITE请求一样,但是Cseq的方法部分必须是ACK。ACK必须包含和INVITE请求相同的信任状。如果2xx包含一个媒体磋商请求(基于上述的规则),ACK必须在包体中包含一个媒体磋商应答。如果2xx应答的媒体磋商请求不能被接收,UAC核心必须产生一个有合法的应答ACK,并且立刻发送一个BYE请求。

 

当ACK创建以后,[附件4]中规定的步骤用来检测对方地址,端口和transport。这个请求是直接交给通讯层进行通讯的,而不是交给一个客户事务层进行发送。这是由于UAC核心直接处理ACK的重发,而不是事务层进行重发的处理。每次收到一个重发的2xx终结应答的时候都必须发送一个ACK到通讯层。

 

UAC核心认为INVITE事务在接收到第一个2xx应答后的64×T1秒后完成。在这个时间点后,所有没有转换成为建立连接状态的早期对话都会被终止。一旦UAC确认INVITE事务完成了,那么缺省认为不会收到新的2xx应答了。如果,在相应了对INVITE请求的全部应答之后,UAC并不希望创建这个对话,那么UAC必须通过15节描述的那样发送BYE请求来结束对话。

9.2.    UAS处理

9.2.1. 处理INVITE

UAS核心从事务层收到INVITE请求。首先根据8.2节定义的步骤进行处理请求,8.2节中定义的是跟对话内外无关的请求的处理。如果处理顺利完成(没有产生应答),UAS核心根据如下步骤进行额外处理:

1、   如果INVITE请求包含一个Expires头域,UAS核心就设置一个时钟计数=这个头域值。如果时钟到了,这个邀请就过期了。如果在UAS尚未产生终结应答的时候就超时了,那么487(请求终止)应答应当产生给UAC。

2、   如果请求是一个对话中的请求,12.2.2节定义的方法无关的处理步骤将首先进行处理。这个处理可能会影响到会话;14节讲述了细节。

3、   如果请求的To头域包含了一个tag,但是对话的ID与现存的任何一个对话都不匹配,那么UAS可能是由于崩溃而重新启动的,或者是由于接收到了本应当发送给另外一个UAS的请求(或者就简单是由于请求填写错误)。12.2.2节提供了这种情况的处理指引。从这开始的处理将假定这个INVITE是在对话外的,并且INVITE请求的目的是建立一个新的会话。INVITE请求可能包含一个会话描述,在这种情况下是希望和UAS进行会话媒体的磋商。即使INVITE请求是对话外发出的,这个INVITE参与的用户也有可能正是那个会话中的参与方。这个是由于在多方会议中,某个正在会议中的用户,被其他参与方邀请参加。如果需要鉴别这样的情况,UAS可以使用会话描述来检查是否重复邀请。比如,SDP包含了会话的ID和版本号。如果这个用户本身就是会话中的一方,并且session参数包含的会话描述没有改变,UAS可能就悄悄接受这个邀请(就是说,在不提示用户的情况下发送2xx应答)。
如果INVITE并没有包含某个会话描述(session description),UAS就是被邀请创建一个会话,并且UAC已经希望UAS来提供这个会话offer。UAS必须在它的给UAC的第一个非失败的可靠消息中提供这个offer。在本规范中,给INVITE请求的2xx应答中就应当提供这个offer。
UAS可以提示进度,接受,转发,或者拒绝这个邀请。在这些情况下,它通过按照8.2.6节描述的步骤建立应答。

9.2.1.1.     提示进度

如果UAS不能马上接受或者拒绝邀请,那么它可以提示某种形式的进度给UAC(比如提示一个回铃声等等)。这是通过一个101到199的临时应答实现的。这些临时应答建立了早期对话(early dialog)(通过8.2.6和12.1.1)。如果UAS愿意,UAS可以发送多个临时应答。每一个临时应答都必须包含相同的dialog ID。这些临时应答都并非可靠传送的。

如果UAS打算延长一点时间来响应这个INVITE请求,它需要请求一个”extension”来防止proxy来取消这个事务。proxy有权利来取消超过3分钟未完成的事务。要防止这个取消,UAS必须每分钟发送一个非100临时应答,防止由于1xx临时应答的非可靠传输导致的临时应答丢失。

如果呼叫出于等待状态(比如用户设置成为呼叫等待的)或者这个呼叫正在和PSTN电话系统进行通讯(PSTN系统允许呼叫没有应答),一个INVITE事务是可以被延长处理时间的。

9.2.1.2.     INVITE请求转发

如果UAS决定转发这个呼叫,就需要发出3xx的应答。300(多重选择),301(永久转移),302(临时转移)应答中应当包含一个Contact头域,这个头域包含了一个或者多个表明需要重试的URI新地址。这个应答交给INVITE服务端事务层,由服务端事务层负责应答的重发。

9.2.1.3.     INVITE请求的拒绝

拒绝INVITE请求的常见情景是被叫方不想或者不能在终端系统上接收这个呼叫。486(用户忙)应当在这样的情况下返回。如果UAS知道没有其他终端系统能够响应这个呼叫,就应当返回一个600(Busy Everywhere)。不过,通常情况下UAS是不太会知道这个情况的,并且这个应答也是罕见的。这些应答是交给INVITE服务端的事务层进行发送的,由这个事务层来保证应答的重发机制的。如果UAS拒绝的是INVITE请求包含的媒体磋商offer,UAS应当返回一个488(Not Acceptable Here)应答。这个应答应当包含一个Warning头域来解释为何offer被拒绝。

9.2.1.4.     接受INVITE请求

UAS核心产生一个2xx应答。这个应答建立一个对话,然后遵循8.2.6节和12.1.1节的描述进行处理。

响应INVITE请求的2xx应答包含Allow头域和Supported头域,并且可能包含Accept头域。包含这些头域的目的是为了让UAC不需要再次请求就能够知道UAS的特性以及UAS的扩展支持。

如果INVITE请求包含了一个媒体磋商请求offer,并且UAS还没有发送应答,2xx应答中必须包含针对这个offer的应答。如果INVITE请求没有包含这个offer,而且UAS也尚未发出offer,2xx应答必须包含这个媒体磋商offer。

当应答构建好了以后,它会交给INVITE的服务端事务层进行发送。注意,INVITE的服务端事务将会由于收到这个终结应答并且交给通讯层进行发送而销毁。因此,有必要在没有收到ACK的时候,每隔一定的时间就直接交给通讯层进行发送。2xx交给通讯层进行发送的时间间隔是从T1秒开始,并且每次发送后就加倍,直到到达T2秒的时间间隔(T1和T2的时间间隔定义在17节)。当收到了针对这个应答的ACK请求之后,重发就终止了。这个是与使用什么通讯协议来发送这个应答是无关的。

由于2xx的重发是端到端的,并且在UAS和UAC之间存在采用UDP通讯的节点。所以要保证通过这些节点进行可靠的传送,就必须采用间隔时间重发的机制,哪怕UAS本身的通讯机制是可靠的。

如果服务端的对2xx应答的重发经过了64×T1秒还没有收到ACK请求,那么dialog就认为是confirmed,但是会话却应当终止。这个是用过15节描述的方法发送BYE请求来结束。

 

 

10. 更新已经存在的会话(UPDATE

成功的INVITE请求同时建立两个用户代理之间的对话和呼叫-应答模式的会话。第8章说明了怎样使用目标更新请求修改现有的对话(如,修改对话的远程目标URI)。本章介绍了怎样修改当前会话。此修改包括,修改地址或端口、添加媒体流、删除媒体流等等。通过在建立会话的相同对话中发送新的INVITE来完成。在现有对话中发送INVITE是re-INVITE。

注意,单个的re-INVITE可以同时修改对话和会话的参数。

呼叫者和被呼叫者都可以修改现有的会话。

UA检测媒体错误的行为是本地策略的事情。但是,当网络拥塞时,为了避免大量的网络流量,不推荐自动生成re-INVITE和BYE。在任何请情况中,如果要自动发送这些消息,应该在随机的间隔后发送这些消息。

注意,上面的章节提及了自动生成re-INVITE和BYE。如果用户因为媒体错误而挂断,那么,UA 应该和平常一样发送BYE 请求。

10.1.        UAC行为

在INVITEs中用于会话描述的呼叫-应答模式也同样适用于re-INVITE。例如,想要添加媒体流的UAC,将创建包含此媒体流的新呼叫,并在INVITE请求中将其发送给其对等物。重点要指出的是,要发送会话的全部描述,而不仅仅是改变。这支持在不同元素中的无状态处理,也支持自动恢复能力。当然,UAC 可以发送无状态描述的re-INVITE,在这种情况中,re-INVITE的第一个可信非错误的响应将包含呼叫(在本规范中,即是2xx响应)。

如果会话描述格式有版本号,那么,呼叫应该指出已经改变了会话描述的版本。

按照第8 章介绍的,遵循与在现有对话内的规则请求相同的方法,设置re-INVITE 的To、From、Call-ID、Cseq和Request-URI。

因为,UAS一般不会警告用户接受re-INVITE,UAC可以选择不为re-INVITE添加Alert-Info头字段和Content-Disposition“Alert”消息体。

不像INVITE可以分发,re-INVITE不会分发,因此,它仅能产生单一的最终响应。re-INVITE 不会分发的原因是,Request-URI确定了目标是和它建立对话的UA,而不是确定用户的记录地址。

注意,当正在任一方向进行其它的INVITE事务时,UAC不能在对话内发起新的INVITE事务。

1.如果有正在进行的INVITE客户端事务,那么TU必须等到事务完成或结束状态,才可以发起新的INVITE。

2.如果有正在进行的INVITE服务器事务,那么TU必须等到事务完成或结束状态,才可以发起新的INVITE。

然而,当INVITE事务正在处理时,UA可以发起普通的事务。当普通的事务正在处理时,UA可以发起INVITE事务。

如果UA 接收到re-INVITE的非2xx最终响应,那么,将像没有发布re-INVITE一样,

不改变会话参数。注意,如果非200 最终响应是481(呼叫/事务不存在)或者408(请求超时),或者请求根本没有接收到re-INVITE 的响应(即是INVITE 客户端事务返回超时),那么,UA将结束对话。

如果UAC接收到re-INVITE的491响应,那么,它应该启动有T值的计时器,T选择如下:

²  如果对话ID有自己的Call-ID(指它生成的值),那么,T是以10ms为单位、在2.1到4 秒内随机选择的值。

²  如果对话ID没有自己的Call-ID,那么,T是以10ms 为单位、在0到2秒内随机选择的值。

当计时器溢出,如果它仍然要修改会话状态,那么,UAC 应该再次尝试re-INVITE。例如,如果呼叫已经用BYE 挂断,那么将不能出现re-INVITE。

发送re-INVITE和为re-INVITE的2xx响应生成ACK的规则和初始INVITE的规则相同。

10.2.        UAS行为

UAS在发送第一个INVITE的最终响应之前,接收到相同会话的、低Cseq序列号的第二个INVITE,UAS必须对第二个INVITE返回500响应(服务器内部错误),并且必须包括在0到10秒之间随机选择值的Retry-After 头字段。

UAS正在处理会话已经发送的INVITE时,接收到INVITE,它必须给接收到的INVITE返回491响应(请求待处理)。

如果UA接收到现有对话的re-INVITE,它必须检查会话描述的版本标识符,如果没有版本标识符,认为会话描述的内容已经改变。

如果会话描述已经改变,那么,可能在要求用户确认后,UAS 必须调整会话参数。

会话描述的版本可以用来调节新到达会议的能力——添加删除媒体、从单点到多播会议。

如果不能接受新会话描述,UAS可以通过对re-INVITE返回488响应(在此不能接受)拒绝它。此响应应该包含Warning 头字段。

如果UAS生成2xx响应,但不能接受ACK,那么,它应该生成BYE结束会话。

因为,UAC一般不将此信息返回给用户,UAS可以选择不为re-INVITE生成180(响铃)响应。因为此原因,在响应re-INVITE 时,UAS可以选择不使用Alert-Info头字段和Content-Disposition“Alert”消息体。

在2xx中提供呼叫(因为INVITE不包含呼叫)的UAS应该服从发送呼叫更新现有会话的约束,建立呼叫,就像UAS正在做出新的呼叫。特别的是,此方法应该包括UA愿意支持的媒体格式和媒体类型。UAS必须确保会话描述与UAS先前的会话描述在对等物需要支持的媒体格式、传输和其它参数等方面重叠。这就避免了对等物拒绝会话描述。如果UAC不能接受它,UAC应该生成带有有效会话描述的响应,然后发送BYE,结束会话。

11. 结束会话(BYE

会话的状态和对话的状态是紧密相关的。当用INVITE发起会话时,不同UAS产生的1xx和2xx响应都创建对话,如果此响应完成呼叫/应答交换,那么,它也创建会话。结果,每个会话都与创建它的对话相关联。如果初始的INVITE生成非2xx最终响应,那么,它将结束通过此请求的响应创建的所有会话(如果有)和对话(如果有)。由于完成了事务,非2xx最终响应也防止了INVITE创建更深层次的会话作为INVITE的结果。BYE请求用来结束具体的会话和尚未建立的会话。在这种情况中,具体的会话和对话是一个UA与对话中另一个对等UA建立的。当在对话中接收到BYE,应该结束和此对话相关的所有会话。UA不能在对话外发送BYE。呼叫者UA可以在确认的和早期的对话中发送BYE;被呼叫者UA 可以在确认的对话中发送BYE,但是不能在早期的对话中发送BYE。然而,在被呼叫者UA接收到其2xx响应的ACK和服务器事务超时之前,它不能在确认的对话中发送BYE。如果在此对话相关的应用层状态中没有定义SIP扩展,那么,BYE也可以结束对话。

对话和会话中INVITE的非2xx最终响应的效果是使用CANCEL attractive。CANCEL尝试将非2xx最终响应强制发送给INVITE(特别是,487)。因此,如果UAC希望完全放弃其呼叫尝试,它发送CANCEL。如果INVITE导致了INVITE的2xx最终响应,这意味着正在处理CANCEL时,UAS接受了此邀请。UAC可以继续2xx响应建立的会话,也可以使用BYE 结束会话。

在SIP中,没有很好的定义“挂断”的概念。挂断是很具体的细节,但是也是很通用的用户接口。一般,当用户挂断,它表示想要结束建立会话的尝试和结束已经创建的会话。对于呼叫者UA,如果初始的INVITE没有创建最终响应,那么挂断意味着CANCEL请求;对于在最终响应后所有确认的对话,挂断意味着BYE。对于被呼叫者UA,一般来说,挂断意味着BYE。

可能是,当用户拿起电话,生成2xx,在接收到ACK后,挂断可能会导致BYE。这并不是指,用户在接收到ACK前不能挂断电话,仅仅是指,为了正确的清除,用户电话的软件需要在一小段时间维持状态。如果特定的UI 允许用户在其应答之前拒绝呼叫,403(Forbidden)是一个很好的表示方式。按上面的规则,可以发送BYE。

Item

Headerfield

Sending

Receiving

Ref.

RFCstatus

Profilestatus

Ref.

RFCstatus

Profilestatus

1

Accept

[26]20.1

o

o

[26]20.1

m

m

1A

Accept-Contact

[56B]9.2

c18

c18

[56B]9.2

c22

c22

2

Accept-Encoding

[26]20.2

o

o

[26]20.2

m

m

3

Accept-Language

[26]20.3

o

o

[26]20.3

m

m

3A

Allow

[26]20.5

o

o

[26]20.5

m

m

4

Allow-Events

[28]7.2.2

c1

c1

[28]7.2.2

c2

c2

5

Authorization

[26]20.7

c3

c3

[26]20.7

c3

c3

6

Call-ID

[26]20.8

m

m

[26]20.8

m

m

7

Content-Disposition

[26]20.11

o

o

[26]20.11

m

m

8

Content-Encoding

[26]20.12

o

o

[26]20.12

m

m

9

Content-Language

[26]20.13

o

o

[26]20.13

m

m

10

Content-Length

[26]20.14

m

m

[26]20.14

m

m

11

Content-Type

[26]20.15

m

m

[26]20.15

m

m

12

CSeq

[26]20.16

m

m

[26]20.16

m

m

13

Date

[26]20.17

c4

c4

[26]20.17

m

m

14

From

[26]20.20

m

m

[26]20.20

m

m

14A

Geolocation

[89]4.1

c23

c23

[89]4.1

c23

c23

14B

Geolocation-Routing

[89]4.2

c23

c23

[89]4.2

c23

c23

14C

Max-Breadth

[117]5.8

n/a

c29

[117]5.8

c30

c30

15

Max-Forwards

[26]20.22

m

m

[26]20.22

n/a

c31

16

MIME-Version

[26]20.24

o

o

[26]20.24

m

m

16A

P-Access-Network-Info

[52]4.4

c9

c10

[52]4.4

c9

c11

16B

P-Asserted-Identity

[34]9.1

n/a

n/a

[34]9.1

c6

c6

16C

P-Charging-Function-Addresses

[52]4.5

c13

c14

[52]4.5

c13

c14

16D

P-Charging-Vector

[52]4.6

c12

n/a

[52]4.6

c12

n/a

16E

P-Debug-ID

[140]

o

c27

[140]

o

c28

16F

P-Preferred-Identity

[34]9.2

c6

x

[34]9.2

n/a

n/a

16G

Privacy

[33]4.2

c7

n/a

[33]4.2

c7

c7

17

Proxy-Authorization

[26]20.28

c5

c5

[26]20.28

n/a

n/a

18

Proxy-Require

[26]20.29

o

n/a

[26]20.29

n/a

n/a

18A

Reason

[34A]2

c17

c21

[34A]2

c24

c24

19

Record-Route

[26]20.30

n/a

c31

[26]20.30

n/a

c31

19A

Referred-By

[59]3

c19

c19

[59]3

c20

c20

19B

Reject-Contact

[56B]9.2

c18

c18

[56B]9.2

c22

c22

19C

Request-Disposition

[56B]9.1

c18

c18

[56B]9.1

c22

c22

20

Require

[26]20.32

m

m

[26]20.32

m

m

20A

Resource-Priority

[116]3.1

c25

c25

[116]3.1

c25

c25

21

Route

[26]20.34

m

m

[26]20.34

n/a

c31

21A

Security-Client

[48]2.3.1

c15

c15

[48]2.3.1

n/a

n/a

21B

Security-Verify

[48]2.3.1

c16

c16

[48]2.3.1

n/a

n/a

21C

Session-ID

[162]

o

c32

[162]

o

c32

22

Supported

[26]20.37

o

o

[26]20.37

m

m

23

Timestamp

[26]20.38

c8

c8

[26]20.38

m

m

24

To

[26]20.39

m

m

[26]20.39

m

m

25

User-Agent

[26]20.41

o

o

[26]20.41

o

o

25A

User-to-User

[126]7

c26

c26

[126]7

c26

c26

26

Via

[26]20.42

m

m

[20]20.42

m

m

c1:              IFA.4/22THENoELSEn/a--actingasthenotifierofeventinformation.

c2:              IFA.4/23THENmELSEn/a--actingasthesubscribertoeventinformation.

c3:              IFA.4/7THENmELSEn/a--authenticationbetweenUAandUA.

c4:              IFA.4/11THENoELSEn/a--insertionofdateinrequestsandresponses.

c5:              IFA.4/8ATHENmELSEn/a--authenticationbetweenUAandproxy.

c6:              IFA.4/25THENoELSEn/a--privateextensionstotheSessionInitiationProtocol(SIP)forassertedidentitywithintrustednetworks.

c7:              IFA.4/26THENoELSEn/a--aprivacymechanismfortheSessionInitiationProtocol(SIP).

c8:              IFA.4/6THENoELSEn/a--timestampingofrequests.

c9:              IFA.4/34THENoELSEn/a--theP-Access-Network-Infoheaderextension.

c10:           IFA.4/34ANDA.3/1THENmELSEn/a--theP-Access-Network-InfoheaderextensionandUE.

c11:           IFA.4/34AND(A.3/7AORA.3/7DORA3A/84)THENmELSEn/a--theP-Access-Network-InfoheaderextensionandASactingasterminatingUA,ASactingasthird-partycallcontrollerorEATF.

c12:           IFA.4/36THENoELSEn/a--theP-Charging-Vectorheaderextension.

c13:           IFA.4/35THENoELSEn/a--theP-Charging-Function-Addressesheaderextension.

c14:           IFA.4/35THENmELSEn/a--theP-Charging-Function-Addressesheaderextension.

c15:           IFA.4/37ORA.4/37ATHENoELSEn/a--securitymechanismagreementforthesessioninitiationprotocolormediasecheaderfieldparameterformarkingsecuritymechanismsrelatedtomedia(note).

c16:           IFA.4/37ORA.4/37ATHENmELSEn/a--securitymechanismagreementforthesessioninitiationprotocolormediasecheaderfieldparameterformarkingsecuritymechanismsrelatedtomedia.

c17:           IFA.4/38THENoELSEn/a--theReasonheaderfieldforthesessioninitiationprotocol.

c18:           IFA.4/40THENoELSEn/a--callerpreferencesforthesessioninitiationprotocol.

c19:           IFA.4/43THENmELSEn/a--theSIPReferred-Bymechanism.

c20:           IFA.4/43THENoELSEn/a--theSIPReferred-Bymechanism.

c21:           IFA.3/2THENmELSEIFA.4/38THENoELSEn/a--P-CSCF,theReasonheaderfieldforthesessioninitiationprotocol.

c22:           IFA.4/40THENmELSEn/a--callerpreferencesforthesessioninitiationprotocol.

c23:           IFA.4/60THENmELSEn/a--SIPlocationconveyance.

c24:           IFA.4/38THENmELSEn/a--theReasonheaderfieldforthesessioninitiationprotocol.

c25:           IFA.4/70BTHENmELSEn/a--inclusionofCANCEL,BYE,REGISTERandPUBLISHincommunicationsresourcepriorityforthesessioninitiationprotocol.

c26:           IFA.4/76THENoELSEn/a--transportingusertouserinformationforcallcentersusingSIP.

c27:           IFA.4/80THENoELSEn/a--theP-Debug-IDheaderfieldforthesessioninitiationprotocol.

c28:           IFA.4/80THENmELSEn/a--theP-Debug-IDheaderfieldforthesessioninitiationprotocol.

c29:         IFA.4/71AND(A.3/9BORA.3/9C)THENmELSEIFA.3/1ANDNOTA.3C/1THENn/aELSEo--addressinganamplificationvulnerabilityinsessioninitiationprotocolforkingproxies,IBCF(IMS-ALG),IBCF(ScreeningofSIPsignalling),UE,UEperformingthefunctionsofanexternalattachednetwork.

c30:           IFA.4/71THENmELSEn/a--addressinganamplificationvulnerabilityinsessioninitiationprotocolforkingproxies.

c31:           IFA.3/1ANDNOTA.3C/1THENn/aELSEo--UE,UEperformingthefunctionsofanexternalattachednetwork.

c32:           IFA.4/91THENmELSEn/a--theSession-IDheader.

NOTE:       Supportofthisheaderinthismethodisdependentonthesecuritymechanismandthesecurityarchitecturewhichisimplemented.Useofthisheaderinthismethodisnotappropriatetothesecuritymechanismdefinedby3GPPTS33.203[19].

 

 

11.1.        UAC行为

一旦构造了BYE,UAC核心创建新的非INVITE客户端事务,并将其传送给BYE请求。BYE请求一旦发送给客户端事务,UAC 必须认为会话结束了(并因此停止发送和侦听媒体)。如果BYE响应是481(呼叫/事务不存在)或者408(请求超时),或者请求根本没有接收到BYE的响应(即是INVITE客户端事务返回超时),那么,UAC必须认为会话和对话结束了。

11.2.        UAS行为

UAS首先遵循第5.2 节介绍的通用UAS处理过程来处理BYE请求。

UAS核心接收到BYE请求,检查它是否和现有对话匹配。如果BYE不能和现有对话匹配,那么,UAS核心必须生成481(呼叫/事务不存在)响应,并将其发送给服务器事务。

此规则意味着,将拒绝UAC 发送的无标签BYE。这是对RFC 2543的修改——它允许无标签的BYE。

UAS核心接收现有对话的BYE请求,并且发现和现存的对话匹配,必须遵循对话处理过程处理请求。一旦完成,UAS应该结束会话(并因此停止发送和侦听媒体)。它唯一不可以选择的情况是多播会话,在多播会话中,即使会话的其他参与者已经结束了其包含的会话,都有可能参与(participation)。不管它是否结束参与会话,UAS核心必须对BYE生成2xx 响应,并将其发送到服务器事务传输。

UAS必须响应任何此对话中接收的挂起的请求。推荐对于这些挂起的请求生成487(请求结束)响应。

12. 取消请求(CANCEL

CANCEL请求,是用于取消客户端发送的前一请求。特别的是,它要求UAS 停止处理请求,并为请求生成错误响应。对占用服务器很长时间才能响应的请求来说,CANCEL请求是最有用的。因为这样,CANCEL请求在占用服务器很长时间响应的地方很有用。为此,对需要很长时间生成响应的INVITE请求,CANCEL是最好的。按照常例,接收到INVITE的CANCEL请求,但是没有发送最终响应的UAS,可能会“停止响铃”,然后给INVITE发送特定的错误代码(487)。

代理和用户代理客户端都可以构造CANCEL请求。

有状态代理对CANCEL做出响应,而不是简单地转发它从下游元素接收的响应。因此,因为每个有状态代理的跳跃点都响应它,CANCEL被称为“逐跳”请求。

12.1.        UAC行为

不应该发送CANCEL取消INVITE外的请求。

因为INVITE外的请求是立即响应的,为非INVITE发送CANCEL会创造竞态条件。

使用下列过程来构造CANCEL请求。CANCEL请求中的Request-URI、Call-ID、To、Cseq的数字部分和From 头字段,必须与要取消的请求中的一样,包括标签。客户端构造的CANCEL必须有单一的Via与要取消的请求中的最上面Via值匹配。这些头字段使用相同的值,允许CANCEL和它要取消的请求匹配。然而,此方法的CSeq头字段必须有CANCEL值。这允许它凭借自身的实力确定和处理为事务。

如果要取消的请求包括Route 头字段,那么CANCEL请求必须包括此Route 头字段值。

这是必需的以便于无状态代理可以正确地路由CANCEL请求。

CANCEL请求不能包含任何Require和Proxy-Require头字段。

一旦构造了CANCEL,客户端应该检查是否接收到要取消请求(这里指“原始请求”)的任何(临时或者永久)响应。

如果没有接收到临时响应,必须发送CANCEL请求,当然,客户端必须等待发送请求之前的临时响应。如果原始请求产生最终响应,不应该发送CANCEL,因为它是有效的无操作,而CANCEL对已经生成最终响应的请求没有影响。

当客户端决定发送CANCEL时,它为CANCEL创建客户端事务,并将其和CANCEL请求以及目的地址、端口和传输一起发送。CANCEL请求的目的地址、端口和传输必须和发送请求的一样。

在接收到之前请求的响应之前,如果允许发送CANCEL,那么,服务器将在原始请求之前接收到CANCEL。

注意,原始请求对应的事务和CANCEL事务是完全独立的。然而,UAC 取消请求不依靠接收原始请求的487(请求超时)响应,因为与RFC2543 兼容的UAS 不会生成这样的响应。如果在64*T1 秒内没有原始请求的最终响应,客户端应该考虑取消的原始事务,并且应该破坏客户端事务处理原始请求。

12.2.        UAS行为

CANCEL方法要求服务器边的TU取消挂起的事务。TU确定使用CANCEL请求取消的事务,然后假定请求方法是CANCLE和ACK之外的任何方法,并进行事务匹配过程。取消匹配事务。

服务器的CANCEL程序请求与服务器的类型有关。无状态代理将转发CANCEL,有状态代理可以响应CANCEL,并生成自己的CANCEL请求,同时,UAS将响应CANCEL。

UAS 首先根据第5.2节介绍的通用UAS 处理方法处理CANCEL请求。然而,因为CANCEL请求是逐跳的,并且不可以重新提交,为了在Authorization头字段得到正确的凭证,服务器不会向它们发出挑战。注意,CANCEL请求也不包含Require头字段。

如果UAS 没有找到与上面过程的CANCEL匹配的事务,那么它应该返回481(呼叫腿/事务不存在)响应。如果原始请求的事务仍然存在,接收到CANCEL请求的UAS行为与它是否已经发送了原始请求的最终响应有关。如果它对会话状态和原始请求生成的响应没有影响,那么CANCEL请求对原始请求的处理没有影响。如果UAS没有发布原始请求的最终响应,那么,其行为和原始请求的方法有关。如果原始请求是INVITE,UAS应该立即响应INVITE,返回487(请求结束)。CANCEL请求对本规范中定义的其它方法的事务处理没有影响。不管原始请求的方法是什么,只要CANCEL可以匹配现有的事务,那么,UAS回答CANCEL请求200(OK)响应。遵循第5.2.6 节介绍的过程构造此响应。注意,CANCEL响应的To标签和原始请求响应的To标签应该是一样的。CANCEL响应传送给服务器事务发送。

13. 即时消息(MESSAGE

即时消息被定义为一组参与实体之间的实时消息交互,通常情况下,这些消息是文字信息,并且这些消息不需要存储。SIP即时消息通过扩展方法MESSAGE实现。

当用户想要发送即时消息时,该用户通过MESSAGE方法发起一个SIP请求。MESSAGE请求的Request –URI可以是SIP URI,也可以是其它类型的地址。

传递消息内容包含在MESSAGE请求的消息体中,该消息体可以是任何MIME类型,包括message/ CPIM 。但更建议message/cpim,因为已有的IM系统标准是message/cpim格式

MESSAGE消息被送达之前,可能通经过一系列SIP proxy,每个SIP proxy需要重写请求URI以提供消息传递的路由信息。

像SIP其它请求一样,收到MESSAGE应回临时应答和最终应答。200-OK只说明消息成功到达了目的地,并不代码用户已经阅读。

MESSAGE请求并不创建对话。

13.1.        UAC行为

MESSAGE body必须支持plain/text格式。可以选择支持message/cpim格式。由于不创建一个dialog,所以MESSAGE不应该包含contact头域。MESSAGE可以在in dialog里发送,此时代表这个消息和某个dialog有关联关系(即发消息的URI为SIP URI)。

最终应答的含义,

200-OK:消息已成功送达目的地,但不保证对方用户已阅;

202-Accept:消息已成功发送到某网关,但不保证网关一定能把该消息送达目的地。

外发proxy有可能把MESSAGE分叉,可以加Expire头域,Date头域表明消息的生存时间。

13.2.        使用IM URI

Request URI,From头域,To头域可以填SIP URI,实在不行也可以填IM URI,此时会有proxy解析成SIP URI。

和路由相关的头域中的URI必须是SIP URI。

13.3.        UAS的操作

和SIP相关的操作参见rfc3261。

 200-OK:UAS收到MESSAGE,应立即回200-OK,但是是否把消息的内容显示给用户与本地策略有关 (是不是可以用来制作黑名单功能?) 。200-OK不能带body,,也不能携带Contact头域。

202-Accepted:如果自己不是MESSAGE的最终用户,就回202-Accepted。意味着该MESSAGE会被尽力转发,但不保证一定能到达目的地。

4xx, 5xx :4xx, 5xx表示消息未被成功发送。

6xx :6xx表示消息虽被成功发送,但已被拒收。

支持MESSAGE就必须支持text/plain格式的MIME type。也可以选择支持message/cpim格式。

如果消息携带有Expire头域,就处理超时,否则没有超时的概念。

如果UAS收到消息时该消息已经超时,可以选择处理该消息这和本地策略有关。例如可以选择丢弃,也可以正常显示给用户(标明超时),或采取其它策略。

如果消息不能被正确中继,如何处理该消息也与本地策略有关。

13.4.        拥塞控制

MESSAGE用信令携带媒体,所以流量会很大,需要特殊考虑。 如果可能,MESSAGE最好使用有拥塞控制的传输层协议,如TCP,SCTP。

消息本身的大小不一不要超过1300个字节,除非你知道确切的PMTU大小。

对于不采用Dialog方式的消息,发往同一个目的URI的MESSAGE,如果上一个transaction还没有结束,就不允许发送下一个MESSAGE;而且如果不是路由设置每一跳在传输中采用拥塞控制,用Dialog传送的MESSAGE也禁止这么做。

有人曾建议为了减少拥塞,MESSAGE不必回临时应答。实际上没有必要规定这个。因为很多代理服务器根本就不关心是否是MESSAGE方法,他们只管转发。

 

14. Proxy行为

SIP代理是将SIP请求路由到用户代理服务器和将SIP响应路由到用户代理客户端的元素。到达UAS 的请求可以穿透其间的多个代理。每个代理都可以作出路由决定,并在将请求转发到下一个元素之前对其修改。响应将通过代理路由,该代理与逆序请求穿透的代理相同。代理作为SIP元素的逻辑角色。当请求到达时,该元素在作为代理之前先确定是否需要响应其上的请求。例如,在充当代理之前,该请求可能难以理解或者该元素需要客户端的凭证。该元素可能用适当的错误代码作出响应。当直接响应请求时,该元素则扮演UAS 的角色,并且其行为必须如第5.2 节所述。

对于每个新的请求,代理可以以有状态或者无状态模式操作。当采用无状态模式时,代理仅充当一种简单转发元素。它转发每一个请求下行到一个由请求所决定的目的地,该目的地是基于请求由目标和路由决定确定的。它简单地转发它接收的每个上流响应。一旦请求被转发,无状态代理将丢弃该请求相关的所有状态信息。

有状态代理将保留每个入站请求的信息(特别是事务状态),并且它所发送的任何请求都作为入站请求处理结果。有状态代理使用入站请求信息来影响与该请求相关的下一步消息处理。有状态代理可以选择“分发”请求,并将它路由到多个目的地。转发给多个位置的请求都必须有状态处理。

在某些情况中,代理可能在未成为有状态事务时就使用有状态传输协议(如TCP)转发请求。例如,代理可以将请求从一个TCP 连接转发到另一个无状态事务,只要它在消息里放有足够多的信息以将该响应向下转发给该请求所到达的相同连接上。在不同传输类型之间所转发的请求必须有状态的转发事务,这里代理的TU 必须主动地确保在每一个传输上都是可靠传输。

在请求处理期间,只要有状态代理不作阻止其回到初始无状态的事情(例如,分发或生成一个100 响应),它就可以转换为无状态操作模式。当完成这样的转换时,丢弃了所有状态。代理不应发起CANCEL 请求。

无论请求是有状态还是无状态,相关的许多处理都是相同的。

14.1.        有状态代理

当处于有状态模式时,代理则完全作为一个SIP事务处理引擎。在此按照服务器和客户端事务模拟其行为。有状态代理通过高级代理处理组件(作为代理核心)将一个服务器事务与多个客户端事务联系在一起。入站请求由服务器事务来处理。服务器事务处理后的请求传送到代理核心。代理核心确定将该请求路由到何处,并选择一个或者多个下一跳位置。每个下一跳位置的出站请求都由其自身相关的客户端事务来处理。代理核心收集来自客户端事务的响应,然后使用客户端事务将响应发送到服务器事务。

有状态代理为每个所接收的新请求创建新的服务器事务。随后按第14章介绍的服务器事务,处理请求的转发。在发送及时的临时请求给第5.2.6节介绍的服务器事务(如,100(Trying))时,代理核心必须作为UAS。因此,有状态代理不应该对非INVITE请求生成100(Trying)响应。

这是代理行为的模型,而不是软件。可以自由地采用任何方法来复制该模型定义的外部行为。

对于所有新的请求,包括未知方法、作为代理的元素,请求必须:

1. 确认请求

2. 预处理路由信息

3. 确定请求目标

4. 向每个目标转发请求

5. 处理所有响应

14.2.        请求确认

在元素代理请求之前,它必须确认消息的有效性。有效消息必须经过以下检查:

1. 合理语法

2. URI 模式

3. Max-Forwards

4. (可选)循环检测

5. Proxy-Require

6. Proxy-Authorization

如果其中任何检查失败,该元素必须作为用户代理服务器(参见第5.2节),然后响应错误代码。

注意代理不需要检测已合并的请求,它不应将已合并的请求作为错误的条件。接收请求的端点将解析合并,如第5.2.2节所述。

1、合理的语法检查

请求必须足够规格化,以便于与服务器事务一起处理。在剩余的这些请求确认步骤中或者请求转发章节所涉及的组件必须是规格化组件。对于其它组件,则对规格化的要求不是很严格,当转发消息时,可以忽略此组件或者该组件保持不变。举个例子来说,由于Date头字段的格式不好,元素将不能接受请求。同样的,代理不应该在转发请求之前将格式不好的Date头字段删除。

本协议可用来扩展。新扩展可以随时定义一些新的方法和头字段。这样元素不能因为请求中包含它所不知道的方法和头字段而拒绝代理请求。

2、URI 模式检查

如果Request-URI的URI模式不为代理所理解,代理应拒绝该请求,并返回416(不支持URI 模式)响应。

3、Max-Forwards 检查

Max-Forwards头字段用于限制SIP请求可以穿透的元素数。

如果请求不包含Max-Forwards头字段,Max-Forwards检查通过。

如果该请求包含Max-Forwards头字段,该字段是比零大的字段值,则Max-Forwards检查也通过。

如果该请求包含Max-Forwards头字段,该字段值为零,元素不需转发请求。如果该请求用于OPTION,该元素可以作为最终接受者,并作出响应。此外,元素必须返回483(太多跳跃点)响应代码。

4、可选循环检测检查

在转发请求前,元素可以对转发循环作检查。如果请求包含了Via头字段,所发送的值等于代理预先放置在请求中的值,该请求先由该元素转发。请求通过该元素循环或者合理的螺旋。为了确定了请求是否循环,该元素可以完成分支参数计算,并将它与Via 头字段中所接收的参数进行比较。如果参数匹配,请求循环。如果它们不相同,则请求正螺旋,处理继续。如果探测出发生循环,则该元素返回482(循环探测)响应。

5、Proxy-Require检查

对协议作进一步扩展,则可以引入代理特殊处理的功能。端点在请求中加入使用这些特性的Proxy-Require(代理需求)头字段,告知代理除非理解该特性,否则不处理该请求。如果该请求包含Proxy-Require头字段,它带有一个或者多个该元素所不理解的可选标签,元素必须返回420(错误扩展)响应。该响应必须包括Unsupported头字段,该字段列出了该元素不理解的可选标签。

6、Proxy-Authorization如果代理要求在转发请求之前进行身份认证,那么必须进行请求检查。

14.3.        路由信息处理

代理必须检查请求的Request-URI。如果请求的Request-URI包含了该代理预先放置在Record-Route 头字段值,代理必须使用Route 头字段中的最后一个值代替请求中Request-URI 的值,并且将该值从Route 头字段中去掉。一旦代理接收到已修改的请求,它将继续处理。

这种情况只有在元素向作为严格路由器的代理(可以是一个端点)发送请求时发生。对所接收的请求重写必须具有这些元素的向后兼容性。它也允许遵循本规范的元素,通过严格路由代理保留Request-URI。

本规范不强制代理保持状态,以便于它检查先前放置在Record-Route头字段中的URI。反过来说,代理只需要在这些URI中放置足够多的信息,它就可以在随后出现时可以识别其值。

如果Request-URI包含maddr参数,那么代理必须检查所配置代理负责的值是否在地址集或者域中。如果Request-URI包含带值的maddr参数,该值由代理负责,并且使用Request-URI中所指示(明确指示或者默认)的端口和传输来接收请求,那么,代理必须去除maddr参数和任何非默认端口或者传输参数,并且继续处理,就像这些值从未在请求中出现一样。

如果所接收请求带有与代理匹配的maddr,但是该maddr参数与URI中所指示的端口或者传输不同。这样就需要使用所指示的端口和传输将请求转发给代理。

如果Route 头字段中的第一个值指明这个代理,该代理必须将此值从请求中去掉。

14.4.        确定请求目标

接下来,代理计算出请求的目标。目标集合可以由请求的内容预先确定,也可以从抽象定位服务中获得。集合中的每个目标都作为URI。

如果请求的Request-URI包含maddr参数,Request-URI必须作为唯一的目标URI放在目标集合中,并且,代理必须继续请求转发。

如果Request-URI的域表示此域不是该元素负责的域,那么,Request-URI 必须作为唯

一的目标URI 放在目标集合中,同时,此元素必须继续请求转发的任务(第16.6 节)。

在很多情况中,代理可能接收到其不负责的域的请求。防火墙代理处理出站呼叫(HTTP

代理处理出站请求的方式)是可能发生此情况的一个实例。

如果请求的目标集合没有如上所述预先确定,那么,它意味着元素是对Request-URI的域负责任的,同时,元素可以使用它想要的任何机制,确定发送请求的地址。这些机制可以作为访问抽象定位服务的模型。这可能由以下几个部分组成——获取SIP注册服务器创建的定位服务信息、读取数据库、查询状态服务器、使用其他协议和在Request-URI中简单地执行算法替代。当访问注册服务器构造的定位服务时,在将其用作索引之前,首先要将Request-URI规范化。这些机制的输出用作构造目标集合。

如果Request-URI没有为代理提供足够的信息来确定目标集合,那么,它应该返回485(模糊)响应。此响应应该包含Contact头字段——包含已作尝试的新地址的URI。如,对sip:John.Smith@company.com的INVITE可能有些含糊不清,其定位服务列出了多个John Smiths。

在请求中或关于请求或元素当前环境的任何信息都可以用作构造目标集合。例如,依赖于头字段和消息体的内容和状态、请求间隔的延迟、请求到达的接口、之前请求的错误、甚至是元素的当前利用率,可以构造不同的目标集合。

当通过这些服务对潜在的目标定义时,将其URI添加到目标集合中。目标仅能在目标集合中放置一次。如果在目标集合中已经有目标URI(以URI 类型相同的定义为基础),那么,不能再添加目标URI。

如果原始请求的Request-URI没有指出代理负责的资源,那么,代理不能在目标集合中添加其它的目标。

只有代理对此URI负责时,代理才可以在转发期间修改Request-URI的URI。如果代理不对此URI负责,那么,它将不能使用下面介绍的3xx和416响应。

如果原始请求的Request-URI指出了代理负责的资源,那么,在开始请求转发后,代理可以在目标集合中添加目标。它可以使用在处理过程中获取的任何信息来确定新目标。例如,代理可以选择将重定向响应(3xx)中获取的联系信息合并到目标集合中。如果在建立目标集合的同时,代理使用一个动态信息资源(如,它查询SIP 注册服务器),那么,在处理请求的过程中,它应对资源监控。一旦新的地址有效,应该将其添加到目标集合中。如上所述,任何给定的URI不能多次添加到目标集合中。

仅允许URI 在目标集合中添加一次,可以减少不必要的网络流量,从重定向请求中获取的合并联系信息的情况,防止了无穷的网络递归。

例如,当目标URI和入站的请求URI相同时,通常的定位服务是“无操作”。为了进一步处理,请求发送到指定的下一跳代理。在请求转发期间,以SIP和SIPS URI表示的下一跳识别符作为最上面的Route头字段值插入到请求中。

如果Request-URI指出此代理上的资源不存在,那么,代理必须返回404(没找到)响应。

如果在应用以上所有之后,目标集合仍然为空,代理必须返回480(暂时不可用)错误响应。

14.5.        转发请求

一旦目标集非空时,代理便开始转发请求。有状态代理可以以任何顺序处理这个目标集合。它可以串行处理多个目标,即允许客户端事务在下一个事务开始前完成。它也可以采用每个目标并行处理的方式启动客户端事务。它还可以将目标集合任意分组,对这些组串行处理,或者对每个组中的目标并行处理。

常用的排序机制是使用目标的q值参数,这些参数可从Contact头字段中获取。目标的处理顺序是从最高q值到最低q值。具有相同q值的目标可并行处理。

当接收响应时,有状态代理必须具有维护对象集合的机制,然后将对每个转发请求的响应与原始请求相关联。对于该模型而言,这种机制就是由代理层在转发第一个请求之前创建的“响应上下文”。

对于每个目标,代理都遵循以下步骤发送请求:

1、 复制所接收的请求

2、 更新Request-URI

3、 更新Max-Forwards头字段

4、 添加Record-Route头字段值(可选的)

5、 添加其它头字段(可选)

6、 后处理路由信息

7、 确定下一跳的地址、端口和传输协议

8、 添加一个Via头字段值

9、 如果需要,添加一个Content-Length头字段

10、 转发新请求

11、 设置计时器C

每个步骤详述如下:

1、 复制请求

代理首先将接收到的请求复制。这个副本最初必须包含所接收到的请求的所有头字段。在一下描述中没有明确说明的字段不可以去掉。副本应与所接收的请求保持相同的头字段顺序。代理不能用通用字段名对字段值重新排序。代理也不能添加、修改或删除消息体。

在实际执行中有时并不需要完成复制请求;但是主要前提条件是每个下一跳的处理都以相同的请求开始。

2、 Request-URI

必须用目标的URI代替位于副本起始行的Request-URI。如果这个目标的URI含有Request-URI中不允许的任何参数,那么必须删除它们。

这就是代理角色的本质。代理会通过这种机制将请求路由到目的地。

在某些情况下,接收到的Request-URI 未经修改便放到了目标集合中。对于该目标而言,无需执行以上替换操作。

3、 Max-Forwards

如果副本包含Max-Forwards头字段,那么代理必须将其值减1。

如果副本不含Max-Forwards头字段,那么代理必须添加一个Max-Forwards字段值,其值为70。

现有的某些UA 在请求中没有提供Max-Forwards 字段。

4、 Record-Route

如果这个代理希望保留在该请求所创建的对话中后续请求的路径上(假定这个请求会创建一个对话),那么即使已经存在Route头字段,它也必须在副本中任何已有的Record-Route头字段值之前插入一个Record-Route头字段值。

建立对话的请求可以包含一个预先加载的Route头字段。

如果这个请求已经是对话的一部分,那么,如果代理希望保留在对话中后续请求的路径上,它就应当插入一个Record-Route头字段值。在通常端点操作的情况下,这些Record-Route 头字段值不会对端点使用的路由集合产生任何影响。

如果代理选择不向已经是对话的一部分的请求中添加Record-Route头字段值,那么代理将会保留在该路径上。但是当失败端点重新构建对话时,将会从这个路径上去掉这个代理。

代理会向任何请求添加Record-Route头字段值。如果请求不启动对话,那么端点将忽略这个值。欲了解端点如何使用Record-Route头字段值构建Route头字段的详情。

请求路径中的每个代理都会单独选择是否添加Record-Route头字段值——请求中Record-Route头字段的状态并不迫使该代理添加一个值。

放入Record-Route 头字段值中的URI 必须是SIP或SIPS URI。这个URI必须包含一个lr参数。这个URI 可以与请求转发到的每个目的地不同。除非代理知道(如在私有网络中)下一个将在后续请求路径中的下游元素支持此传输协议,URI不应包含传输参数。

这个代理提供的URI将被其它元素用来作路由决策。一般说来,这个代理无法知道其它元素的性能,因此它必须将其本身限制为SIP执行的强制元素:SIP URI和TCP/UDP传输。

当对放置在Record-Route头字段的URI应用服务器定位的第四步时,这个URI必须对插入此URI的元素解析,这样后续请求就可以访问相同的SIP元素。如果Request-URI 包含SIPS URI,或顶端Route头字段值(在步骤6 的后处理后)包含SIPS URI,那么放置在Record-Route头字段的URI必须是SIPS URI。此外,如果没有在TLS之上接收到这个请求,代理就必须插入一个Record-Route头字段。与之类似的情况:代理在TLS 上接收请求,但是生成的请求没有在Request-URI或顶端Route头字段值中(在步骤6 的后处理后)的SIPS URI,那么代理必须插入一个非SIPS URI的Record-Route头字段。

在整个对话期间,位于安全边界的代理必须保留此边界。

当放置在Record-Route头字段中的URI以响应的形式回传时,如果它需要重写,那么这个URI必须与众不同,以便在此时可以定位。(这个请求可通过此代理螺旋,导致了添加多个Record-Route头字段值)。

代理可在Record-Route头字段值中包含参数。这些参数值将在对该请求的某些响应中得到回应,这些响应如:对INVITE的200(OK)响应。这样的参数对于在消息中而不是在代理中保持状态会很有用。

如果某代理需要存在于任何类型的对话(如一用户要跨越防火墙)路径中,那么它应当用一个它不理解具有对话语义的方法向每个请求添加一个Record-Route头字段值。

代理放置在Record-Route 头字段中的URI,仅仅在出现URI 的事务所创建的任何对话的生命周期内有效。例如,对话有状态代理可在对话终止后可以拒绝接受在Record-Route中有该值的后续请求。当然,非对话有状态协议没有对话何时终止的概念,但它们可以对值中信息编码,以将其与后续请求的对话标识符相比较,然后会拒绝与那些信息不匹配的请求。

端点不能在提供它的对话外使用从Record-Route头字段获得的URI。

代理需要观察对话中所有消息的某些服务可能需要Record-Routing。但是,Record-Routing会减慢处理过程,并降低可扩展性,使得代理只在特定服务需要的情况下进行Record-Route。

Record-Route过程旨在为启动对话的任何SIP 请求工作。INVITE 是本规范中唯一属于这类的请求,但是这个协议的扩展可以定义其它请求。

5、 添加其他头字段

在这一点上,代理可以向副本添加任何其它适当的头字段。

6、 对路由信息进行后处理

代理可以设置本地策略,要求请求在传送到目的地之前访问特定代理集合。代理必须确保所有这些代理都是松散路由。一般说来,如果这些代理位于同一管理域中,这点可能比较容易明白。该代理集合由URI集合(每个URI都包含lr参数)表示。该代理集合必须放入副本中的Route头字段中,并且位于任何现有的值之前,如果这些值存在的话。

如果代理可以设置本地策略,要求请求访问一个特定代理,那么将Route值放入Route头字段中的可选办法是跳过下面描述的第10步的转发步骤,而仅向那个特定代理的地址、端口以及传输协议确定的目的地发送请求。如果这个请求有Route头字段,那么除非知道下一跳代理是松散路由,否则不能使用这种可选方法。此外,虽然这个方法也可用,但对于操作的健壮性、灵活性、通用性和连贯性来说,Route插入机制是更可取的。而且,如果Request-URI包含SIPS URI,那么必须使用TLS与该代理进行通信。

如果副本包含一个Route头字段,那么代理对其第一个值中URI检查。如果此URI不含有lr参数,这个代理必须对该副本做如下修改:

􀁺 这个代理必须将Request-URI作为最后一个值放入Route头字段中。

􀁺 然后该代理必须将第一个Route头字段值放在Request-URI 中,并将第一个Route头字段值从Route头字段中删除。

将Request-URI附加在Route头字段中,是通过严格路由元素传送Request-URI中的信息的机制的一部分。将第一个Route头字段值加到Request-URI中会将消息格式化,严格路由元素期望以这种格式来接收这条消息(其自身的URI在Request-URI中,下一个要访问的位置在第一个Route头字段值中)。

7、 确定下一跳的地址、端口和传输协议

代理可设置本地策略将请求发送到特定IP地址、端口和传输协议确定的目的地,而这个目的地与Route值和Request-URI值无关。如果代理不确定这个IP地址、端口和传输协议是否与作为松散路由器的服务器对应,那么不可以使用此策略。但是,对于通过特定下一跳发送请求的这种机制,我们并不推荐;对于这种情况,可以使用Route头字段。

在没有这种替换机制情况下,代理应按照第四条中所列出的步骤确定往何处发送请求,如下描述。如果代理已对请求重新格式化以将其发送到前面第六步描述的严格路由元素,代理应将这些步骤应用到请求的Request-URI。否则,如果Route头字段的第一个值存在,也就是Request-URI存在,代理必须对其应用这些步骤。这些步骤将产生一个有序的数据集(地址、端口、传输协议)。不管使用哪个URI作为第四条步骤的输入,如果Request-URI指定一个SIPS资源,代理就必须将输入URI当作SIPS URI,按照第四条步骤的规定执行。

正如第四条所描述的,代理必须不断尝试将消息传送到元组集的第一个元组,然后依次传送元组集的第二个元组、第三个元组,直到传送成功为止。

对于准备接收消息的元组,代理必须为将消息格式化为适合于该元组的消息,并使用第八条和第10条所描述的新的客户端事务发送请求。由于每一次尝试都使用一个新客户端事务,因此每一次尝试都代表一个新的分支。因而,由第8步中插入的Via头字段提供的分支参数必须互不相同。

如果客户端事务报告发送请求失败或者状态机超时,该代理将继续发送到有序元组系列的下一个地址。如果到了这个有序系列的末尾,请求便无法转发到目标集合的这个元素中。

代理不需要在响应上下文中放入任何东西,但是它的行为就像是这个目标集合的元素返回408(请求超时)最终响应。

8、 添加一个Via 头字段值

代理必须在副本中现有的Via头字段值之前插入一个Via头字段值。这个值的构造遵循第5.1.1节相同的规定。这意味着代理将计算自己的分支参数,分支参数对于其对应的分支来说要具有全局唯一性,并且包含必备的magic cookie。请注意,这意味着对于由代理产生的螺旋请求或者循环请求的不同实例来说,分支参数应有所区别。

选择检测循环的代理在它们用来构造分支参数的值上还有其它限制。选择检测循环的代理应当创建一个分支参数,这个参数由应用分为两部分。第一部分必须满足上述第5.1.1节所述的限制。第二部分用来完成循环检测并区别循环请求与螺旋请求。当请求返回给代理时,通过验证那些对请求处理产生影响的字段没有改变,完成循环检测。分支参数这一部分中的值应当反映所有字段,包括任何Route头字段、Proxy-Require头字段和Proxy-Authorization头字段。这是为了确保如果请求路由回代理,并且这些字段中的其中一个发生更改,那么它将被视为螺旋请求而不是循环请求。创建此值的通用方法是对以下内容作加密哈希运算:所接收请求(在转换之前)的TO标记、From标记、Call-Id头字段、Request-URI、最上面的Via头、Cseq头字段的序列号,并且如果Proxy-Require和Proxy-Authorization头字段出现时,还包括它们。用于计算哈希的算法是与执行程序有关,然而以16进制表示的MD5,是一个不错的选择。(对于标记来说,不允许使用Base64。)

如果代理希望对循环进行检测,那么它提供的branch参数必须依赖于所有影响请求处理的信息,包括入站的Request-URI和任何影响该请求的进入或路由的头字段。对于区分循环请求与那些在返回给服务器之前其路由参数发生更改的请求,这是必需的。

请求方法不能包含在分支参数的运算中。特别是CANCEL请求和ACK请求(用于non-2xx响应)必须与它们取消或确认的对应的请求有相同的分支参数值。在服务器端处理分支参数的那些相关的请求中使用这些分支参数。

9、 如果需要,添加一个Content-Length头字段

如果使用流传输协议将请求发送到下一跳,并且副本不包含Content-Length头字段,那么这个代理必须插入一个带有请求主体的正确值的Content-Length头字段。

10、 转发请求

有状态代理必须为这个请求创建新的客户端事务,并指导这个事务使用第7 步确定的地址、端口和传输协议发送请求。

11、 设置计时器C

为了处理INVITE请求从不生成最终响应这种情况,TU使用一个称为计时器C的计时器。

当INVITE请求得到代理时,必须为每个客户端事务设置计时器C。必须将计时器设置为大于三分钟。

14.6.        响应处理

当某元素接收到响应时,它首先会试图对匹配该响应的客户端事务定位。如果没有找到匹配的客户端事务,这个元素必须将这个响应(即使这个响应是一个信息响应)作为无状态代理(如下所述)处理。如果找到了匹配的客户端事务,那么这个响应便会传递到客户端事务。

在没有客户端事务(或更普遍地说,知道发送了一个相关请求)的情况下转发响应会提高健壮性。特别是它确保将对INVITE请求的“延迟的”2xx响应恰当地转发。

客户端事务将响应传送到代理层时,必须经过以下的处理步骤:

1. 找到合适的响应上下文

2. 为临时响应更新计时器C

3. 去掉最上面的Via

4. 对响应上下文添加响应

5. 检查响应是否应当立即转发

6. 当需要的时候,从响应上下文中选择最佳最终响应

如果在每个与响应上下文相关联的客 户端事务终止后没有最终响应得到转发,那么代理必须选择并转发它目前所见到的“最合适”的响应。

所转发的每一个响应必须执行以下处理。每个请求可能有多个响应得到转发:至少每个请求有一个临时响应和一个最终响应。

7. 如果需要,集合授权头字段值

8. 选择性重写Record-Route头字段值

9. 转发这个响应

10. 生成任何所需的CANCEL 请求

上面的每个步骤详述如下:

1. 查找上下文

代理对其创建的“响应上下文”进行定位。余下的处理步骤将在这个上下文中进行。

2. 为临时响应更新计时器C

对于INVITE事务来说,如果该响应是一个临时响应,其状态代码为包含101和199在内,从101至199(即除100 以外)的任意值,那么代理必须对那个客户端事务的计时器C进行重新设置。可以给计时器重新设置一个不同的值,但是这个值必须大于3分钟。

3. Via

代理从响应中删除最上面Via头字段值。

如果响应中没有保留Via头字段值,那么这个响应就是这个元素的响应,不必转发。本

节所描述的剩余处理工作不将对该消息执行,而是遵循第5.1.3 节描述的UAC处理规则(已

经发生了传输层处理)。

例如,当元素生成CANCEL 请求时,这种情况会发生。

4. 向上下文添加响应

在与上下文相关联的服务器事务上生成最终响应之前,所接收到的最终响应存储在响应上下文中。这个响应可能是那个服务器事务上所返回的候选最佳最终响应。即使这个响应没有被选中,构成最佳响应可能也需要这个响应中的信息。

如果代理选择通过向目标集合添加联系人来在3xx响应中对联系人进行递归操作,那么它必须在将这个响应添加到响应上下文之前将这些联系人从响应中删除。但是,如果原先请求的Request-URI是SIPS URI,那么代理不应当对非SIPS URI进行递归操作。如果代理对3xx响应中的所有联系人都进行递归操作,那么代理不应当向响应上下文添加所产生的无联系人响应。

在向响应上下文添加响应之前去掉联系人可以避免下一个上游元素重新尝试该代理已经尝试过的位置。

3xx响应既可包含SIP,也包含SIPS和非SIP URI。代理可以选择递归SIP和SIPS URI,并将其余部分放在将要返回的响应上下文,有可能是在最终响应中。

如果代理接收到了一个请求的416(不支持的URI 模式)响应,该请求的Request-URI模式不是SIP,但是原始接收请求中的模式是SIP或者SIPS(即在代理该请求时,代理将模式从SIP或SIPS更改到了其它模式),那么该代理应当向目标集合添加一个新的URI。这个URI 应当是刚刚尝试过的非SIP URI的SIP URI版本。在tel URL的情况下,这一步通过将tel URL的电话订阅用户部分放在SIP URI的用户部分中,并将主机部分设置为优先请求所发送的区域。

就像3xx 响应一样,如果代理通过尝试SIP或SIPS URI来“递归”416,416不应添加到响应上下文中。

5. 为转发检查响应

直到最终响应在服务器事务发送之前,必须立即转发以下响应:

²  除100(Trying)以外的任何临时响应

²  任何2xx响应

如果接收到一个6xx响应,那么它不会被立即转发,但是有状态代理应当取消所有的客户端待处理事务,而且它不能在该上下文中创建任何新的分支。

这是对RFC 2543 所做的更改,RFC 2543 要求代理将6xx响应立即转发。对于INVITE事务来说,该方法有个问题:2xx响应能够到达另一个分支,而在这种情况下,代理就必须转发2xx。结果是UAC可以在接收到2xx 响应之前接收到6xx 响应,而这是不允许发生的。根据新规则,在接收6xx之前,代理将发布一条CANCEL请求,通常这条请求会从所有的未决客户端事务中产生487响应,然后此刻6xx便会上游转发。

在服务器事务上发送一条最终响应之后,必须立即转发以下响应:

²  对INVITE 请求的任何2xx 响应

有状态代理不必立即转发任何其它响应。特别是有状态代理不可以转发任何100(Trying)响应。那些后来有可能作为“最佳”响应转发的响应已经集中在一起,如“向上下文添加响应”这一步骤所述。

任何被选择用来立即转发的响应,必须按照从“ 集合授权头字段值”步骤到“Record-Route”步骤中所描述的内容处理。

这一步骤与下一个步骤会确保有状态代理能向非INVITE请求准确转发一个最终响应,或者能向INVITE请求准确转发一个非2xx响应或者或者多个2xx响应。

6. 选择最佳响应

如果没有最终响应按照上述规则得到传送,并且该响应上下文中的所有客户端事务都已经终止,那么有状态代理必须向响应上下文的服务器事务发送一个最终响应。

有状态代理必须从那些所接收到的以及在响应上下文中存储的响应中选择“最佳”最终响应。

如果在上下文中没有最终响应,那么代理必须向服务器事务发送一个408(响应超时)响应。

否则,代理必须转发来自响应上下文中所存储的响应中的一个响应。如果6xx类响应存在于该响应上下文中,代理必须从6xx 类响应中选择。如果目前没有6xx类响应,代理应当从存储在响应上下文中的最低级响应类中选择。代理可以在所选类中任意选择响应。对于可以提供影响请求重新提交的信息的响应,代理应给予优先选择权。例如,如果选择4xx类,应首先选择的响应为401、407、415、420 和484。

一个接收503(服务不可用)响应的代理不应该将该响应上游转发,除非该代理可以确定它代理的任何后续请求也可以生成503 响应。换句话说,转发503 意味着这个代理明白它无法为任何请求提供服务,而不仅仅是不能为生成503 的请求中的Request-URI 提供服务。如果所接收到的唯一响应是503,那么这个代理应当生成一个500响应并将其上游转发。所传送的响应必须按照从“集合授权头字段值”步骤到“Record-Route”步骤中所描述内容处理。

例如,如果代理将一个请求转发到4 个位置,然后接收到503、407、501 和404这几个响应,那么它可以选择传送407(需要代理认证)响应。

在建立对话过程中可能会涉及到1xx响应和2xx响应。当请求不包含To 标记时,UAC使用响应中的To标记来区分由一个创建请求的对话的多个响应。如果请求不包含标记,代理不能向1xx和2xx的To头字段中插入一个标记。代理也不允许修改1xx或2xx响应的To头字段中的标记。

由于代理不可以向不包含标记的请求的1xx响应的To头字段插入标记,那么它自身无法发布非100临时响应。但是它可以将请求分支给一个与代理共享相同元素的UAS。这个UAS可以返回其自身临时响应,进入一个带有该请求启动程序的早期对话中。UAS不需要成为代理的谨慎处理。它可以是用与代理相同的代码空间实现的虚拟UAS。

3-6xx响应是逐跳传送的。当发布一个3-6xx响应时,元素会有效地充当UAS,通常根据从下游元素接收到的响应来发送自己的响应。当一个元素只是简单地将一个3-6xx响应转发到一个不包含To标记的请求时,该元素应当保存To标记。

代理不能对包含To标记的请求所转发的任何响应中的To标记进行修改。

如果代理替换了所转发的3-6xx响应中的To标记,对于上游元素来说没有什么不同,但保存原来的标记可以有助于调试。

当代理将几个响应的消息集合在一起时,可以任意从它们当中选择一个To标记,但是生成新的To标记可能会使调试容易一些。例如,当把401(未授权)和407(需要代理认证)结合在一起,或把从未加密的3xx响应的Contact值和未授权的3xx响应的Contact值结合在一起时,这种情况会发生。

7. 集合Authorization头字段值

如果选择的响应是401(未授权)或407(需要代理验证),那么代理必须从这个响应上下文目前接收到的所有的其它401(未授权)响应和407(需要代理认证)响应中,收集所有的WWW-Authenticate头字段值和Proxy-Authenticate头字段值,并在转发之前将它们不加修改地添加到这个响应中。产生的401(未授权)响应或407(需要代理认证)响应可能会有几个WWW-Authenticate头字段值和Proxy-Authenticate头字段值。

这是必需的,因为请求转发到的某些或者所有目的地,可能具有已请求的凭证。客户端需要解决所有的这些难题,并在它重新尝试请求时为它们中的每一个提供凭证。

8. Record-Route

如果选中的响应包含一个原先由该代理提供的Record-Route头字段值,那么该代理可在转发这个响应之前选择重写该值。这使得代理可以下一个上游元素或下游元素提供与其不同的URI。代理可以以任何理由选择使用本机制。例如,本机制对于多宿主主机来说颇为有用。

如果代理通过TLS接收到请求,并通过非TLS连接发送这个请求,那么代理必须将Record-Route头字段中的URI 重写为SIPS URI。如果代理通过非TLS连接接收到请求,但将其通过TLS发送,那么代理必须将Record-Route头字段中的URI 重写为SIP URI。由代理提供的新的URI 所满足的条件必须与对请求中Record-Route的URI的约束相同,并且要做以下修改:

该URI不应包含传输参数,除非代理知道在后续请求的路径中的下一个上游(与下游相对)元素支持此传输协议。

当代理决定修改响应中的Record-Route头字段值时,它执行的一个操作是定位它已经插入的Record-Route值。如果请求螺旋,并且这个代理在每个螺旋的迭代中插入了Record-Route值,那么在响应(它必须以逆时针方向进行适当的迭代)中定位正确的值便比较棘手。以上规则建议希望重写Record-Route头字段值的代理会将足够明显的URI插入到Record-Route头字段中,以便可以选择正确的URI来进行重写操作。达到这一目标的一个推荐的机制是,对于代理来说,要向URI的用户部分附加一个唯一的用于代理实例的标识符。

当响应到达时,代理会对标识符与代理实例相匹配的第一个Record-Route进行修改。修改的结果是,没有这部分数据的URI会附加到URI 的用户部分。进行了下一个迭代之后,相同的算法(即用参数查找顶端Record-Route 头字段值)将会正确提取那个代理插入的下一个Record-Route头字段值。

并不是请求的每个响应都包含Record-Route头字段, 代理向该请求添加了Record-Route 头字段值。如果响应含有Record-Route头字段,它将包含代理添加的值。

9. 转发响应

执行了“集合授权头字段值”步骤到“Record-Route”步骤的处理后,代理可对选中的响应执行任何特定于功能的操作。代理不能添加、修改或删除消息体。除非另指明,否则代理不能删除Via 头字段值以外的任何头字段值。特别是,代理在处理与该响应相关的请求时,不能删除任何它已经添加到下一个Via头字段值中所接收的参数。代理必须将这个响应传送到与该响应上下文相关联的服务器事务。这将导致响应被发送到目前位于最上面Via头字段值中的位置。如果服务器事务不可以再处理传输,那么该元素必须通过将响应发送到服务器传输来将其无状态转发。该服务器事务可指示发送响应失败或状态机器中信令超时。这些错误可以作为诊断使用,但是协议并不需要代理进行补救。直到所有与其相关的事务都终止为止,即使在转发最终响应之后,代理都必须对响应上下文进行维护。

10. 生成CANCEL

如果所转发的响应是一个最终响应,那么代理必须为所有与该响应上下文相关联的、待处理的客户端事务生成CANCEL请求。代理也应当在接收到一个6xx响应时为所有与该响应上下文相关联的、待处理的客户端事务生成CANCEL请求。待处理的客户端事务是这样的:

它已收到临时响应,但未收到最终响应(即该事务处于进行状态),并且尚未具有为其产生的相关的CANCEL 请求。

转发最终请求时对CANCEL 待处理客户端事务的需求不能确保端点不会收到INVITE的多个200(OK)响应。多个分支上的200(OK)响应可在CANCEL请求得到发送并处理之前生成。此外,将来的扩展有望不考虑发布CANCEL 请求的需求。

14.7.        处理计时器C

如果计时器C 应当触发,那么代理必须用任何它所选择的值来重置这个计时器,或者终止客户端事务。如果客户端事务接收到临时响应,那么代理必须生成一个与该事务相匹配的CANCEL请求。如果客户端事务未收到临时响应,那么代理的行为与事务接收到一个408(请求超时)响应相同。

允许代理可以重置计时器使得代理在计时器触发时可以根据当前情况(如利用率)对事务的生命周期进行动态扩展。

14.8.        处理传输错误

如果传输层在代理试图转发一个请求时通知它出现了错误,那么这个代理的行为与所转发请求接收到了一个503(服务不可用)响应相同。

如果传输层在代理转发响应时通知有错误产生,那么它将会停止转发这个响应。代理不应当因为这个通知而取消任何与这个响应上下文相关联的尚未处理的客户端事务。

如果代理取消了其尚未处理的客户端事务,那么单一的恶意或不正常的客户端可能会导致所有的事务因其Via头字段而失败。

14.9.        CANCEL处理

有状态代理可能会向它在任何时间生成的任何其它请求生成CANCEL。当代理接收到一个匹配的CANCEL请求时,它必须取消任何与这个响应上下文相关的尚未处理的客户端事务。

根据INVITE的Expires头字段中指定的消逝的时间段,有状态代理可以为尚未处理的INVITE客户端事务生成CANCEL请求。但是,这通常是不需要的,因为所涉及到的端点会注意对事务的端点发信号。

当CANCEL请求由其自身的服务器事务在有状态代理中处理时,新的响应上下文不会为其产生。但代理层会为处理与这个CANCEL相关的请求的服务器事务搜索其现有的响应上下文。如果找到了匹配的响应上下文,那么这个元素必须立即向CANCEL请求返回一条200(OK)响应。在这种情况下,该元素的作用如同第8.2 节中定义的用户代理服务器。此外,该元素必须为这个上下文中所有的待处理的客户端事务生成CANCEL请求。

如果没有找到响应上下文,那么这个元素没有可以请求应用CANCEL的任何信息。它必须将这个CANCEL请求无状态转发(它可能先前已经无状态转发了相关的请求)。

14.10.   无状态代理

当进行无状态操作时,代理是一个简单的消息转发装置。无状态操作的多数处理与有状态操作相同。下面详细描述了两者的不同之处。

无状态代理没有事务的任何概念,也没有用来描述有状态代理行为的响应上下文的概念。但是无状态代理会从传输层直接接收消息,包括请求和响应。结果是,无状态代理不能在其自身重传消息。但是它们却会将接收到的所有重传的消息转发(它们没有区分原始请求与重传请求的能力)。此外,当对无状态处理一条请求时,元素不能生成其自己的100(Trying)响应或任何其它临时响应。

无状态代理必须对请求进行验证。无状态代理必须遵循第14.4至第14.5节描述的请求处理步骤,以下情况除外:无状态代理必须从目标集合中选择一个唯一的目标。这个选择必须只取决于消息中的字段和服务器的时间不变量属性。特别是每次处理重传的请求时,必须将其转发到相同的目的地。而且,CANCEL和非路由ACK请求必须生成与和它们相关的INVITE相同的选择。

无状态代理必须遵循第14.6节描述的请求处理步骤,以下情况除外:

²  跨时空的对唯一分支ID的需求也可应用到无状态代理中。但是无状态代理不能简单地使用随机数生成器来计算分支ID的第一个组件(如第14.6节第8条所述)。这是因为,请求的重传需要具有相同的值,而无状态代理无法辨别原始请求和重传请求。因此,每次转发重传请求时,使其具有唯一性的分支参数的组件必须相同。所以对无状态代理而言,分支参数必须作为在重传过程中不变的消息参数的组合功能进行计算。

无状态代理可以使用任何它乐意使用的技术来保证其分支ID在事务中的唯一性。但是推荐以下步骤。代理对接收到的响应的顶端Via头字段中的分支ID进行检查。如果它以magic cookie开始,那么出站请求的分支ID的第一个组件可用接收到的分支ID的哈希来计算。否则,分支ID的第一个组件使用所接收的请求的顶端Via、To头字段中的标记、From头字段中的标记、Call-ID头字段、Cseq号(但不是方法)以及Request-URI的哈希来计算。在通过两个不同的事务时,这些字段中的一个会改变。

²  第14.6节指定的所有其它消息转化都必须使得重传请求能得到相同的转化。特别是,如果代理向Route头字段插入Record-Route值或将在Record-Route头字段中加入URI,该代理必须在重传请求中设置相同的值。至于Via分支参数,这意味着这种转变的根据必须是时间不变量配置或请求的重传不变量属性。

²  无状态代理将确定从哪里转发请求,如第14.6节第10条对有状态代理的描述。这个请求将被直接发送到传输层,而非经过客户端事务发送。

由于无状态代理必须将重传的请求转发到相同的目的地,还要向这些请求中的每一条添加相同的分支参数,所以它只能使用消息本身的信息和时间不变量配置数据来进行计算。如果配置状态不是时间不变量(例如,如果更新了一个路由表),那么变化影响到的任何请求可能在相当于变化前或变化后的事务超时窗口的时间间隔中不会被无状态传送。在这个间隔中处理受到影响的请求的方法是确定一种解决方案转发请求。一般的解决方案是将这些请求有状态地转发到事务。

无状态代理不能对CANCEL请求执行特别的处理。与许多其它请求一样,它们由上述规则处理。特别是无状态代理将相同的Route头字段的处理方法应用到了CANCEL请求中,而无状态代理也将这种方法应用到了任何其它请求中。

第14.7节描述的响应处理不会应用到具有无状态行为的代理上。当响应到达无状态代理时,该代理必须检查第一个(顶端)Via头字段值中的sent-by值。如果这个地址与代理相匹配(这个值与该代理插入到前一个请求中的值相等),那么这个代理必须从响应中将这个头字段值删除,并将结果转发到下一个Via头字段值中表示的位置。代理不能添加、修改或删除消息体。除非另行指定,否则代理不能删除任何其它头字段值。如果这个地址与代理不匹配,那么必须丢弃该消息。

14.11.   代理路由处理总结

在没有本地策略的情况下,代理对包含Route头字段的请求所执行的处理可以归纳为以下几个步骤:

1. 代理将对Request-URI进行检查。如果它表示的是一个该代理所拥有的资源,那么代理将用运行定位服务的结果来代替它。否则,代理不会对Request-URI进行更改。

2. 代理将对顶端Route头字段值中的URI进行检查。如果该URI表示这个代理,那么代理将把它从Route头字段中删除(因为已经遍历了这个路由节点)。

3. 如果没有Route头字段值,代理将把这个请求转发到顶端Route头字段值或Request-URI中的URI表示的资源。当代理对此URI应用步骤4中所描述的要求时,代理可确定要使用的地址、端口和传输协议。

如果在请求路径中没有遇到严格路由的元素,那么Request-URI将总会表示请求的目标。

15. 事务

SIP是一个事务协议:组件间的交互发生在一系列独立的消息交换中。具体来说,SIP事务由一个单一的请求和对这个请求的任何响应(包括零或多个临时响应以及一个或多个最终响应)组成。事务中的请求是INVITE(称为INVITE 事务)时,只有最终响应不是2xx响应时这个事务才包括ACK。如果最终响应是2xx,那么不应将ACK视为事务的一部分。这种区分的根源在于向UAC传递INVITE的所有200(OK)响应非常重要。为了将这些响应传递到UAC,UAS要负责重传它们,并且UAC要负责用ACK对它们进行确认。由于这个ACK只是由UAC重传的,因此可以有效地将其视为自身的事务。

事务分为客户端与服务器端。客户端称为客户端事务,服务器端称为服务器事务。客户端事务发送请求,服务器事务发送响应。客户端事务与服务器事务都是嵌入任何元素中的逻辑功能。具体来说,它们存在于用户代理和有状态代理服务器中。在这个实例中,UAC执行客户端事务,其出站代理执行服务器事务。出站代理还会执行一个客户端事务,该事务会将请求发送到入站代理的服务器事务。这个入站代理也会执行一个客户端事务,这个事务将请求发送给UAS 的服务器事务中。如图 1所示。

 

图 1事务关系

无状态代理不包含客户端事务或服务器事务。事务存在于一端的UA(或有状态代理)与另一端的UA(或有状态代理)之间。就SIP 事务而言,无状态事务是透明的。客户端事务从嵌入客户端的元素(这个元素称为“事务用户”或TU;它可以是UA,也可以是有状态代理)接收请求,并将请求可靠地传递给服务器事务。客户端事务还负责接收响应并将这些响应传递给TU,同时将任何重传响应或不允许的响应(如对ACK的响应)过滤。此外,在INVITE请求的情况下,客户端事务负责为任何接收2xx响应的最终响应生成ACK请求。

与此相似,服务器事务从传输层接收请求并将请求交付给TU。服务器事务会过滤来自网络的任何重传请求。服务器事务接受TU 的响应并将它们交付给传输层,以在网络上进行传输。在INVITE事务中,它为任何最终响应(除2xx响应之外)接收ACK请求。

2xx响应及其ACK采用特殊的处理方法。这个响应只能由UAS重传,并且其ACK 由UAC生成。这种端到端的处理方法是必要的,以便呼叫方知道接收呼叫的用户集。由于使用了这种特殊的处理方法,2xx 响应由UA核心进行重传,而不是事务层。与此相似,UA核心也会为2xx生成ACK。沿路径的每个代理仅转发INVITE的2xx响应以及相应的ACK。

15.1.        客户端事务

客户端事务通过对状态机的维护来提供其功能。

TU通过一个简单的接口与客户端事务进行通信。当TU想发起一个新事务时,这个接口会创建一个客户端事务,并把将要发送的SIP请求的目的地的IP地址、端口和传输协议传递给客户端。客户端事务开始执行其状态机。有效的响应会从客户端事务上传到TU。

就TU 传递请求的方法而言,有两种客户端事务状态机。其中一种用于处理INVITE请求客户端事务。这种机器称INVITE客户端事务。另一种用于处理除INVITE和ACK以外的所有请求的客户端事务 。这种机器称非INVITE客户端事务。ACK没有客户端事务。如果TU希望发送ACK,那么它可以直接将ACK 传送到传输层进行传输。

INVITE事务因其扩展的持续时间而与其它方法的事务不同。通常地,为了对INVITE进行响应,需要用户输入内容。发送响应所需的长时间的延时赞成一个三向握手。另一方面,其它方法的请求有望迅速完成。由于非INVITE事务依靠双向握手,TU应对非INVITE请求立即做出响应。

15.1.1. INVITE客户端事务

15.1.1.1. INVITE 事务概述

INVITE事务由一个三向握手组成。客户端事务发送INVITE,服务器事务发送响应,客户端事务还要发送一个ACK。对不可靠的传输(如UDP),客户端事务会在时间间隔T1后重传请求,每次重传后该时间翻倍。T1是对往返时间(RTT)的估计,其缺省值为500ms。这里描述的几乎所有的事务计时器都可以用T1测量,并通过更改T1来调整它们的值。可靠传输上的请求不会重传。接收到一个1xx响应后,任何重传都停止,客户端会等待进一步的响应。服务器事务会发送额外的1xx响应,这些1xx响应不会通过服务器事务进行可靠的传送。服务器事务最终会决定发送一个最终响应。对不可靠的传输来说,响应周期性地重传,而对可靠的传输来说,响应则只会发送一次。对客户端事务接收到的每一个最终响应,客户端事务都会发送一个ACK,其目的是结束响应的重传。

15.1.1.2. 正式描述

图 2显示了INVITE客户端事务的状态机。当TU用INVITE请求发起一个新的客户端事务时,事务必须进入起始状态,即“正在呼叫中”。客户端事务必须将请求传送到传输层以进行传输。如果使用了不可靠的传输,那么客户端事务必须启动值为T1的计时器A。如果使用了可靠的传输,那么客户端事务则不应启动计时器A(计时器A对请求的重传进行控制)。对于任何传输,客户端事务都必须启动具有64*T1秒值的计时器B(计时器B 对事务的超时进行控制)。

当计时器A触发时,客户端事务必须将请求重传到传输层,并且必须将计时器的值重置为2*T1。在传输层上下文中重传的正式定义是:取出先前发送给传输层的消息,再次将其发送到传输层。

当计时器A在2*T1秒后触发时,必须重传请求(假定客户端事务仍然处于这种状态)。这一过程必须继续,以便每次传输后在翻倍的时间间隔内重传请求。只有在客户端事务处于“正在呼叫中”状态时,才能完成重传。

T1的缺省值为500ms。T1是客户端事务与服务器事务间RTT的估计值。元素可以在不允许连接Internet的关闭的私有网络中使用较小的T1值(虽然不推荐)。如果事先知道(如在高延迟访问链接上)RTT较大,那么推荐将T1的值选得大一些。不管T1的值是什么,都必须使用重传的指数退避。

如果当计时器B触发时客户端事务仍处于“正在呼叫中”状态,那么客户端事务应当通知TU发生了超时。客户端事务不能生成ACK。64*T1的值与在不可靠传输下发送七个请求所需的时间总和相等。

如果客户端事务处于“正在呼叫中”状态时接收到一个临时响应,那么它将转换到“进行”状态。在“进行”状态中,客户端事务不再重传请求。而且,临时响应必须传送到TU。当客户端事务处于“进行”状态时,任何临时响应都必须上传到TU。

当处于“正在呼叫中”状态或“进行”状态时,接收到状态码为300-699的响应会导致客户端事务转换到“完成”状态。客户端事务必须将接收到的响应上传到TU,还必须生成一个ACK 请求,即使在传输是可靠的情况下也是如此(第15.1.1 节给出了从响应构造ACK的指导原则),然后将ACK 请求传送到传输层进行传输。ACK 发送到的地址、端口和传输协议必须与原始请求发送到的地址、端口和传输协议相同。客户端事务应当在进入“完成”状态时启动计时器D,对不可靠传输它的值至少应为32秒,而对可靠的传输其值应为零。计时器D反映了当使用不可靠传输时服务器事务可以停留在“完成”状态的时间总量。这与INVITE服务器事务中的计时器H(其缺省值为64*T1)相等。但是,客户端事务不知道服务器事务使用的T1值,因此要使用32s这个绝对最小值,而不是根据计时器D来设定T1值。

在“完成”状态时,接收到的最终响应的任何重传都会导致向传输层重传ACK,以进行重传,但是不能将新接收到的响应上传到TU。重传响应定义为:根据第15.1.3 节的规则与同一客户端事务相匹配的任何响应。

如果计时器D在客户端事务处于“完成”状态时触发,那么客户端事务必须转换到终止状态。

 

图 2 INVITE客户端事务

当处于“正在呼叫中”或“进行”状态时,接收2xx响应必定导致客户端事务进入“终止”状态,并且响应必须要上传到TU。对这个响应的处理取决于TU是代理核心还是UAC核心。UAC核心将为这个响应生成ACK,而代理核心则总是将200(OK)转发到上游。由于对200(OK)的处理并不是发生在事务层,因此代理与UAC会对它有不同的处理。

在客户端事务进入“终止”状态时它本身必须被销毁。实际上这对保证准确的操作是必须的。原因是对INVITE的2xx响应的处理是不同的:每个响应都是由代理转发的,并且在UAC中的ACK处理也是不同的。因此,每个2xx都需要传送到代理核心(以便可以转发)和UAC核心(以便它可以得到确认)。在事务层中没有进行处理操作。在传输接收到响应的任何时候,如果传输层(使用第15.1.3 节中的规则)没有找到匹配的客户端事务,响应将直接传送到UAC核心。由于第一个2xx已经销毁了匹配的客户端事务,后续的2xx会发现没有匹配的客户端事务,所以才会直接传送到核心。

15.1.1.3. ACK请求的构造

这一章指定了在客户端事务中发送的ACK请求的构造。为2xx生成ACK的UAC核心必须遵循第9 章描述的规则。

由客户端事务构造的ACK请求必须包含Call-ID、From 和Request-URI的值,这些值与客户端事务传送到传输层的请求(称为“原始请求”)中的那些头字段的值相等。ACK中的To头字段必须与正在被确认的响应中的To头字段相等,但由于它添加了标记参数,因此它常常与原始请求中的To头字段不同。ACK必须包含一个单一的Via头字段,它必须与原始请求的顶端Via头字段值相等。ACK中的Cseq头字段包含的序列号值必须与原先请求中的相同,但是方法参数必须与“ACK”相等。

如果其响应正在被确认的INVITE请求有Route头字段,那么这些头字段必须在ACK中出现。这是为了确保可以通过任何下游无状态代理正确地路由ACK。

虽然任何请求都可以包含一个消息体,但是ACK中的消息体比较特殊,因为如果没有理解消息体就无法拒绝请求。因此,不推荐在非2xx的ACK中放置消息体,但是如果已经放置了消息体,假定INVITE的响应不是415,那么消息体类型要限制在任何在INVITE中出现的类型。如果INVITE的响应是415,那么ACK中的消息体可以是415中Accept头字段中列出的任何类型。

例如,请考虑以下请求:

INVITE sip:bob@biloxi.com SIP/2.0

Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff

To: Bob <sip:bob@biloxi.com>

From: Alice <sip:alice@atlanta.com>;tag=88sja8x

Max-Forwards: 70

Call-ID: 987asjd97y7atg

CSeq: 986759 INVITE

该请求的非2xx 最终响应的ACK 请求如下所示:

ACK sip:bob@biloxi.com SIP/2.0

Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff

To: Bob <sip:bob@biloxi.com>;tag=99sa0xk

From: Alice <sip:alice@atlanta.com>;tag=88sja8x

Max-Forwards: 70

Call-ID: 987asjd97y7atg

CSeq: 986759 ACK

15.1.2. INVITE 客户端事务

15.1.2.1. INVITE事务概述

非INVITE事务不使用ACK。它们是简单的请求--响应交互。对于不可靠的传输来说,请求在一个时间间隔(时间间隔起始值为T1,在到T2前该时间间隔每次翻倍)内进行重传。如果接收到一个临时响应,那么对不可靠传输而言,将继续重传(但时间间隔在T2内)。服务器事务只有在接收到重传请求时,才会重传它发送的最后一个响应,这个响应可以是临时响应,也可以是最终响应。这就是即使在临时响应之后,仍需继续重传请求的原因:它们是为了确保可靠的传输最终响应。

与INVITE事务不同,非INVITE事务对2xx响应并不做特殊的处理。结果是,只向UAC传送了非INVITE的一个2xx响应。

15.1.2.2. 正式描述

 

图 3 非INVITE客户端事务

图 3显示了非INVITE客户端事务的状态机。它与INVITE状态机非常相似。

当TU用请求发起新的客户端事务时,事务会进入“尝试”状态。进入这个状态时,客户端事务应当将计时器F设置为在64*T1秒内触发。这个请求必须传送到传输层进行传输。如果使用的是不可靠的传输,那么客户端事务必须将计时器E设置为在T1秒之内触发。如果计时器E在客户端事务仍处于尝试状态就触发,那么计时器将会被重置,但是这次重置的值为MIN(2*T1,T2)。当计时器再一次触发时,它会被重置为MIN(4*T1,T2)。这一过程将会继续,以便在一个以指数递增的时间间隔(最大值为T2)内发生重传。T2的缺省值为4秒,如果服务器事务未立即响应的话,T2代表非INVITE服务器事务将对请求发出响应所用的时间总和。对于T1和T2的缺省值来说,这将会产生500ms、1s、2s、4s、4s、4s的时间间隔。

如果计时器F在客户端事务仍处于“尝试”状态时触发,那么客户端事务应当向TU报告超时,然后应进入“终止”状态。如果在“尝试”状态下接收到了一个临时响应,那么这个响应必须传送到TU,然后客户端事务应转换到“进行”状态。如果在“尝试”状态接收到一个最终响应(状态码为200-699),那么这个响应必须要传送到TU,客户端事务则必须转换到“完成”状态。

如果计时器E在客户端事务处于“进行”状态时触发,那么请求必须传送到传输层进行重传,计时器E的值也必须重置为T2秒。如果计时器F在“进行”状态时触发, TU必须得到超时通知,并且客户端事务必须转换到终止状态。如果在“进行”状态时接收到一个最终响应(状态码为200-699),那么这个响应必须要传送到TU,而客户端事务则必须转换到“完成”状态。

一旦客户端事务进入“完成”状态,对不可靠传输,它必须将计时器K设置在T4秒之内触发;对可靠传输,计时器应设置为零。“完成”状态的存在是为了对可能接收到的任何额外重传响应起到缓冲作用(这也是客户端事务只对于不可靠的传输才保留的原因)。T4 表示网络清除客户端事务和服务器事务间消息所需的时间总和。T4的缺省值为5s。当响应使用第15.1.3 节中指定的规则与同一事务匹配时,它便是重传响应。如果计时器K在这个状态触发,那么客户端事务则必须转换到“终止”状态。

一旦事务处于终止状态,必须立即销毁它。

15.1.3. 将响应与客户端事务匹配

当客户端的传输层接收到响应时,它必须确定哪一个客户端事务来处理这个响应,以进行第15.1.1节和第15.1.2节所描述的处理。为此,需要使用顶端Via头字段中的分支参数。在两种情况下响应会与客户端事务匹配:

1. 响应在顶端Via头字段中的分支参数值与创建事务的请求的顶端Via头字段的分支参数值相同;

2. Cseq头字段中的方法参数与创建事务的请求的方法匹配。由于CANCEL请求组成了共享分支参数值的不同事务,因此需要这个方法。

如果请求通过多播发送,那么它可能会从不同的服务器生成多个响应。这些响应在顶部Via中有相同的分支参数值,但在To标记中它们的分支参数值却不同。接收到的第一个响应将会使用上面的规则,而其它响应将视为重传响应。这并非出现了错误;多播SIP只提供根本的“single-hop-discovery-like”服务,这个服务只限于处理单一的响应。

15.1.4. 处理传输错误

当客户端事务向传输层发送请求时,如果传输层发生错误,可以遵循以下步骤。

客户端事务应当通知TU发生了传输错误,并直接转换到“终止”状态。TU将处理错误转移机制。

15.2.        服务器事务

服务器事务负责将请求传递到TU以及对响应进行可靠的传输。它通过状态机来完成这些任务。当收到请求时,并且请求需要事务处理时(实际情况并非总是如此),核心创建服务器事务。

与客户端事务相同,服务器事务的状态机取决于接收到的请求是否是INVITE 请求。

15.2.1. INVITE 服务器事务

图 4是INVITE 服务器事务的状态图。

 

图 4 INVITE服务器事务

当为请求构造服务器事务时,服务器事务便进入了“进行”状态。服务器事务必须生成一个100(Trying)响应,除非它知道TU将在200ms内生成一个临时或最终响应,在这种情况下,它可能会生成一个100(Trying)响应。为了避免网络拥塞,需要临时响应迅速结束重传请求。除了把在响应的To头字段中插入标记(当请求的To 头字段中没有标记时)这一点从MAY降为SHOULD NOT以外,100(Trying)响应是根据第5.2.6节的步骤构造的。这个请求必须传送到TU。

TU将任何数量的临时响应传送到服务器事务。只要服务器事务处于“进行”状态,所有这些响应都要传送到传输层进行传输。这些响应不是由事务层可靠发送的(它们不是由事务层重传的),因此不会导致服务器事务的状态改变。如果在“进行”状态中收到了重传请求,那么TU 接收到的最新的临时响应必须要传送到传输层以进行重传。如果一个请求根据第15.2.3 节的规则与同一服务器事务相匹配,那么这个请求便是重传请求。

当处于“进行”状态时,如果TU将一个2xx响应传送到服务器事务,那么服务器事务必须将这个响应传送到传输层进行传输。2xx响应不是由服务器事务重传的,而是由TU重传的。然后服务器事务必须转换到“终止”状态。

当处于“进行”状态时,如果TU向服务器事务传送一个状态码为300-699的响应,那么这个响应必须要传送到传输层以进行传输,并且状态机必须进入“完成”状态。对于不可靠的传输来说,要将计时器G设置为在T1秒内触发,而对于可靠的传输则无需设置触发时间。

在RFC 2543中,即使对于可靠的传输,响应也总是要重传的。本规范在这一点上对RFC 2543进行了改动。

当进入“完成”状态时,对所有的传输,计时器H必须设置为在64*T1秒触发。计时器H确定服务器事务何时不再重传响应。它的值应与计时器B相同,等于客户端事务继续重发请求的时间总和。如果计时器G触发,那么响应便会再次发送到传输层进行重传,计时器G设置为在MIN(2*T1,T2)秒内触发。从这个时间开始,当计时器G触发时,响应便会再次传送到传输层进行传输,而计时器G的值将会重置为先前的两倍,直到值超过T2,此时,应将计时器G的值重置为T2。这与非INVITE客户端事务处于“尝试”状态时对请求进行重传的行为如出一辙。此外,当处于“完成”状态时,如果接收到重传请求,那么服务器应当将响应传送到传输层进行重传。

如果服务器事务在“完成”状态时接收到ACK,那么它必须转换到“确认”状态。由于在这个状态可以忽略计时器G,因此,所有的响应都将停止重传。

如果在“完成”状态中计时器H触发,这表明服务器事务从未接收到ACK。在这种情况下,服务器事务必须转换到“终止”状态,并且必须向TU 指明发生了事务错误。

“确认”状态是为了接收任何到达的附加的ACK消息,该消息是由重传的最终响应触发的。当进入这种状态时,对于不可靠传输计时器I设置为在T4秒内触发;而对于可靠传输则设置为零。计时器I一旦触发,服务器必须转换到“终止”状态。

一旦事务处于“终止”状态,必须要立即销毁它。与客户端事务相似,这是为了确保INVITE的2xx响应的可靠性。

15.2.2. INVITE 服务器事务

图 5给出了非INVITE 服务器事务的状态机。

 

图 5 非INVITE服务器事务

这个状态机在“尝试”状态时初始化,初始化时会向状态机发送一个除INVITE或ACK之外的请求。这个请求将上传到TU。一旦处于“尝试”状态,任何进一步的重传请求都会被丢弃。如果请求使用第15.2.3节中的规则与同一服务器事务相匹配,那么这个请求便是重传请求。当处于“尝试”状态时,如果TU将一个临时响应传送到了服务器事务,那么服务器事务必须进入“进行”状态。这个响应必须要传送到传输层传输。在“进行”状态时从TU接收到的任何进一步的临时响应都必须传送到传输层进行传输。假若在“进行”状态接收到重传请求,那么最新发送的临时响应必须传送到传输层重传。如果在“进行”状态中TU将最终响应(状态码为200-699)传送到服务器,那么事务必须进入“完成”状态,这个响应则必须传送到传输层进行传输。

当服务器事务进入“完成”状态时,对不可靠传输,它必须将计时器J设置为在64*T1秒内触发;对可靠传输,设置为零秒触发。当处于“完成”状态时,在接收到重传响应的任何时候,服务器事务都必须将最终响应传送到传输层重传。在“完成”状态时,任何由TU传送到服务器事务的其它最终响应都必须被丢弃。服务器事务将保持这种状态,直到计时器J触发,这时服务器事务必须转换到“终止”状态。

当服务器事务进入“终止”状态时,必须要销毁它。

15.2.3. 将请求与服务器事务匹配

当服务器从网络接收到请求时,该请求必须与现有的事务相匹配。匹配按以下方式进行:首先要检查请求顶端Via头字段中的分支参数。如果有分支参数,并且以magic cookie “z9Hg4BK”开头,那么这个请求便是由符合本规范的客户端事务生成的。因此,客户端发送的所有事务中的各个分支参数都应当不同。如果满足以下条件,则请求与事务相匹配:

1. 请求中的分支参数与创建事务的请求的顶端Via头字段中的分支参数相等;

2. 请求的顶端Via头字段中的sent-by值与创建事务的请求的顶端Via头字段中的sent-by值相等;

3. 请求的方法与创建事务的方法相同(除ACK以外,它的创建事务的请求方法为INVITE)。

以上匹配规则适用于INVITE事务和非INVITE事务。

Sent-by值是作为匹配过程的一部分使用的,因为不同客户端可能会对分支参数进行意外或恶意的复制。

如果顶端Via 字段中没有分支参数,或者分支参数不包含magic cookie,那么可以使用以下步骤。这些步骤用来处理与遵从RFC 2543规范的实现的向后兼容问题。

如果一个INVITE请求的Request-URI、To标记、From标记、Call-ID、Cseq以及顶端Via头字段与创建事务的INVITE请求的对应内容相匹配,那么它与这个事务是匹配的。在这种情况下,INVITE是创建这个事务的原始请求的重传请求。如果ACK请求的Request-URI、From标记、Call-ID、Cseq 号(不是方法)以及顶端Via头字段与创建事务的INVITE请求的对应内容相匹配,并且这个ACK的To标记与服务器事务发送的响应的To标记相匹配,那么这个ACK请求就与这个事务相匹配。匹配是根据为每个头字段定义的匹配规则进行的。在ACK匹配过程中在To头字段中包括一个标记有助于区分2xx的ACK与代理上其它响应的ACK,代理有可能将两种响应一起转发(在异常情况下,这是有可能发生的。具体说来,当代理分发一个请求,然后崩溃,响应可能会传递到另一个代理,这个代理可能会终止向上游转发多个响应)。可以认为,如果一个ACK请求与和前一个ACK匹配的INVITE事务相匹配,那么它是先前ACK请求的重传。

对于所有其它请求方法而言,如果一个请求的Request-URI、To标记、From标记、Call-ID、Cseq(包括方法)以及顶端Via头字段与创建事务的请求的对应内容相匹配的话,那么该请求便与这个事务相匹配。匹配是根据为每个头字段定义的匹配规则进行的。当一个非INVITE请求与一个现有的事务相匹配时,它是创建这个事务的请求的重传。

由于匹配规则包括Request-URI,因此服务器无法将响应与事务相匹配。当TU将一个响应传送到服务器事务时,它必须将其传递到这个响应指向的特定的服务器事务。

15.2.4. 处理传输错误

在服务器端的事务实例将相应的响应发到传输层后,在传输层传输失败的情况下,可进行如下处理:

首先,可以选择将响应发往另一个作为备份的实体。

如果上述尝试都传输失败,事务层应该将失败通知给TU,并将相应的事务实例的状态迁移为“终止”。

16. 传输

传输层负责通过网络传送请求和响应,传输分为面向连接传输和非面向连接传输,当传输为面向连接时,还要确定请求或者响应可用的连接。

传输层可以管理永久连接,这些连接使用的传输协议有TCP和SCTP,或者基于TCP和SCTP的TLS,包括那些开放的传输层的协议,这些连接还包括客户机或者服务器传输层的开放连接,客户机和服务器传输层可共同使用该连接,可以通过该连接的远端地址、端口、传输协议所组成的三元组来检索该连接,如果一个连接开放,该索引设成目的地IP地址、端口和传输协议的三元组。如果一个连接被传输层所接受,该索引设成源IP地址、端口和传输协议的三元组。由于源端口通常是暂时的,所以传输层所接受的连接一般不会重新使用。所以通常两个对等代理服务器在使用面向连接传输协议时,会用不用两个连接,用于各自方向发起的事务。

本标准建议,在最后一个消息通过之后,该连接仍需要开放一段时间。该时间段至少等于实体将一个事务从实例进行到终止状态所用时间的最大值。这样,事务可以在其发起的连接完成(例如请求、响应、INVITE、用于非2xx响应的ACK)。该时间段的值至少为64*T1。然而如果一个实体使用一个更大的定时器C,这个持续时间将更长。

所有的SIP实体都必须能实现UDP和TCP。SIP实体也可以使用其他的协议。

16.1.        客户端

16.1.1. 发送请求

传输层的客户端负责发送请求并接受响应。传输层的用户将请求、IP地址、端口、传输协议以及组播目的地的TTL传递到客户机传输层。

如果一个请求在小于200字节或者大于1300字节的路径MTU中,而该MTU值未知,那么该请求必须使用RFC 2914中规定的拥塞控制协议,例如TCP协议。如果这与顶端Via中所指定的传输协议不同,那么顶端Via的值需要修改。这有效的防止了使用UDP会造成的消息碎片,并且为大块的消息提供了拥塞控制。对于UDP来说能够处理最大数据包就是65535字节并包括IP和UDP字头。

消息尺寸和MTU之间的200字节的“缓冲区”适应了SIP中响应消息一般比请求大的情况。例如,可以在INVITE响应中附加Record-Route头字段值。有了这个额外的缓冲区,响应可以比请求大170字节,而在IPV4中不必被分块(假设没有IPSec时,IP/UDP消耗大约30字节)。当路径MTU未知时,基于以太网的MTU是1500字节来将MTU设为1300字节。

如果一个实体由于消息大小的缘故才需要通过TCP发送某请求,否则该请求可以通过UDP传输,如果建立连接时引起下面两种情况:ICMP协议不支持,和重新建立TCP连接,此时该实体就应该使用UDP重新发送请求。

向组播地址发送请求的客户机必须在Via头字段值中附加“maddr”参数指明目的地组播地址,对于IPv4来说应该增加一个值为1的“ttl”参数。IPv6的组播的内容不在本部分范围之内。这个规定对SIP组播产生了限制。它的基本功能是“单跳发现(single-hop-discovery-like)”业务,也就是向一组同类的服务器发送请求,但是只需要其中一个服务器处理该请求即可。注册时可以使用该功能。客户机事务层应该接收第一个请求,其余的因为包含同样的Via分支标识符而被视为重发。

发送请求之前,客户端事务层必须在Via头字段中插入一个“sent-by”字段。该字段包括一个IP地址或者是主机名和端口。本部分建议使用FQDN(全资格域名)方式。该字段用于以下情况下发送请求。如果没有规定端口,根据传输协议不同而取不同的端口缺少值,UDP取5060而TCP和SCTP取5061.

在进行可先传输时,应在收到请求的连接上发送响应。因此,客户端传输层必须做准备在同一个连接上接收响应。发生错误时,服务器可以建立一个新连接发送响应。在这种情况下,传输层也必须在源IP地址上引入一个连接,从源IP地址和“sent-by”字段中所指的端口发送请求。它还必须准备在服务器端选择的地址和端口上引入一个连接。

在不可靠单播传输时,客户端传输层必须准备在源IP地址上接收响应,源IP地址就是发送请求的地址,端口号为“sent-by”字段中的值。另外,与可先传输一样,某些特定情况下,响应也将被传输到其他地方。

在组播的情况下,客户端传输层必须作为发送请求的组播群中的一员在与发送请求相同的组播群和端口上接收响应。

如果一个原有的连接对于某请求的目的IP地址、端口和传输协议开放,则本部分建议这个连接用于发送请求而另外一个连接也可以开放并使用。

如果某请求使用组播发送,它就会被送往一组用户所提供的地址、端口和TTL。如果某请求使用不可靠单播传输方式发送,它应付被送往传输用户所提供的IP地址和端口。

16.1.2. 接收响应

客户机传输层收到响应后需要检查顶端Via的值。如果“sent-by”参数中的值与客户端传输层插入到请求中的值不一样,该响应就必须被丢弃。

如果存在一些客户端事务,客户机传输层将在原有的事务中查找与该响应所匹配的事务。如果找到匹配事务,就必须将该响应判定以对应的事务中处理。反之该响应就必须被送到内核服务器做进一步处理,根据内核服务器的不同,对这些响应有不同的处理。

16.2.        服务器

16.2.1. 接收请求

服务器可以通过DNS来搜索对方服务器,搜索结果以SIP或者SIPS URI形式给出,服务器应该通过搜索结果中的任何IP地址、端口和传输协议来接收请求。另外,必须将一个URI放到REGISTER请求或者重定向响应中的Contact字段,或者放在请求或者响应中的Record-Route头字段中,URI也可以用放到网页或者名片上的形式给出。本部分建议,服务器在公共接口上接受请求是应用不用默认的端口值(TCP和UDP是5060,而TCP上的TLS是5061),私有网络或者同一个主机上运行多个服务器的情况除外。因为如果消息太大则必须使用TCP而不能用UDP传输,所以任何使用UDP端口和接口的服务器必须能够在TCP上使用同样的端口和接口。反之,服务器不必因为使用了TCP的一个特定端口和接口就要求在UDP情况下使用同一特定端口和接口。服务器传输层通过任何传输协议收到请求后,必须检查Via头字段顶端的“sent-by”参数的值。如果“sent-by”参数的主机位置包含一个域名或者包含一个不同于数据包源地址的IP地址,服务器必须在Via头字段中添加一个“received”参数。该参数必须包括所收数据包的源地址,这样,服务器传输层就可以将响应发送到发出请求的源IP地址。

然后,服务器传输层将在服务器端事务中寻找与请求相匹配的事务。如果找到了对应的服务器事务,就将请求送到这个事务来处理;如果没有找到相匹配的事务,就将请求送到内核服务器,并建立一个新的服务器端事务来处理它。如果UAS内核服务器对INVITE请求发出2xx服务器事务即终结,这就意味着如果ACK到达,将没有相匹配的服务器事务。基于上述原则,ACK就被送往UAS内核进行处理。

16.2.2. 发送响应

服务器传输层使用Via字段的顶端值来决定将响应发送目的。具体过程如下:

²  如果“sent-protocol”为可靠的传输协议,如TCP或者SCTP,或者基于TCP或SCTP的TLS且现有的连接仍然可用,则必须使用该连接传输响应到建立该事务的初始请求的源地址。这就要求服务器传输层保持服务器端事务和传输连接的关联。如果该连接不可用,服务器应与“received”参数中的IP地址之间开放一个新连接,并使用“sent-by”中的端口值,如果没有指定端口就使用该传输协议的缺省端口值。如果该连接失败,服务器应该根据RFC 3263中的程序确定所要开放的连接的IP地址和端口并向其发送响应消息。

²  否则,如果Via字段包含“maddr”参数,就必须将响应转发到参数中所列的地址,所用端口为“sent-by”中的指定端口值,如果没有指定,端口值为5060.如果地址为组播地址,就应该使用“ttl”参数中指标TTL值来发送响应,如果该参数不存在,TTL的值为1.

²  不可靠的单播传输的情况下,如果Via含有“received”参数,则响应就被送往“received”中指定的地址,所用端口为“sent-by”中指定端口值,如果没有指定,端口值就为5060。如果传输失败,例如得到ICMP“端口不可达”响应,就应该使用RFC 3263中的Section 5的程序来确定响应发送的目的。

²  否则,如果没有接收者标签,就应该将响应送到“sent-by”中指定的地址

16.3.        数据帧

面向消息传输的情况下(例如UDP),如果消息包含Content-Length头字段,则消息体则应为该字段所指示的长度。越长的数据包必须被丢弃。如果传输的数据包在消息体结束之前结束,则产生错误。如果消息是一个响应,则它必须被丢弃。如果消息为一个请求,实体就应该产生一个400(Bad Request)响应。如果该消息没有Content-Length头字段,那么消息体长度就认为是所传输的数据包的长度。

面向流传输的情况下(例如TCP),Content-Length头字段指示消息体的大小,面向流传输的情况下必须使用Content-Length头字段。

16.4.        错误处理

如果传输的用户通过不可靠传输协议传输消息,并产生ICMP错误,则按照ICMP错误的类型确定处理方法。如果为主机、网络、端口或者协议不可用的错误或者参数错误,应由传输层通知用户。源终止和TTL超时的ICMP错误都将忽略。

如果传输的用户要求通过可靠传输协议传输消息且连接失败,那么传输层应该通知用户。

17. 普通的消息成分

17.1.        SIPSIPS URI

SIP和SIPS URI用于指示一个通信资源。像所有的URI一样,SIP或SIPS URI也可以用于网页、电子邮件消息和出版物。其中包含了与该通信资源建立并维持会话所需要的信息。

通信资源的例子如下:

在线业务的用户

多方电话的情况

消息系统的语音信箱

网关业务的PSTN号码

某组织里的一个组(例如“销售组”或者“技术支持”)

SIPS URI所指示的为安全的资源,即UAC与该URI所属的域之间使用TLS传输。该资源与某个用户间通信是安全的,且所使用安全机制由该域的本地策略所决定。如果希望得到安全的通信,任何由SIP URI所指标的资源在改变其URI方案之后可以升级至SIPS URI。

17.1.1. SIP URI的构成

“SIP:”和“SIPS”的方案参见RFC 2396。格式类似于邮件URL,分别规定SIP头字段和SIP消息体。这就可以在网页上或者电子邮件消息里使用URI规定会话的主题、媒体类型和紧急程度等。SIP URI通用格式为:

sip:user:password@host:port;uri-parameters?headers

SIPS URI的格式也是一样的,但方案是SIPS而不是SIP。

以上符号定义如下:

User:指定被寻址的主机资源的标识符。“host”通常用来指示一个域。URI中“userinfo”由user和password以及@符号组成,如果目的主机没有用户或者主机本身就是被指定的资源,则userinfo部分为可选。如果有@符号,那么user字段就不可为空,如果被寻址的主机可以处理电话号码,例如,IP电话网关,其telephone-subscriber字段就可以用来作为user字段,SIP URI中telephone-subscriber的编码方式参见本规范

Password:password与user相关,SIP和SIPS URI的语法中允许该字段存在。但是不建议使用该字段。因为鉴权信息以明码文本的形式通过,所以几乎所有的情况下都不安全。Password只是user部分的延伸,本规范不对其特殊的定义,可以把“user:password”部分看作一个字符串。

Host:指定SIP资源。Host部分包含一个FQDN或者是一个数值表示的IPv4或者IPv6地址。建议该字段使用FQDN方式。

Port:指定请求要被发送的端口。

URI parameter:包括transport,maddr,ttl,user,method以及lr参数。这些参数用于以URI构建一个请求,它们附加在hostport之后,以分号隔开,其格式为:

Parameter-name=parameter-value

虽然一个URI可以有若干个参数,但是一个参数名最多只能出现一次。

Transport:用来确定发送SIP的传送机制,见RFC 3263的规定。SIP可以任何网络传送协议。各种协议的参数名的定义参数UDP、TCP和SCTP的相关规范。

Maddr:用于指定用户所要联系的服务器地址,它优先于host字段的地址。Maddr存在时,URI中的port和transport字段都用于maddr所指定的地址。为了发送请求,需要获得目的地址的地址、端口以及传输协议。Maddr字段是松散源路由的一个简单的形式。它允许URI指定一个到达目的地时必须通过的代理服务器。本规范不建议在该路径上继续使用maddr参数,而是应该使用文件中讲的另一种路由机制来预先建立一个路径组,它含有一个描述所要通过的节点的完整URI。

Ttl:UDP组播数据包的生存时间值,只能用于maddr为组播地址并且传送协议是UDP的情况下,例如:确定对于alice@altanta.com的呼叫,使用ttl值为15,组播地址为239.255.255.1,URI形式如下:

sip:alice@altanta.com;maddr=239.255.255.1;ttl=15

这组有效的telephone-subscriber字符串是有效的user字符串的一个子集。URI中的user参数用来区分那些电话号码和user名不同的URI。如果user字符串包含一个格式为telphone-subscriber的电话号码,则应该存在“phone”这个值。即使没有这个参数,如果本地用户名的规定允许,SIP URI也可以把@之前的部分看做一个电话号码。

Mehtod:规定由URI构建SIP请求的方法,由方法参数指定。

Lr:该参数存在的情况下,用来指示负责该资源的实体实施路由机制。该参数可以存在于URI代理服务器中的Record-Route头字段,也可以存在于预先建立的路由组URI中。一个基于URI发送的请求如果没有lr参数,由接收实体就被认为执行的严格路由机制并重定消息格式来保存Request-URI中原有信息。既然URI参数机制是可扩展的,SIP实体就必须忽略其不理解的URI参数。

Headers:该字段位于由URI构建的请求消息中。SIP请求的的Headers字段可以在URI中用“?”来指定。Header的名字和值是由&分开的hname=hvalue对,当hname为“body”时表明相关的hvalue是SIP请求的消息体。

表 1 SIP URI中各成分的使用及其缺省值

 

default

Req.-URI

To

From

Contact

R-R/Route

external

User

--

o

o

o

o

o

o

Password

--

o

o

o

o

o

o

Host

--

m

m

m

m

m

m

Port

(1)

o

-

-

o

o

o

User-param

ip

o

o

o

o

o

o

Method

INVITE

-

-

-

-

-

o

Maddr-param

--

o

-

-

o

o

o

Ttl-param

--

o

-

-

-

o

o

Transp.-param

UDP

o

-

-

o

o

o

Lr-param

--

o

-

-

-

o

o

Other-param

--

o

o

o

o

o

o

headers

--

-

-

-

o

-

o

(1):缺省的port值与传送协议有关。Sip:使用UDP、TCP、或者SCTP时为5060。Sip:使用基于TCP的TLS是5061。

表1总结了在URI出现在不同的上下文中时SIP和SIPS URI各个组成部分的用法。External这一列讲述了URI位于SIP消息体之外的情况,例如网页上或者商业名片上。标注“m”表示强制使用,标注“o”表示可选,标注“-”表示禁止。如果URI有禁止项存在,SIP实体处理到它的时候应该忽略这些项。第二列指出如果一个可选项没有出现时的缺省值。“--”指出这项或者不可选或者没有缺省值。

Contanct头字段中的URI根据字段出现的上下文的不同而有不同的限制。一组适用于建立和维持对话的消息(INVITE和200响应),另外一组适应于注册和重定向消息(REGISTER,对它的200(OK)响应以及对于任何方法的3xx响应)。

17.1.2. 字符转义的要求

在SIP URI中,定义一组需要转义的字符时,就要遵循RFC 2396中的要求使用““%”HEX HEX”机制进行转义。RFC 2396规定:任何给定的URI组成部分中所保留的字符集实际是由该组成部分所定义的。一般情况下,如果一个URI的字符使用转义的US-ASCⅡ码所代替后语言被改变,这个字符就应该保留。US-ASCⅡ字符之外的字符,例如空格、控制符还有URI中的分隔符都必须被转义。URI不可以包含未转义的空格和控制符。

对于每个部分来说,有效的BNF的扩展定义了可以不用转义的字符。除此以外的字符都要被转义。例如“@”不是user成分的字符,因此user为j@s0n时,至少@符需要编码为“j%40s0n”。扩展的hname和hvalue符号表明所示的URI头字段名和值中保留的字符必须被转义。

User部分的telephone-subscirber子集的转义有特殊的要求。如RFC 2806所述,telephone-subscriber未保留的字符集中包含许多不同的语法形式的字符,当使用SIP URI时,这些字符需要被转义,任何telephone-subscriber中出现的字符如果没有出现在BNF的扩展定义中则必须被转义。

SIP和SIPS URI中的host部分不允许字符转义(%字符在扩展中无效)。将来国际化域定案之后这个规定可能会发生改变,现在的具体实现中,不可以通过将所收到的host中的转义字符理解为未转义的字面的意思来提高鲁棒性。但是如果要求满足IDN的要求的话,将来的情况可能完全不同。

17.1.3. SIP URI举例

sip:alice@atlanta.com

sip:alice:secretword@atlanta.com;transport=tcp

sips:alice@atlanta.com?subject=project%20x&priority=urgent

sip:+1-212-555-1212:1234@gateway.com;user=phone

sips:1212@gateway.com

sip:alice@192.0.2.4

sip:atlanta.com;method=REGISTER?to=alice%40atlanta.com

sip:alice;day=tuesday@atlanta.com

最后一个例子的user字段值为“alice;day=tuesday”。转义规则允许该字段中分号保留未转义。本协议的目的就是要求该字段不透明,所以这个值如何构成也仅仅在负责该资源的SIP实体中有意义。

17.1.4. URI比较

本规范中定义的某些操作需要确定两个SIP或SIPS URI是否等价。本规范规定,注册服务器需要比较REGISTER请求的Contact URI中的绑定。根据以下规则判定SIP和SIPS URI是否等价:

²  SIP和SIPS URI不相等

²  比较SIP和SIPS URI的userinfo(含密码的userinfo或者telephone-subscriber格式)时需要区分大小写,除非特殊要求,比较URI的其余成分都不区分大小写。

²  比较SIP和SIPS URI时,参数和头字段的顺序与等价性无关。

²  除了“保留”组(参见RFC 2396)以外,所有的字符都等价于它们对应的““%”HEX HEX”编码。

²  DNS搜索主机名得到的IP地址与该主机名不一致。

²  两个URI等价,要求用户、密码、主机、端口都必须一致。

省略用户部分的URI与包含用户部分的URI不致。省略密码的URI与包含密码的URI也不致

省略任何含有缺少值部分的URI与包含该部分并且指定值等于缺少值的URI不致。例如,省略掉可选端口的URI与指定端口为5060的URI不一致,transport-parameter,ttl-parameter,user-parameter,以及Method都是同样的道理。(规定sip:user@hostsip:user@host:5060不等价与RFC 2543规定完全不同。)从相同的URI中选到的地址等价。sip:user@host:5060端口总是5060sip:user@host可以通过[4]的DNS SRV机制解析为另外的端口。

URI的参数比较规则如下:

两个URI中出现的参数必须一致。

user、ttl、或method参数只在其中一个URI中出现,即使包含有缺少省,也一定不能与另外的URI一致。

包含maddr参数的URI与不包含maddr的URI不一致

其余的参数如果只在其中一个URI中出现时,比较的时候忽略不计。

URI的header成功 定不能忽略。两个一致的URI中必须同时包含成分一致header。

17.1.5. URI构成请求

直接由URI构成时,商业名片、网页以致协议内部资源(如已注册的地址)的URI的头字段或者消息体可能包含一些不合适部分。

构成请求中的必须包括Request-URI中的transport,maddr,ttl,user参数。如果URI包含一个method参数,它的值必须作为请求的方法。Request-URI中不可以有method参数。未知的URI参数必须放在消息的Request-URI中。

出现在URI中的头字段或者消息体都应当包含在消息里,基于请求中的每个组成部分明显标记该请求。

具体实现中,不应明显标记那些容易受到威胁的头字段From,Call-ID,CSeq,Via和Record-Route。

具体实现中,为了在恶意攻击的情况下不被作为不知情的代理利用,不可以明显标记那些请求的Route字段的值。

有些头字段可能会引起位置或能力的错误判断,所以不应该明显标记它们。包括Accept,Accept-Encoding,Accept-Language,Allow,Contact,Organization,Supported,User-Agent。

具体实现中,应当校验描述性头字段的准确性,包括:Content-Disposition,Content-Encoding,Content-Language,Content-Length,Content-Type,Date,Mime-Version和Timestamp。

如果从给定的URI构建的请求不是有效的SIP请求,那么该URI也是无效的,该请求不应被传输,并应寻找出现再次URI的原因。构建请求无效的原因有很多,包括头字段语法错误,URI参数组合无效,消息体描述错误等。

发送一个由给定的URI构成的请求中所要求的能力可能难以达到。例如URI可能指定一种不可实现的传送协议或者扩展。这种情况下应该拒绝发送这个请求而不是修改它来适应它的能力。不可以发送需要某个它不支持的扩展协议的请求。

例如,这种请求可以通过现有的Require头参数来构造,也可以通过或方法URI参数来构造,该参数带有未知的值或明确不支持的值。

17.1.6. SIP URItel URL的关联

如果一个tel URL要被转换成SIP URI时,tel URL中的整个telephone-subscriber部分和一些参数都被放在SIP URI中的userinfo中。例如:

tel:+358-555-1234567; postd=pp22变成

sip:+358-555-1234567;postd=pp22@foo.com;user=phone

而不是sip: +358-555-1234567 @foo.com;postd=pp22;user=phone

通常,以这种方式,等价的“tel”URL转变成的SIP或SIPS URI可能不等价,SIP URI中的userinfo比较的时候区分大小写,tel URL中的大小写不区分的部分和tel URL参数重新排序虽然不影响tel URL的等价性,但是转变成SIP或SIPS URI就不等价了,例如:

tel:+358-555-1234567;postd=pp22

tel:+358-555-1234567;POSTD=PP22

是等价的,而

sip:+358-555-1234567;postd=pp22@foo.com;user=phone

sip:+358-555-1234567;POSTD=PP22@foo.com;user=phone

却不等价。

同样,

tel:+358-555-1234567;postd=pp22;isub=1411

tel:+358-555-1234567;isub=1411;postd=pp22

是等价的,而

sip:+358-555-1234567;postd=pp22;isub=1411@foo.com;user=phone

sip:+358-555-1234567;isub=1411;postd=pp22@foo.com;user=phone

不等价

为减轻这个问题,将放到userinfo部分的telephone-subscriber中的大小写不区分的部分统一改为小写(tel URL所有的成分除将来扩展的参数以外都是大小写不区分的),telephone-subscriber参数按照名字排序(isdn-subaddress和post-dial这种参数除外,它们总是排在前面)。根据上面的规定

tel:+358-555-1234567;postd=pp22 和

tel:+358-555-1234567;POSTD=PP22

都将成为

sip:+358-555-1234567;postd=pp22@foo.com;user=phone

tel:+358-555-1234567;tsp=a.b;phone-context=5 和

tel:+358-555-1234567;phone-context=5;tsp=a.b

都将成为

sip:+358-555-1234567;phone-context=5;tsp=a.b@foo.com;user=phone

17.2.        选项标签

选项标签是用来指定SIP扩展选项的识别符且为唯一的。这些标签用于Require,Proxy-Require,Supported以及Unsupported这些头字段中,这些选项以“选项参数=符号”的形式作为参数出现在这些头字段中。选项标签在RFC的相关标准中定义。为了可以保证厂商互通性,可参考IANA注册的选项标签。

17.3.        标签

“tag”参数用于SIP消息中的To和From头字段。它通常用来识别一个对话,由Call-ID和对话的双方各一个的标签组成。当UA在对话之外发送请求的时候,它只包含一个From标签,提供“一半”对话ID,对话由收到响应结束,双方在To标签里提供另一半ID。分叉代理的SIP请求即可以由一个请求建立多个对话。因此,对话双方都必须要有标识符:没有接收者确认,发件人不能确认这个对话是由一个请求建立的多个对话的哪一个。

UA生成一个标签插入到请求或者响应中,这个标签必须是全局唯一的并且至少是32比特的随机编码。当UA要将自己加入一个会话中支,它需要在INVITE请求的From头字段中插入一个标签,在其响应的To头字段中插入一个不同的标签。同样,两个对于不同呼叫的INVITE有不同的From标签,对于两个不同的呼叫的响应也有不同的To标签。

除了要求全局唯一,根据具体实践不同对建立标签的规则也有不同的要求。系统在允许的范围之内出错,标签有助于将圣诞倒换到备用的服务器上。在出错的服务器上通过备份可以识别出这个对话的部分请求,UAS可以选择标签来恢复该圣诞以及其他相关的状态。

 

18. 头字段

本章完整的列举了头字段的语法、语义、用法。头字段与各种方法和代理服务器的关系总结于表 2

表 2 头字段概览

Header field

where

proxy

ACK

BYE

CAN

INV

OPT

REG

Accept

R

 

-

o

-

o

m*

o

Accept

2xx

 

-

-

-

o

m*

o

Accept

415

 

-

c

-

c

c

c

Accept-Encoding

R

 

-

o

-

o

o

o

Accept-Encoding

2xx

 

-

-

-

o

m*

o

Accept-Encoding

415

 

-

c

-

c

c

c

Accept-Language

R

 

-

o

-

o

o

o

Accept-Language

2xx

 

-

-

-

o

m*

o

Accept-Language

415

 

-

c

-

c

c

c

Alert-Info

R

ar

-

-

-

o

-

-

Alter-Info

180

ar

-

-

-

o

-

-

Allow

R

 

-

o

-

o

o

o

Allow

2xx

 

-

o

-

m*

m*

o

Allow

r

 

-

o

-

o

o

o

Allow

405

 

-

m

-

m

m

m

Authentication-Info

2xx

 

-

o

-

o

o

o

Authorization

R

 

o

o

o

o

o

o

Call-ID

c

r

m

m

m

m

m

m

Call-Info

 

ar

-

-

-

o

o

o

Contact

R

 

o

-

-

m

o

o

Contact

1xx

 

-

-

-

o

-

-

Contact

2xx

 

-

-

-

m

o

o

Contact

3xx

d

-

o

-

o

o

o

Contact

485

 

-

o

-

o

o

o

Content-Disposition

 

 

o

o

-

o

o

o

Content-Encoding

 

 

o

o

-

o

o

o

Content-Language

 

 

o

o

-

o

o

o

Content-Length

 

ar

t

t

t

t

t

t

Content-Type

 

 

*

*

-

*

*

*

Cseq

c

r

m

m

m

m

m

m

Date

 

a

o

o

o

o

o

o

Error-Info

300-699

a

-

o

o

o

o

o

Expires

 

 

-

-

-

o

-

o

From

c

r

m

m

m

m

m

m

In-Reply-To

R

 

-

-

-

o

-

-

Max-Forwards

R

amr

m

m

m

m

m

m

Min-Expires

423

 

-

-

-

-

-

m

MIME-Version

 

 

o

o

-

o

o

o

Organization

 

ar

-

-

-

o

o

o

Priority

R

ar

-

-

-

o

-

-

Proxy-Authenticate

407

ar

-

m

-

m

m

m

Proxy-Authenticate

401

ar

-

o

o

o

o

o

Proxy-Authorization

R

dr

o

o

-

o

o

o

Proxy-Require

R

ar

-

o

-

o

o

o

Record-Route

R

ar

o

o

o

o

o

o

Record-Route

2xx,18x

mr

-

o

o

o

o

-

Reply-To

 

 

-

-

-

o

-

-

Require

 

ar

-

c

-

c

c

c

Retry-After

404,

413,

480,

486

 

-

o

o

o

o

o

Retry-After

500,503

600,603

 

-

o

o

o

o

o

Route

R

adr

c

c

c

c

c

c

Server

r

 

-

o

o

o

o

o

Subject

R

 

-

-

-

o

-

-

Supported

R

 

-

o

o

m*

o

o

Supported

2xx

 

-

o

o

m*

m*

o

Timestamp

 

 

o

o

o

o

o

o

To

c(1)

r

m

m

m

m

m

m

Unsupported

420

 

-

m

-

m

m

m

User-Agent

 

 

o

o

o

o

o

o

Via

R

amr

m

m

m

m

m

m

Via

rc

dr

m

m

m

m

m

m

Warning

r

 

-

o

o

o

o

o

WWW-Authenticate

401

ar

-

m

-

m

m

m

WWW-Authenticate

407

ar

-

o

-

o

o

o

 

“where”列定义可以使用该头字段的请求和响应的类型。每个值含义如下:

R:头字段只能在请求中出现;

r:头字段只能在响应中出现;

2xx、4xx,等等:头字段可以用于的响应代码。

c:头字段是从请求复制到响应的。

如果”where”栏目是空白,表示头字段可以在所有的请求和应答中出现。

“proxy”列描述了proxy在头字段上的操作

a:如果头字段不存在,proxy可以增加或者连接头字段

m:proxy可以修改头字段值

d:proxy可以删除头字段值

r:proxy必须能读取这个头字段,因此这个头字段不能加密。

接下来6列描述某一个方法中可以出现的头字段:

c:条件;对头字段的要求依赖于消息的上下文

m:头字段是强制要有的。

m*:头字段应该被发送,但是客户端/服务端可以接收没有该字段的消息。

o:头字段是可选的。

t:头字段应该被发送,但是客户端/服务端可以接收没有该字段的消息。如果使用基于流的传送协议(例如TCP),那么必须含有该头字段。

*:如果消息体不为空,那么头字段是必须。

-:不可使用该字段。

“Optional”意味着这个元素可以在请求或者应答中包含该头字段,但UA也可以忽略它, Require头字段例外。”mandatory”(强制)要求请求中或者响应中必须含有该头字段,收到该请求的UAS或者UAC必须能够理解该字段。”Not applicable”(不可使用)要求请求消息不可以含有该字段,UAS必须忽略含有这些字段的请求消息;同样,对于响应,标注了“Not applicable”的头字段意味着UAS不可以将该字段放于响应中,并且UAC必须忽略响应中的该字段。

UA应该忽略它所不理解的扩展头字段参数,当整个消息太大时,某些普通的头字段可以使用缩略形式。Contact、From以及To字段都包含一个URI。如果该URI包含逗号、问号或者分号,该URI必须用三角括号括起来。任何URI参数也都包括在这些三角括号内。如果某URI没有在三解括号内,并且参数使用分号分隔,那么这些参数就认为是头字段参数,而不是URI参数。

18.1.        Accept

Accept头字段参照HTTP语法规定,语义也基本相同。唯一不同的是如果没有Accept头域,服务器应该默认其值为application/sdp。空的Accept头域意味着没有可接受的媒体类型。

例子:

Accept: application/sdp;level=1,application/x-private,text/html

18.2.        Accept-Encoding

Accept-Encoding类似Accept,限制响应中可接受的内容编码。

Accept-Encoding允许为空。它等价于Accept-Encoding:identity,也就是说,只有identity时允许没有编码。如果没有Accept-Encoding存在,那么服务端应该使用缺省值:identity。

例如:

Accept-Encoding:gzip

18.3.        Accept-Language

Accept-Language用来在请求中指定响应中首选的语言,用于响应中作为消息体的原因描述、对话描述或者状态响应。如果没有Accept-Language,那么服务器应当假设所有的语言客户端都可以接受。

Accept-Language的语法遵照HTTP。基于“q”参数排序的规定也适用于SIP。

例如:

Accept-Language: da, en-gb; q= 0.8, en;q=0.7

18.4.        Alert-Info

当INVITE请求含有Alert-Info时,该字段对UAS定义了另外一个可用的铃音。当在180(Ringing)响应中出现时,该字段对UAC定义了另外一个可以使用的回铃音。代理服务器插入该字段是可以提供一种独特的铃声。

Alter-Info能会带来潜在的安全隐患。

另外,用户应该也可以修改铃声以使铃声可用。这有助于防止由于不信任的实体使用了该字段而导致通信中断。

例如:

Alter-Info: <http://www.example.com/sounds/moo.wav>

18.5.        Allow

Allow列出了发起请求UA支持的方法列表。UA能理解的所有方法都必须列于该头字段中。消息中若无该头字段,则意味UA未提供任何关于它所支持方法的信息,并不意味着UA不支持任何方法

响应消息中的Allow包含OPTIONS以外其他的方法,因此可以减少所需消息数量。

例如:

Allow: INVITE,ACK,OPTIONS,CANCEL,BYE

18.6.        Authentication-Info

Authentication-Info为通信双方提供HTTP分类鉴权信息。如果某请求已经基于Authorization头字段完成了鉴权,那么UAS可以在该请求的2xx的响应中包含一个Authentication-Info字段,语法和语义规定见RFC 2617。

例如:

Authentication-Info: nextnonce=”47364c23432d2e131a5fb210812c”

18.7.        Authorization

Authorization中包含UA进行认证的鉴权证书。

Authorization和Proxy-Authorization,不遵循多头字段值的一般规则。虽然多个数值之间没有逗号分隔,该头字段名仍可以出现多次。并且不可以按照4.3中的规则将其合并成一个头字段行

例如:

Authorization:Digest username=”Alice”, realm=”atlanta.com”,

nonce = ”84a4cc6f3082121f32b42a2187831a94”,

response=”7587245234b3434cc3412213e5f113a5432”

18.8.        Call-ID

Call-ID用来唯一标识某个客户端的某个特定的INVITE或所有的注册请求。一个多媒体会议可以发起多个不同Call-ID的呼叫,例如,某用户数次邀请某人加入同一个会议。Call-ID区分大小写并逐字节比较,缩写形式为i。

例如:

Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@biloxi.com

i:f81d4fae-7dec-11d0-a765-00a0c91e6bf6@192.0.2.4

18.9.        Call-Info

Call-Info若在请求中则提供主叫的附加信息,若在响应中则提供被叫附加信息。”purpose”参数描述了URI的用途。”icon”参数包含了一个呼叫方或者被叫方的图标。”info”参数则为主叫或者被叫的一般描述;”card”参数提供一个名片,其余参数可以通过INNA注册。

但是,使用Call-Info可能会带来一些安全隐患。如果某被叫接到一个恶意主叫提供的URI,被叫方可能会显示显现一些不恰当或者攻击性的内容,或者一些危险的、非法的内容。因此,仅当UA能够证明发出的Call-Info字段的实体是真实并可信的,该UA才使用Call-Info的信息。这并不一定要求是对等的UA,代理服务器也可以在请求中插入该字段。

例如:

Call-Info: http://www.example.com/alice/photo.jpg;purpose=icon,

http://www.example.com/alice/;purpose=info

18.10.   Contact

Contact字段值包含一个URI,其含义取决于所在的请求或响应的类型。

Contact还可以包含了一个显示的名字、含有URI参数的URI和头字段参数。

本文档定义了Contact参数“q”和“expires”。这些参数只用于REGISTER的请求及其响应以及3xx的响应。

当Contact头字段包含一个显示名称时,那么带参数的URI应当用”<”和”>”括起来。否则,URI后面的参数都认为是头字段参数而不是URI参数。

 

即使“display-name”为空,只要”addr-spec”包含逗号、分号或者问号,也必须使用“name-addr”中的格式。display-name和”<”之间的LWS(线性空白)可有可无。

解析显示名称、URI、URI参数以及头字段参数的规则同样适用于To和From头字段。

Contact头字段的作用类似于HTTP中的Location头字段。但是HTTP中的Location只允许1个不用引号标注的地址。由于URI中可以包含逗号和分号,它们可能被误认为头字段或者参数的分隔符。

Contact的缩写是m(“moved”)。

例如:

Contact: “Mr.Watson” <sip:watson@worcester.bell-telephone.com>;q=0.7;

expires=3600,

“Mr. Watson” mailto:watson@bell-telephone.com ;q=0.1

m: <sips:bob@192.0.2.4>;expires=60

18.11.   Content-Disposition

Content-Disposition描述了消息体,或者消息的多个部分,或者消息体的一个部分应被UAC或者UAS怎样解释。该头字段扩展了MIME Content-Type。

SIP定义了Content-Disposition几个新的“disposition-types”。“session”值表示消息体部分描述了一个呼叫时或者呼叫前的媒体会话。“render”值表示了消息体应被显示或者回传给用户。注意”render”比”inline”更适合避免MIME消息体作为一个大的消息的一部分做展示(由于SIP消息的MIME消息体经常不被展示给用户)。出于向后兼容的考虑,如果Content-Disposition不存在,服务器应当假设Content-Type为application/sdp的消息体是所要描述的“session”,其他消息体的值为“render”。

 “icon”表示消息体部分包含了一个用于表示呼叫者或者被叫者的icon图标,当UA收到这个消息,就可以展示一下,或者在对话过程中一致展示。“alert”指明该消息体部分包含一些信息应该由UA通知用户接收请求的时候回传给用户,通常一个请求发起一个对话。例如,180临时性响应发出之后,告警该消息体应该作为一个铃声信息回传给电话机。

任何含有“disposition-type”的MIME消息体只有在该消息被鉴权后才处理

参数handling-param指定了如果UA不理解所收到的某消息体的内容类型或者处理类型,UAS应该如何处理。该参数定义了“optional”和“required”两个值,如果没有该参数,默认值为“required”。关于该参数参见RFC 3204。

例如:

Content-Disposition: session

18.12.   Content-Encoding

Content-Encoding是对“media-type”(媒体类型)的一个修正。它的值指定了适用于该实体的编码以及为了获得Content-Type指定的媒体类型所需要使用的解码机制。Content-Encoding主要用于消息体压缩而且不丢失底层媒体类型标识。如果某个实体可以使用多个编码方式,则编码方式按其使用的顺序排列。

所有的Content-Encoding的值都不区分大小写。其符号值必须在IANA上注册。

客户端可以在请求中进行包体的内容编码。服务端也可以在应答中进行内容编码。服务端必须只能应用客户端在请求中的Accept-Encoding头域中列出的编码类型。

Content-Encoding简写是e。

例如:

Content-Encoding:gzip

e: tar

18.13.   Content-Language

参见HTTP相减规范,举例如下:

Content-Language: fr

18.14.   Content-Length

Content-Length头字段用十进制数指定发送的消息体的大小(字节数)。具体实现时,应该使用该字段指示所传递消息体的大小而不考虑该实体的媒体类型。本协议规定,使用基于流的传输协议时必须使用该字段。

本字段所指标的消息体的大小不包括分隔头字段和消息体的CRLF符。该字段的有效值为大于等于零的数。如果消息中无消息体,那么该字段值必须设为零。省略Content-Length字段简化了动态的产生响应的类CGI脚本程序。

Content-Length简写是l

例如:

Content-Length:349

l:173

18.15.   Content-Type

Content-Type头字段指定发给对方的消息体的媒体类型。如果消息体不为空,那么Content-Type头字段就必须存在。如果消息体是空的,并且该头字段存在,那么就表示了特定类型的媒体的包体长度为0(比如空的音频文件)。

Content-Type简写是c

例如:

Content-Type: application/sdp

c: text/html;charset=ISO-8859-4

18.16.   CSeq

Cseq位于请求消息中,包含一个十进制数字序列和一个请求方法。这个数字序列必须是一个32位的无符号整数。Cseq请求方法区分大小写的。Cseq用于把某对话中的事务进行排序且提供一种唯一标识某事务的方法,并能够区分某请求是新的请求还是重发的请求。如果两个CSeq的数字序列以及方法都相等,那么两个Cseq头域就是等价的。

例如:

Cseq:4711 INVITE

18.17.   Date

Date头字段包含日期和时间。和HTTP/1.1不同,SIP只支持最近的RFC 1123格式的日期。SIP限制了在SIP-date中的时区是“GMT”,在RFC 1123中支持任意的时区。RFC1123的日期是区分大小写的。

Date头域反映了请求或者响应第一次被发送的那一刻的时间。没有后备电池的终端系统可以利用Date字段获得当前时间。然而,由于是GMT格式的,所以,它要求客户端知道和GMT的时差。

例如:

Date:Sate,13 Nov 2010 23:29:00 GMT

18.18.   Error-Info

Error-Info头字段用来提供出错状态码的附加信息。

UAC具备用户接口功能,包括PC软客户端的弹出窗口接口、音频接口、通过网关连接的音频电话或端点的接口。当服务器产生错误信号的时候,它可以发送一个带详细描述的出错状态码,或者可发送一个音频记录, Error-Info头字段可以同时发送这两种信号,UAC可以选择任何一种方式通知主叫。

UAC可以把在Error-Info中的一个SIP或者SIPS URI当作重定向消息的Contact头字段,并且据此产生一个新的INVITE,并建立一个已记录的会话。非SIP URI可以回送给用户。

例如:

SIP/2.0 404 The Number you have dialed is not in service

Error-Info: <sip:not-in-service-recording@atlanta.com>

18.19.   Expires

Expires头字段给定了消息(或者内容)的有效时间。其含义因请求方法不同而不同。INVITE的有效时间并不影响会话的实际持续时间。会话持续时间的表达方法由会话描述协议SDP规定。

该字段的值是一个十进制整数,单位为秒,其值介于0到(232-1)之间。

这个头域的值是一个以秒计数的整数,从0到(2**32)-1,从收到请求开始计数。

 

例如:

Expires:5

18.20.   From

From头字段用于指示请求的发起者。这可能与对话的发起者并不同。被叫发送给主叫的请求在From字段中使用被叫的地址。

“display-name”参数可选,主要用于人机接口。如果用户需要隐藏其标识,那么系统应当使用”Anonymous”作为显示名字。即使是”displayname”是空的,如果“addr-spec” 包含一个逗号、问号或者分号,那么就必须使用“name-addr”的格式。相关的格式参见4.3.1节描述。

如果两个From字段的URI一致并且参数也一致,那么这两个头字段就是等价的。如果扩展参数在一个头字段中存在,在另外一个头域字段不存在,那么比较这两个头字段时应将这个参数忽略。这意味着名字和三角括号的存在与否并不影响其等价性。

From的简写是f

例子:

From: “A. G. Bell” <sip:agb@bell-telephone.com> ; tag=a48s

From: sip:+12125551212@server.phone2net.com;tag=887s

f: Anonymous <sip:c8oqz84zk7z@privacy.org>;tag=hyh8

18.21.   In-Reply-To

In-Reply-To头字段列举了本次呼叫相关的或者返回的Call-ID。客户端可以缓存这些Call-ID,并放在所返回的呼叫的In-Reply-To字段中。这允许自动呼叫分配系统(ACD)将返回的呼叫路由到第一个呼叫发起者。这也允许被叫过滤这些呼叫,仅返回那些被接受的呼叫。这个头字段并不可替代请求鉴权。

例如:

In-Reply-To: 70710@saturn.bell-tel.com,17320@saturn.bell-tel.com

18.22.   Max-Forwards

Max-Forwards头字段必须在每一个SIP请求中使用,来限制中间转发请求到下一个节点的proxy或者gateway的个数。当某个客户端沿着某条链路发送请求消息的时候,使用该字段可以有效防止链路中出错或者发生回环。

Max-Forwards是一个0-255的整数,指示该请求还允许被转发的次数。每当服务器转发这个请求一次,这个数字就减一。建议的初始值是70。当不能确定有无循环路由的时候,必须在头域中增加本头域。例如,B2BUA应当增加这个头域。

例如:

Max-Forwards:6

18.23.   Min-Expires

Min-Expires头字段定义了由服务器控制的软状态实体更新间隔的最小值。这也包括注册服务器存储的Contact字段。该头字段的值是0~232-1的十进制整数,单位为秒。

例如:

Min-Expires:60

18.24.   MIME-Version

参见HTTP/1.1。举例如下:

MIME-Version: 1.0

18.25.   Organization

Organization头字段包含了发出请求或者响应消息的SIP节点所属的组织名称。该字段可以用来让客户端软件过滤呼叫。

例如:

Organization: Boxes by Bob

18.26.   Priority

Priority头字段定义客户端请求紧急程度。Priority描述了对于接收用户或其代理,请求消息所具有的优先级。例如,这可能是决定呼叫转发和处理的优先要素。对于判定优先级来说,如果消息没有包含Priority字段,那么处理的时候应当当作”normal”优先级处理。Priority不影响通讯资源的优先顺序,比如路由上的包转发的优先级或者访问PSTN网关的优先级。该头字段有“non-urgent”、“norma”、“urgent”和“emergency”取值。强烈建议“emergency”只用于影响到生命、身体、或者财产危急时候才使用。

例如:

Subject: A tornado is heading our way!

Priority: emergency。

或者

Subject: Weekend plans

Priority: non-urgent.

18.27.   Proxy-Authenticate

Proxy-Authenticate头字段包含一个鉴权质询口令。

例如:

Proxy-Authenticate: Digest realm=”atlanta.com”,

domain=”sip:ss1.carrier.com”,qop=”auth”,

nonce=”f84f1cec41e6cbe5aea9c8e88d359”,

opaque=””,stale=FALSE,algorithm=MD5

18.28.   Proxy-Authorization

Proxy-Authorization头字段用于用户对要求鉴权的proxy标识自己。Proxy-Authorization头字段包含一个证书,其中包含UA对于proxy的鉴权信息和所要请求的资源的域。

关于多字段名的一般规定并不适用于Proxy-Authorization和Authorization头字段。虽然多个数值之间没有逗号分隔,该头字段名仍可以出现多次,但是不可以将它们结合成一个单独的头字段行。

例如:

Proxy-Authorization: Digest username=”Alice”,realm=”atlanta.com”,

nonce=”c60f3082ee1212b402a21831ae”,

response=”245f23415f11432b3434341c022”

18.29.   Proxy-Require

Proxy-Require头字段用来指定proxy所必须支持的相关的特性。

例子:

Proxy-Require:foo

18.30.   Record-Route

Record-Route头字段是proxy在插入到请求消息中的,用来强制会话中的后续请求经过本proxy的。

例子:

Record-Route: <sip:server10.biloxi.com;lr>,

<sip:bigbox3.site3.atlanta.com;lr>

18.31.   Reply-To

Reply-To头字段包含了逻辑上返回目的地URI,这个可能和From头字段不同。如果用户需要保持匿名,则该字段必须从请求中省略掉,或者使用一种不显现任何个人信息的方式。

即使“display-name”为空,如果“addr-spec”包含逗号、问号或者分号,那么就需要使用“name-addr”的格式来填写。

例如:

Replay-To: Bob <sip:bob@biloxi.com>

18.32.   Require

Require头字段用于UAC告诉UAS处理请求时需要支持那些特性。该字段为可选,但不可以被忽略。

该字段包含一个option tag的列表。每一个option tag定了一个要处理请求,要求UAS必须支持的SIP扩展。通常,这用于定义一个需要支持的扩展头域的集合。

例如:

Require:100rel

18.33.   Retry-After

Retry-After头字段用于500(Server Internal Error)或者503(Service Unavailable)响应中,可以对请求发起客户端指示多久后服务不可用。在404(Not Found)、413(Request Entity Too Large)、480(Temporarily Unavailable)、486(Busy Here)、 600 (Busy),或者603(Decline)响应中表明被叫何时可用。这个字段的值是一个秒为单位的正整数(十进制),从响应生成开始计时。

本字段中可以使用一个注释项标明于回呼时间的附加信息,该注释项为可选。“duration”参数指明被叫从空闲的开始保持空闲的时长。该参数可选。

例如:

Retry-After: 18000;duration=3600

Retry-After:120 (I’m in a meeting)

18.34.   Route

Route头字段用于强制一个请求经过一个proxy路由列表。

例如:

Route: <sip:bigbox3.site3.atlanta.com;lr>,

<sip:server10.biloxi.com;lr>

18.35.   Server

Server头字段包含UAS处理请求所使用的软件信息。

服务器的特定软件版本可能会使服务器由于特定软件安全漏洞导致服务器受到攻击。实现上应当使得Server头域是一个可以配置的选项。

例如:

Server:HomeServer v2

18.36.   Subject

Subject头字段包括呼叫的概述或者呼叫的性质,过滤呼叫时,可以不必解析会话描述。会话描述不必与邀请使用同一个对象。

Subject缩写是s

例如:

Subject: Need more boxes

s: Tech Support

18.37.   Supported

Supported头字段列举了UAC或者UAS支持的所有扩展。

Supported头字段包含了一个UAS或者UAC所支持的option tag列表。如果本字段是空的,表示不支持任何扩展。

Supported缩写是k

例如:

Supported: 100rel

18.38.   Timestamp

Timestamp头字段给出UAC向UAS发出请求的时间。

例如:

Timestamp:54

18.39.   To

To头字段指定请求的逻辑上接收者。“display-name”参数用于人机接口,为可选。“tag”参数一般用于标识对话。

To头字段等价性的判定同From头字段。

To头域的缩写是t。

举例如下:

To: The Operator <sip:operator@cs.columbia.edu>;tag=287447

t: sip:+12125551212@server.phone2net.com

18.40.   Unsupported

Unsupported头字段列出了不被UAS支持的特性列表。

例如:

Unsupported:foo

18.41.   User-Agent

User-Agent头字段包含了发起请求的UAC信息。该字段的主义参见HTTP/1.1。

如果显示UA的特定软件版本信息,一量该软件存在安全漏洞,该UA就容易受到攻击,应把User-Agent字段作为可配置的选项

例如:

User-Agent:Softphone Beta1.5

18.42.   Via

Via头字段指定目前请求消息经过的路径,同时指定响应也要按该路径返回。Via头字段的branch ID参数提供了事务的标识符,proxy用它来检测环路。

Via头字段包含了用于发送消息的通讯协议、客户端主机名或者网络地址,可能还有接收应答响应的端口号。Via头字段还可以包含参数“maddr”、“ttl”、“received”和“branch”,具体实现时,branch参数的值必须用magic cookie“z9hG4bK”打头。

这里定义的通讯协议是UDP、TCP、TLS和SCTP,TLS是基于TCP的TLS。如:

Via: SIP/2.0/UDP erlang.bell-telephone.com:5060;branch=z9hG4bK87asdks7

Via: SIP/2.0/UDP 192.0.2.1:5060 ;received=192.0.2.207;branch=z9hG4bK77asjd

Via缩写是v

上面例子中,一个拥有两个地址(192.0.2.1和192.0.2.207)的多源(multi-homed)主机发出消息。发送方可能用错了网络接口。Erlang.belltelephone.com发现了不匹配,就在前一跳的Via字段中插入一个包含实际发送该数据包的址的参数。

主机或者网络地址以及端口号不需要遵循SIP URI的语法。“:”或者“/”的任何一边的LWS都是允许的。如下所示:

Via: SIP / 2.0 / UDP first.example.com: 4000;ttl=16

;maddr=224.2.0.1 ;branch=z9hG4bKa7c6a8dlze.1

虽然要求所有的请求中都包含branch参数,但该字段的BNF仍然规定branch参数是可选的。这样可增强与RFC 2543定义实体之间的互操作性。

18.43.   Warning

Warning头字段是与响应状态有关的附加信息。Warning头字段值放于响应中发送,其中包含一个三位告警码、主机名以及告警文本信息。

“warn-text”应为可被用户理解的自然语言,可以根据以下几种情况选择:用户的位置、请求中的Accept-Language字段、响应中的Content-Language字段。默认的语言是i-default。

以下列举了已定义的“warn-code”和英文的warn-text。这些告警是由会话描述所引入的失败。告警码的第一位是3则表明为SIP告警。300-329表明是因为会话描述中的关键词引起的错误;330-339表示错误与会话描述要求的基本网络业务有关;370-379表明错误与会话描述要求的QoS有关;390-399是除上述情况之外的错误。

300 Incompatible network protocol:(不兼容的网络协议),One or more network protocols contained in the session description are not available.(在会话描述中的一个或者多个网络协议不适用)

301 Incompatible network address formats(不兼容的网络地址格式):One or more network address formats contained in the session description are not available. (会话描述中的一个或者多个网络地址格式不合法)

302 Incompatible transport portocol(不兼容的通讯协议):One or more transport protocols described in the session description are not available. (会话描述中的一个或者多个通讯协议不存在)。

303:Incompatible bandwidth units(不兼容的带宽单位): One or more bandwidth measurement units contained in the session description were not understood.(会话描述中的一个或者多个带宽单位不支持)。

304 Media type not available(媒体类型不存在): One or more media types contained in the session description are not available. (会话描述中的一个或者多个媒体类型不存在)。

305 Incompatible media format(媒体格式不兼容): One or more media formats contained in the session description are not available.(会话描述中的一个或者多个媒体格式不兼容)。

306 Attribute not understood(媒体属性不支持): One or more of the media attributes in the session description are not supported.(会话描述中的一个或者多个媒体属性不支持)。

307 Session description parameter not understood(会话描述参数不支持): A parameter other than those listed above was not understood.(列出的会话描述参数不支持)。

330 Multicast not available(多点传输不允许): The site where the user is located does not support multicast.(用户定位的这个服务器不支持多点传送)。

331 Unicast not available(Unicast不支持): The site where the user is located does not support unicast communication (usually due to the presence of a firewall)。(用户定位的节点不支持unicast通讯(通常由于在防火墙之后))。

370 Insufficient bandwidth(带宽不足): The bandwidth specified in the session description or defined by the media exceeds that known to be available.(会话描述的带宽要求或者媒体要求的带宽超过限制)。

399 Miscellaneous warning(杂项警告): The warning text can include arbitrary information to be presented to a human user or logged. A system receiving this warning MUST NOT take any automated action.(这个警告信息可以包含给用户的任意信息或者做日志记录。接收到这个警告的系统禁止做任何自动操作)。

1xx和2xx消息是HTTP/1.1使用的。

附加的“warn-code”是IANA定义的。

例如:

Warning: 307 isi.edu "Session parameter ’foo’ not understood"

Warning: 301 isi.edu "Incompatible network address type ’E.164’"

18.44.   WWW-Authenticate

WWW-Authenticate头字段包含了认证信息。

例如:

WWW-Authenticate:Digest realm=”atlanta.com”,

domain=”sip:boxesbybob.com”,qop=”auth”,

nonce="f84f1cec41e6cbe5aea9c8e88d359",

opaque="", stale=FALSE, algorithm=MD5

 

19. 响应代码

SIP的响应代码在HTTP/1.1的基础上有所扩展。这里只涉及到SIP响应代码,并补充了6xx响应代码。

19.1.        临时响应1xx

临时响应即报告性的响应,用来指明所联系的服务器还没有确定性的响应。如果服务器需要200ms以上的时间才能发出最终响应,则它就需要首先发送一个1xx响应。1xx响应不能进行可靠传输。它也不能让客户端发送一个ACK请求。临时响应(1xx)可以包括一些消息体,其中包含会话描述SDP。

19.1.1. 100 Trying

100 Trying表明下一跳服务器已经收到该请求,但是对这次请求并未进行具体的处理。和其他临时响应一样,该响应使UAC停止重发INVITE请求。与其他临时响应不同,该响应不能使用有状态服务器前转。

19.1.2. 180 Ringing

UA收到INVITE请求之后用该响应通知用户,该响应也可以用来初始化一个本地回铃。

19.1.3. 181 Call is Being Forwarded(呼叫被转发)

服务器可以用使用该状态码表示该呼叫正被前转到另外一组终点。

19.1.4. 182 Queued

当被叫方正忙,并且服务器决定将呼叫排队等候,而不是拒绝呼叫的时候,那么就应当返回该响应。当被叫方一旦恢复接收呼叫,将返回适当的终结应答。该响应中可以包括一个表示原因的短语,比如:”5 calls queued;expected waiting time is 15minutes”。服务器可以发出多个182(Queued)响应来更新呼叫等待的状态。

19.1.5. 183Session Progress

183(Session Progress)响应用来传递呼叫进程的信息,其中包括原因短语、头字段、消息体来描述呼叫进程更详细的信息。

19.2.        成功信息2xx

该响应表明请求成功

19.2.1. 200 OK

该响应表示请求成功。与响应一起返回的信息取决于请求中使用的方法。

19.3.        转发请求3xx

该响应指标用户新位置信息,或者指定可以满足本次呼叫所需要的其他服务。

19.3.1. 300 Multiple Choices

请求中的地址可以解析为几个选项,每个选项都有自己特定的位置。用户或者UA可以确定一个首先的通信端点并且将该请求重定向到该位置。

请求中的消息体可能包含一个资源特征和位置的列表,用户或者UA可以从中选择一个Accept头字段中所允许的最合适的资源特征和位置。该消息不定义MIME类型。

这些选项可作为Contact字段列出。SIP响应可包含几个Contact字段或者在一个Contact字段中有多个地址。UA可以使用Contact字段的中的值自动重定向,也可以要求用户对选项进行确认。如果被叫可以通过多个不同的位置到达,且服务器不能代理该请求,则可以使用该状态码。

19.3.2. 301 Moved Permently

当用户已经不在Request-URI头字段的地址中,请求发起用户就应该重发请求至Contact头字段中的新地址。请求方应该更新本地姓名地址簿和用户位置并将将来的请求重定向到新地址。

19.3.3. 302 Moved Temporarily

请求发起用户应向Contact头字段中的新地址重发请求。新请求中的Request-URI是响应中Contact头字段里的值。Contact头字段中URI的有效期可以收Expires头字段或者Contact头字段中的expires参数来定义。Proxy和UA可以在有效期内使用URI。如果没有明确定义有效期,则该地址仅可有效递归一次,而以后的事务就不可以再使用该URI。

如果用户向Contact头字段中的URI发送请求失败,则应向重定向请求中的URI尝试发送请求。有效期过后之后该URI就不再使用,这时可以有一个新临时URI。

19.3.4. 305 Use Proxy

请求的资源必须通过Contact头域中指出的proxy来访问。Contact头域指定了一个proxy的URI。接收到这个应答的对象应当通过这个proxy重新发送这个单个请求。305(UseProxy)必须是UAS产生的。

 

19.3.5. 380 Alternative Service

呼叫不成功,但是可以尝试另外的服务。

19.4.        Request Failure 4xx

该响应由服务器发出表明请求失败。客户机不应(例如增加合适的授权)将原请求不加修改并重新发送。但将原请求发向不同的服务器也可能成功。

19.4.1. 400(Bad Request)

该响应表示请求由于语法错误该而不能被理解。响应的原因短语中应详细指出语法错误。

19.4.2. 401 (Unauthorized)

该响应表示请求消息需要用户鉴权。该响应由UAS和注册服务器发起。407 (Proxy Authentication Required)由代理服务器发起。

19.4.3. 402 (Payment Required)

保留将来使用。

19.4.4. 403 (Forbidden)

该响应表示服务器能理解但是拒绝执行请求消息。即使该请求已经鉴权也不能进行中继。

19.4.5. 404 (Not Found)

该响应表示服务器可以确定用户不在Request-URI头字段指定的域中。如果Request-URI头字段所指定的域与请求的接收方所能处理的域不一致时,也应该发送该响应。

19.4.6. 405 (Method Not Allowed)

该响应表示在Request-URI头字段指定的地址上,请求中的方法能够被理解但并不允许使用。该响应中必须包括一个Allow头字段来列举指定地址上所允许的方法。

19.4.7. 406 (Not Acceptable)

该响应表示,根据请求的Accept头字段,该请求所指定的资源生成响应的消息体中包含的某些内容特性是不被接受的。

19.4.8. 407 (Proxy Authentication Required)

该响应类似于401 (Unauthorized),不同的它指定客户机必须首先向代理服务器鉴权自己。该状态码可用于接入到通信信道中。

19.4.9. 408 (Request Timeout)

该响应表示服务器不能在适当的时长内产生响应。例如当它不能及时确定用户的位置时。客户端收到该响应后,可以不加修改便重发原请求。

19.4.10.          410 (Gone)

该响应表示服务器中被请求的资源不可用且服务器不知道转发地址,并且这种情况是永久性的。如果服务器不知道这种情况是否为永久性的,此时则应该使用404 (Gone)状态码。

19.4.11.          413 (Request Entity Too Large)

该响应表示,如果请求的消息体超出服务器能够处理范围,服务器将拒绝处理该请求。服务器可以关闭此连接以防客户端不断发送同一个请求。

如果这种情况是暂时的,服务器应在响应中加入一个Retry-After头字段用来指定多久以后客户机可以重发该请求。

19.4.12.          414 (Request-URI Too Long)

该响应表示,如果Request-URI超出服务器能够处理的范围,服务器将拒绝处理该请求。

19.4.13.          415 (Unsupported Media Type)

该响应表示服务器不支持某请求方法的消息体格式而拒绝处理该请求。根据具体内容的不同,服务器必须用响应Accept、Accept-Encoding或 Accept-Language头字段返回服务器可以接收的格式列表。

19.4.14.          416 (Unsupported URI Scheme)

该响应表示,由于服务器不理解URI的方案而不能处理该请求。

19.4.15.          420 (Bad Extension)

该响应表示,服务器不理解Proxy-Require或Require 头字段中协议的扩展规定。服务器必须在响应中的Unsupported字段中包含一个它不支持的扩展的列表。

19.4.16.          421 (Extension Required)

该响应表示,UAS需要某个特定的扩展才能处理该请求,但是这种扩展没有列在请求中的Supported头字段中。该响应必须包含一个Require头字段列举所需要的扩展。

除非UAS不能向客户提供任何其他所需的业务否则不应该使用该响应。如果Supported字段中没有所需的扩展,服务器只能用客户端所支持的扩展规定对该请求进行SIP的基本处理。

19.4.17.          423 (Interval Too Brief)

该响应表示,由于请求更新资源的间隔时间太短,服务器拒绝该请求。注册请求的Contact字段中定义的有效期太短,注册服务器可以使用该响应拒绝请求。

19.4.18.          480 (Temporarily Unavalilable)

该响应表示,与被叫方成功的联系上,但是被叫目前不可用者。在响应的Retry-After字段中可以指定一个合适的呼叫时间,在原因短语应该给出一个详细的原因指明为什么被叫方不可用。这个值可以由UA来设置。

如果重定向服务器或者代理服务器知道Request-URI中指定的用户但是目前并没有其有效位置,就可以返回该状态码。

19.4.19.          481 (Call/Transaction Does Not Exist)

该响应表示UAS收到的请求与现有的对话或者事务没有相对应的。

19.4.20.          482 (Loop Detected)

该响应表示服务器检测到有环路。

19.4.21.          483 (Too Many Hops)

该响应表示,服务器收到的请求中的Max-Forwards值为零。

19.4.22.          484 (Address Incomplete)

该响应表示,服务器收到的Request-URI不完整并应在原因短语中提供附加信息。该状态码允许异步拨号(overlapped dialing)。当用户使用异步拨号的方式时并,客户端并不知道拨号字串的的长度。因此它发送的字符串比实际的长,并提示用户输入更多的数字。直到不再收到484状态码为止。

19.4.23.          485 (Ambiguous)

该响应表示请求中的Request-URI不明确。该响应中的Contact字段中可以包含另外一个明确的地址,由于显示替代的Request-URI可能会破坏用户或者组织的保密性。 这种情况下,服务器必须可以做出404(Not Found) 响应,或者服务器能够禁止列举可能的URI选项。

例子如下:

sip:lee@example.com:

SIP/2.0 485 Ambiguous

Contact: Carol Lee <sip:carol.lee@example.com>

Contact: Ping Lee <sip:p.lee@example.com>

Contact: Lee M. Foote <sips:lee.foote@example.com>

有些电子信箱以及语音信箱系统可以提供这种功能。该状态码与3xx状态码语义不同:对于300响应,假设可以通过所提供的选项到达同一个人或者服务。自动化的选择或者连续的查找只对3xx有意义,而使用485 (Ambiguous)响应时则需要用户干涉。

19.4.24.          486 (Busy Here)

该响应表示,已经成功的和被叫终端连接,但是被叫目前不能在该终端系统执行呼叫,响应中的Retry-After字段可以指定一个合适的呼叫时间。该用户在其他地方可用。如果客户机知道没有别的终端系统可以接受本次呼叫那么应该使用600 (Busy)状态码。

19.4.25.          487 (Requet Terminated)

该响应表示,请求被BYE或者CANCEL请求终止。CANCEL请求不可以返回该响应。

19.4.26.          488 (Not Acceptable Here)

该响应与606 响应的含义相同,但是仅指Request-URI中指定的资源,如果在别处,该请求可能成功。

该响应中可能存在包含媒体能力描述的消息体,该消息体格式根据INVITE请求中的 Accept字段(如果不存在就是 application/sdp)规定。

19.4.27.          491 (Request Pending)

该响应表示,UAS收到请求但是在同一个对话中该UAS还有一个等待处理的请求。

19.4.28.          493 (Undecipherable)

该响应表示,UAS收到的请求包含一个加密的MIME消息体而接收方没有合适的解码密钥。该响应可以只包含一个消息体,该消息体包含一个公共密钥用来加密发送给UA的MIME消息体。

19.5.        5xx (Server Failure)

该响应表示服务器内部出错导致失败。

19.5.1. 500 (Server Internal Error)

该响应表示,服务器遇到意外的情况使它不能执行该请求。客户端可以显示这种特定的出错情况,并且可以几秒钟重发该请求。

如果情况是暂时的,服务器可以在Retry-After字段中指定多久之后客户机可以重发该请求。

19.5.2. 501 (Not Implemented)

该响应表示服务器不支持实现该请求所需要的功能。如果UAS无法识别该请求的方法并且不支持该方法,就可以发送该响应。如果为代理服务器,它转发请求时都不考虑请求的方法。

如果服务器识别了请求中的方法但是并不支持该方法应该发送405 (方法不允许)响应

19.5.3. 502 (Bad Gateway)

当服务器作为网关或者代理服务器时,需要接入到某下行服务器来完成请求,该下行服务器发出该响应表示其为无效网关。

19.5.4. 503 (Service Unavailable)

该响应表示由于服务器过载或者正在维护而导致服务器暂时不能处理该请求。服务器可以在Retry-After中指明何时可重发该请求。如果没有Retry-After则客户端必须按照收到的是500 (Server Internal Error)响应处理。

代理服务器或 UAC收到一个该响应之后应该将该原请求转发到替代的服务器上。如果响应中存在Retry-After字段,则在该字段定义的时间之内该客户机不能再向原来的服务器发送任何请求。

服务器也可以不必发送该响应,而直接拒绝连接或者丢弃原请求。

19.5.5. 504 (Server Time-out)

该响应表示,服务器接入到一个外部服务器来处理请求,但是没有及时收到该外部服务器的响应。如果在Expires字段中规定的时间之内没有收到上行服务器发来的响应,就应该使用408 (Request Timeout)响应。

19.5.6. 505 (Version Not Supported)

该响应表示服务器不支持请求中的协议的版本。

19.5.7. 513 (Message Too Large)

该响应表示,由于消息体的长度超过服务器的处理能力限制,服务器不能处理该请求。

19.6.        6xx (Global Failures)

该响应表示服务器对于某一特定用户的确定的信息。

19.6.1. 600 (Busy Everywhere)

该响应表示与被叫终端连接成功,但是被叫因为忙而不能接收呼叫。该响应中的Retry-After字段指定过多久之后可以重新呼叫。如果被叫不希望给出拒绝本次呼叫的原因则应该使用603 (Decline)。该响应只用于客户端知道没有别的终端可以接收该请求的情况,否则应该返回486响应。

19.6.2. 603 (Decline)

该响应表示,与被叫已经成功连接,被叫用户明确表示不能参与此呼叫。该响应中的Retry-After字段可以指定过多久之后可以重新呼叫。只有客户端知道没有别的终端可以接收该请求才可以使用该响应。

19.6.3. 604 (Does Not Exist Anywhere)

该响应通知服务器Request-URI中的用户根本不存在。

19.6.4. 606 (Not Acceptable)

该响应表示与用户代理已经成功连接,但是会话描述中如请求的媒体、带宽或者地址形式等都不可接受。

该响应可以包含一个Warning头字段来详细说明不支持该会话描述的原因。

该响应中可以有一个包含媒体能力描述的消息体,它的格式依据INVITE请求中的Accept头字段,如果没有该字段,则依据application/sdp。同OPTIONS请求消息的200 (OK)响应的消息体。

通信中不希望有频繁的协商,但如果一个新用户被邀请参加原有的一个会议根据邀请发起者是否发送606响应来决定是否需要协商。

该响应只用于客户机知道没有别的终端可以响应该请求。

 

20. IMSSIP消息的扩展要求

20.1.        综述

本章给出IMS网络对SIP/SDP的一些基本扩展。在IMS网络中采用SIP协议的IMS实体,如CSCF、MGCF、AS等都应该支持本章所列的扩展。

 

20.2.        头字段扩展

20.2.1. Path头字段

20.2.1.1. 概述

在IMS网络中,新扩展了SIP协议的Path头字段。

Path头字段用来记录REGISTER请求从用户UE到S-CSCF(注册服务器)之间的路由。通过该头字段,用户归属网络的S-CSCF可以知道用户UE当前所接入的P-CSCF的地址,继而将发往该用户的请求(包括初始会话请求)通过该P-CSCF发送给用户的UE。

20.2.1.2. 基本操作   

Path头字段的用法与Record-Route类似,但是只能用在REGISTER及其200响应消息中。

如P-CSCF期望自己保留在后续发往UE的请求消息路由中,则将自已的URI插入到REGISTER请求的Path头字段中,并置于顶端。

如果注册服务器接受了注册请求,则按照原顺序将Path头字段存储起来,然后将Path头字段的值复制到REGISTER请求的2xx响应中,当S-CSCF接收到发往用户的请求时,就添加一个Route头字段,其内容就是Path头字段的内容。

20.2.1.3. Path的语法

Path = “Path” HCOLON path-value *(COMMA path-value)

Path-value = name-addr *(SEMI rr-param)

Path扩展的选项标签(option-tag)是:path。

有关Path头字段扩展的详细内容见IETF RFC 3327.

20.2.2. Service-Route头字段

20.2.2.1. 概述

与Path头字段相对应,IMS网络扩展了Service-Route头字段。Service-Route头字段用来记录从用户UE接入的P-CSCF到用户归属的S-CSCF之间的路由。通过该头字段,用户UE可以设置从接入的P-CSCF到归属网络的S-CSCF的路由,将该用户发起的请求(包括初始会话请求)直接发送给S-CSCF,而不需要再通过I-CSCF来转接。

20.2.2.2. 基本操作

Service-Route头字段只用在REGISTER请求的200响应中。

通常情况下,S-CSCF可以在REGISTER请求的200响应中插入Service-Route头字段,并将该头字段设为自己的URI。

Path和Service-Route的关系类似于Record-Router和Route的关系,只不过前者用于注册过程中,而后才用于会话建立过程中。

20.2.2.3. Service-Route的语法

Service-Route = “Service-Route” HCOLON sr-value *(COMMA sr-value)

Sr-value = name-addr *(SEMI rr-param)

有关Service-Route头字段扩展的详细内容见IEFT RFC 3608.

20.2.3. Orig参数

20.2.3.1. 概述

“Orig”参数是一个uri的参数(uri-parameter),用于向S-CSCF指示这是一个始发业务而不是一个终结业务,或向I-CSCF指示应该执行始发程序。该参数见3GPP TS 24.229规定。

20.2.3.2. 基本操作

在特定的业务中,AS在S-CSCF和I-CSCF地址的后面添加orig参数,当S-CSCF发现其地址后有orig参数,则触发相关始发业务;当I-CSCF发现其址后有orig参数,则执行相关的始发程序。

20.2.3.3. Orig参数的语法

Orig参数的语法格式如下所示:

Uri-parameter=transport-parm / user-param /method-param /ttl-param / maddr-param /lr-param /orig / other-param

orig=”orig”

20.2.4. P-Associated-URI头字段

20.2.4.1. 概述

P-Associated-URI头字段使得S-CSCF(注册服务器)可以返回与注册的地址记录(AOR)相关联的一组URI地址,从而使得用户在注册一个URI地址时,可以隐性注册他自己的其他相关联的URI地址。

20.2.4.2. 基本操作

P-Associated-URI头字段只用在REGISTER的200响应中,由归属网络的S-CSCF在REGISTER的200响应中插入。

P-CSCF需要保存P-Associated-URI中含有显示名字的公有用户标识,并且将这些标识与已注册的公有用户标识进行关联,例如已注册的用户标识和相关联的隐性注册的身份。

如果P-Associated-URI中包含显示名字,P-CSCF需要保存含有显示名字的缺省的公有用户标识。P-Associated-URI中包含该用户所有的公有用户标识,但是并非都是已注册的标识。第一个URI是已经注册的公有用户标识,P-CSCF应该将P-Associated-URI中的第一个URI做为用户缺省的公有用户标识。

20.2.4.3. P-Associated-URI语法

P-Associated-URI = "P-Associated-URI" HCOLON (p-aso-uri-spec)*(COMMA p-aso-uri-spec)

p-aso-uri-spec = name-addr *(SEMI ai-param)

ai-param = generic-param

有关P-Associated-URI头字段扩展的详细内容见IETF RFC 3455。

20.2.5. P-Called-Party-ID

20.2.5.1. 概述

当被叫用户的S-CSCF收到初始请求之后,会修改请求中的Request-URI为被叫用户注册的Contact地址,为了不丢失原来的Request-URI信息,即被叫用户的公有用户标识,将该信息保存在P-Called-Party-ID头字段中。

20.2.5.2. 基本操作

被叫用户归属网络的S-CSCF在将初始请求(包括INVITE、SUBSCRIBE、OPTION、MESSAGE、REFER请求)转发给被叫用户的P-CSCF时,会用被叫用户注册的Contact地址覆盖请求消息中的Request-URI。为了使被叫用户知道该请求是发往哪个公有用户标识,S-CSCF应该在初始请求中增加P-Called-Party-ID头字段,用该头字段携带原来请求中的Request-URI,即被叫用户的公有用户标识。

被叫用户的P-CSCF在收到UE发送来的对上述请求的1XX或2XX响应时,应该删除P-Preferred-Identity,而根据P-Called-Party-ID生成P-Asserted-Identity。

20.2.5.3. 5.6.3 P-Called-Party-ID的语法

P-Called-Party-ID = "P-Called-Party-ID" HCOLON called-pty-id-spec

called-pty-id-spec = name-addr *(SEMI cpid-param)

cpid-param = generic-param

有关P-Called-Party-ID头字段扩展的详细内容见IETF RFC 3455。

20.2.6. P-Visited-Network-ID

20.2.6.1. 概述

P-Visited-Network-ID头字段用来向用户的归属网络指示用户当前漫游的网络的标志,便于归属网络查找与漫游网络的漫游协议。

P-Visited-Network-ID头字段可由拜访网络的P-CSCF在INVITE、REGISTER、SUBSCRIBE、OPTION、MESSAGE、REFER请求中提供。

20.2.6.2. 基本操作

P-CSCF在REGISTER请求消息中必须携带P-Visited-Network-ID头字段,其他请求消息不作要求。S-CSCF在将该头字段路由出归属网络时,应删除该头字段。如果S-CSCF的下一跳还是在归属网络中时,也建议在请求中删除该头字段。

20.2.6.3. P-Visited-Network-ID的语法

P-Visited-Network-ID = "P-Visited-Network-ID" HCOLON vnetwork-spec *(COMMA vnetwork-spec)

vnetwork-spec = (token / quoted-string) *(SEMI vnetwork-param)

vnetwork-param = generic-param

有关P-Visited-Network-ID头字段扩展的详细内容见IETF RFC 3455。

20.2.7. P-Access-Network-Info

20.2.7.1. 概述

P-Access-Network-Info头字段用来向归属网络指示用户接入IMS网络的接入方式和用户位置信息。

20.2.7.2. 基本操作

P-Access-Network-Info头字段由UE在其发送的每一个请求(包括ACK和CANCEL)或响应中插入,但是该请求应具有完整性保护时才可以携带该字段。

CSCF不能插入或修改P-Access-Network-Info头字段,除非UE不能插入该字段。

S-CSCF应在将消息转发出去时删除P-Access-Network-Info头字段,除非下一跳是与S-CSCF同在一个信任域内的AS。

 

20.2.7.3. P-Access-Network-Info的语法

P-Access-Network-Info = “P-Access-Network-Info” HCOLON access-net-spec *(COMMA access-net-spec)

access-net-spec       = access-type [SEMI np] *(SEMI access-info)

access-type          = "IEEE-802.11" / "IEEE-802.11a" / "IEEE-802.11b" / "IEEE-802.11g" / "3GPP-GERAN" / "3GPP-UTRAN-FDD" / "3GPP-UTRAN-TDD" / "ADSL" / "ADSL2" / "ADSL2+" / "RADSL" / "SDSL" / "HDSL" / "HDSL2" / "G.SHDSL" / "VDSL" / "IDSL" / "3GPP2-1X" / "3GPP2-1X-HRPD" / "DOCSIS" / token

np                 = "network-provided"

access-info          = cgi-3gpp / utran-cell-id-3gpp / dsl-location / i-wlan-node-id / ci-3gpp2 / extension-access-info

extension-access-info  = gen-value

cgi-3gpp            = "cgi-3gpp" EQUAL (token / quoted-string)

utran-cell-id-3gpp     = "utran-cell-id-3gpp" EQUAL (token / quoted-string)

i-wlan-node-id       = "i-wlan-node-id" EQUAL (token / quoted-string)

dsl-location         = "dsl-location" EQUAL (token / quoted-string)

ci-3gpp2           = "ci-3gpp2" EQUAL (token / quoted-string)

有关P-Access-Network-Info头字段扩展的详细内容和具体参数的取值见IETF RFC 3455和3GPP TS 24229。

 

20.2.8. P-Charging-Function-Address

20.2.8.1. 概述

P-Charging-Function-address用来指示本网络内的在线计费功能和离线计费功能的地址。IMS中使用的计费功能地址包括计费数据功能(CDF)地址和在线计费功能 (OCF)地址,CDF用于离线计费,OCF用于在线计费。

计费功能地址由用户的归属网络分配,用于其他实体向该地址发送计费信息。 

P-Charging-Function-Addresses 头字段中的参数,CDF 中使用"ccf",OCF中使用"ecf"。

20.2.8.2.  5.9.2 基本操作

在一个P-Charging-Function-address头字段中可能存在多个CDF地址和OCF地址。每个ccf 或 ecf参数至少含有一个地址。第一个地址是首选的,对于每个网络来说,第二个地址都是用于备份的。

CDF的地址和OCF的地址由归属网络的S-CSCF从HSS中获取并传递到其他网元,并仅在归属网络内传递,由归属网络的边界节点负责删除。

S-CSCF应在收到的初始请求或响应中添加P-Charging-Function-address头字段,发送给用户iFC中包含的所有位于归属网络的AS,或者用户归属网络内的P-CSCF或I-CSCF;在向其他网络转发请求之前删除该字段。

 

20.2.8.3. 5.9.3 P-Charging-Function-Address的语法

P-Charging-Addr = "P-Charging-Function-Addresses" HCOLON charge-addr-params * (SEMI charge-addr-params)

charge-addr-params = ccf / ecf / generic-param

ccf = "ccf" EQUAL

gen-value ecf = "ecf" EQUAL gen-value

有关P-Charging-Function-Address头字段扩展的详细内容见IETFRFC 3455。

20.2.9. P-Charging-Vector

20.2.9.1. 概述

P-Charging-Vector头字段用于在IMS网络实体之间传送IMS计费标识(ICID)和相关的计费信息,包括IMS计费标识icid、始发网络运营商标识、终结网络运营商标识以及接入网计费信息参数等信息。 

20.2.9.2. 5.10.2 基本操作

发起方的P-CSCF应在从UE收到的初始请求中添加P-Charging-Vector头字段。

接收方的P-CSCF应在从UE接收到的第一个响应中添加P-Charging-Vector头字段。 P-Charging-Vector头字段携带以下两个信息:

²  IMS计费标识(ICID):IMS计费标识是IMS网元(包括AS)之间共享的一个会话级的标识,IMS实体之间通过ICID来关联相关的CDR。ICID也用在独立事务的请求消息中(如SUBSCRIBE、NOTIFY、MESSAGE)。P-CSCF在请求或响应中添加P-charging-Vector 头字段,并在该头字段中给出ICID参数。在响应中添加的ICID的值应该与同一事务的请求中的ICID的值相同。信令沿途的的IMS网元都应该将ICID保存到本地。

²  运营商间标识(IOI):运营商间标识是在发送网络、接收网络和内容提供商之间共享的一个全球唯一的标识。发送网络在请求消息的P-Charging-Vector头字段中插入“orig-ioi”参数,用来指示请求始发的运营商网络;接收网络在响应消息中插入的“term-ioi”参数,则用来指示产生该响应消息的运营商网络。有三种类型的IOI参数:

  • 1类IOI:在P-CSCF(通常是拜访网络)和归属网络的S-CSCF之间传递,1类始发和终结的IOI参数通过REGISTER请求和响应消息进行交换;
  • 2类IOI:在始发网络的S-CSCF和终结网络的S-CSCF之间传递,或在始发网络的S-CSCF和MGCF(终结网络为PSTN/PLMN/软交换)之间传递,或在MGCF(始发网络为PSTN/PLMN/软交换)和终结网络的S-CSCF之间传递。2类始发和终结的IOI参数通过与会话有关或无关的请求和响应消息进行交换;
  • 3类IOI:在归属运营商的S-CSCF/I-CSCF和任意的AS之间传递, 3类始发和终结的IOI参数通过与会话有关或无关的请求和响应消息进行交换。

P-CSCF、I-CSCF、S-CSCF或AS在收到IOI参数后,都需要将该参数存到本地,在后续的请求或响应消息中都应该添加适当类型的“orig-ioi”和“term-ioi”参数。

20.2.9.3. P-Charging-Vector的语法

P-Charging-Vector = "P-Charging-Vector" HCOLON icid-value *(SEMI charge-params)

charge-params = icid-gen-addr / orig-ioi / term-ioi / access-network-charging-info / generic-param

icid-value = "icid-value" EQUAL gen-value

icid-gen-addr = "icid-generated-at"

EQUAL host orig-ioi = "orig-ioi" EQUAL gen-value

term-ioi = "term-ioi" EQUAL gen-value

access-network-charging-info = (gprs-charging-info / i-wlan-charging-info / xdsl-charging-info / packetcable-charging-info / generic-param) gprs-charging-info = ggsn SEMI auth-token [SEMI pdp-info-hierarchy] *(SEMI extension-param)

ggsn = "ggsn" EQUAL gen-value

pdp-info-hierarchy = "pdp-info" EQUAL LDQUOT pdp-info *(COMMA pdp-info) RDQUOT pdp-info = pdp-item SEMI pdp-sig SEMI gcid [SEMI flow-id] pdp-item = "pdp-item" EQUAL DIGIT

pdp-sig = "pdp-sig" EQUAL ("yes" / "no") gcid = "gcid" EQUAL 1*HEXDIG

auth-token = "auth-token" EQUAL 1*HEXDIG

flow-id = "flow-id" EQUAL "(" "{" 1*DIGIT COMMA 1*DIGIT "}" *(COMMA "{" 1*DIGIT COMMA 1*DIGIT "}")")"

extension-param = token [EQUAL token] i-wlan-charging-info = "pdg"

xdsl-charging-info = bras SEMI auth-token [SEMI xDSL-bearer-info] *(SEMI extension-param) bras = "bras" EQUAL gen-value

xDSL-bearer-info = "dsl-bearer-info" EQUAL LDQUOT dsl-bearer-info *(COMMA dsl-bearer-info) RDQUOT

dsl-bearer-info = dsl-bearer-item SEMI dsl-bearer-sig SEMI dslcid [SEMI flow-id] dsl-bearer-item = "dsl-bearer-item" EQUAL DIGIT

dsl-bearer-sig = "dsl-bearer-sig" EQUAL ("yes" / "no") dslcid = "dslcid" EQUAL 1*HEXDIG

packetcable-charging-info = packetcable [SEMI bcid] packetcable = "packetcable-multimedia" bcid = "bcid" EQUAL 1*48(HEXDIG)

其中,access-network-charging-info见3GPP TS 24.229对IETF RFC 3455的扩展。 有关P-Charging-Vector头字段扩展的详细内容见IETF RFC 3455.

20.3.        鉴权参数

20.3.1. 概述

IMS对SIP协议的WWW-Authenticate头字段定义了一个新的“auth-param”参数值。该参数主要用在401(REGISTER)响应中,用于携带IK(完整性密钥)和CK(加密密钥)向UE发起质询。

同时,也对SIP协议的Authorization头字段定义了一个新的“auth-param”参数值。该参数主要用在REGISTER请求中,携带“integrity-protected”参数,用于P-CSCF检查UE发送的注册请求是否被修改过。

这个参数见3GPP TS 24.229的规定。

20.3.2. 基本操作

20.3.2.1. WWW-Authenticate扩展的auth-param参数

S-CSCF在执行认证过程中,如果采用IMS-AKA认证方式,则需要从HSS下载S-CSCF所需的所有与安全相关的参数,即所谓的认证向量(AV)。

认证向量包括以下参数:

²  随机质询(RAND);

²  期望的结果(XRES);

²  网络鉴权令牌(AUTN);

²  完整性密钥(IK);

²  加密密钥(CK)。

在注册过程中,用户的UE首先发出初始REGISTER请求。由于初始REGISTER未带任何认证信息,归属网络的S-CSCF应返回401响应,并在响应的WWW-Authenticate头字段中给出从HSS下载的RAND、AUTN、IK和CK参数,其中IK和CK参数为新扩展的参数。

P-CSCF在收到401响应后,应该保存IK和CK参数,并将这两个参数从401响应中删除,之后,再将401响应转发给用户的UE。

用户的UE通过AUTN对归属网络进行鉴权,判断该401响应是否是自己的归属网络所发送的。如果UE确认该401响应是自己归属网络的S-CSCF发送的,则UE会通过401响应中提供的RAND和共享密钥计算出质询响应RES,同时也会计算出IK。UE会将RES放在第二个REGISTER请求的Authorization头字段中,通过P-CSCF发送给S-CSCF。

S-CSCF应该将接收到的RES与AV中的XRES相比较,如果这两个参数完全相同,则S-CSCF就成功的完成了对用户的认证。

UE计算出来的IK、P-CSCF从S-CSCF获得的IK将作为它们之间建立安全关联的共享密钥。

20.3.2.2. Authorization扩展的auth-param参数

“integrity-protected”参数由P-CSCF在REGISTER请求的Authorization头字段中添加。如果REGISTER消息是从与UE建立的安全关联上收到的,同时包含鉴权响应参数,则“integrity-protected”应设成“yes”,否则设为“no”。S-CSCF会根据此信息决定是否需要向收到的REGISTER请求发起质询。 5.11.3 相关扩展参数的语法

20.3.2.3. WWW-Authenticate头字段的auth-param参数的扩展

auth-param = 1#( integrity-key / cipher-key )

integrity-key = "ik" EQUAL ik-value

cipher-key = "ck" EQUAL

ck-value ik-value  = LDQUOT *(HEXDIG) RDQUOT

ck-value = LDQUOT *(HEXDIG) RDQUOT 

20.3.2.4. Authorization头字段的auth-param参数的扩展

auth-param = "integrity-protected" EQUAL ("yes" / "no" / "tls-yes")

 

20.4.        安全机制的协商

20.4.1. 概述

为了保证UE和P-CSCF之间传递的消息的安全性,UE和P-CSCF之间需要协商并采用一个共同的安全机制。目前,UE和P-CSCF之间至少需要支持IPSec安全机制。他们之间通过新扩展的Security-Client、Security-Server和Security-Verify三个头字段进行协商所采用的安全机制,以及告诉对方自己受保护的客户端和服务器端口。

 

20.4.2. 5.12.2 基本操作

Security-Client通常在初始REGISTER请求中用于指示UE所支持的安全机制、加密算法以及自己的受保护的客户端和服务器端口等信息。

Security-Server在由P-CSCF到REGISTER的401响应中,用来指示P-CSCF所支持的安全机制、加密算法以及自己的受保护的客户端和服务器端口等信息。

UE通过Security-Verify对P-CSCF的相关安全信息进行确认。 通过这三个头字段的三次握手,UE和P-CSCF之间就可以协商好所采用的安全机制和彼此的受保护的服务器端口和客户端端口。

为了确保所有请求和响应都是通过IPSec安全关联发出,P-CSCF需要在发往UE的每一个初始请求或响应的Record-Route头字段中,将其受保护的服务器端口设为其地址的一部分。由于受保护的端口号信息仅是在UE和P-CSCF之间有意义,所以,P-CSCF在将请求或响应消息转发给S-CSCF或其他实体之前,在指示自己地址的Via、Record-Route头字段中不用添加受保护的端口信息。

而对于UE,则需要:

²  在每个请求消息的Contact和Via(不包括初始REGISTER请求的Via)头字段中,将受保护的服务器端口设置为其地址的一部分;

²  在它发出的每个初始请求的Route头字段中,将P-CSCF受保护的服务器端口作为P-CSCF地址的一部分。

Security-Client、Security-Server和Security-Verify头字段的具体用法见3GPP TS 33.203附录H的相关要求。

20.4.3. Security-ClientSecurity-ServerSecurity-Verify头字段的语法

security-client = "Security-Client" HCOLON sec-mechanism *(COMMA sec-mechanism) security-server = "Security-Server" HCOLON sec-mechanism *(COMMA sec-mechanism) security-verify = "Security-Verify" HCOLON sec-mechanism *(COMMA sec-mechanism) sec-mechanism = mechanism-name *(SEMI mech-parameters)

mechanism-name = "ipsec- 3gpp" / "tls" mech-parameters  = ( preference / algorithm / protocol / mode / encrypt-algorithm / spi-c / spi-s / port-c / port-s )

preference = "q" EQUAL qvalue qvalue = ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] ) algorithm = "alg" EQUAL ( "hmac-md5-96" / "hmac-sha-1-96" )

protocol = "prot" EQUAL ( "ah" / "esp" )

mode = "mod" EQUAL ( "trans" / "tun"/ "UDP-enc-tun"  )

encrypt-algorithm = "ealg" EQUAL ( "des-ede3-cbc" /"aes-cbc" / "null" )

spi-c = "spi-c" EQUAL

spivalue spi-s = "spi-s" EQUAL spivalue

spivalue = 10DIGIT; 0 to 4294967295

port-c = "port-c" EQUAL port

port-s = "port-s" EQUAL port

port = 1*DIGIT

20.5.        前提条件

20.5.1. 概述

为了避免在资源预留好之前就向被叫用户振铃,在IMS网络对SIP和SDP协议进行了扩展,引入了前提条件的概念。前提条件与会话中的媒体流的资源预留情况相关联,只有满足了前提条件,即预留了期望的资源之后,才向被叫用户振铃。

前提条件主要扩展了SDP的三种属性:当前状态(curr)、期望状态(des)和确认状态(conf),分别表示指定的媒体流当前资源预留的情况、期望的资源预留状态和用于请求对端发送资源预留确认的条件。

为了保证通信实体对前提条件的正确处理,同时,也引入了一个新扩展的SIP选项标签(option-tag)“precondition”。

20.5.2.  5.13.2 基本操作

在IMS中,前提条件是与会话相关的网元应支持的能力,但是在一次会话中是否采用,取决于具体的应用场景。

如果主叫用户是通过无线方式接入到IMS网络,则主叫用户接入侧应该采用前提条件。本部分规定,如果主叫用户支持前提条件,由于并未明确被叫用户是否支持前提条件,因此“precondition”的扩展选项标签应通过Support头字段来携带,而不能通过Required头字段来携带。

如果主叫用户是通过无线方式接入到IMS网络,采用前提条件的处理方式如下:

如果主叫侧资源没有准备好,将在SDP中将媒体置成“Inactive”。如果被叫用户回送的响应消息中表明被叫侧确实不支持前提条件,则主叫侧应该将资源预留好,之后通过re-INVITE/UPDATE方式重新与被叫建立会话。

如果主叫侧资源已经准备好,则通过Support来携带“precondition”,并在SDP中携带自己所支持的媒体格式,被叫侧可以根据自己的情况进行媒体协商或者资源预留。

如果主叫用户是通过固定方式接入到IMS网络的,则可以不采用前提条件。如果采用前提条件,应与无线接入的处理方式一致。

被叫用户在会话的建立过程中可以采用前提条件。但是,如果主叫用户不支持前提条件,则被叫侧不能采用前提条件。在被叫侧不采用前提条件时,UE应在向用户振铃之前,先预留好本地接入的资源。

UE在使用前提条件时,应遵照IETF RFC 3312中的有关处理程序。资源预留采用分段预留方式,而不采用端到端的方式,即status-type只采用“local”或“remote”,不采用“e2e”。

有关前提条件具体的扩展内容见IETF RFC3312和IETF RFC4032。 

20.5.3. 5.13.3 前提条件的相关参数的语法

current-status = "a=curr:" precondition-type SP status-type SP direction-tag

desired-status = "a=des:" precondition-type SP strength-tag SP status-type SP direction-tag

confirm-status =  "a=conf:" precondition-type SP status-type SP direction-tag

precondition-type =  "qos" | token

strength-tag = ("mandatory" | "optional" | "none"  | "failure" | "unknown")

status-type =  ("e2e" | "local" | "remote")

direction-tag =  ("none" | "send" | "recv" | "sendrecv")

注:目前只规定了qos一种前提类型,这个类型主要依赖于无线链路上预留的带宽以及网络中路由器对传输大量语音和数据的分组数据的处理优先级。

 

20.6.        SIP信令压缩

20.6.1. 概述

为了节省空中接口的资源,需要对SIP协议进行压缩。SIP协议的压缩对IMS网络来说是一个非常重要的应用。

当UE通过无线方式接入到P-CSCF时,即P-Access-Network-Info头字段包含下列任意取值时, P-CSCF和UE之间的SIP消息应该进行压缩:

²  3GPP-GERAN;

²  3GPP-UTRAN-FDD;

²  3GPP-UTRAN-TDD;

²  3GPP2-1X;

²  3GPP2-1X-HRPD。

对于这类UE和P-CSCF来说,应支持SIP压缩,但不一定启用SIP压缩。UE和P-CSCF可以通过协商说明是否愿意使用SIP压缩。P-CSCF和通过无线方式接入的UE应符合IETF RFC3486定义的压缩协商机制以及IETF RFC3320中规定的信令压缩规范。

用于指示是否支持信令压缩的SIP机制见IETF RFC3486的规定,具体的方式是在Via头字段和SIP URI中分别扩展了一个comp参数,且目前为该参数只定义了一个值:comp=SigComp,用来指示是否愿意使用信令压缩。

信令压缩的具体规范见IETF RFC3486、IETF RFC3320、IETF RFC4896的规定。

20.6.2.  5.14.2 基本操作

如果UE在REGISTER请求的Contact头字段中添加“comp=SigComp”参数,则表示UE在后续的以自己为目的的初始请求中愿意采用压缩形式。

UE作为请求发起方,如果UE在初始请求的Contact头字段中添加“comp=SigComp”参数,则表示UE接受该对话的所有后续请求愿意采用压缩形式。

UE作为请求接收方,如果UE在初始请求的第一个响应中的Contact头字段中添加“comp=SigComp”参数,则表示UE接受该对话的所有后续请求愿意采用压缩形式。

如果UE在任何请求消息的Via头字段中添加“comp=SigComp”参数,则表示UE愿意接受对这个请求的所有响应采用压缩形式。

如果P-CSCF在发往UE的消息中对应于自己的Record-Route中添加“comp=SigComp”参数,则表示P-CSCF愿意接受该对话的后续请求采用压缩形式。

如果P-CSCF在任何请求的Via头字段中添加“comp=SigComp”参数,则表示P-CSCF愿意接受该请求的所有响应采用压缩形式。

 

20.6.3. 5.14.3 相关语法

与SIP信令压缩相关的扩展参数的语法如下:

²  对于URI来说,SIP压缩扩展的是“uri-parameter”:

compression-param =  "comp=" ("sigcomp" / other-compression)

other-compression = token

²  对于Via头字段来说,SIP压缩扩展的是“via-extension”参数:

via-compression = "comp" EQUAL ("sigcomp" / other-compression)

other-compression = token

 

20.7.        IMS网络中的SIP定时器

信令消息在空中接口的处理会带来传输的时延,因此YD/T 1522.1中规定的一些SIP定时器在某些情况下可能需要修改。表6给出在IMS网络中的一些SIP定时器的建议值。

表6的第一列给出了YD/T 1522.1定义的定时器;第二列给出了该这些定时器的默认值,适用于IMS网络中CSCF、MGCF等网元设备之间的通信,不适用于空中接口。

当UE通过无线方式接入到P-CSCF时,即P-Access-Network-Info头字段包含5.14.1节所提到的任意取值时,P-CSCF采用第三列的取值。其他情况下,P-CSCF还是采用SIP定时器默认的取值,即第一列的取值。

SIP定时器

SIP定时器

IMS网元默认设置

与无线接入的UE相连的P-CSCF

含义

T1

500ms(缺省)

2s

往返时间(RTT)的估值

T1

4s

16s

非INVITE请求和INVITE响应的最大重传间隔

T4

5s

17s

消息在网络中的最大时长

Timer A

Initially T1

Initially T1

INVITE重传间隔(UDP)

Timer B

64*T1

64*T1

INVITE事务超时定时器

Timer C

> 3min

> 3min

Proxy中的INVITE事务超时定时器

Timer D

> 32s(UDP)

> 128s

等待响应重传的时间

0s(TCP/SCTP)

0s(TCP/SCTP)

Timer E

初始的T1

初始的T1

非INVITE请求的重传间隔(UDP)

Timer F

64*T1

64*T1

非INVITE事务超时定时器

Timer G

初始的T1

初始的T1

INVITE的响应的重传间隔

Timer H

64*T1

64*T1

等待ACK的时间

Timer I

T4(UDP)

T4(UDP)

等待ACK重传的时间

0s(TCP/SCTP)

0s(TCP/SCTP)

Timer J

64*T1 for UDP

64*T1(UDP)

等待非INVITE请求重传的时间

0s(TCP/SCTP)

0s(TCP/SCTP)

Time K

T4(UDP)

T4(UDP)

等待响应重传的时间

0s(TCP/SCTP)

0s(TCP/SCTP)

 

20.8.        SIP协议的应用

IMS域网元实体在SIP消息流程中的具体行为详情见《IMS核心业务流程.doc》

20.8.1. P-CSCF处理过程

20.8.1.1. 概述

P-CSCF应支持Path和Service-Route头字段。Path头字段仅仅用于REGISTER请求和它的200OK响应中。Service-Route头字段用于注册请求的200OK响应消息中。

P-CSCF在向UE发送任何请求或者响应前,P-CSCF应去除消息中存在的P-Charging-Function-Addresses和P-Charging-Vector头字段。

一旦 P-CSCF接收到UE发出的任何响应或者请求,P-CSCF 将:

²  去除存在的P-Charging-Function-Addresses和P-Charging-Vector头字段并忽略该头字段中的数据。

²  在传递该消息时,可以插入先前保存的数据到P-Charging-Function-Addresses和P-Charging-Vector头字段中。

如果P-CSCF部署在拜访网络时,它忽略S-CSCF和I-CSCF发送来的消息的P-Charging-Function-Addresses。

当请求或响应消息中的P-Access-Network-Info头字段带有“network-provided”参数,P-CSCF应移除P-Access-Network-Info头字段

当P-CSCF 接收到来自S-CSCF 的任何请求和响应,P-CSCF 将去除消息体中P-Media-Authorization 头。

注3: 如果基于本地策略业务应用时,P-CSCF将插入P-Media-Authorization头,见5.2.7.2 和5.2.7.3。

注4: P-CSCF将对发往UE的注册和认证以外的SIP消息,进行安全性保护。P-CSCF将丢弃没有完整性保护的sip消息(注册和认证消息除外)。注册和认证处理中完整性保护和检查在5.2.2中进行了定义。

除了 305(Use Proxy)响应,P-CSCF 不会重复回复3xx 响应。

20.8.1.2. 注册

P-CSCF应使用SIP默认端口接收初始注册请求。P-CSCF仅使用相同的端口接收后安全保护的注册消息及后续的SIP消息,无需使用协商端口交换受保护的消息。

当P-CSCF 接收到一个UE发起的注册请求:

1) 在消息体中增加一上Path头字段,并将P-CSCF的SIP URI设置到Path头字段中,使以后所有发送给用户的消息都经过P-CSCF传送

2) 增加Require头字段,包括“path”选项标签;

3) 增加P-Visited-NetWork-ID头字段,内容是自己的网络标识,归属网络通过该标识可获目前正服务于用户的拜访网络

4) 插入P-Charging-Vector头,包括icid、orig-ioi等参数,参看3GPP TS 32.260 中的描述;

5) 当注册请求受到认证过程中的完整性保护且包括认证挑战响应,或者该请求在成功认证后安全关联创建且没有认证挑战响应时,在Authorization头中,插入"integrity-protected"参数值设置为"yes",其他情况该参数设置为“No”。

5) 当注册请求没有完整性保护时,将检查Security-Client是否存在。如果存在,则去除并保存,如果不存在,P-CSCF则回复4xx响应。

6) 当注册请求带有完整性保护,则P-CSCF应:

a) 检查受保护请求的安全关联。如果安全关联是一个临时的,于是请求消息中期望带上Security-Verify和Security-Client头字段。如果没有,P-CSCF将返回4xx响应。如果有,P-CSCF将对比请求消息中Security-Verify和P-CSCF发送给UE的认证消息中Security-Server内容,以及请求中Security-Client和被挑战注册请求中Security-Client内容。如果不匹配,可能存在中间攻击。该请求应该被拒绝,通过发送4xx响应。如果匹配,P-CSCF将去除Security-Verify 和Security-Client头。

b) 如果注册请求中安全关联已经建立,则:

- 消息体中如果有Security-Verify头,则P-CSCF将去除之;

- Security-Client头中包含新的参数值,如果缺少该头或者必须的参数,P-CSCF将返回4xx响应。

- P-CSCF将传递消息给S-CSCF前,将保存并去除Security-Client头中内容;

c) P-CSCF将检查具有完整性保护的注册消息中Authorization头中的私有用户标识是否与先前被挑战或被认证的私有用户标识一致。如果不同,P-CSCF回复403(Forbidden)响应。

7) 插入P-Visited-Network-ID头,设置为先前提供的,用于标识拜访网络的值。

8) 决定归属网络的I-CSCF,并将请求消息发往该I-CSCF。

如果被选择的I-CSCF:

- 不响应注册请求,仅作为中继,或者

- 对于注册请求,发送3xx(重定向)响应和480(临时无效)响应,

则P-CSCF将选择一个新的I-CSCF,并发送初始的注册请求。

注1: I-CSCF的列表可以是RFC 3263中描述获得,或者在P-CSCF中设定的。

如果P-CSCF传递注册请求到I-CSCF失败,P-CSCF将发送408(请求超时)响应或者504(服务器超时)响应,参看RFC3261处理过程。

当 P-CSCF 接收到注册请求的401(未鉴权)响应时:

1) 删除与UE之间,临时建立的安全关联;

2) 移除401响应消息中的CK IK参数,并与对应的私有用户标识和临时安全关联进行绑定。当移除CK、IK后,P-CSCF将传递401响应给UE。

3) 插入Security-Server头,头中包括P-CSCF静态安全列表和3GPP TS 33.203 附录H中描述的安全关联参数。在RFC 3329中,P-CSCF将支持"ipsec-3gpp"安全机制。在Ipsec层算法上,P-CSCF 将支持HMAC-MD5-96 (RFC 2403 [20C]) 和HMAC-SHA-1-96(RFC 2404) ;

4) 利用UE和P-CSCF之间私有用户标识的临时SIP层生命期,建立一个临时安全关联。进一步描述参看3GPP TS 33.203 [19] 和 RFC 3329 [48]。P-CSCF将设置临时SIP层生命期为临时安全关联等待注册鉴权时间。

用注册请求受保护的安全关联向UE发送401响应,或者用注册请求没有受保护的安全关联发送响应。

注2: S-CSCF发送到UE的401挑战响应,作为注册的响应,P-CSCF插入Security-Server头。

P-CSCF在注册过程中,和UE之间协商和设置两套安全关联设置,S-CSCF将对UE进行认证。进一步的描述参看3GPP TS 33.203 [19]。

当 P-CSCF 接收到注册请求的200OK 响应时,P-CSCF 将检查Expires 头或者contact 头中expires 中的值。如果值不等于0,P-CSCF 将:

1) 按照顺序保存Service-Route头列表,P-CSCF将为各个公有用户标识保存注册有效期。P-CSCF将用列表作为可用路由信息。如果注册是刷新注册,P-CSCF将取代已存在的Service-Route列表。

2) 关联Service-Route头列表和已注册的公有用户标识(难道不同pui会不同的Service-Route?);

3) 存储P-Associated-URI头中,与注册的公有用户标识相关联的公有用户标识。

4) 存储P-Associated-URI头列表中第一公有用户标识作为默认公有用户标识,以便后续使用。

注3: 当多个公有用户标识注册时,P-CSCF可能存储多个默认公有用户标识。

5) 存储P-Charging-Function-Addresses中的值;

6) 如果安全关联有效,设置安全关联的SIP层生命期,采用先前存在的安全关联生命期和完成的注册生命期加上30s,两者间的最大值。

7) 如果存在的是临时安全关联,则改变其为新的安全关联设置,比如采用先前存在的安全关联生命期和完成的注册生命期加上30s,两者间的最大值来设置SIP层生命期。

8) 采用请求消息采用的安全关联的保护措施,进行200OK响应的保护。

当 P-CSCF 从UE 接收到基于新的安全关联的SIP 消息(包括注册请求),而P-CSCF 侧还没有使用新的安全关联,则:

1) 减少安全关联老的设置的SIP层生命期为64*T1(如果当前值大于64*T1);

2) 对后续给UE的消息采用新建立的安全设置(如将新建立的安全关联投入使用)。

注4: 在上述情况下,P-CSCF将基于新建立的安全关联发送请求到UE。在UDP层,发送给UE的响应采用新建立的安全关联;在TCP层,发送给UE的响应采用与请求一致的安全关联。

注5: 当从UE接收到SIP消息(包括注册请求)采用一套不同于P-CSCF新建立的安全关联设置,P-CSCF将不会对安全关联设置采取任何行为。

当老的安全关联的 SIP 层生命期到期,如SIP 层生命期小于64*T1,并且新建立安全关联还未建立使用,对后续发往UE 的消息,P-CSCF 将用新建立的安全关联(见注3)。

当 P-CSCF 发送注册请求的200OK 响应中,包括re-authentication,P-CSCF 将:

1) 保持用于重认证的注册请求的安全关联设置;

2)保存在认证过程中新建立的安全关联;

3) 如果存在其他安全关联设置,删除之;

4) 对于后续发送给UE的请求,继续使用用于重认证的注册请求的安全关联设置。

当发送决定初始认证的注册请求的 200OK 响应时,如初始注册请求未受保护,P-CSCF 将:

1) 保存在认证过程中创建的安全关联设置;

2) 如果存在其他安全关联设置,删除之;

3) 在后续发给UE的消息,采用新建立的安全关联设置。

注6 : P-CSCF保持着两套路由头列表。第一套路由头列表是注册时创建的,仅用于UE发起的初始请求。这个列表对每个公有用户标识的注册有效。第二套路由列表是在从初始Invite消息和关联响应的Record Route头中构建的,用于对话的过程中。一旦对话终止,则丢弃第二套路由列表。

当 SIP 层生命期超时,P-CSCF 将从Ipsec 数据库中删除安全关联。

20.8.1.3. 订阅注册用户状态事件包

一旦接收到用户注册请求的 200OK 响应,P-CSCF 将向S-CSCF 订阅注册事件包,RFC3680中有描述。

1) 产生一个订阅请求,包括下面元素:

- Request-URI设置为P-CSCF希望订阅的源,比如默认公有用户标识的SIP URI;

- From头,设置为P-CSCF的SIP URI;

- To头,设置为包含默认公有用户标识的SIP URI;

- Event头,设置为“reg”;

- Expires头,设置为注册请求200OK响应中Expires头的值大;

- P-Asserted-Identity头,设置P-CSCF的SIP URI,该P-CSCF是在用户注册Path头中插入的那个P-CSCF。

- P-Charging-Vector头,包括TS 32.260描述的icid参数;

2) 决定归属网络的I-CSCF(如用DNS服务);发送订阅请求去 I-CSCF 前的处理过程见RFC3261。

一旦接收到订阅请求的 2xx 响应,P-CSCF 将存储已建立的对话的信息,和Expires 头中的超期时间值。

如果要求连续订阅,则在先前注册的公有用户标识超期前600s,或者当初始订阅超期时间大于1200s 时,在超期前600s 时,或者当初始订阅超期时间小于1200s 时,在超过一半时间时,P-CSCF 将用注册事件包自动刷新订阅。

20.8.1.4. 多公有用户标识的注册

一旦接收到订阅请求的 2xx 响应,P-CSCF 将维持产生的对话(对话是通过Call-ID, To 和From 标识的)

在订阅注册事件包过程中产生了对话,一旦接收到一个关于该对话的NOTIFY 请求,P-CSCF将执行如下操作:

1) 对于每个公有用户标识,各自的<registration>中的状态属性设置为"active"时;

- 隶属于<registration>下的<contact>中状态属性设置为"active";

- 隶属于<registration>下的<contact>下<uri>中,设置为UE的contact地址;- <contact>中event属性设置为"registered" or "created";

P-CSCF将:

- 绑定注册的公有用户标识与各个用户的contact信息。

- 增加公有用户标识到用户已注册的公有用户标识列表中;

2) 对于每个公有用户标识,各自的<registration>中的状态属性设置为"active"时;

- 隶属于<registration>下的<contact>中状态属性设置为"terminated";

- 隶属于<registration>下的<contact>下<uri>中,设置为UE的contact地址;

- <contact>中event属性设置为"deactivated", "expired", "probation", "unregistered", 或者"rejected";

P-CSCF将认为指示的共有用户标识将为用户而注销,并释放各自用户该公有标识的存储信息。

3) 对于每个公有用户标识,各自的<registration>中的状态属性设置为"terminated"时;

- 隶属于<registration>下的<contact>下<uri>中,设置为UE的contact地址;

- contact>中event属性设置为"deactivated", "expired", "probation", "unregistered", 或者"rejected";

P-CSCF将认为指示的公有用户标识将为UE而注销,并释放各自用户这些公有标识的所有存储信息,并从用户已经注册的公有用户标识列表中移除这个公有用户标识。

如果用 PVI 注册的所有PUI 都被注销了,P-CSCF 将接收到来自S—CSCF 的NOTIFY 请求,

该请求可以如5.4.2.1.2 所述,订阅状态设置为"terminated"。如果该请求的订阅状态没有设置为"terminated",P-CSCF 可能不订阅注册事件包,或者让订阅超时。

注1: 一旦收到一个NOTIFY请求,且请求消息中Subscription-State头设置为"terminated",P-CSCF认为订阅注册事件包终止(比如P-CSCF已经发送了一个订阅请求,请求中Expires头为0)。

注2: 当用户注册一个公有用户标识时,S-CSCF可能隐式注册多个公有用户标识。下面段落提供了一套机制通知P-CSCF关于隐式注册的多个公有用户标识。

20.8.1.5. 注销

20.8.1.5.1.  用户发起的注销

 

当 P-CSCF接收到注册请求的200OK响应时,P-CSCF将检查消息体Expries头和/或Contact头中expires字段中的值。如果值为0,P-CSCF 将:

1) 去除To头中的拥有用户标识,并且从已注册的公有用户标识列标重去除所有关联的公有用户标识和存储的信息。

2) 检查是否UE已经留下其它已注册的公有用户标识。当所有UE已注册的公有用户标识都被注销了,P-CSCF将删除与UE间的安全关联,在服务器事务(见RFC3261)执行注销终止后。

注 1 : 一旦接收到NOTIFY请求,请求中<registration>中状态属性设置为"terminated"(如所有公有用户标识都被注销)和Subscription-State头设置为"terminated",P-CSCF认为订阅注册注册事件包终止(就如P-CSCF发送一个订阅请求,请求中Expries头设置为0)。

注 2 : 目前没有区分注册请求和注销请求的需求,P-CSCF因为管理原因,可以区分注册和注销请求,但是在SIP层处理注册和注销是没有差别的。

注 3 : 当注册请求仅对应于一个已注册公有用户标识,但隐式注册关系到其它几个公有用户标识,当P-CSCF发送该请求的200OK响应,P-CSCF将去除和UE间的安全关联。

所有后续SIP信令无法到达UE。

 

20.8.1.5.2.  网络发起的注销

一旦接收到关于订阅注册事件包产生的对话的 NOTIFY 消息,见5.2.3 中描述,消息体中保护一个或者多个<registration>元素,都是UE 已经注册的。

- state属性设置为"terminated";

- state属性设置为"active",且<contact>中state状态设置为"terminated",关联的事件属性设置为"rejected" 或"deactivated";

P-CSCF 将去除这些公有用户标识的的所有存储信息,去除该用户已经注册的公有用户标识列表。

一旦接收到 NOTIFY请求,请求中<registration>state 属性为"terminated"(也就是所有公有用户标识都注销),且Subscription-State头设置为"terminated"或者当所有公有用户标识都注销,P-CSCF将降低与UE 间的安全关联。

注 1 : P-CSCF和UE间的安全关联降低等级,允许包含注销事件得NOTIFY请求到达UE。

注 2 : 当P-CSCF接收到NOTIFY请求,请求中Subscription-State头为"terminated",P-CSCF认为订阅事件包终止(也就是像P-CSCF向S-CSCF发送一个订阅请求,请求中Expires设置为0)。

20.8.1.6. REGISTER方法之外的所有对话和一般事务的一般处理

20.8.1.6.1.  介绍

本节流程对除了REGISTER 方法以外的所有请求和响应适用

20.8.1.6.2.  MOMT的确定

当接收了一个初始请求或者目标刷新或者单独事务,P-CSCF:

――如果请求利用了终呼的信息,将按照20.8.1.6.4节描述的来执行终呼流程。在注册时终呼信息被增加到Path 消息头(即P-CSCF 入口),例如,消息从特定的端口获得或者最顶端Route 头包含了特殊的用户部分或者参数。

――如果以上信息没有被请求使用,则执行起呼流程,见20.8.1.6.3节所述。

20.8.1.6.3.  UE发起的请求

当 P-CSCF 收到对话或者单独事务的初始请求,并且请求中P-Preferred-Identity头字段匹配已经注册的公有用户标识,P-CSCF确定该公有用户标识为请求发起者。

当 P-CSCF 收到对话或者单独事务的初始请求,并且请求中P-Preferred-Identity头字段不匹配任何一个已经注册的公有用户标识,或者请求没有包含P-Preferred-Identity头字段,P-CSCF将缺省的公有用户标识确定为请求发起者。如果有一个以上的缺省公有用户标识,P-CSCF从中随机抽取一个。

注1:From头不构成任何确定流程的部分。

当 P-CSCF从UE收到的对话或者单独事务的初始请求,并且关于请求的发起者的Service-Route列表存在,P-CSCF 将:

1) 验证收到的在Service-Route头(在最后一次成功注册或者重注册期间)中的URI列表是否和接收的请求中的预加载的Route 头是否匹配。不是整个字符串而是一个一个URI进行验证。如果验证失败,P-CSCF 要么:

a) 返回400(Bad Request)响应,响应可能存在包含有警告代码399 的Warning 头;

P-CSCF 不会前转该请求,并且不将继续Step 2 以后的操作;或者b)使用注册或者重注册回的最后200OK 响应消息所带的Service-Route 头替换预加载Route 头;

2) 增加自己的地址到 Via头。按照RFC3261流程,P-CSCF的Via头以包含P-CSCF端口号的格式,以及:

a) P-CSCF的可以解析为IP地址的FQDN,或者

b) P-CSCF的IP地址;

3) 当增加自己的SIP URI到Record-Route头顶部,按照包含P-CSCF端口号(等待被叫的后续请求)的格式,以及:

a) P-CSCF 的可以解析为IP 地址的FQDN,或者

b) P-CSCF 的IP 地址;

4) 如果存在P-Preferred-Identity头,则要移除,并插入P-Asserted-Identity消息头,代表请求发起者的值;

5) 按照规范3GPP TS 32.260增加带有icid参数的P-Charging-Vector。

6) 如果是INVITE 请求,还要保存请求中Contact, CSeq, 以及Record-Route 头的值,以便必要的时候P-CSCF 能够释放会话;(完成以上步骤后),按照RFC3261,基于最顶端 Route 头,前转该请求。当 P-CSCF 收到以上请求的1XX 或者2xx 响应,P-CSCF 将:

1) 保存P-Charging-Function-Addresses 消息头的值;

2) 保存Record-Route 的列表;

3) 保存Dialog ID,并且与会话的私有用户标识和公有用户标识关联;

4) 重新填写自己的Record Route 为与主叫协商的被保护服务器的端口号,依照RFC3485附加压缩参数;并且

注 2:对于每一对安全关联,P-CSCF 关联两个端口,一个是保护服务器端口,一个是保护客户端端口。如何选择保护端口,参照3GPP TS 33.203。

5) 如果该响应与INVITE 请求相对应,保存Contact, From, To 和Record-Route 头,以便必要时能够释放会话。

在按照 RFC3261[26]进行前转响应到UE 之前,需要进行以上操作。

当 P-CSCF 收到UE 发送的对话的目标刷新请求,P-CSCF 将:

1) 验证请求的发起者是否关联了一个对话:

a) 如果请求没有与请求发起者有关的现存的会话,P-CSCF 将向发起者发送403(Forbidden)响应。响应可能保护带有warn-code 399 的Warning 头。P-CSCF 不将前转该请求。不需要其他的操作;或者

b) 如果请求有与请求发起者有关的现存的会话,P-CSCF 继续下面的步骤;

2) 验证请求中的Record-Route 头列表和本地保存的同一个对话的列表是否匹配。验证是按一个一个URI 进行比较,而不是整个字符串匹配。如果匹配失败,P-CSCF 将:

a) 返回400(Bad Request)响应。响应可能包含带有warn-code 399 的Warning 头;P-CSCF也不前转该请求,同时也不进行Step 3 以后的步骤;或者

b) 使用本地保存的同一个对话的Recodr-Route 中的列表替换Route 头的值。

3) 增加自己的地址到Via 头。按照RFC3261[26]流程,P-CSCF 的Via 头以包含P-CSCF端口号的格式,以及:

a) P-CSCF 的可以解析为IP 地址的FQDN,或者

b) P-CSCF 的IP 地址;

4)当增加自己的SIP URI 到Record-Route 头顶部,按照包含P-CSCF 端口号(等待被叫的后续请求)的格式,以及:

a) P-CSCF 的可以解析为IP 地址的FQDN,或者

b) P-CSCF 的IP 地址;

5) 对于INVITE 对话(例如,由INVITE 请求发起的对话),用请求中的Contact 和CSeq头替换本地保存的,以便P-CSCF 必要时能够释放会话;

注3:只有收到1xx或者2xx响应,保存的contact和CSeq才有效。对于其他情形,以前的仍然有效。

按照 RFC 3261[26]流程,基于最顶端Route 进行前转请求之前,需要进行以上步骤。

当 P-CSCF 收到以上请求(刷新)的1xx 或者2xx 响应后,P-CSCF 将:

1) 和收到初始请求的响应一样,需要重新填写自己的Record Route 为与主叫协商的被保护服务器的端口号,依照RFC3486[55]附加压缩参数;并且

2) 使用响应中携带的Contact 头值取代保存的Contact 头,以便P-CSCF 在必要的时候释放会话。

在按照 RFC 3261[26]流程进行前转响应到UE 之前,进行以上操作。

当 P-CSCF 收到来自单独事务的UE 的请求,并且对于请求发起者的Service-Route 头列表存在,P-CSCF 将:

1) 验证收到的在Service-Route 头(在最后一次成功注册或者重注册期间)中的URI

列表是否和接收的请求中的预加载的Route 头是否匹配。不是整个字符串而是一个一个URI进行验证。如果验证失败,P-CSCF 要么:

a) 返回400(Bad Request)响应,响应可能存在包含有警告代码399 的Warning 头;P-CSCF 不会前转该请求,并且不将继续Step 2 以后的操作;或者

b)使用注册或者重注册回的最后200OK 响应消息所带的Service-Route 头替换预加载Route 头;

2) 如果存在P-Preferred-Identity 头,则要移除,并插入P-Asserted-Identity 头,代表请求发起者的值;并且

3) 增加带有icid 参数P-Charging-Vector 头,见 3GPP TS 32.260[17];(完成以上步骤后),按照RFC3261,基于最顶端Route 头,前转该请求。

当收到以上请求(单独事务)的响应,P-CSCF 将:

1)保存P-Charging-Function-Addresses 头的值;

完成以上步骤后,按照 RFC3261[26]前转该响应到UE。

当P-CSCF 收到来自UE 的后续请求,但不是目标刷新请求(包括关联一个已经存在的对话,但是该方法未知),P-CSCF 将:

1) 验证请求的发起者是否关联了一个对话:

a) 如果请求没有与请求发起者有关的现存的会话,P-CSCF 将向发起者发送403(Forbidden)响应。响应可能包含带有warn-code 399 的Warning 头。P-CSCF 不将前转该请求。不需要其他的操作;或者

b) 如果请求有与请求发起者有关的现存的会话,P-CSCF 继续下面的步骤;

2) 验证请求中的Record-Route 头列表和本地保存的同一个对话的列表是否匹配。验证

是按一个一个URI 进行比较,而不是整个字符串匹配。如果匹配失败,P-CSCF 将:

a) 返回400(Bad Request)响应。响应可能包含带有warn-code 399 的Warning 头;P-CSCF也不前转该请求,同时也不进行Step 3 以后的步骤;或者

b) 使用本地保存的同一个对话的Recodr-Route 中的列表替换Route 头的值。

3) 对于非INVITE 对话,增加一个带有icid 参数的P-Charging-Vector 头,见3GPP TS 32.260; 并且

4)对于INVITE 对话,使用收到的请求中的Cseq 替换保存的Cseq 头,以便P-CSCF必要时能够释放会话。

按照 RFC 3261流程,基于最顶端 Route 进行前转请求之前,需要进行以上步骤。

当 P-CSCF 收到UE 的未知方法的请求(未与存在对话关联),并且存在该请求发起者的Service-Route 头,P-CSCF 将:

1) 验证Service-Route 头(最后一次成功注册或者重新注册获得)中包含的URI 列表是否为请求中预加载Route 头的子集。验证是一个一个URI 进行,而不是整个字符串。如果验证失败,P-CSCF 将:

a) 返回400(Bad Request)响应。响应可能包含带有warn-code 399 的Warning 头;P-CSCF不前转该请求,并且不进行Step 2 以后的步骤;或者

b) 使用最后一次注册的200OK 响应中的Route 头的值代替请求中Route 头;并且

2) 如果存在P-Preferred-Identity 头,移除该头,插入P-Asserted-Identity 头,代表当前请求的发起者。

在按照 RFC 3261流程,基于Route 头进行前转请求之前,进行以上操作。

20.8.1.6.4.  请求在UE终止

 

posted @ 2016-06-16 15:05  StevensFollower  阅读(32092)  评论(0编辑  收藏  举报