1.2 SIP协议功能、背景和前景
Address-of-Record:Address-of-Record(AOR)是一个SIP或SIPS URI,它指向带位置服务的一个域,位置服务可以将一个URI与另一个URI(可能找到用户的URI)映射。典型的,通过注册来填写位置服务。通常认为AOR是用户的“公开地址”。
Call:呼叫是一个非正式术语,它是指对等实体间的通信,通常是建立多媒体对话。
Call Stateful:如果一个代理从初始INVITE到终止BYE请求都保留了对话的状态,那么该代理有呼叫状态。有呼叫状态代理通常是有状态事务。但反之则不一定成立。
Conference:包含多个参与者的多媒体会话。
Dialog:对话是两个UA间持续一段时间的对等SIP关系。对话由SIP消息建立,如INVITE请求的2xx响应。用呼叫标识符、本地标签和远程标签标识对话。对话即RFC2543中的呼叫腿。
Final Response:终止SIP事务的响应,与不终止SIP事务的临时响应相反,所有2xx、3xx、4xx、5xx和6xx响应都是最终响应。
Header Field:头字段是SIP消息头的一个组件。一个头字段可以是一个或多个头字段行。头字段行由一个头字段名和零或多个头字段值组成。给定的头字段行中的多个头字段值用逗号隔开。某些头字段只能有一个头字段值,因此,它们通常只有一个头字段行。
Home Domain:此域为SIP用户提供服务。典型的,它通常是注册的记录地址中URI中出现的域。
Initiator, Calling Party, Caller:用INVITE请求发起会话(和对话)的一方。从发送建立对话的初始INVITE请求到该对话终止,呼叫者保持此角色。
Invitee, Invited User, Called Party, Callee:接收用于建立新会话的INVITE请求的一方。从接收用于建立对话的初始INVITE请求到该对话终止,被呼叫者保持此角色。
Loop:一个请求到达代理,然后被转发,最后又返回到同一个代理。当请求第二次到达代理时,Request-URI与第一次相同,其它影响代理操作的头字段也不变,因此代理能对该请求作出与第一次相同的处理决定。循环的请求是错误的,由协议描述检测和处理循环请求的程序。
Message:协议中SIP元素间发送的数据。SIP消息是请求或响应。
Outbound Proxy:从客户端接收请求的代理,尽管它可能不是Request-URI解析的服务器。一般手动为UA配置一个出站代理,或通过自动配置协议获知一个代理。
Provisional Response:服务器使用该响应指示进行的响应,该响应不终止SIP事务。1xx响应是临时响应,其它响应都认为是最终响应。
Recursion:当客户端在响应的Contact头字段中产生一个或多个URI的请求时,客户端递归一个3xx响应。
Registrar:注册员是服务器,它接收REGISTER请求,并把从请求中接收的信息放入其所在的域的位置服务中。
Request:为调用一个特殊的操作。客户端向服务器发送的SIP消息。
Ringback:回铃是呼叫者的应用产生的信令音调(signalingtone),表明被呼叫者正在响铃。
Server:服务器是一个网络元素,它接收请求,并为这些请求发送响应。服务器的实例有代理、用户代理服务器、重定向服务器和注册员。
Session:在SDP规范中这样描述:“多媒体会话是多媒体发送者、接收者以及发送者和接收者间数据流的集合。多媒体会议是多媒体会话的实例。”(RFC2327[1])(定义的SDP会话包含一个或多个RTP会话。)正如所定义的,在同一会话中,被呼叫者可以被不同的呼叫邀请多次。如果使用SDP,会话由源字段中的SDP用户名、会话ID、网络类型、地址类型和地址元素的串接定义。
Spiral:螺旋是发送到代理,继续转发,再次回到该代理的SIP请求,但是这次将做出不同于原始请求的处理决定,通常表示请求的Request-URI与先前的不同。螺旋不是一个错误情况,与循环不同。典型的原因是呼叫转发。一个用户呼叫joe@example.com.com,代理将其转发到Joe的PC,PC反之将其转发给bob@example.com。该请求再次转发到.com代理。但是,这不是循环。因为此时该请求的目标用户不同于上次,它被称为螺旋,这是一种有效的情况。
Stateless Proxy:本规范定义的在处理请求过程中,不维持客户端和服务器事务状态机的逻辑实体。无状态代理转发它从下游接收到的每个请求和从上游接收的每个响应。
Target Refresh Request:将在对话中发送的目标更新请求定义为请求,它能修改对话的远程目标。
Upstream:事务中消息的转发方向,它是指响应从用户代理服务器流向用户代理客户端的方向。
User Agent Client(UAC):用户代理客户端是创建新请求,然后使用客户端事务状态机发送请求的逻辑实体。UAC角色仅存在事务的持续时间内。换言之,如果软件发起一个请求,它仅在该事务的持续时间内是一个UAC。如果随后它接收到一个请求,在处理此事务时,它被假想成一个用户代理服务器角色。
User Agent Server(UAS):用户代理服务器是一个逻辑实体,它产生SIP请求的响应。响应接收、拒绝和重定向请求。该角色仅存在于事务期间。换言之,如果软件对请求作出响应,那么它在事务期间就是UAS。如果随后它产生一个请求,那么在处理事务的期间我们就把它假想成用户代理客户端。
User Agent(UA):既能作为用户代理客户端又能作为用户代理服务器的逻辑实体。角色UAC和UAS,以及代理和重定向服务器都是定义在事务的基础上的。例如,当用户发起一个呼叫发送初始INVITE请求时,它作为UAC;当它从被呼叫者接收BYE请求时,作为UAS。类似的,同一软件能作为一个请求的代理服务器和下一个请求的重定向服务器。以上定义的代理、位置和注册服务器都是逻辑实体。实现时可能将它们结合到一个应用中。
一个服务器在正常呼叫时作为Proxy Server,而如果其所管理的用户移动到了别处,或者网络对被呼叫地址有特别策略,则它就成了Redirect Server,告知呼叫发起者该用户新的位置。。
4.1. 请求
Request-Line以CRLF结束。除在终止行CRLF序列中外,其它的地方都不允许CR或LF。在元素中不允许任意数量的空格(LWS)。
Method:用于注册Contact信息的REGISTER;用于建立会话的INVITE、ACK和CANCEL;用于终止会话的BYE和用于查询服务器能力的OPTIONS。用于即时消息的MESSAGE;SIP扩展在RFC中可能有附加方法。
SIP元素可能支持“SIP”和“SIPS”以外的Request-URI模式,如RFC 2806中的“tel”URI模式。SIP元素可使用任何机制将非SIPURI转换成SIPURI、SIPS URI或其它模式。
与HTTP/1.1不同,SIP将版本号视为字符串。而实际上,这是没有区别的。
SIP响应在起始行中有一个Status-Line,作为与请求的区分。Status-Line依次由协议版本号、数字Status-Code和以及相关的文本分析(textual phrase)组成,它们之间用字符SP隔开。
Status-Line=SIP-Version SP Status-Code SP Reason-Phrase CRLF
建议这些原因分析的一些特定用语,实现可以先用其它的文本,例如,在请求的Accept-Language头字段中指明的语言。
1xx:informational-已经收到请求、继续处理请求。
3xx:Redirection-为完成呼叫请求,还须采取进一步地动作。
5xx:ServerError-服务器出错,不能执行合法请求。
例如:
4.3. 头字段
HTTP/1.1中指出其值用逗号分隔的、具有相同字段名的多个头字段能组合成一个头字段。这同样适用于SIP,但对不同的语法有特殊的规则。特别的,SIP头的语法格式如下:
它允许将名称相同的头字段组合成用逗号分隔的一列。除非头字段值为“*”,Contact头字段允许用逗号分隔。
头字段遵循RFC 2822的第2.2节中的通用头格式。每个头字段依次由:字段名、冒号“:”和字段值组成。
消息头的正式语法允许冒号的两边有任意多个空格;但是,实现时应避免字段名和冒号间的空白,在冒号和字段值间使用一个空格(SP)。
Subject : lunch
Subject: lunch
头字段可扩展为多行,方法是在每个附加行前添加一个空格(SP)或横向制表(HT)。一行的结束以及下一行开始的空格都看作一个空格(SP)字符。因此,以下两种方式意义相同:
Subject: I know you’re there,
and talk to me!
实现应能以每行一值或逗号分隔值的格式处理相同名称的多个头字段行。
Route:
Route:
Route:
Subject: Lunch
Route:
Route:
Route:
Route:
Route:
Route:
field-name: field-value*(;parameter-name=parameter-value)
Contact:
且Content-Disposition: session;handling=optional与
以下两个头字段意义不同:
Warning:370 dev null "CHOOSE A BIGGER PIPE"
4.4. 消息体
消息体的Internet媒体类型由Content-Type头字段指定。如果对体进行了任何编码,如压缩,那么必须在Content-Encoding头字段中指出。否则,必须省略Content-Encoding。如果可行,消息体的字符集作为Content-Type头字段值的一部分。
SIP消息可能包含二进制体或体部分。如果发送者没有明确指定字符集参数,定义“文本”类型的媒体子类型有默认的字符集值“UTF-8”。
在Content-Length 头字段中指定以字节计算的体长度。第20.14 节详细描述了头字段的必须内容。
用户代理表示终端系统。它包括用户代理客户端 (UAC)和用户代理服务器(UAS),UAC生成请求,UAS响应请求。外部因素(用户点击按钮或PSTN线信号)促使UAC生成请求,并处理响应。UAS接收请求,并且根据用户输入、外部因素、程序执行结果或者其它机制,生成响应。
UAC和UAS过程取决于两个因素。第一个是,请求或响应是在对话的内部还是外部;第二个是,请求的方法。
5.1. UAC行为
5.1.1. 生成请求
Request-URI消息初始Request-URI应该设置成To字段的URI值。但应注意,REGISTER方法例外。保密性原因或者便于将这些字段设置成相同的值(特别是在传输过程中,原始UA期望改变Request-URI),可能不符合需要。
To To头字段首先指明了想要的请求的“逻辑”接收者或者用户的记录地址或者作为请求目标的资源。这不一定是请求的最终接收者。To字段可能包含SIP或者SIPS URI,在适当的时候,它也可以使用其它URI模式(例如,tel URL (RFC 2806 [8]))。所有SIP执行必须支持SIPS URI模式。任何支持TLS的执行必须支持SIPS URI模式。
当UA 不希望指明应该解释用户输入的电话号码的域时,可以使用tel URL。相反,UA希望指明请求通过的每个域。例如,在飞机场的用户可能已经登机,通过飞机场的带外代理发送请求。如果键入“411”(美国本地目录帮助的电话号码),这需要通过飞机场——而不是用户归属域的带外代理解释并处理它。在这种情况中,tel:411 将是正确的选择。
From From头字段表示请求发起者的逻辑身份,有可能是用户的记录地址。和To字段一样,它包含了URI和显示名称,显示名称是可选的。SIP元素用它来确定应用于请求的处理规则(如,自动呼叫拒绝)。同样地,因为没有逻辑名字,不包含IP地址或者UA运行主机的正式域名的From URI很重要。
通常,特殊UA产生的、在请求中填充到From头字段的值是用户或者用户本地域的管理员预先提供的。如果多个用户使用特殊UA,那么,它具有可交换的描述,包括对应于描述用户身份的URI。为了确定它们是From 头字段所声称的人,请求的接收者可以认证请求的发起者。
Call-ID Call-ID头字段作为集合一系列消息的唯一标识符。在对话中,每个UA 发送的所有请求和响应中,Call-ID 必须是一样的。UA 的每个注册中,它应该是一样的。
推荐在生成Call-ID 时,使用密码学上的随机标识符(RFC 1750 [11])。执行时可以使用这种格式“localid@host”。Call-ID 是区分大小写的,并且逐字节比较的。
对于选择请求的Call-ID 头字段的值,不需要规章界面或用户界面。
Max-Forwards Max-Forwards头字段是用作限制请求传输到其目的地跳跃的点数。它是一个整数,在每个跳跃点上减一。如果请求在到达其目的地之前,Max- Forwards 值到0,将返回483(太多跳跃点)错误响应,拒绝其请求。
Via Via头字段表示事务中使用的传输,并标识了响应发送的位置。仅在选择了要到达的下一个跳跃点后(这可能包括[4]中过程的使用),才在传输中加上Via 头字段的值。
对于UA发送的所有请求,其分支参数的值必须在时间和空间上是唯一的。此规则的异常是CANCEL和非2xx 响应的ACK。CANCEL请求有与它取消的请求相同的分支值。非2xx 响应的ACK也有与它所应答的INVITE响应相同的分支ID。
当请求是通过传输层处理的,那么将发送Via头的maddr、ttl 和sent-by组件。
如果Request-URI或top Route头字段值包含SIPS URI,Contact头字段也必须包含SIPS URI。
列出的可选标签必须引用标准协议栈RFC中定义的扩展。这就防止了服务器为了接收
如果UAC坚持要UAS理解,UAC为处理请求而用于请求的扩展,它必须在请求中插入Require头字段,列出这些扩展的可选标签。如果UAC希望将扩展用于请求中,并坚持它所要经历的任何代理都可以理解这些扩展,它必须在请求中插入Proxy-Require头字段,列出这些扩展的可选标签。
Additional Message Components 在创建了新请求,并合理地构造上面所介绍的头字段后,可以添加任何其他的可选头字段,作为具体方法的头字段。
5.1.2. 发送请求
请求的目的地是可计算的。除非有本地的策略指明,目的地必须通过[4]中介绍的DNS过程才可以确定。如果路由集合中的第一个元素指示了严格的路由器,那么必须将DNS过程用于请求的Request-URI。否则,必须将DNS过程用于请求中的第一个Route头字段(如果存在),如果没有Route 头字段,将DNS过程用于请求的Request-URI。这些过程产生有序的地址集合、端口和传输。如果Request-URI指定SIP源,那么与过程[4]使用哪个URI无关;如果输入的URI是SIPS URI,那么UAC必须遵循过程[4]。
这确保了没有添加Record-Route头字段值的带外代理将不参与随后请求的路径。它也允许不能解析第一个Route URI的终端,将此任务委派给带外代理。
5.1.3. 处理应答
响应最初是在传输层处理,然后传输到处理层。处理层完成其处理,然后将响应传输到TU。TU的大多数响应处理是指定方法的。但是,还有一些通用的行为与方法无关。
Unrecognized Responses UAC必须将其不识别的最终响应视为对等于x00类的响应代码,并且,UAC必须能够处理所有的x00响应代码。
Vias 如果在响应中存在不止一个Via头字段,那么UAC应该丢弃这些信息。在请求发起者之前的其他Via 头字段值的状态,暗示消息是错误指向的或者是不可靠的。
任何新请求都可能接收到包含其自己原始URI的3xx响应作为联系。两个位置可以互相配置成重定向。将任何给定的URI 仅在目标集合放置一次可以防止无穷的重定向环路。
如果联系列表中的地址造成错误,与在下一章所定义的一样,元素移到列表中的下一地址,直到列表用完为止。如果列表已经用完,那么此请求错误。
当接收到具体联系地址失败时,客户端应该尝试下一个连接地址。这包括创建新的客户端事务来传递新的请求。
注意,在一些实例中,在联系地址中通信的头字段可以改为添加到原始重定向请求的现有请求的头字段中。作为通用规则,如果头字段接受了逗号分隔的列标值,那么新的头字段可以添加到原始重定向请求的现有值中。如果头字段不能接受多个值,那么,可以用联系地址中通信的头字段值重写原始重定向请求。例如,如果与下列值一起返回联系地址:
那么,将重写原始重定向请求的Subject 头字段,HTTP URI 不过是附加在现有的Call-Info 头字段值后面。
最后,一旦构造了新请求,那么,使用新的客户端事务来发送新请求,因此,必须在最上面Via字段中有新的分支ID。
在一些实例中,与接收到的状态代码和逾时间隔的状态有关,可以在UAC中临时或者永久地缓存Contact头字段值。
如果接收到401(未经许可)或407(需要代理认证)响应,那么UAC应该遵循认证过程,使用凭证来重试请求。
如果接收到415(不支持的媒体类型)响应,UAS不支持请求中包含的媒体类型。UAC应该重试请求,此时仅使用响应中Accept头字段列出的类型,响应中Accept-Encoding头字段列出的编码和响应中Accept-Language头字段列出的语言。
如果接收到420(错误的扩展)响应,此请求包含Require 或者Proxy- Require头字段,列出了代理或者UAS不支持的可选标签特征。UAC应该重试请求,此时,忽略响应中扩展列出的Unsupported头字段。
其它的4xx响应,包括仍然在定义的,重试可以与也可以不与方法和使用案例有关。
当UAS处理对话外的请求时,与方法无关,要遵循一套处理规则。
5.2.1. 方法检查
如果方法是服务器支持的一种,那么,将继续处理。
如果UAS不能理解请求中的头字段(即是没有在本规范或者其它支持的扩展中定义此头字段),那么服务器必须忽略此头字段,并继续处理消息。UAS应该忽略任何在处理请求中非必需的、非格式化的头字段。
然而,Request-URI识别处理请求的UAS。如果Request-URI使用了UAS不支持的模式,它应该拒绝此请求,返回416(不支持URI 模式)响应。如果Request-URI不识别UAS将要接受请求的地址,它应该拒绝此请求,返回404(没找到)响应。典型地,使用REGISTER方法来为具体的联系地址绑定其记录地址的UA,将查找Request-URI与联系地址相等的请求。接收Request-URI的其它潜在资源包括,UA发送的、建立或者更新对话的请求和响应的Contact 头字段。
由于分发,相同的请求从不同的路径多次发送到UAS。UAS处理第一个接收到的这样的请求,对于第一个以外的请求,生成482(发现环路)响应。
UAC使用Require头字段告诉UAS——为了正确地处理请求,UAC希望UAS支持的SIP扩展。如果UAS不理解Require 头字段中列出的可选标签,它必须返回状态代码420(错误的扩展)。UAS必须添加Unsupported头字段,并列出请求的Require 头字段中它所不理解选项。
ACK 请求2xx 响应必须仅包含在初始请求中出现的Require和Proxy-Require值。
UAC -> AS: INVITEsip:watson@bell-telephone.com SIP/2.0
UAS-> UAC: SIP/2.0 420 Bad Extension
当两边都理解了所有选项时,此行为确保了无延时地进行客户端-服务器交互;如果不理解选项,将减慢速度(如上例)。对于完好匹配的客户端-服务器对,节省了协商机制经常需要的来回路程,交互处理很快。
5.2.3. 内容处理
5.2.4. 应用扩展
适用于非421响应的任何扩展必须在响应的Require头字段中列出来。当然,服务器不能应用响应的Require头字段没有列出来的扩展。结果,响应的Require头字段仅包含标准协议栈RFC中定义的可选标签。
假定通过了前面子章节的所有检查,UAS处理就成为面向具体方法的。后面章节分别介绍了REGISTER、OPTIONS 、INVITE、BYE、MESSAGE等请求处理。
当UAS希望为请求构造响应时,那么它遵循后面章节介绍的通用过程。在本节没有详细介绍的,正在讨论的响应代码的其他行为,也是必需的。
Sending a Provisional Response 生成响应大的、非面向具体方法的原则是,UAS不应该发布非INVITE请求的临时响应;而是,应该尽可能地生成非INVITE请求的最终响应。
Headers and Tags 响应的From 字段必须和请求的From 头字段相同,响应的Call-ID字段必须和请求的Call-ID 头字段相同,响应的CSeq 字段必须和请求的CSeq 头字段相同,
5.2.7. 无状态UAC行为
无状态UAS角色主要是处理发布挑战响应的不需认证的请求。如果对不需认证的请求进行有状态的处理,那么,恶意的不需认证的请求可以创建大量的事务状态,可能会减慢或者挂掉UAS的呼叫处理,实际上,将造成拒绝服务。
² 无状态UAS不能够发送临时(1xx)响应。
² 无状态UAS必须忽略ACK请求。
² 必须以无状态方式生成To 头字段——为相同请求一贯地生成相同标签的方式。
SIP提供了发现机制。如果用户要发起和另一个用户的会话,SIP必须发现可到达目的用户的当前主机。发现处理经常是SIP网络元素完成,比如代理服务器和重定向服务器——它们负责接收请求,决定要发送请求的用户位置,然后将它发送到相应的位置。为了完成这些,SIP网络元素查询了抽象服务——定位服务,这提供了特定域的地址绑定。这些地址绑定将输入的SIP和SIPS URI(如,sip:bob@biloxi.com)映射到想要的用户“更近”的一个或多个URI(如,sip:bob@engineering.biloxi.com)。最后,代理将查询定位服务,将接收到的URI映射到想要的接收者常驻的用户代理。
建立定位服务内容有很多种方法。其中之一是管理。在上面的实例中,通过访问公司数据库可以知道Bob是工程部门的一员。但是,SIP为UA提供了一种机制明确地创建绑定。这种机制就是注册。
SIP不强制执行定位服务的具体机制。唯一的要求是域中的注册服务器必须能够在定位服务中读和写数据,域中的代理和重定向服务必须能够读取相同的数据。在同一域内,注册服务器与特定的SIP代理服务器可以在同一接点。
REGISTER请求添加、删除和查询绑定。REGISTER请求可以在记录地址和一个或多个联系地址之间添加新绑定。合适地通过认证的第三方可以完成代表特定记录地址的注册。客户端也可以删除以前的绑定或者查询绑定,确定记录地址绑定当前所在的位置。
REGISTER请求不建立对话。UAC可以在REGISTER请求中包括基于第5.1节介绍的预有的路由集合的Route头字段。在REGISTER请求和响应中的Record-Route头字段没有意义,如果存在,必须忽略。特别的,UAC不能根据REGISTER请求的任何响应中存在和缺少的Record-Route头字段创建新的路由集合。
Request-URI: Request-URI指定了注册服务器指明的定位服务域。( 如sip:chicago.com)。不能出现SIPS URI的userinfo和@组件。
From: From头字段包含负责注册的人的记录地址。除非是第三方注册,此值和To头字段的值是一样的。
如果相同的客户端使用不同的Call-ID值,那么注册服务器不能检测延时的REGISTER请求是否没有排序到达。
Contact: REGISTER请求可能包括有一个或多个地址绑定值的Contact头字段。直到它们接收到来自注册服务器的前一请求的最终响应,或之前的REGISTER请求超时,UA才能发送新的注册(即是包含与转发相对的新Contact头字段值)。
action:RFC 2543 不赞成action 参数。UAC 不应该使用action 参数。
6.1.1. 添加绑定
请求的Contact头字段值主要是由SIP和SIPS URI组成的,它确定具体的SIP终端(如,“sip:carol@cube2214a.chicago.com”),同时,也可以使用其它的URI模式。例如,SIPUA可以选择注册电话号码(使用tel URL,RFC 2806)和email 地址(使用mail to URL,RFC 2368 )作为的记录地址的联系人。
一旦客户端在注册服务器上建立了绑定,如果需要,它可以发送包含新绑定和修订现有绑定的随后注册。REGISTER 请求的2xx 响应,将在Contact 头字段中包含完整的、在此注册服务器上注册记录地址的绑定列表。
注册不需要更新绑定。典型的是,UA仅更新其自己的联系地址。Setting the Expiration Interval of Contact Addresses 当客户端发送REGISTER请求时,它可以建议逾时间隔的状态,表示客户端注册有效的时间。(注册服务器基于其本地策略选择实际的时间间隔。)
如果在REGISTER中,表示建议到期时间的两种机制都不存在,那么,客户端表示,它要服务进行选择。
6.1.2. 删除绑定
REGISTER-specific Contact头字段值“*”用于所有的注册,但是,如果Expires头字段不用值“0”表示,不能使用“*”。
6.1.3. 提取绑定
6.1.4. 更新绑定
在单个引导周期,UA应该为所有的注册使用相同的Call-ID。除非有重定向,注册更新应该发送到与原始注册相同的网络地址。
如果REGISTER 请求的响应包含有Data 头字段,那么客户端可以使用此头字段获取当前的时间,设置内部时钟。
UA可以使用三种方法来确定发送注册的地址:通过配置、使用记录地址和多播。可以用注册服务器地址配置UA,这种方法超出了本规范的范围。如果没有可配置的注册服务器地址,那么,UA应该使用通用的SIP服务器定位机制,将主机部分的记录地址作为请求的Request-URI和地址。例如,UA为用户“sip:carol@chicago.com”将REGISTER请求寻址到“sip:chicago.com”。
在有些情况中,多播注册可能不适用,例如,如果多播事务共享相同的本地网络。
一旦构造了REGISTER方法,并确定了消息的目的地,那么,UAS遵循第5.1.2节介绍的过程,将REGISTER请求发送给处理层。如果因为REGISTER没有响应,处理层返回超时错误,UAS不应该立即向相同的注册服务器再尝试注册。
6.1.8. 错误响应
6.2. 处理REGISTER请求
在适当的时候,注册服务器可以重定向REGISTER请求。通用的用法是,注册服务器侦听多播接口,用302(暂时清除)响应将多播REGISTER请求重定向到其自己单播接口。
注册服务器可能接收到穿越代理的请求,它认为REGISTER是未知的请求,并添加Record-Route头字段值。
当接收到REGISTER请求,注册服务器遵循以下步骤:
2. 为了保证注册服务器支持任何必要的扩展,注册服务器必须像第5.2.2节介绍的UAS一样处理Require 头字段。
4. 注册服务器应该确定,认证用户是否有权修改记录地址的注册。例如,注册服务器可能查询授权数据库——它映射了用户名和用户有权修改的一系列记录地址。如果认证用户无权修改绑定,注册服务器必须返回403(Forbidden),并跳过剩下的步骤。
5. 注册服务器从请求的To头字段取出记录地址。如果记录地址不可用于Request-URI域,那么注册服务器发送404(Not Found)响应,并跳过剩下的步骤。URI必须转换成规范的格式。为了实现这一点,必须删除所有的URI 参数(包括user-param),同时将所有的转义字符串转换成保留格式。此结果用作一系列绑定的索引。
如果请求有其他的Contact头或者非零的到期时间,那么,请求是无效的,服务器返回400(Bad Request)响应,并跳过剩下的步骤。如果没有,注册服务器检查,Call-ID是否和每个绑定的存储值一致。如果没有,它必须删除这些绑定。如果一致,仅在请求的Cseq高于绑定的存储值时,删除绑定。否则,必须放弃更新,同时请求失败。
² 如果字段值有expires参数,此值必须当作请求的到期时间。
² 如果都没有,本地配置的默认值必须当作请求的到期时间。
在限制需要保持的状态和减少可能的注册停滞的同时,允许注册服务器设置注册时间间隔,防止过于频繁的注册更新。注册的逾时间隔频繁地用于创建服务上。其中一个实例是,follow-me服务,在这里,终端用户可能仅在一个很短的周期内可用。因此,注册服务器应该接受简短注册,如果时间间隔很短以至于更新会降低注册服务器的性能,那么,应该拒绝该请求。
此算法确保了忽略相同UA 无序的请求。
当且仅当,绑定更新和添加成功,必须提交绑定更新(即是使得代理和重定向服务器可见)。如果其中之一失败了(例如,因为后台数据库提交失败),那么,请求必须失败,返回500(Server Internal Error)响应,同时必须删除所有尝试的绑定更新。
SIP方法OPTIONS允许UA 查询其它UA 和代理服务器的能力。这就允许客户端不必“Ringing”另一方,发现关于支持的方法、内容类型、扩展和编码等等的信息。例如,在客户端将Require 头字段插入到INVITE 列出的它所不确定目的UAS 支持的选项时,客户端可以使用OPTIONS查询目的UAS,检查Supported头字段是否返回此选项。所有的UA必须支持OPTIONS 方法。
换言之,服务器接收到Max-Forwards头字段为0的OPTIONS请求,可能不管Request-URI而直接响应请求。
作为通用UA的行为,如果OPTIONS没有响应,处理层可以返回超时错误。这可以说明目标不可到达,因此是无效的。
7.1. 构造OPTIONS请求
Contact头字段可能出现在OPTIONS中。
OPTIONS请求的响应假定为是在原始请求Request-URI的范围内的。然而,仅当OPTIONS作为建立对话的一部分发送时,它才能保证生成OPTIONS响应的服务器可以接收到将来的请求。
OPTIONS sip:carol@chicago.com SIP/2.0
Max-Forwards: 70
From: Alice
CSeq: 63104 OPTIONS
Accept: application/sdp
7.2. 处理OPTIONS请求
在对话中接收到OPTIONS请求生成200 (OK)响应,和对话外构造的一样,对对话没有任何影响。
如果代理服务器生成OPTIONS响应,那么,代理返回200(OK),列出服务器的能力。此响应不包括消息体。
消息体可能发送,其类型由OPTIONS请求的Accept头字段确定(如果Accept头字段不存在,默认值为application/sdp)。如果此类型包括可以描述媒体能力的类型,那么,UAS应该为此目的在响应中包括消息体。在[12]中介绍了在application/sdp情况下,构造此消息体的详情。
SIP/2.0 200 OK
To:
Call-ID: a84b4c76e66710
Contact:
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE
Accept-Encoding: gzip
Supported: foo
Content-Length: 274
一个UA的核心概念就是对话。对话是表现为两个用户代理(UA)之间的持续一段时间的点对点的SIP关系。对话(Dialog)使得用户代理之间的消息顺序传递和两个用户代理之间的请求正确路由更加容易。对话(Dialog)可以认为是对SIP消息解释的上下文关系。第8节讲述了方法无关的UA处理和响应对话(Dialog)外的请求。本节将讨论如何通过请求和应答来创建一个对话(Dialog),并且在对话(Dialog)中如何发起和响应后续的请求。
dialog ID同样是和所有的To头域中包含了tag参数的请求及应答相关。
一个对话包含一些特定的状态用于以后的对话中的消息传送。这个状态由dialog ID,本地序列号(用来排序UA到对方的请求的序列),远程序列号(用来排序请求从远端到本UA),本地URI,远端URI,remote target,一个布尔类型的标记”secure”,路由集合(一组有序的URI)组成。
对话是由对一组特定请求的没有失败的应答来创建的。在本规范中,只有包含To tag的2xx和101-199应答,并且请求是INVITE的,会建立一个对话。当收到一个非终结应答的时候,对话会建立成”early”状态,并且成为early dailog。创建对话的时候可以使用Extension来定义扩展。13节描述了INVITE请求的更多细节。在这里,我们描述与方法无关的对创建对话状态的处理。
8.1.1. UAS行为
UAS接着创建这个对话的状态。对话状态必须维持直到对话结束。
路由集合必须设置成为请求中的Record-Route的URI列表,保留所有的URI参数和顺序。如果请求中没有Record-Route头域,那么路由集合必须设置成为空。这个路由集合,即便是空的,为了以后的对话中的请求,也要覆盖任何预先存在(pre-existing)的路由集合。remote taget必须设置成为请求的Contact头域中的URI。
远程URI(remote URI)必须设置成为From头域中的URI,并且本地URI必须设置成为TO头域中的URI。
当一个UAC发出一个请求,这个请求能够建立一个对话(比如这个请求是INVITE),它必须在Contact头域中提供一个基于全局的SIP或者SIPS URI(例如,可以在对话外使用的SIP URI)。如果请求包含一个Request-URI或者最上的Route头域是SIPS URI,Contact头域也必须包含的是SIPS URI。
如果这个请求是基于TLS发送的,并且Request-URI包含一个SIPS URI,那么”secure”标志被设置成为TRUE。
本地序列号必须设置成为请求中的Cseq头域的序列号。远程序列号必须设置成为空(他会由远端的UA在对话中发送请求而建立)。dialog ID中的呼叫标志必须设置成为请求的Call-ID头域的值。dialog ID的本地tag必须设置成为请求中的From头域的tag,dialog ID的远程tag必须设置成为应答中的To头域的tag。UAC必须能够处理接收到的应答的To头域中没有tag的情况,在这个情况下,tag值取值成为空。这是为了能够向下兼容RFC2543,它没有规定To的tag。
当两个UA之间的对话建立以后,他们都可以在对话中初始化一个新的事务(transaction)。如果UA发送请求,将遵循UAC的事务规则。UA接收请求将遵循UAS的规则。在建立对话的事务过程中,UA扮演的角色可能是不一样的。
注意ACK不是一个刷新target的请求。
8.2.1.1. 产生请求
在请求序列中的原始请求的To和From头域的URI的使用方法是为了向下兼容RFC2543协议的,在RFC2543协议中,使用URI作为对话的标志。在这个规范中,只有tags用于区分对话。有可能在本协议的后续版本中,在对话中的请求必须强制反应原始请求的To和From头域的URI将会去除。
通过使用32位的长整数,使得即使每秒种产生1笔请求,也会要136年才会用完这个整数出现重复。这个序列号的初始值的选取是为了让对话中后续的请求序列号不会重复。非0的初始值可以考虑采用时间来作为初始的序列号。一个客户端可以用31位有符号整数或者32位无符号整数来存放时间作为初始化的序列号。
如果路由集合不为空,并且路由集合的第一个URI包含lr参数(见19.1.1),那么UAC必须填写remote target URI到Request-URI,并且必须包含Route头域,这个Route头域按照顺序填写路由集合和路由集合的参数。
例如,如果remote targe是: sip:user@remoteua 并且路由集合包括:
那么请求应该有下列的Request-URI和Route头域
Route:
在对话内的任何一个刷新target的请求中,都应当包含一个Contact头域,并且这个URI除非有必要,否则都应当是和对话内上次请求的URI值一样。如果”secure”标志设置成为TRUE,那么URI也应当是SIPS URI。
8.1.2节中的步骤一般把请求发送到Route头域的最上一个地址,或者如果没有Route头域,那么就发送到Request-URI地址。由于受到特定的限制,这些步骤也允许把请求发送到另外一个地址(比如在route set中没有的缺省的外发proxy)
UAC将会从transaction层收到请求的应答。如果客户端的事务层返回一个超时,这会等同于一个408(请求超时)的应答。UAC处理3xx应答的时候,在这个应答是在对话内的请求的应答的处理方法和在对话外的处理方法是一样的。这个方法在8.1.3.4节中描述。需要注意的是,虽然UAC会尝试新的地址(处理3xx应答的时候),但是它依旧使用对话内的路由集合来构造请求的Route头域。
如果对话那的请求的应答是481应答(呼叫/事务不存在Call/Transaction Does Not Exits)或者一个408(请求超时),那么UAC应当终止这个对话。并且UAC应当在请求完全没有应答的时候(客户端transaciton将会通知TU这个超时)客户端transaction终止这个对话。
8.2.2. UAS行为
UAS从transaction层收到请求。如果请求的To头域有tag字段,UAS的处理核心需要校验对话的ID,拿请求中的tag和现存的对话相比较。如果匹配成功,那么就是一个在对话中的请求。在这种情况下,UAS首先使用8.2节中的对话外请求处理的步骤。如果请求To头域包括了一个tag字段,但是对话的ID并不匹配现存的对话,UAS可能是因为崩溃而重新启动,或者收到了一个另外(可能是错误的)UAS(UAS可以构造To的tags,这样UAS在灾备恢复下,可以把这个tag看成它自己的)。还有一种简单的可能是请求发送错误了。在这个基础上,UAS可以选择接受或者拒绝请求。在允许的情况下,尽量处理这些请求会提供灾难恢复的机制。UAS如果希望支持这样的特性就必须遵循一些原则,比如用始终使用单调递增的Cseq序列号,甚至是在重新启动之后也这样,在重启动后重建路由集合,处理越界的RTP时间戳和序列号等等。
对于在对话中接收到的,那些不会用任何形式更改对话状态的请求,比如OPTIONS请求,他们等同于在对话外的处理请求。
如果一个proxy废弃掉一个UAC产生的请求,并且UAC重新递交这个请求的时候。这个请求是会具有一个全新的Cseq序列号。UAS是不会收到第一个请求的,这样,Cseq序列号就会出现间隔,这样的间隔并非是一种错误的情况。
8.3. 终止对话
当UAC希望初始化一个会话(比如,audio,video或者游戏),它首先构造一个INVITE请求。这个INVITE请求一个服务器来建立一个会话。这个请求可能会由proxy层层转发,最后到达一个或者多个可能能够处理这个邀请的UAS。这些UAS需要看看是否用户接收这个邀请。然后UAS可以接收这个请求(也就是会话建立了),通过发送2xx应答。如果邀请被拒绝,根据拒绝的原因,3xx,4xx,5xx或者6xx应答将会发送。在发送终结应答之前,UAS可以发送一些临时应答(1xx)应答给UAC,以便UAC能够掌握建立会话的进度。
INVITE的一个2xx应答会建立一个会话,同时也建立了一个基于发送INVITE请求的UA和产生2xx应答的UA之间的对话。因此,当从多个远程UA收到了多个2xx应答(可能由于INVITE的分支),每一个2xx建立一个不同的对话(dialog)。所有这些对话都是同一个呼叫的组成部分。
9.1. UAC处理
由于初始化的INVITE请求是一个对话外的请求,它遵循8.1.1节的步骤创建。除此之外还有专门针对INVITE的附加处理步骤。
在INVITE中可以包含一个Accept头域(20.1节)。这个标志了UA在后续建立的对话中,能兼容的接收和发送的Content-Type。Accept头域支持不同会话描述格式(session descrioption format)的时候特别有用。
UAC还可以根据需要增加Subject(20.36节),Organization(20.25节)和User-Agent(20.41节)头域。这些头域都包含了INVITE的相关资料。UAC可以给INVITE增加一个消息体。8.1.1.10节讲述了如何构造Content-Type头域来描述消息体。
o 初始化请求必须在INVITE中,如果不在INVITE请求中,就必须在UAS回送给UAC的第一个非失败的可靠消息中。在这个规范中,这个应答就是2xx应答。
o 如果初始请求是在第一个可靠的非失败的UAS回送给UAC的消息中,那么应答必须在这个消息的确认消息中(在本规范中,就是给2xx应答的ACK确认消息)
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头域不存在,Content-Type 是application/sdp的包体实现就等同于Content-Disposition”session”,其他Content-Type的情况就是实现”render”。
9.1.2. 处理INVITE应答
9.1.2.1. 1xx应答
early dialog只会在下边这个情况中需要:如果一个UAC需要在完成初始的INVITE事务之前,给对方发送一个对话内的请求的时候,就需要early dialog。在临时应答中的头域可以在当对话是early state的时候都有效(也就是说,比如一个临时应答的Allow 头域包含的方法,在对话状态是early state的时候都是有效的。[由于Allow是允许的方法集合,所以,当对话状态是早期对话的时候,这个Allow的集合是不会改变的,但是当创建正式的dialog之后,Allow的集合可能会改变哦]。)
一个3xx应答可能包含一个或者多个Contact头域值,这个头域值提供了被叫方可能存在的地点。UAC可以根据3xx应答的状态码(21.3节)来决定是否尝试这些新的地址。
在INVITE请求中,可能会收到单个非2xx终结应答。4xx,5xx,6xx应答如果包含了Contact头域,那么这个头域值指示了错误的详细信息的解释地点。后续的终结应答(只有可能在发生错误的情况下),必须被忽略掉。
一旦接收到了非2xx终结应答,UAC处理核心就认为INVITE事务结束了。INVITE客户事务处理生成对这个应答的ACK(参见17节)。
单个INVITE请求可能会导致多个2xx应答返回给UAC,这是因为proxy可以分支。每一个应答都是由To中的tag参数来进行区分的,并且每一个应答都代表了一个独立的对话,具备单独的对话ID。
注意在对话状态中,只有路由集合不需要重新计算。其他部分比如对话内的最大的序列号(远程的和本地的)等都不需要重新计算。路由集合只是由于需要向后兼容而需要重新计算。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.1. 处理INVITE
1、 如果INVITE请求包含一个Expires头域,UAS核心就设置一个时钟计数=这个头域值。如果时钟到了,这个邀请就过期了。如果在UAS尚未产生终结应答的时候就超时了,那么487(请求终止)应答应当产生给UAC。
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节描述的步骤建立应答。
如果UAS不能马上接受或者拒绝邀请,那么它可以提示某种形式的进度给UAC(比如提示一个回铃声等等)。这是通过一个101到199的临时应答实现的。这些临时应答建立了早期对话(early dialog)(通过8.2.6和12.1.1)。如果UAS愿意,UAS可以发送多个临时应答。每一个临时应答都必须包含相同的dialog ID。这些临时应答都并非可靠传送的。
如果呼叫出于等待状态(比如用户设置成为呼叫等待的)或者这个呼叫正在和PSTN电话系统进行通讯(PSTN系统允许呼叫没有应答),一个INVITE事务是可以被延长处理时间的。
如果UAS决定转发这个呼叫,就需要发出3xx的应答。300(多重选择),301(永久转移),302(临时转移)应答中应当包含一个Contact头域,这个头域包含了一个或者多个表明需要重试的URI新地址。这个应答交给INVITE服务端事务层,由服务端事务层负责应答的重发。
拒绝INVITE请求的常见情景是被叫方不想或者不能在终端系统上接收这个呼叫。486(用户忙)应当在这样的情况下返回。如果UAS知道没有其他终端系统能够响应这个呼叫,就应当返回一个600(Busy Everywhere)。不过,通常情况下UAS是不太会知道这个情况的,并且这个应答也是罕见的。这些应答是交给INVITE服务端的事务层进行发送的,由这个事务层来保证应答的重发机制的。如果UAS拒绝的是INVITE请求包含的媒体磋商offer,UAS应当返回一个488(Not Acceptable Here)应答。这个应答应当包含一个Warning头域来解释为何offer被拒绝。
UAS核心产生一个2xx应答。这个应答建立一个对话,然后遵循8.2.6节和12.1.1节的描述进行处理。
如果INVITE请求包含了一个媒体磋商请求offer,并且UAS还没有发送应答,2xx应答中必须包含针对这个offer的应答。如果INVITE请求没有包含这个offer,而且UAS也尚未发出offer,2xx应答必须包含这个媒体磋商offer。
由于2xx的重发是端到端的,并且在UAS和UAC之间存在采用UDP通讯的节点。所以要保证通过这些节点进行可靠的传送,就必须采用间隔时间重发的机制,哪怕UAS本身的通讯机制是可靠的。
10. 更新已经存在的会话(UPDATE)
注意,单个的re-INVITE可以同时修改对话和会话的参数。
UA检测媒体错误的行为是本地策略的事情。但是,当网络拥塞时,为了避免大量的网络流量,不推荐自动生成re-INVITE和BYE。在任何请情况中,如果要自动发送这些消息,应该在随机的间隔后发送这些消息。
10.1. UAC行为
如果会话描述格式有版本号,那么,呼叫应该指出已经改变了会话描述的版本。
因为,UAS一般不会警告用户接受re-INVITE,UAC可以选择不为re-INVITE添加Alert-Info头字段和Content-Disposition“Alert”消息体。
注意,当正在任一方向进行其它的INVITE事务时,UAC不能在对话内发起新的INVITE事务。
2.如果有正在进行的INVITE服务器事务,那么TU必须等到事务完成或结束状态,才可以发起新的INVITE。
如果UA 接收到re-INVITE的非2xx最终响应,那么,将像没有发布re-INVITE一样,
如果UAC接收到re-INVITE的491响应,那么,它应该启动有T值的计时器,T选择如下:
² 如果对话ID没有自己的Call-ID,那么,T是以10ms 为单位、在0到2秒内随机选择的值。
发送re-INVITE和为re-INVITE的2xx响应生成ACK的规则和初始INVITE的规则相同。
UAS在发送第一个INVITE的最终响应之前,接收到相同会话的、低Cseq序列号的第二个INVITE,UAS必须对第二个INVITE返回500响应(服务器内部错误),并且必须包括在0到10秒之间随机选择值的Retry-After 头字段。
如果UA接收到现有对话的re-INVITE,它必须检查会话描述的版本标识符,如果没有版本标识符,认为会话描述的内容已经改变。
会话描述的版本可以用来调节新到达会议的能力——添加删除媒体、从单点到多播会议。
如果UAS生成2xx响应,但不能接受ACK,那么,它应该生成BYE结束会话。
在2xx中提供呼叫(因为INVITE不包含呼叫)的UAS应该服从发送呼叫更新现有会话的约束,建立呼叫,就像UAS正在做出新的呼叫。特别的是,此方法应该包括UA愿意支持的媒体格式和媒体类型。UAS必须确保会话描述与UAS先前的会话描述在对等物需要支持的媒体格式、传输和其它参数等方面重叠。这就避免了对等物拒绝会话描述。如果UAC不能接受它,UAC应该生成带有有效会话描述的响应,然后发送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也可以结束对话。
在SIP中,没有很好的定义“挂断”的概念。挂断是很具体的细节,但是也是很通用的用户接口。一般,当用户挂断,它表示想要结束建立会话的尝试和结束已经创建的会话。对于呼叫者UA,如果初始的INVITE没有创建最终响应,那么挂断意味着CANCEL请求;对于在最终响应后所有确认的对话,挂断意味着BYE。对于被呼叫者UA,一般来说,挂断意味着BYE。
11.1. UAC行为
11.2. UAS行为
UAS核心接收到BYE请求,检查它是否和现有对话匹配。如果BYE不能和现有对话匹配,那么,UAS核心必须生成481(呼叫/事务不存在)响应,并将其发送给服务器事务。
UAS核心接收现有对话的BYE请求,并且发现和现存的对话匹配,必须遵循对话处理过程处理请求。一旦完成,UAS应该结束会话(并因此停止发送和侦听媒体)。它唯一不可以选择的情况是多播会话,在多播会话中,即使会话的其他参与者已经结束了其包含的会话,都有可能参与(participation)。不管它是否结束参与会话,UAS核心必须对BYE生成2xx 响应,并将其发送到服务器事务传输。
12. 取消请求(CANCEL)
代理和用户代理客户端都可以构造CANCEL请求。
12.1. UAC行为
因为INVITE外的请求是立即响应的,为非INVITE发送CANCEL会创造竞态条件。
如果要取消的请求包括Route 头字段,那么CANCEL请求必须包括此Route 头字段值。
CANCEL请求不能包含任何Require和Proxy-Require头字段。
如果没有接收到临时响应,必须发送CANCEL请求,当然,客户端必须等待发送请求之前的临时响应。如果原始请求产生最终响应,不应该发送CANCEL,因为它是有效的无操作,而CANCEL对已经生成最终响应的请求没有影响。
在接收到之前请求的响应之前,如果允许发送CANCEL,那么,服务器将在原始请求之前接收到CANCEL。
12.2. UAS行为
服务器的CANCEL程序请求与服务器的类型有关。无状态代理将转发CANCEL,有状态代理可以响应CANCEL,并生成自己的CANCEL请求,同时,UAS将响应CANCEL。
如果UAS 没有找到与上面过程的CANCEL匹配的事务,那么它应该返回481(呼叫腿/事务不存在)响应。如果原始请求的事务仍然存在,接收到CANCEL请求的UAS行为与它是否已经发送了原始请求的最终响应有关。如果它对会话状态和原始请求生成的响应没有影响,那么CANCEL请求对原始请求的处理没有影响。如果UAS没有发布原始请求的最终响应,那么,其行为和原始请求的方法有关。如果原始请求是INVITE,UAS应该立即响应INVITE,返回487(请求结束)。CANCEL请求对本规范中定义的其它方法的事务处理没有影响。不管原始请求的方法是什么,只要CANCEL可以匹配现有的事务,那么,UAS回答CANCEL请求200(OK)响应。遵循第5.2.6 节介绍的过程构造此响应。注意,CANCEL响应的To标签和原始请求响应的To标签应该是一样的。CANCEL响应传送给服务器事务发送。
即时消息被定义为一组参与实体之间的实时消息交互,通常情况下,这些消息是文字信息,并且这些消息不需要存储。SIP即时消息通过扩展方法MESSAGE实现。
传递消息内容包含在MESSAGE请求的消息体中,该消息体可以是任何MIME类型,包括message/ CPIM 。但更建议message/cpim,因为已有的IM系统标准是message/cpim格式
像SIP其它请求一样,收到MESSAGE应回临时应答和最终应答。200-OK只说明消息成功到达了目的地,并不代码用户已经阅读。
13.1. UAC行为
最终应答的含义,
202-Accept:消息已成功发送到某网关,但不保证网关一定能把该消息送达目的地。
13.2. 使用IM URI
和路由相关的头域中的URI必须是SIP URI。
和SIP相关的操作参见rfc3261。
202-Accepted:如果自己不是MESSAGE的最终用户,就回202-Accepted。意味着该MESSAGE会被尽力转发,但不保证一定能到达目的地。
6xx :6xx表示消息虽被成功发送,但已被拒收。
如果消息携带有Expire头域,就处理超时,否则没有超时的概念。
如果消息不能被正确中继,如何处理该消息也与本地策略有关。
MESSAGE用信令携带媒体,所以流量会很大,需要特殊考虑。 如果可能,MESSAGE最好使用有拥塞控制的传输层协议,如TCP,SCTP。
对于不采用Dialog方式的消息,发往同一个目的URI的MESSAGE,如果上一个transaction还没有结束,就不允许发送下一个MESSAGE;而且如果不是路由设置每一跳在传输中采用拥塞控制,用Dialog传送的MESSAGE也禁止这么做。
SIP代理是将SIP请求路由到用户代理服务器和将SIP响应路由到用户代理客户端的元素。到达UAS 的请求可以穿透其间的多个代理。每个代理都可以作出路由决定,并在将请求转发到下一个元素之前对其修改。响应将通过代理路由,该代理与逆序请求穿透的代理相同。代理作为SIP元素的逻辑角色。当请求到达时,该元素在作为代理之前先确定是否需要响应其上的请求。例如,在充当代理之前,该请求可能难以理解或者该元素需要客户端的凭证。该元素可能用适当的错误代码作出响应。当直接响应请求时,该元素则扮演UAS 的角色,并且其行为必须如第5.2 节所述。
有状态代理将保留每个入站请求的信息(特别是事务状态),并且它所发送的任何请求都作为入站请求处理结果。有状态代理使用入站请求信息来影响与该请求相关的下一步消息处理。有状态代理可以选择“分发”请求,并将它路由到多个目的地。转发给多个位置的请求都必须有状态处理。
在请求处理期间,只要有状态代理不作阻止其回到初始无状态的事情(例如,分发或生成一个100 响应),它就可以转换为无状态操作模式。当完成这样的转换时,丢弃了所有状态。代理不应发起CANCEL 请求。
14.1. 有状态代理
有状态代理为每个所接收的新请求创建新的服务器事务。随后按第14章介绍的服务器事务,处理请求的转发。在发送及时的临时请求给第5.2.6节介绍的服务器事务(如,100(Trying))时,代理核心必须作为UAS。因此,有状态代理不应该对非INVITE请求生成100(Trying)响应。
对于所有新的请求,包括未知方法、作为代理的元素,请求必须:
2. 预处理路由信息
4. 向每个目标转发请求
14.2. 请求确认
1. 合理语法
3. Max-Forwards
5. Proxy-Require
如果其中任何检查失败,该元素必须作为用户代理服务器(参见第5.2节),然后响应错误代码。
1、合理的语法检查
本协议可用来扩展。新扩展可以随时定义一些新的方法和头字段。这样元素不能因为请求中包含它所不知道的方法和头字段而拒绝代理请求。
如果Request-URI的URI模式不为代理所理解,代理应拒绝该请求,并返回416(不支持URI 模式)响应。
Max-Forwards头字段用于限制SIP请求可以穿透的元素数。
如果该请求包含Max-Forwards头字段,该字段是比零大的字段值,则Max-Forwards检查也通过。
4、可选循环检测检查
5、Proxy-Require检查
6、Proxy-Authorization如果代理要求在转发请求之前进行身份认证,那么必须进行请求检查。
代理必须检查请求的Request-URI。如果请求的Request-URI包含了该代理预先放置在Record-Route 头字段值,代理必须使用Route 头字段中的最后一个值代替请求中Request-URI 的值,并且将该值从Route 头字段中去掉。一旦代理接收到已修改的请求,它将继续处理。
本规范不强制代理保持状态,以便于它检查先前放置在Record-Route头字段中的URI。反过来说,代理只需要在这些URI中放置足够多的信息,它就可以在随后出现时可以识别其值。
如果所接收请求带有与代理匹配的maddr,但是该maddr参数与URI中所指示的端口或者传输不同。这样就需要使用所指示的端口和传输将请求转发给代理。
14.4. 确定请求目标
如果请求的Request-URI包含maddr参数,Request-URI必须作为唯一的目标URI放在目标集合中,并且,代理必须继续请求转发。
一的目标URI 放在目标集合中,同时,此元素必须继续请求转发的任务(第16.6 节)。
代理处理出站请求的方式)是可能发生此情况的一个实例。
如果Request-URI没有为代理提供足够的信息来确定目标集合,那么,它应该返回485(模糊)响应。此响应应该包含Contact头字段——包含已作尝试的新地址的URI。如,对sip:John.Smith@company.com的INVITE可能有些含糊不清,其定位服务列出了多个John Smiths。
当通过这些服务对潜在的目标定义时,将其URI添加到目标集合中。目标仅能在目标集合中放置一次。如果在目标集合中已经有目标URI(以URI 类型相同的定义为基础),那么,不能再添加目标URI。
只有代理对此URI负责时,代理才可以在转发期间修改Request-URI的URI。如果代理不对此URI负责,那么,它将不能使用下面介绍的3xx和416响应。
仅允许URI 在目标集合中添加一次,可以减少不必要的网络流量,从重定向请求中获取的合并联系信息的情况,防止了无穷的网络递归。
如果Request-URI指出此代理上的资源不存在,那么,代理必须返回404(没找到)响应。
14.5. 转发请求
常用的排序机制是使用目标的q值参数,这些参数可从Contact头字段中获取。目标的处理顺序是从最高q值到最低q值。具有相同q值的目标可并行处理。
对于每个目标,代理都遵循以下步骤发送请求:
2、 更新Request-URI
4、 添加Record-Route头字段值(可选的)
6、 后处理路由信息
8、 添加一个Via头字段值
10、 转发新请求
每个步骤详述如下:
代理首先将接收到的请求复制。这个副本最初必须包含所接收到的请求的所有头字段。在一下描述中没有明确说明的字段不可以去掉。副本应与所接收的请求保持相同的头字段顺序。代理不能用通用字段名对字段值重新排序。代理也不能添加、修改或删除消息体。
2、 Request-URI
这就是代理角色的本质。代理会通过这种机制将请求路由到目的地。
3、 Max-Forwards
如果副本不含Max-Forwards头字段,那么代理必须添加一个Max-Forwards字段值,其值为70。
4、 Record-Route
建立对话的请求可以包含一个预先加载的Route头字段。
如果代理选择不向已经是对话的一部分的请求中添加Record-Route头字段值,那么代理将会保留在该路径上。但是当失败端点重新构建对话时,将会从这个路径上去掉这个代理。
请求路径中的每个代理都会单独选择是否添加Record-Route头字段值——请求中Record-Route头字段的状态并不迫使该代理添加一个值。
这个代理提供的URI将被其它元素用来作路由决策。一般说来,这个代理无法知道其它元素的性能,因此它必须将其本身限制为SIP执行的强制元素:SIP URI和TCP/UDP传输。
在整个对话期间,位于安全边界的代理必须保留此边界。
代理可在Record-Route头字段值中包含参数。这些参数值将在对该请求的某些响应中得到回应,这些响应如:对INVITE的200(OK)响应。这样的参数对于在消息中而不是在代理中保持状态会很有用。
代理放置在Record-Route 头字段中的URI,仅仅在出现URI 的事务所创建的任何对话的生命周期内有效。例如,对话有状态代理可在对话终止后可以拒绝接受在Record-Route中有该值的后续请求。当然,非对话有状态协议没有对话何时终止的概念,但它们可以对值中信息编码,以将其与后续请求的对话标识符相比较,然后会拒绝与那些信息不匹配的请求。
代理需要观察对话中所有消息的某些服务可能需要Record-Routing。但是,Record-Routing会减慢处理过程,并降低可扩展性,使得代理只在特定服务需要的情况下进行Record-Route。
5、 添加其他头字段
6、 对路由信息进行后处理
如果代理可以设置本地策略,要求请求访问一个特定代理,那么将Route值放入Route头字段中的可选办法是跳过下面描述的第10步的转发步骤,而仅向那个特定代理的地址、端口以及传输协议确定的目的地发送请求。如果这个请求有Route头字段,那么除非知道下一跳代理是松散路由,否则不能使用这种可选方法。此外,虽然这个方法也可用,但对于操作的健壮性、灵活性、通用性和连贯性来说,Route插入机制是更可取的。而且,如果Request-URI包含SIPS URI,那么必须使用TLS与该代理进行通信。
阳光保险集团股份有限公司是中国500强企业、中国服务业100强。业务遍及深圳、石家庄、郑州、太原、合肥、长沙、南昌、福州、海口、南宁、贵阳、昆明、西宁、兰州、银川、乌鲁木齐、呼和浩特、拉萨、大连、青岛、宁波、厦门。随着客户群的增加,服务人员也逐年增长。EnjoyTalk快速对接阳光保险集团原有业务系统,快速上线,贴心服务客户!
中国婚博会全球超大规模婚博会、世界级品牌结婚展。每年北京、上海、广州、杭州、成都、天津、武汉六大城市先后举行大型婚博会,客服人员的联络沟通工作至关重要,EnjoyTalk通信为其提供统一通信解决方案,某店遇到特殊状况,总部或者其他分点可无缝接入保证正常通话,确保展会工作人员的联络有序进行。
宅急送快递服务覆盖国内黑龙江、辽宁、吉林、河北、河南、湖北、湖南、山东、山西、陕西、安徽、浙江、江苏、福建、广东、海南、四川、云南、贵州、青海、甘肃、江西31个省(区、市)及港澳台地区。EnjoyTalk通信7*24小时服务体系,响应及时,保证8000座席呼叫中心系统正常稳定运行。