SIP协议解析与实现(c和c++使⽤osip)10
第七章 注册
第⼀节 总览
SIP提供了⼀种发现⽤户的能⼒。如果⼀个⽤户想与另外⼀个⽤户开启⼀个会话,SIP必须能够发现⽬标⽤户的当前主机。这种发现的过程常常由SIP⽹络元素使⽤,如代理服务器或重定向服务器,这些服务器能够接收⼀个请求,并根据⽤户的位置信息探测到将请求发送到哪⾥并发送。SIP⽹络元素考虑了⼀个位置服务。该服务⽀持对⼀个特定的域名进⾏地址绑定。这些地址绑定信息将收到的像sip: 的SIP或SIPS URI信息进⾏映射成⼀个或多个像sip:bob@这样对于⽤户来说更确切的SIP或SIPS URI。最终,⼀个代理将根据位置服务将接收到的URI映射成⽤当前使⽤户代理位置。
注册服务器为特定的域名下的位置服务创建绑定关系,这种绑定关系是指为⼀个AOR(address-of-record)URI绑定⼀个或多个可联系的地址。因此,当⼀个代理在当前域名下接收到⼀个请求,该请求的Request-URI与AOR相匹配,那么代理将该请求发送到注册在该AOR上的联系地址。通常,只有发送给这个AOR的请求能够被发送到AOR所在的域名下的时候,在⼀个域名下注册⼀个AOR才是有意义的。在⼤多数情况下,这意味着注册服务的域名需要与AOR的URI中的域名⼀致。
有许多⽅法使创建位置服务的内容。其中⼀种⽅法是后台管理。上⾯的例⼦中,通过读取公司数据库,获知Bob是众多⼯程部门中的⼀名员⼯。尽管如此,SIP提供⼀种使UA可以明确创建⼀个绑定的机制。这个机制就是注册服务。
注册服务必须发送⼀个REGISTER请求给⼀个特殊类型的UAS,这个UAS就是注册服务器。⼀个注册服务器是⼀个域名下的位置服务的前端,它根据REGISTER请求的内容读取和写⼊映射关系。这个位置服务通常为当前域名下代理服务器提供服务,⽽这个代理服务器为被路由到当前域名下的请求提供应答。
整个注册过程的流程图在图2中给出。注意注册服务器和代理服务器都是逻辑⾓⾊,它们可能是⽹络上的⼀个设备;为了清晰起见,在图中将这两部分分离开了。也要注意如果两个服务器是分离的元素,UA可能通过⼀个代理服务器发送请求到注册服务器。
SIP对位置服务的实现没有特殊的要求。唯⼀的要求是某些域名下的注册服务器必须能够读取和写⼊数据到位置服务,⽽在该域名下的代理服务器和重定向服务器必须也有能⼒读取这些数据。⼀些域名下的注册服务器可能与特定的SIP代理服务器被部署在⼀起。
第⼆节 构造REGISTER请求
REGISTER请求可以⽤来添加、删除和查询绑定信息。⼀个REGISTER请求能够为⼀个AOR和⼀个或多个联系地址创建⼀个新的绑定。注册服务器在第三⽅认证后,可以作为⼀个特殊的AOR。⼀个客户也能够删除早先的绑定也能够查询AOR当前的绑定。
除⾮特殊说明,REGISTER请求的结构和客户发送⼀个REGISTER请求的⾏为与在RFC3261第8.1和17.1节描述的UAC⼀般性⾏为⼀样。
⼀个REGISTER请求不建⽴对话。当有⼀个像RFC3261第8.1节描述的预先存在的路由集时,⼀个UAC可能在⼀个REGISTER请求中包含⼀个Route头域。在REGISTER请求或者应答中Record-Route头域没有意义,并且如果它存在必须忽略它。此外,UAC必须不基于⼀个对REGISTER请求的应答中,出现或者不出现的Record-Route头域,创建⼀个新的路由集。
下⾯的头域,除了Contact,必须被包含在REGISTER请求中。⼀个Contact头域可能被包含:
nevertheless用法Request-URI: 这个Request-URI指定当前位置服务的域名,这个位置服务是注册服务器所知道的(例如,"")。其中组成SIP URI的"urinfo"和"@"部分不能出现。
To: To头域包括要被注册服务器创建、查询或者修改的的AOR。To头域由于格式中包含⼀个⽤户名,所以它和Request-URI头域不相同。这个AOR必须是⼀个SIP或者SIPS URI。
From: From头域包含这个信息的⽤户的AOR。除⾮请求是⼀个第三⽅注册请求,否则这个值与To头域相同。
fornasari
Call-ID: ⼀个UAC所有的注册信息应该使⽤相同的Call-ID头域的值,以便注册信息发送到⼀个注册服务器。
如果同⼀个客户使⽤不同的Call-ID,那么注册服务器不能探测REGISTER请求是否因为延时没有按照顺序接收。
CSeq: CSeq头域的值保证REGISTER请求适当的顺序。对每个拥有相同Call-ID的REGISTER请求,UA必须为CSeq值增加⼀。
Contact: REGISTER请求可能包含⼀个Contact头域,该头域中包含0或多个地址绑定的信息。
当UA没有接收到注册服务器发送的对前⼀个REGISTER请求的最终应答或者发送前⼀个请求还没有超时前前,它不能发送⼀个新的注册信息(也就是,包含新的Contact头域的值,⽽不是重发)
美白小秘方bob
+----+
| UA |
| |
partyanimal+----+
|
|3)INVITE
|
< +--------+ V
+---------+ 2)Store|Location|4)Query +-----+
|Registrar|=======>| Service|<=======|Proxy|
+---------+ +--------+=======>+-----+
A 5)Resp |
mechanical
| |
| |
1)REGISTER| |
| |
+----+ |
| UA |<-------------------------------+
cube2214a| | 6)INVITE
+----+
carol
引道Figure 2: REGISTER example
下⾯列出REGISTER请求中有特殊含义的Contact头域的参数:
action: "action"参数在RFC2543中是不建议使⽤的。所以UAC应该不使⽤"action"参数。
expires: "expires"参数指出UA希望当前绑定多长时间有效。这个值是⼀个以秒为单位的数字。如果这个参数没有被指定,那么这个值由Expires头域中的值代替。某些实现中⼤于2**32-1(4294967295秒或136年)的值视为等于2**32-1。不合法的值应该被视为等于3600.
添加绑定
REGISTER请求是向注册服务器发送包含联系地址的请求,联系地址是其它发送到该AOR上的SIP请求所要发送到的地址。AOR被包含在REGISTER请求的To头域。
请求中Contact头域的值通常由标识指定SIP终端(例如,"sip:carol@")的SIP或SIPS URI组成,但是它们可能使⽤任何URI模式。例如,⼀个SIP UA能够决定注册电话号码(使⽤tel URI, REF2806[9])或者电⼦邮件地址(使⽤⼀个mailto URI, RFC2368[32])作为⼀个AOR的联系地址的Contact头域。
例如,Carol,使⽤的AOR是"sip:",将在域名下的SIP注册服务器中注册。她的注册信息将被域名下的代理服务器⽤来将发送给Carol的AOR上的请求路由到她的SIP终端。
⼀旦⼀个客户在注册服务器中创建了绑定,它可能发送⼀些后继的注册信息,这些后继的注册信息包括新的绑定或者对已存在的绑定的修改信息。对REGISTER请求的2xx应答要包含如下信息。在Contact头域需要包含在当前注册服务器中,对这个AOR已经被注册的完整的绑定信息列表。
如果REGISTER请求中To头域中的AOR是⼀个SIPS URI,请求中任何Contact头域的值都应该也是SIP URI。客户应该仅在使⽤其它⽅法确保联系地址安全的情况下,才能够使⽤⾮SIP URI注册在该客户的AOR下。这能⽤于处理在⾮TLS协议下,⾮SIP协议的URI或者⾮SIP的设备的安全问题。
注册信息不需要更新所有的绑定信息。通常⼀个UA只更新他⾃⼰的联系地址。
设置联系地址的有效期
当客户发送⼀个REGISTER请求,它可能提供⼀个建议的有效期,⽤来指出客户希望这个注册信息在多长时间内有效。(在RFC3261第10.3节描述注册服务器根据本地策略选择实际的间隔时间。)
⽤户可以使⽤两种⽅法为⼀个绑定设置有效期:通过⼀个Expires头域或者⼀个Contact头域的"expires"参数。后⾯这种⽅法可以在同⼀个REGISTER请求中有多个绑定信息的情况下,针对每个绑定信息设置有效期。⽽前⼀种⽅法为所有不包含"expires"参数的Contact头域的值统⼀设置有效期。
如果设置有效期的两种⽅式都没有使⽤,那么这表⽰客户希望有效期由服务器端决定。
多个联系地址间的优先级
如果在REGISTER请求中有多个Contact头域,这说明进⾏注册的UA希望将这些Contact头域的值都与To头域中的AOR进⾏绑定。可以在Contact头域中的列表中使⽤"q"参数来指定它们的优先级。"q"参数指出这个Contact头域的值与其它Contact头域的值针对当前的AOR的优先级。RFC3261第16.6节描述了⼀个代理服务器如何使⽤这个优先级。
移除绑定信息
注册信息是⼀个软状态,并且在不刷新的情况下会失效,但是它仍然可以被直接移除。客户能够调整RFC3261第10.2.1节描述的注册服务器上选择的有效期。UA通过REGISTER请求为⼀个联系地址指定"0"有效期来⽴即移除⼀个绑定信息。UA应该⽀持这种机制⽤来在⼀个绑定有效期到达之前移除掉这个绑定信息。
REGISTER指定Contact头域的值是"*"表⽰处理所有的注册信息,但是必须在Expires头域的值为"0"时才能使⽤它。
使⽤"*"作为Contact头域的值允许⼀个已经注册的UA移除所有于这个AOR的绑定信息,但不⽤知道这些联系地址的值。
获取绑定信息
对任何REGISTER请求的成功应答都包含已经存在的绑定的完整列表,⽆论请求中是否包含Contact头域。如果⼀个REGISTER中没有Contact头域,那么绑定列表将不产⽣变化。
刷新绑定信息
每个UA都要对早先创建的绑定信息进⾏刷新。⼀个UA不应该刷新其它UA建⽴的绑定信息。
注册服务器发送的200(OK)应答的Contact头域中包含当前所有绑定信息的列表。UA通过RFC3261第19.1.4节描述的对⽐规则,对⽐每⼀个联系地址是否有效。如果有效,它要根据expires参数或者Expires头域来更新有效期。当到达有效期前,UA为每个绑定信息发送了⼀个REGISTER请求来更新有效期。也可能将⼀些更新请求合并到⼀个REGISTER请求。
UA应该在⼀个周期内使⽤相同的Call-ID发送注册信息。⽤于刷新的注册信息应该被发送到与原始注册信息相同⽹络地址,除⾮请求被重定向。
设置内部时钟
如果对⼀个REGISTER请求的应答包含⼀个Date头域,客户可能使⽤这个头域来设置当前时间从⽽设置所有内部时钟。
发现⼀个注册服务器
UA能够使⽤三种⽅法决定向哪个地址发送注册请求:通过配置,使⽤AOR,和使⽤⼴播。⼀个UA是能够通过配置获得注册服务器的地址,这种⽅法超出了本⼿册范围。如果没有配置注册服务器的地址,UA应该使⽤Request-URI中的AOR的主机名部分,并⽤⼀般的SIP服务器定位机制把请求发送到这⾥[4]。例如,"sip:"⽤户的UA将REGISTER请求定向到""。
最后,⼀个UA能够使⽤配置好的⼴播。⼴播注册消息到已知的"所有的SIP服务器"的⼴播地址"ast"(IPv4的224.0.1.75)。IPv6的⼴播地址还没有被分配;当需要的时候这个地址将被单独的在⽂档中说明。SIP UA可能监听这个地址并且使⽤它获得本地的其它⽤户(见[33]);尽管如此,他们部队请求进⾏应答。
⼴播注册信息可能不能使⽤在⼀些环境下,例如,如果多个商务应⽤共享同⼀个本地局域⽹。
传送⼀个请求
⼀旦REGISTER⽅法被构造,并且消息要发送的⽬标被确定,UAC按照在RFC3261第8.1.2节描述的程序将REGISTER消息转给事务层。
如果事务层因为REGISTER请求没有应答,并返回了⼀个超时错误,UAC应该不⽴即重新尝试向同⼀
个注册服务器发送注册信息。
⽴即重试很可能还是超时。因为超时情况的发⽣,⽽等待⼀个合理的时间间隔后再重试对降低不必要的⽹络负载是⼀个好的⽅法。这⾥没有规定这个等待时间间隔是多少。
错误应答
如果⼀个UA接收到⼀个423(Interval Too Brief)应答,它可能需要为REGISTER请求中所有的联系地址设置更⼤的有效期,新的有效期要⼤于或者等于423(Interval Too Brief)应答的Min-Expires头域的值。
处理REGISTER请求
⼀个注册服务器是⼀个UAS,该UAS应答REGISTER请求并且维护⼀个绑定列表,该绑定列表提供给在它管理域名范围内的代理服务器和重定向服务器使⽤。⼀个注册服务器根据RFC3261第8.2节和17.2节处理请求,但是它只接受REGISTER请求。⼀个注册服务器必须不创建6xx应答。
⼀个注册服务器能够适当的重定向REGISTER请求。通常⽤于注册服务器在⼀个多播地址上监听,并使⽤302(Moved Temporarily)应答将多播的REGISTER消息重定向到它⾃⼰的单播地址上。
注册服务器必须忽略REGISTER请求中的Record-Route头域。注册服务器在任何对REGISTER请求的应答中必须不包含Record-Route头域。
⼀个注册服务器可能接收到⼀个通过代理服务器的REGISTER请求,这个代理服务器认为这个请求是未知请求,并且向这个请求中添加⼀个Record-Route头域。
⼀个注册服务器知道(例如,通过配置)它所管理的绑定列表所在的域名。REGISTER请求必须按顺序被接收到该请求的注册服务器处理。REGISTER请求也必须进⾏原⼦处理,这意味着⼀个指定的REGISTER请求要么被完全的处理,要么没有被处理。每⼀个REGISTER消息被处理时,必须独⽴于任何其它的注册信息或更改的绑定信息。
当接收到⼀个REGISTER请求,注册服务器按照下⾯的步骤处理:
1. 注册服务器通过检查Request-URI决定是否它有权限为Request-URI中指定的域名进⾏绑定。如果没有权限,并且如果该服务器也作为代理服务器,它应该将这个请求发送到那个域名下,按照RFC3261第16节介绍的⽅法代理发送消息。
hideous
2. 为了保证代理服务器⽀持任何需要的扩展,注册服务器必须像在RFC3261第8.2.2节描述的那样处理Require头域的值。
3. ⼀个注册服务器应该对UAC进⾏验证。对于SIP UA的验证机制在RFC3261第22节描述。注册⾏为不能超越SIP验证框架。如果没有验证机制,注册服务器能够得到From头域的地址作为验证的依据。
blou
4. 注册服务器应该决定是否验证后的⽤户有权修改它的AOR相关的注册信息。例如,⼀个注册服务器可能使⽤⼀个验证数据库,该验证数据库存储⽤户名和AOR列表的映射关系,那些拥有令牌的⽤户可以修改绑定信息。如果被验证过的⽤户没有被授权修改绑定信息,注册服务器必须返回⼀个403(Forbidden)应答并略过下⾯的步骤。
在⽀持第三⽅注册的架构下,⼀个实体可能被授权来更新多个与它关联的AOR的注册信息。
5. 注册服务器从请求的To头域解析出AOR。如果AOR在Request-URI指定的域名下不是有效的,注册服务器必须发送⼀个404(Not Found)应答并且略过剩下的步骤。然后URI必须⽴即被转换成⼀个规范的格式。所有的URI参数必须被移除掉(包括⽤户参数ur-param),并且任何⾮法字符必须被转换成合法格式。最终作为绑定信息的索引使⽤。
6. 注册服务器检查请求是否包含Contact头域。如果没有它将略过其它步骤⽽到最后⼀步。如果有Contact头域,注册服务器在Contact头域的值中检查是否包含特定的"*"和Expires头域。如果请求有⽽外的Contact头域或者⼀个不为零的有效期时间,那么这个请求是⽆效的,服务器必须返回400(Invalid Request)并且略过剩下的步骤。否则,注册服务器检查Call-ID的值是否每个绑定信息的值
相符合。如果不符合,它将移除这个绑定。如果符合它仅仅移除绑定信息中CSeq的值⼩于请求的CSeq值的绑定信息。否则,更新必须终⽌并且请求失败。
7. 注册服务器现在依次处理每⼀个在Contact头域中的联系地址。对于每⼀个地址,它按照下⾯的步骤决定有效期:
- 如果头域的值有"expires"参数,这个值必须作为请求的有效期。
empty的反义词
- 如果没有这样的参数,但是请求有⼀个Expires头域,这个头域的值必须作为有效期。
- 如果都没有,必须指定本地设置的默认值为有效期。
注册服务器可能决定⼀个⼩于请求有效期的值。如果并且只有如果请求的有效期⼤于零并且⼩于⼀⼩时并且⼩于⼀个注册服务器配置的最⼩值的时候,注册服务器发送423(Interval Too Brief)应答来拒绝注册信息。这个应答必须包含⼀个Min-Expires头域,该头域的值是注册服务器期望的最⼩有效期。然后它略过剩下的步骤。
在需要维持注册状态,并且注册信息会失效的时候,允许服务器设置注册信息的有效期可以避免频繁的刷新注册信息。注册信息的有效期经常在服务创建时使⽤。⼀个例⼦是当⽤户可能只在某个终端上停留很短的时间时的follow-me(跟随我)服务。因此,注册服务器应该接受有效期较短的注册信息;
⼀个请求只有当刷新时间太短以⾄于会降低注册服务器性能时才会被拒绝。
coconut对于每⼀个地址,注册服务器使⽤URI的对⽐原则搜索当前绑定信息的列表。如果绑定信息不存在,它会尝试添加⼀个。如果绑定信息存在,注册服务器检查Call-ID的值。如果已存在的绑定信息的Call-ID的值与请求中Call-ID的值不相同,如果这个绑定信息的有效期是0则应该删除它,如果这个绑定信息的有效期不是0则更新它。如果Call-ID的值相同,注册服务器对⽐CSeq值。如果请求中CSeq的值⽐绑定信息中的值⼤,注册服务器必须像上⾯那样更新或者删除绑定信息。否则,不能进⾏更新并且返回失败应答。
这是为确保从⼀个相同的UA发送的,但没有按正确时序接收到的请求被忽略的算法。
每⼀个绑定记录从请求中记录Call-ID和CSeq的值。
当且仅当所有的绑定都被更新并且附加操作的都成功后,绑定信息才必须被提交(提交也就是说,这个修改使代理服务器和重定向服务器可见)。如果有些操作失败了(例如,由于后台数据库提交失败),必须使⽤500(Server Error)应答请求,并且所有临时更新的绑定信息都必须被移除。
8. 注册服务器返回⼀个200(OK)应答。这个应答必须包含列举所有当前绑定信息的Contact头域。每⼀个Contact头域的值必须给出⼀个"expires"参数,这个参数指出由注册服务器决定的有效期。这个应答应该包含⼀个Date头域。