SIP协议是一个基于文本的协议,使用UTF-8字符集(RFC2279[7])。
一个SIP消息既可以是一个从客户端到服务器端的请求,也可以是一个从服务器端到客户端的一个应答。
即使在字符集上和语法细节上有所不同,请求(7.1)还是应答(7.2)消息都基于RFC2822格式的。(SIP允许包头域不是标准的RFC2822包头域)。这两种消息类型都由一个起始行,一个或者多个包头域,一个可选的消息中文组成。
一般消息= 起始行
*消息包头
CRLF
[消息正文]
起始行= 请求行/状态行
起始行、每一个包头行,空行、都必须由回车换行组成(CRLF)。即使消息中文没有,也必须有一个空行跟随。
除了在字符集上的区别以外,很多SIP的消息和包头域的格式都同HTTP/1.1一样。我们在这里就不重复它的语法和语义了,我们用[HX.Y]来标志HTTP/1.1规范(RFC2616[8])的X.Y节的描述。
SIP并非一个HTTP的超集或者扩展。
SIP请求是根据起始行中的Request-Line来区分的。一个Request_line包含方法名字,Request-URI,用单个空格(SP)间隔开的协议版本。
Request-Line由CRLF结束。除了用作行结束标志以外,不允许CR或者LF出现在其他地方。在其他域中,不允许出现线形的空白(liner whitespace LWS)
Request-Line = Method SP Request-URI SP SIP-VERSION CRLF
Method: 这个规范规定了6中方法:REGISTER用于登记联系信息,INVITE,ACK,CANCEL用于建立会话,BYE用于结束会话,OPTIONS用于查询服务器负载。SIP扩展、标准RFC追加可能包含扩展的方法。
Request-URI: Request-URI是一个SIP或者SIPS URI,他们在19.1节由描述。也可以是一个通用的URI(RFC 2396[5])。它标志了这个请求所用到的用户或者服务的地址。Request-URI禁止包含空白字符或者控制字符,并且禁止用”<>”括上。
SIP 元素可以支持除了SIP或者SIPS之外所规定的Request-URIs。比如”tel” URI模式(RFC 2806[9])。SIP元素可以用他们自己的机制来转换non-SIP URIs到SIP URI,SIPS URI或者其他什么格式的URI。
SIP-Version:请求和应答消息都包含当前使用的SIP版本,这个遵循[H3.1](类似HTTP用SIP替代,用SIP/2.0替代HTTP/1.1)中关于版本的规定,版本依赖,升级版本号。一个应用,发出的SIP消息一定包含了SIP-Version “SIP/2.0”。这个SIP版本串是大小写不铭感的,但是在实现中必须发送大写。
不像HTTP/1.1,SIP把版本号当作一个文本串处理。在实现上,这个应该不会有区别。
SIP应答和SIP请求的区别在于在START-LINE中是否包含一个STATUS-LINE。一个status-line在由数字表达的status-code之前,是一个协议的版本串,每一个元素之间用一个单个SP(空格)分开。
除了最后用作结束标志以外,CR/LF不允许出现在其他地方。
status-line = SIP-VERSION SP STATUS-CODE SP Reasong-Phrase CRLF
Status-Code 是一个3位的数字result code,用来标志处理请求的一个结果。Reason-Phrase是一个简短的Status-Code的说明。Status-Code是为了能自动处理使用的,但是Reason-Phrase是用来给用户看得。一个客户端并不要求一定要显示或者解释这个Reason-Phrase。本文档建议输出这个reason-phrase,实现中可以选择其他文本,比如用请求包头中指定的合适语言来显示。
status-code的第一个数字表示了应答的类型。接下来两个数字并不作分类使用。基于这个原因,任何status code在100到199的可以统称位”1xx应答”,类似的,在200到299的可以统称位”2xx应答”,依此类推。SIP/2.0允许6类应答:
1xx:临时应答-请求已经接收,正在处理这个请求。
2xx:成功处理-请求已经成功接收,并且正确处理了这个请求。
3xx:重定向-还需要附加的操作才能完成这个请求,本请求转发到其他的服务器上处理。
4xx:客户端错误--请求包含错误的格式或者不能在这个服务器上完成。
5xx:服务器错误-服务器不能正确的处理这个显然合法的请求。
6xx:全局错误-请求不能被任何服务器处理。
21节定义了详细的代码说明。
SIP头域和HTTP头域在语法和语义上都比较类似。特别的,SIP头域遵循[H4.2]关于消息头的语法的定义,并且遵循多行的扩展头域的规则。(后者 is specified in HTTP with implicit whitespace and folding)。这个规范遵循RFC2234[10],并且把清晰的空白和封装作为内在的语法规则。
[H4.2]也定义了具有相同域名的多个头域,他们的值是用逗号分开的列表,可以合并到一个头域中。这个也适用于SIP,但是细节上略有不同,因为语法不同。实际上,任何SIP的包头语法都是基于如下范式的:
header = “ header-name” HCOLON header-value *(COMMA header-value)
这个允许合并在具有同一个域名的多个头域,到一个用逗号分割的单个头域中。Contact头域除了当域值是”*”之外,都允许用逗号分割的列表。
头域遵循在RFC2822的2.2节定义的通用头域格式。每一个头域都由一个域名加上冒号(”:”)和域值组成。
field-name:field-value
消息头的正则语法在25节中有介绍介绍。
在消息头中,允许在冒号的左右有任意个数的空白;但是,在实现中,建议避免域名和冒号中间有空格,并且建议在冒号和值之间使用单个空格(SP)。
Subject: lunch
Subject : lunch
Subject :lunch
Subject: lunch
所以,上面的都是合法的,也是相等的,但是最后一种是我们所推荐的。
头域可以扩展成为多行的,只要在每一个附加行前边用至少一个SP或者水平TAB(HT)打头就可以了。这种多行的头域在行结尾并且在下一行之前的空白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等等)放在消息头的最前边,这样可以提高处理的速度。相同域名的域之间的顺序非常重要。只有当单个头域的域值是可以用逗号分割的列表的时候,才可以表达成为同一个域名的多个头域(这就是说,如果遵循7.3定义的语法)。也就是意味着必须可以将同一个域名的多个头域在不改变消息语义的前提下,改换表达成为一对”域名: 域值”;这个转换是通过顺序增加每一个域的域值,域值之间用逗号分割。这个规则有几个例外,就是WWW-Authenticate,Authorization,Proxy-Authenticate,和Proxy-Authorization头域。多个头域行可以在消息头中出现,但是由于他们的语法并不遵循7.3中定义的通用格式,所以,他们并不能合并成为单个头域行。
在实现上,必须能够既能够处理多个头域行的情况,也必须能够处理用逗号分割的合并的单个头域行的情况。
下边的几组头域是相等的:
Route: <sip:[email protected]>
Subject: Lunch
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>, <sip:[email protected]>
Route: <sip:[email protected]>
Subject: Lunch
Subject: Lunch
Route: <sip:[email protected]>, <sip:[email protected]>
<sip:[email protected]>
下边各组是合法的,但是并不相等。
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>,<sip:[email protected]>,<sip:[email protected]>
每一个头域值的格式是依赖于它的头域名的。他可以是任意顺序的TEXT-UTF8字符,也可以是一个空格,标记,分隔符,引号括起来的字串的组合。很多头域都回附带一个通用的域值格式。这个域值格式是由分号分开的参数名和参数值的组合:
field-name: field-value *(;parameter-name=parameter-value)
虽然在域值里边可以有任意数量的parameter-name/parameter-value对,但是不能允许有相同的parameter-name存在(唯一性)。除了特别指出的头域之外,头域中的域名、域值、parameter name parameter-value都是大小写不敏感的。标记词始终是大小写不铭感的。除非有特别的指定,引号串的字符串是大小写敏感的。例如:
Contact: <sip:[email protected]>;expires=3600
和
CONTACT: <sip:[email protected]>; ExPiReS=3600
相同。
Content-Disposition: session;handling=optional
和
content-disposition: Session;HANDLING=OPTIONAL
相同。
下边的两个头域不相同:
Warning: 370 devnull “Choose a bigger pipe”
Warning: 370 devnull “CHOOSE A BIGGER PIPE”
有一些头域是仅仅在请求(或者应答)中有效的。这些头域叫做请求头域或者应答头域。如果消息中的头域与这个消息的类型不匹配(比如在应答消息中出现的请求头域),这个头域必须被忽略。20节定义了每一个头域的分类。
SIP提供了一个用缩写格式来表达通用头域名字的机制。这个有助于避免消息过大而导致通讯层无法传输(比如在UDP传输的时候超过了最大传输单元(MTU))。这个缩写格式在20节定义。
缩写格式的消息头域名字可以在不改变消息语义的情况下替代较大的消息头域名字。在单个消息中,头域名字既可以用长的格式,也可以用缩写格式。在实现中,必须同时支持对长名字和缩写名字的处理。
请求信息,包括这个规范以后的扩展的新请求,都可以包含一个消息正文体。对消息正文体的解释依赖域请求的方法(请求类型)。对于应答消息来说,请求方法和应答状态(response status code)决定了消息正文体的格式。所有的应答消息都可以有一个消息正文体(body)。
消息中的internet媒体类别必须在Content-Type头域中指明。如果消息正文(body)通过某种形式的编码(encoding),比如压缩等等,都必须在Content-Encoding 头域中指明,否则Content-Encoding域必须忽略。如果可行,消息体的字符集作为Content-type头域的值的一部分表达。
在RFC2046[11]中定义的多部分”multipart” MIME类型可以在消息体中应用。在由多部分组成的消息体发送的时候,如果接受方的实现中,包头域的Accept域中,不包含多部分的标记,那么发送方必须发送一个非多部分的session description。
SIP消息可以包含二进制的包体或者部分包体。如果发送方没有其他显示的字符集参数指出,媒体的文本”text”子类型会是缺省的字符集”UTF-8”。
在Content-Length头域中存放了包体的字节长度。第20.14节讲述了本域的详细解释。
HTTP/1.1的“chunked”传输编码方式并不适用于SIP。(备注:chuncked编码传输方式是通过把消息正文体分为一系列的块来传输的,每一块有它自己的大小标记)
不同于HTTP的是,SIP实现可以使用UDP或者其他非可靠传输协议。每一帧包括一个请求或者应答。第18节讲述了非可靠传输的应用。
在处理以面向流的通讯为基础的SIP消息的时候,必须忽略在开始行之前的CRLF[H4.1]。
Content-Length头域用来确定每一个SIP消息在通讯流中的结束位置的。在基于面向流通讯基础上的SIP消息一定要使用这个头域。
Implementations that send requests
containing multipart message bodies MUST send a session description
as a non-multipart message body if the remote implementation requests
this through an Accept header field that does not contain multipart.