8. 通用用户代理行为 (General User Agent Behavior)
用户代理 (User Agent) 代表一个端系统。它包含一个用户代理客户端 (UAC, User Agent Client), 用于生成请求, 以及一个用户代理服务器 (UAS, User Agent Server), 用于响应请求。UAC能够基于某些外部刺激 (用户点击按钮或PSTN线路上的信号) 生成请求并处理响应。UAS能够接收请求并基于用户输入、外部刺激、程序执行结果或其他机制生成响应。
当UAC发送请求时, 请求会通过若干代理服务器 (Proxy Server), 这些服务器将请求转发到UAS。当UAS生成响应时, 响应会被转发回UAC。
UAC和UAS的处理过程主要取决于两个因素。首先, 基于请求或响应是在对话内部还是外部; 其次, 基于请求的方法。对话 (Dialog) 在第12节中详细讨论; 它们代表用户代理之间的点对点关系, 由特定的SIP方法 (如INVITE) 建立。
在本节中, 我们讨论在处理对话外部的请求时, UAC和UAS行为的与方法无关的规则。这当然包括那些自身建立对话的请求。
对话外部的请求和响应的安全程序在第26节中描述。具体来说, 存在UAS和UAC相互认证的机制。通过使用S/MIME加密消息体, 也支持有限的隐私功能集。
8.1 UAC行为 (UAC Behavior)
本节涵盖对话外部的UAC行为。
8.1.1 生成请求 (Generating the Request)
UAC制定的有效SIP请求至少必须包含以下头字段: To、From、CSeq、Call-ID、Max-Forwards和Via; 所有这些头字段在所有SIP请求中都是强制性的。这六个头字段是SIP消息的基本构建块, 因为它们共同提供了大多数关键的消息路由服务, 包括消息寻址、响应路由、限制消息传播、消息排序以及事务的唯一标识。这些头字段是除了强制性的请求行 (包含方法、Request-URI和SIP版本) 之外的。
在对话外部发送的请求示例包括用于建立会话的INVITE (第13节) 和用于查询能力的OPTIONS (第11节)。
8.1.1.1 Request-URI
消息的初始Request-URI应该设置为To字段中URI的值。一个值得注意的例外是REGISTER方法; 设置REGISTER的Request-URI的行为在第10节中给出。出于隐私原因或便利性, 将这些字段设置为相同的值也可能是不可取的 (特别是如果发起UA预期Request-URI在传输过程中会被更改)。
在某些特殊情况下, 预先存在的路由集 (Pre-existing Route Set) 的存在可能会影响消息的Request-URI。预先存在的路由集是一组有序的URI, 用于标识服务器链, UAC将向该链发送对话外部的传出请求。通常, 它们由用户或服务提供商通过手动或其他非SIP机制在UA上配置。当提供商希望为UA配置出站代理时, 建议通过提供包含单个URI (出站代理的URI) 的预先存在的路由集来完成。
当存在预先存在的路由集时, 必须遵循第12.2.1.1节中详细说明的填充Request-URI和Route头字段的程序 (即使没有对话), 使用所需的Request-URI作为远程目标URI。
8.1.1.2 To
To头字段首先指定请求的期望"逻辑"接收者, 或者是此请求目标的用户或资源的记录地址 (Address-of-Record)。这可能是也可能不是请求的最终接收者。To头字段可以包含SIP或SIPS URI, 但也可以在适当时使用其他URI方案 (例如tel URL, RFC 2806 [9])。所有SIP实现必须支持SIP URI方案。任何支持TLS的实现必须支持SIPS URI方案。To头字段允许显示名称 (Display Name)。
UAC可以通过多种方式学习如何为特定请求填充To头字段。通常, 用户会通过人机界面建议To头字段, 可能手动输入URI或从某种地址簿中选择它。通常, 用户不会输入完整的URI, 而是输入一串数字或字母 (例如"bob")。如何解释此输入由UA自行决定。使用该字符串形成SIP URI的用户部分意味着UA希望在SIP URI中@符号右侧 (RHS) 的域中解析该名称 (例如sip:bob@example.com)。使用该字符串形成SIPS URI的用户部分意味着UA希望安全通信, 并且该名称将在@符号右侧的域中解析。RHS通常是请求者的家域 (Home Domain), 这允许家域处理传出请求。这对于需要在家域中解释用户部分的功能 (如"快速拨号") 很有用。当UA不希望指定应解释用户输入的电话号码的域时, 可以使用tel URL。相反, 请求通过的每个域都将获得该机会。例如, 机场中的用户可能登录并通过机场中的出站代理发送请求。如果他们输入"411" (这是美国本地目录协助的电话号码), 则需要由机场中的出站代理而不是用户的家域来解释和处理。在这种情况下, tel:411将是正确的选择。
对话外部的请求不得包含To标签 (To Tag); 请求的To字段中的标签标识对话的对等方。由于未建立对话, 因此不存在标签。
有关To头字段的更多信息, 请参见第20.39节。以下是有效To头字段的示例:
To: Carol <sip:[email protected]>
8.1.1.3 From
From头字段指示请求发起者的逻辑身份, 可能是用户的记录地址 (Address-of-Record)。与To头字段一样, 它包含URI和可选的显示名称。SIP元素使用它来确定应用于请求的处理规则 (例如, 自动呼叫拒绝)。因此, From URI不包含IP地址或UA运行的主机的FQDN非常重要, 因为这些不是逻辑名称。
From头字段允许显示名称。如果要隐藏客户端的身份, UAC应该使用显示名称"Anonymous", 以及语法上正确但无意义的URI (如sip:thisis@anonymous.invalid)。
通常, 特定UA生成的请求中填充From头字段的值由用户或用户本地域的管理员预先配置。如果特定UA由多个用户使用, 它可能具有可切换的配置文件, 其中包含与配置文件用户身份对应的URI。请求的接收者可以对请求的发起者进行身份验证, 以确定他们是否是其From头字段声称的人 (有关身份验证的更多信息, 请参见第22节)。
From字段必须包含由UAC选择的新"tag"参数。有关选择标签的详细信息, 请参见第19.3节。
有关From头字段的更多信息, 请参见第20.20节。示例:
From: "Bob" <sips:[email protected]> ;tag=a48s
From: sip:[email protected];tag=887s
From: Anonymous <sip:[email protected]>;tag=hyh8
8.1.1.4 Call-ID
Call-ID头字段充当唯一标识符, 用于将一系列消息组合在一起。对于对话中任一UA发送的所有请求和响应, 它必须相同。对于来自UA的每个注册, 它应该相同。
在UAC在任何对话外部创建的新请求中, Call-ID头字段必须由UAC选择为全局唯一标识符 (在空间和时间上), 除非被特定于方法的行为覆盖。所有SIP UA必须有办法保证它们生成的Call-ID头字段不会被任何其他UA无意中生成。请注意, 当在某些失败响应后重试请求 (这些响应要求对请求进行修改, 例如, 身份验证的挑战) 时, 这些重试的请求不被视为新请求, 因此不需要新的Call-ID头字段; 请参见第8.1.3.5节。
建议在生成Call-ID时使用加密随机标识符 (RFC 1750 [12])。实现可以使用"localid@host"形式。Call-ID区分大小写, 只需逐字节比较。
使用加密随机标识符可以提供一些针对会话劫持的保护, 并降低无意Call-ID冲突的可能性。
为请求选择Call-ID头字段值不需要配置或人机界面。
有关Call-ID头字段的更多信息, 请参见第20.8节。
示例:
Call-ID: [email protected]
8.1.1.5 CSeq
CSeq头字段用作识别和排序事务的方式。它由序列号和方法组成。方法必须与请求的方法匹配。对于对话外部的非REGISTER请求, 序列号值是任意的。序列号值必须可表示为32位无符号整数, 并且必须小于2^31。只要遵循上述准则, 客户端可以使用任何机制来选择CSeq头字段值。
第12.2.1.1节讨论了对话内请求的CSeq构造。
示例:
CSeq: 4711 INVITE
8.1.1.6 Max-Forwards
Max-Forwards头字段用于限制请求在到达目的地的途中可以经过的跳数。它由一个整数组成, 该整数在每个跳处递减1。如果Max-Forwards值在请求到达目的地之前达到0, 它将被拒绝, 并返回483 (Too Many Hops) 错误响应。
UAC必须在其发起的每个请求中插入Max-Forwards头字段, 其值应该为70。选择此数字是为了足够大, 以保证在没有循环的任何SIP网络中请求不会被丢弃, 但又不能大到在发生循环时消耗代理资源。应谨慎使用较低的值, 并且仅在UA知道网络拓扑的情况下使用。
8.1.1.7 Via
Via头字段指示用于事务的传输并标识响应将被发送到的位置。仅在选择了将用于到达下一跳的传输之后才添加Via头字段值 (这可能涉及使用 [4] 中的程序)。
当UAC创建请求时, 它必须在该请求中插入Via。头字段中的协议名称和协议版本必须分别为SIP和2.0。Via头字段值必须包含branch参数。此参数用于标识该请求创建的事务。客户端和服务器都使用此参数。
branch参数值对于UA发送的所有请求, 在空间和时间上必须是唯一的。此规则的例外是CANCEL和针对非2xx响应的ACK。如下所述, CANCEL请求将具有与其取消的请求相同的branch参数值。如第17.1.1.3节所述, 针对非2xx响应的ACK也将具有与其确认的INVITE响应相同的branch ID。
branch ID参数的唯一性属性 (为了便于将其用作事务ID) 不是RFC 2543的一部分。
符合本规范的元素插入的branch ID必须始终以字符"z9hG4bK"开头。这7个字符用作魔术cookie (7被认为足以确保较旧的RFC 2543实现不会选择这样的值), 以便接收请求的服务器可以确定branch ID是按照本规范描述的方式构造的 (即全局唯一)。除了这个要求之外, branch令牌的精确格式是由实现定义的。
Via头的maddr、ttl和sent-by组件将在请求由传输层处理时设置 (第18节)。
代理的Via处理在第16.6项8和第16.7项3中描述。
8.1.1.8 Contact
Contact头字段提供一个SIP或SIPS URI, 可用于联系UA的特定实例以进行后续请求。Contact头字段必须存在, 并且在任何可能导致建立对话的请求中必须恰好包含一个SIP或SIPS URI。对于本规范中定义的方法, 仅包括INVITE请求。对于这些请求, Contact的范围是全局的。也就是说, Contact头字段值包含UA希望接收请求的URI, 并且即使在任何对话之外的后续请求中使用, 该URI也必须有效。
如果Request-URI或顶部Route头字段值包含SIPS URI, 则Contact头字段也必须包含SIPS URI。
有关Contact头字段的更多信息, 请参见第20.10节。
8.1.1.9 Supported和Require
如果UAC支持可由服务器应用于响应的SIP扩展, UAC应该在请求中包含Supported头字段, 列出这些扩展的选项标签 (Option Tag, 第19.2节)。
列出的选项标签必须仅引用标准跟踪RFC中定义的扩展。这是为了防止服务器坚持客户端实现非标准的、供应商定义的功能以接收服务。实验性和信息性RFC定义的扩展明确排除在请求的Supported头字段中使用, 因为它们也经常用于记录供应商定义的扩展。
如果UAC希望坚持UAS理解UAC将应用于请求的扩展以处理请求, 它必须在请求中插入Require头字段, 列出该扩展的选项标签。如果UAC希望将扩展应用于请求并坚持遍历的任何代理都理解该扩展, 它必须在请求中插入Proxy-Require头字段, 列出该扩展的选项标签。
与Supported头字段一样, Require和Proxy-Require头字段中的选项标签必须仅引用标准跟踪RFC中定义的扩展。
8.1.1.10 其他消息组件 (Additional Message Components)
在创建新请求并正确构造上述描述的头字段之后, 将添加任何其他可选头字段, 以及任何特定于方法的头字段。
SIP请求可以包含MIME编码的消息体。无论请求包含什么类型的消息体, 都必须制定某些头字段来描述消息体的内容。有关这些头字段的更多信息, 请参见第20.11至20.15节。
8.1.2 发送请求 (Sending the Request)
然后计算请求的目的地。除非有指定的本地策略, 否则必须通过应用 [4] 中描述的DNS程序来确定目的地, 如下所示。如果路由集中的第一个元素指示严格路由器 (导致如第12.2.1.1节所述形成请求), 则必须将程序应用于请求的Request-URI。否则, 将程序应用于请求中的第一个Route头字段值 (如果存在), 或者如果不存在Route头字段, 则应用于请求的Request-URI。这些程序产生要尝试的地址、端口和传输的有序集。无论使用哪个URI作为 [4] 程序的输入, 如果Request-URI指定SIPS资源, UAC必须遵循 [4] 的程序, 就像输入URI是SIPS URI一样。
本地策略可以指定要尝试的备用目的地集。如果Request-URI包含SIPS URI, 则必须使用TLS联系任何备用目的地。除此之外, 如果请求不包含Route头字段, 则对备用目的地没有限制。这提供了一种简单的替代方案, 作为指定出站代理的预先存在的路由集的替代方案。但是, 不建议使用该方法来配置出站代理; 应该使用具有单个URI的预先存在的路由集。如果请求包含Route头字段, 则应该将请求发送到从其最顶层值派生的位置, 但可以发送到UA确信将遵守本文档中指定的Route和Request-URI策略 (而不是RFC 2543中的策略) 的任何服务器。特别是, 配置了出站代理的UAC应该尝试将请求发送到第一个Route头字段值指示的位置, 而不是采用将所有消息发送到出站代理的策略。
这确保了不添加Record-Route头字段值的出站代理将从后续请求的路径中删除。它允许无法解析第一个Route URI的端点将该任务委托给出站代理。
UAC应该遵循 [4] 中为有状态元素定义的程序, 尝试每个地址直到联系到服务器。每次尝试都构成一个新事务, 因此每次都携带一个不同的最顶层Via头字段值和一个新的branch参数。此外, Via头字段中的传输值设置为为目标服务器确定的任何传输。
8.1.3 处理响应 (Processing Responses)
响应首先由传输层处理, 然后由事务层处理。事务层对响应执行其处理, 然后将响应传递给TU (事务用户)。
本节讨论UAC TU应如何处理从事务层接收到的响应。
8.1.3.1 事务层错误 (Transaction Layer Errors)
在某些情况下, 响应由事务层内部生成。这些情况发生在事务层超时或从传输层接收到错误时。在这些情况下, 事务层向UAC TU指示已发生传输错误。
8.1.3.2 无法识别的响应 (Unrecognized Responses)
UAC应该将任何它无法识别状态代码的最终响应 (Final Response) 视为该类别的x00响应, 并且必须能够处理x00响应。例如, 如果UAC收到432 (未知状态代码) 响应, 它应该将其视为400 (Bad Request) 响应。
如果对INVITE请求的响应带有UAC不理解的状态代码, UAC必须使用ACK确认该响应。
UAC必须将其不理解的任何临时响应 (Provisional Response) 视为100 (Trying) 响应。
8.1.3.3 Via
如果响应的顶部Via头字段值中存在"received"参数, UAC必须将该参数的值视为响应来源的源IP地址。
8.1.3.4 处理3xx响应 (Processing 3xx Responses)
在收到3xx类响应后, UAC应该尝试使用响应的Contact头字段值中提供的URI联系所请求资源的用户或服务。
3xx响应可能包含消息体。除非响应是305 (Use Proxy), 否则重定向响应可以包含多个Contact值, 提供替代位置以指示用户或资源的位置。UAS可以选择Contact值的任意顺序。
如果响应是300 (Multiple Choices), Contact头字段值可能包含可由用户或UAC自动选择的联系位置列表。
如果响应是301 (Moved Permanently) 或302 (Moved Temporarily), 则可以使用Contact头字段值联系用户。305 (Use Proxy) 响应指示必须通过响应中指示的Contact字段中的代理联系该资源。
这个规范不强制要求UAC遵循3xx响应中提供的重定向指示。
8.1.3.5 处理4xx响应 (Processing 4xx Responses)
某些4xx响应代码要求UAC修改请求并重新尝试。这些包括401 (Unauthorized)、407 (Proxy Authentication Required)、413 (Request Entity Too Large)、415 (Unsupported Media Type)、416 (Unsupported URI Scheme) 和420 (Bad Extension)。
对于401和407响应, UAC应该缓存授权凭证, 以便将来可以使用它们, 而无需提示用户。
对于413, UAC应该重试请求, 但使用较小的消息体或根本不使用消息体。
对于415, UAC应该重试请求, 使用Accept头字段中指示的媒体类型。
对于416, UAC应该重试请求, 使用SIP URI方案。
对于420, UAC应该重试请求, 在Require或Proxy-Require头字段中不包含Unsupported头字段中列出的选项标签。
8.2 UAS行为 (UAS Behavior)
当UAS处理对话外部的请求时, 无论方法如何, 都会遵循一组处理规则。第12节提供了有关UAS如何判断请求是在对话内部还是外部的指导。
请注意, 请求处理是原子的。如果接受请求, 则必须执行与其关联的所有状态更改。如果被拒绝, 则不得执行所有状态更改。
UAS应该按照本节后续步骤的顺序处理请求 (即, 从身份验证开始, 然后检查方法、头字段等, 贯穿本节的其余部分)。
8.2.1 方法检查 (Method Inspection)
一旦请求经过身份验证 (或跳过身份验证), UAS必须检查请求的方法。如果UAS识别但不支持请求的方法, 它必须生成405 (Method Not Allowed) 响应。生成响应的程序在第8.2.6节中描述。UAS还必须向405 (Method Not Allowed) 响应添加Allow头字段。Allow头字段必须列出生成消息的UAS支持的方法集。Allow头字段在第20.5节中介绍。
如果方法是服务器支持的方法之一, 则继续处理。
8.2.2 头字段检查 (Header Inspection)
如果UAS不理解请求中的头字段 (即, 该头字段未在本规范或任何支持的扩展中定义), 服务器必须忽略该头字段并继续处理消息。UAS应该忽略处理请求不必要的任何格式错误的头字段。
8.2.2.1 To和Request-URI
To头字段标识From字段中标识的用户指定的请求的原始接收者。由于呼叫转移或其他代理操作, 原始接收者可能是也可能不是处理请求的UAS。当To头字段不是UAS的身份时, UAS可以应用任何策略来确定是否接受请求。但是, 建议UAS接受请求, 即使它们不识别To头字段中的URI方案 (例如tel: URI), 或者To头字段未寻址此UAS的已知或当前用户。另一方面, 如果UAS决定拒绝请求, 它应该生成具有403 (Forbidden) 状态代码的响应并将其传递给服务器事务以进行传输。
但是, Request-URI标识要处理请求的UAS。如果Request-URI使用UAS不支持的方案, 它应该使用416 (Unsupported URI Scheme) 响应拒绝请求。如果Request-URI未标识UAS愿意接受请求的地址, 它应该使用404 (Not Found) 响应拒绝请求。通常, 使用REGISTER方法将其记录地址绑定到特定联系地址的UA将看到Request-URI等于该联系地址的请求。接收到的Request-URI的其他潜在来源包括由UA发送的建立或刷新对话的请求和响应的Contact头字段。
8.2.2.2 合并的请求 (Merged Requests)
如果请求的To头字段中没有标签, UAS核心必须根据正在进行的事务检查请求。如果From标签、Call-ID和CSeq与正在进行的事务完全匹配, 但请求与该事务不匹配 (基于第17.2.3节中的匹配规则), UAS核心应该生成482 (Loop Detected) 响应并将其传递给服务器事务。
同一请求已多次到达UAS, 遵循不同的路径, 很可能是由于分叉 (Forking)。UAS处理接收到的第一个这样的请求, 并对其余请求响应482 (Loop Detected)。
8.2.2.3 Require
假设UAS决定它是处理请求的适当元素, 它会检查Require头字段 (如果存在)。
Require头字段由UAC使用, 以告诉UAS关于UAC期望UAS支持的SIP扩展, 以便正确处理请求。其格式在第20.32节中描述。如果UAS不理解Require头字段中列出的选项标签, 它必须通过生成状态代码为420 (Bad Extension) 的响应来响应。UAS必须添加Unsupported头字段, 并在其中列出请求的Require头字段中它不理解的那些选项。
请注意, 在SIP CANCEL请求中或在为非2xx响应发送的ACK请求中, 不得使用Require和Proxy-Require。如果这些头字段出现在这些请求中, 则必须忽略它们。
2xx响应的ACK请求必须仅包含初始请求中存在的那些Require和Proxy-Require值。
示例:
UAC->UAS: INVITE sip:[email protected] SIP/2.0
Require: 100rel
UAS->UAC: SIP/2.0 420 Bad Extension
Unsupported: 100rel
这种行为确保当双方都理解所有选项时, 客户端-服务器交互将继续进行而不会延迟, 并且仅在不理解选项时才会减慢 (如上例所示)。对于匹配良好的客户端-服务器对, 交互快速进行, 节省了协商机制通常需要的往返。此外, 当客户端需要服务器不理解的功能时, 它还消除了歧义。某些功能 (如呼叫处理字段) 仅对端系统感兴趣。
8.2.3 内容处理 (Content Processing)
假设UAS理解客户端所需的任何扩展, UAS会检查消息体以及描述它的头字段。如果存在类型 (由Content-Type指示)、语言 (由Content-Language指示) 或编码 (由Content-Encoding指示) 不被理解的任何消息体, 并且该消息体部分不是可选的 (如Content-Disposition头字段所示), UAS必须使用415 (Unsupported Media Type) 响应拒绝请求。响应必须包含Accept头字段, 列出它理解的所有消息体的类型, 以防请求包含UAS不支持的类型的消息体。如果请求包含UAS不理解的内容编码, 响应必须包含Accept-Encoding头字段, 列出UAS理解的编码。如果请求包含UAS不理解语言的内容, 响应必须包含Accept-Language头字段, 指示UAS理解的语言。除了这些检查之外, 消息体处理取决于方法和类型。有关处理特定于内容的头字段的更多信息, 请参见第7.4节以及第20.11至20.15节。
8.2.4 应用扩展 (Applying Extensions)
希望在生成响应时应用某些扩展的UAS, 仅当请求的Supported头字段中指示对该扩展的支持时, 才不得这样做。如果不支持所需的扩展, 服务器应该仅依赖基线SIP和客户端支持的任何其他扩展。在极少数情况下, 如果服务器无法在没有扩展的情况下处理请求, 服务器可以发送421 (Extension Required) 响应。此响应指示如果没有对特定扩展的支持, 就无法生成正确的响应。所需的扩展必须包含在响应的Require头字段中。不建议此行为, 因为它通常会破坏互操作性。
应用于非421响应的任何扩展必须列在响应中包含的Require头字段中。当然, 服务器不得应用请求的Supported头字段中未列出的扩展。因此, 响应中的Require头字段将仅包含标准跟踪RFC中定义的选项标签。
8.2.5 处理请求 (Processing the Request)
假设通过了前面小节中的所有检查, UAS处理变为特定于方法的。第10节涵盖REGISTER请求, 第11节涵盖OPTIONS请求, 第13节涵盖INVITE请求, 第15节涵盖BYE请求。
8.2.6 生成响应 (Generating the Response)
当UAS希望构造对请求的响应时, 它遵循以下小节中详细说明的一般程序。可能还需要特定于相关响应代码的其他行为, 这些行为未在本节中详细说明。
一旦完成与响应创建相关联的所有程序, UAS将响应传回从中接收请求的服务器事务。
8.2.6.1 发送临时响应 (Sending a Provisional Response)
对于生成响应的一个主要与方法无关的准则是, UAS不应该为非INVITE请求发出临时响应。相反, UAS应该尽快为非INVITE请求生成最终响应。
当生成100 (Trying) 响应时, 必须将请求中存在的任何Timestamp头字段复制到此100 (Trying) 响应中。如果生成响应存在延迟, UAS应该在响应的Timestamp值中添加延迟值。此值必须包含响应发送时间与请求接收时间之间的差异 (以秒为单位)。
8.2.6.2 头字段和标签 (Headers and Tags)
响应的From字段必须等于请求的From头字段。响应的Call-ID头字段必须等于请求的Call-ID头字段。响应的CSeq头字段必须等于请求的CSeq字段。响应中的Via头字段值必须等于请求中的Via头字段值, 并且必须保持相同的顺序。
如果请求在请求中包含To标签, 则响应中的To头字段必须等于请求中的To头字段。但是, 如果请求中的To头字段不包含标签, 则响应中的To头字段中的URI必须等于To头字段中的URI; 此外, UAS必须向响应中的To头字段添加标签 (100 (Trying) 响应除外, 其中可能存在标签)。这用于标识正在响应的UAS, 可能导致对话ID的组件。相同的标签必须用于对该请求的所有响应, 包括最终响应和临时响应 (再次除了100 (Trying))。标签生成的程序在第19.3节中定义。
8.2.7 无状态UAS行为 (Stateless UAS Behavior)
无状态UAS是不维护事务状态的UAS。它正常响应请求, 但在发送响应后丢弃任何通常由UAS保留的状态。如果无状态UAS接收到请求的重传, 它会重新生成响应并重新发送, 就像它正在响应请求的第一个实例一样。除非该方法的请求处理总是会对相同的请求产生相同的响应, 否则UAS不能是无状态的。这排除了无状态注册器 (Registrar), 例如。无状态UAS不使用事务层; 它们直接从传输层接收请求并将响应直接发送到传输层。
无状态UAS角色主要用于处理未经身份验证的请求, 对这些请求发出挑战响应。如果以有状态方式处理未经身份验证的请求, 则恶意的未经身份验证的请求洪水可能会创建大量事务状态, 这可能会减慢或完全停止UAS中的呼叫处理, 从而有效地创建拒绝服务条件; 有关更多信息, 请参见第26.1.5节。
无状态UAS最重要的行为如下:
- 无状态UAS不得发送临时 (1xx) 响应。
- 无状态UAS不得重传响应。
- 无状态UAS必须忽略ACK请求。
- 无状态UAS必须忽略CANCEL请求。
- To头标签必须以无状态方式生成 - 以将始终为相同请求一致生成相同标签的方式。有关标签构造的信息, 请参见第19.3节。
在所有其他方面, 无状态UAS的行为方式与有状态UAS相同。UAS可以为每个新请求以有状态或无状态模式运行。
8.3 重定向服务器 (Redirect Servers)
在某些架构中, 可能希望减少负责路由请求的代理服务器的处理负载, 并通过依赖重定向来提高信令路径的鲁棒性。
重定向允许服务器将请求的路由信息推送到响应中返回给客户端, 从而将自己从此事务的进一步消息传递循环中移除, 同时仍有助于定位请求的目标。当请求的发起者收到重定向时, 它将基于它收到的URI发送新请求。通过将URI从网络核心传播到其边缘, 重定向允许相当大的网络可扩展性。
重定向服务器在逻辑上由服务器事务层和可以访问某种位置服务 (Location Service) 的事务用户组成 (有关注册器和位置服务的更多信息, 请参见第10节)。此位置服务实际上是一个数据库, 包含单个URI与一组或多组替代位置之间的映射, 在这些位置可以找到该URI的目标。
重定向服务器不发出任何自己的SIP请求。在接收到除CANCEL之外的请求后, 服务器要么拒绝该请求, 要么从位置服务收集替代位置列表并返回3xx类的最终响应。对于格式良好的CANCEL请求, 它应该返回2xx响应。此响应结束SIP事务。重定向服务器为整个SIP事务维护事务状态。客户端负责检测重定向服务器之间的转发循环。
当重定向服务器向请求返回3xx响应时, 它将一个 (或多个) 替代位置的列表填充到Contact头字段中。Contact头字段值的"expires"参数也可以提供, 以指示Contact数据的生存期。
Contact头字段包含提供要尝试的新位置或用户名的URI, 或者可以简单地指定其他传输参数。301 (Moved Permanently) 或302 (Moved Temporarily) 响应也可以提供与初始请求目标相同的位置和用户名, 但指定要尝试的其他传输参数, 例如不同的服务器或多播地址, 或将SIP传输从UDP更改为TCP或反之亦然。
但是, 重定向服务器不得将请求重定向到与Request-URI中的URI相等的URI; 相反, 如果URI不指向自身, 服务器可以将请求代理到目标URI, 或者可以使用404拒绝它。
如果客户端使用出站代理, 并且该代理实际上重定向请求, 则可能出现无限重定向循环。
请注意, Contact头字段值也可以引用与最初调用的资源不同的资源。例如, 连接到PSTN网关的SIP呼叫可能需要传递特殊的信息公告, 例如"您拨打的号码已更改"。
Contact响应头字段可以包含任何指示可以到达被叫方的位置的合适URI, 不限于SIP URI。例如, 它可以包含电话、传真或irc的URI (如果它们已定义) 或mailto: (RFC 2368 [32]) URL。第26.4.4节讨论了将SIPS URI重定向到非SIPS URI的含义和限制。
Contact头字段值的"expires"参数指示URI有效期。参数的值是一个表示秒数的数字。如果未提供此参数, 则Expires头字段的值确定URI的有效期。格式错误的值应该被视为等同于3600。
这为RFC 2543提供了适度的向后兼容性, RFC 2543允许在此头字段中使用绝对时间。如果收到绝对时间, 它将被视为格式错误, 然后默认为3600。
本章小结:
第8章详细规定了用户代理 (UA) 在对话外部处理请求和响应时的通用行为规则, 包括:
- UAC行为: 如何生成请求 (必需头字段), 如何发送请求 (DNS解析、传输选择), 如何处理响应 (3xx重定向、4xx错误等)
- UAS行为: 如何检查方法和头字段, 如何处理内容, 如何生成响应, 无状态UAS的特殊规则
- 重定向服务器: 返回3xx响应, 使用Contact头字段提供替代位置
这些规则构成了SIP协议实现的基础, 确保了不同供应商的SIP实现之间的互操作性。