SIP协议格式解读

SIP协议包括三个部分:起始行、一个/多个字段(field)组成的消息头、一个标志消息头结束的空行(CRLF)以及作为可选项的消息体(message body)组成。
1. 起始行
起始行分请求的起始行和响应的起始行
1.1 请求起始行
一个 Request_line 包含方法名字, Request-URI,用单个空格(SP)间隔开的协议版本。 Request-Line 由 CRLF 结束。除了用作行结束标志以外,不允许 CR 或者 LF 出现在其他地方。
格式:
Request-Line = Method SP Request-URI SP SIP-VERSION CRLF
举例:REGISTER sip: telcomx.tel.com SIP2.0
具体含义:

名称含义
Method规定了 6 中方法:REGISTER 用于登记联系信息,INVITE, ACK,CANCEL 用于建立会话,BYE 用于结束会话,OPTIONS 用于查询服务器负载。 SIP 扩展、标准 RFC 追加可能包含扩展的方法。
SIP元素可以支持除了 SIP 或者 SIPS 之外所规定的 Request-URIs。比如”tel” URI 模式(RFC 2806[9])。SIP 元素可以用他们自己的机制来转换 non-SIP URIs 到 SIP URI, SIPS URI 或者其他什么格式的 URI
Request-URI是一个 SIP 或者 SIPS URI,也可以是一个通用的 URI(RFC 2396[5])。它标志了这个请求所用到的用户或者服务的地址。 Request-URI 禁止包含空白字符或者控制字符,并且禁止用”<>”括上
SIP-Version请求和应答消息都包含当前使用的 SIP 版本,这个遵循[H3.1](类似 HTTP用 SIP 替代,用 SIP/2.0 替代 HTTP/1.1)中关于版本的规定,版本依赖,升级版本号。一个应用,发出的 SIP 消息一定包含了 SIP-Version “SIP/2.0”。这个 SIP 版本串是大小写不铭感的,但是在实现中必须发送大写。
// SIP请求消息的起始行(RFC3261-7.1)
type RequestLine struct {
	Method     string // 请求方法
	RequestURI URI    // SIP消息目标地址,无"<>"尖括号
	SIPVersion string // SIP版本号
}

1.2 响应起始行
SIP 应答和 SIP 请求的区别在于在 START-LINE 中是否包含一个 STATUS-LINE。一个status-line 在由数字表达的 status-code 之前,是一个协议的版本串,每一个元素之间用一个单个 SP(空格)分开。 除了最后用作结束标志以外,CR/LF 不允许出现在其他地方。
格式:
status-line = SIP-VERSION SP STATUS-CODE SP Reasong-Phrase CRLF
举例:SIP/2.0 200 OK
具体含义:

名称含义
SIP-Version请求和应答消息都包含当前使用的 SIP 版本,这个遵循[H3.1](类似 HTTP用 SIP 替代,用 SIP/2.0 替代 HTTP/1.1)中关于版本的规定,版本依赖,升级版本号。一个应用,发出的 SIP 消息一定包含了 SIP-Version “SIP/2.0”。这个 SIP 版本串是大小写不铭感的,但是在实现中必须发送大写。
Status-Code一个 3 位的数字 result code,用来标志处理请求的一个结果。
Reason-Phrase是一个简短的 Status-Code 的说明。Status-Code 是为了能自动处理使用的,但是 Reason-Phrase 是用来给用户看得。一个客户端并不要求一定要显示或者解释这个 Reason-Phrase。

其中,status-code 的第一个数字表示了应答的类型。接下来两个数字并不作分类使用。基于这个原因,任何 status code 在 100 到 199 的可以统称位”1xx 应答”,类似的,在 200到 299 的可以统称位”2xx 应答”,依此类推。SIP/2.0 允许 6 类应答:
1xx:临时应答-请求已经接收,正在处理这个请求。
2xx:成功处理-请求已经成功接收,并且正确处理了这个请求。
3xx:重定向-还需要附加的操作才能完成这个请求,本请求转发到其他的服务器上处理。
4xx:客户端错误--请求包含错误的格式或者不能在这个服务器上完成。
5xx:服务器错误-服务器不能正确的处理这个显然合法的请求。
6xx:全局错误-请求不能被任何服务器处理。

// SIP应答消息的起始行(RFC3261-7.2)
type ResponseLine struct {
	SIPVersion   string // SIP版本号
	StatusCode   int    // 状态码
	ReasonPhrase string // 状态码的说明
}

```cpp
package sip

const (
	// SIP版本号
	SIPVersion = "SIP/2.0"

	// 协议类型
	SchemeSip = "sip"

	// SIP请求方法-RFC3261
	MethodInvite   = "INVITE"
	MethodAck      = "ACK"
	MethodBye      = "BYE"
	MethodCancel   = "CANCEL"
	MethodOptions  = "OPTIONS"
	MethodRegister = "REGISTER"

	// SIP请求方法-其他协议
	MethodPrack     = "PRACK"     // [RFC3262]
	MethodSubscribe = "SUBSCRIBE" // [RFC6665]
	MethodNotify    = "NOTIFY"    // [RFC6665]
	MethodPublish   = "PUBLISH"   // [RFC3903]
	MethodInfo      = "INFO"      // [RFC6086]
	MethodRefer     = "REFER"     // [RFC3515]
	MethodMessage   = "MESSAGE"   // [RFC3428]
	MethodUpdate    = "UPDATE"    // [RFC3311]
	MethodPing      = "PING"      // [https://tools.ietf.org/html/draft-fwmiller-ping-03]
)
**2. SIP 头域**
SIP 的包头语法都是基于如下范式的: 
*header = “ header-name” HCOLON header-value *(COMMA header-value)* *
这个允许合并在具有同一个域名的多个头域,到一个用逗号分割的单个头域中。Contact头域除了当域值是”*”之外,都允许用逗号分割的列表。
每一个头域都由一个域名加上冒号(”:”)和域值组成。 
*field-name:field-value* 
在消息头中,允许在冒号的左右有任意个数的空白;但是,在实现中,建议避免域名和冒号中间有空格,并且建议在冒号和值之间使用单个空格(SP)。
每一个头域值的格式是依赖于它的头域名的。他可以是任意顺序的 TEXT-UTF8 字符,也可以是一个空格,标记,分隔符,引号括起来的字串的组合。很多头域都回附带一个通用的域值格式。这个域值格式是由分号分开的参数名和参数值的组合: 
*field-name: field-value *(;parameter-name=parameter-value)*
虽然在域值里边可以有任意数量的 parameter-name/parameter-value 对,但是不能允许有相同的 parameter-name 存在(唯一性)。除了特别指出的头域之外,头域中的域名、域值、parameter name parameter-value 都是大小写不敏感的。标记词始终是大小写不铭感的。除非有特别的指定,引号串的字符串是大小写敏感的。例如:
***Contact: <sip:alice@atlanta.com>;expires=3600***

```cpp
// SIP头域(RFC3261-7.3)
// 行范式:header = "header-name" HCOLON header-value *(COMMA header-value)
// 头域至少包含TO、FROM、CSeq、Call-ID、Max-Forwards、Via字段
type Header struct {
	Via             ViaList     // (RFC3261-8.1.1.7) 请求路径
	From            User        // (RFC3261-8.1.1.3) 请求的原始发起者
	To              User        // (RFC3261-8.1.1.2) 请求的原始到达者
	CallID          string      // (RFC3261-8.1.1.4) 唯一标志
	CSeq            CSeq        // (RFC3261-8.1.1.5) 命令序列号
	MaxForwards     MaxForwards // (RFC3261-8.1.1.6) 最大转发数量限制
	ContentLength   int         // 正文长度
	ContentType     string      // (可选) 正文格式描述
	Contact         *User       // (可选) (RFC3261-8.1.1.8) 直接访问方式
	Expires         Expires     // (可选) 消息或内容过期时间
	Route           Route       // (可选) 请求的路由表
	RecordRoute     RecordRoute // (可选) 后续消息流处理的服务器列表
	UserAgent       string      // (可选) UAC的信息
	Authorization   string      // (可选) 用户认证信息
	WWWAuthenticate string      // (可选) 支持的认证方式和适用realm的参数的拒绝原因
	UnsupportLines  []string    // 暂不支持的行
}

3. SIP包体
请求信息,包括这个规范以后的扩展的新请求,都可以包含一个消息正文体。对消息正文体的解释依赖域请求的方法(请求类型)。对于应答消息来说,请求方法和应答状态(response status code)决定了消息正文体的格式。所有的应答消息都可以有一个消息正文体(body)。
消息中的 internet 媒体类别必须在 Content-Type 头域中指明。如果消息正文(body)通过某种形式的编码(encoding),比如压缩等等,都必须在 Content-Encoding 头域中指明,否则 Content-Encoding 域必须忽略。如果可行,消息体的字符集作为 Content-type头域的值的一部分表达。
在 RFC2046[11]中定义的多部分”multipart” MIME 类型可以在消息体中应用。在由多部分组成的消息体发送的时候,如果接受方的实现中,包头域的 Accept 域中,不包含多部分的标记,那么发送方必须发送一个非多部分的 session description。1
SIP 消息可以包含二进制的包体或者部分包体。如果发送方没有其他显示的字符集参数指出,媒体的文本”text”子类型会是缺省的字符集”UTF-8”。

// SIP返回状态码信息
type StatusCodeItem struct {
	Code   int
	Reason string
}

// SIP返回状态码
var (
	// 1xx - 临时应答
	StatusTrying               = StatusCodeItem{100, "Trying"}
	StatusRinging              = StatusCodeItem{180, "Ringing"}
	StatusCallIsBeingForwarded = StatusCodeItem{181, "Call Is Being Forwarded"}
	StatusQueued               = StatusCodeItem{182, "Queued"}
	StatusSessionProgress      = StatusCodeItem{183, "Session Progress"}

	// 2xx - 成功处理
	StatusOK = StatusCodeItem{200, "OK"}

	// 3xx - 重定向
	StatusMultipleChoices    = StatusCodeItem{300, "Multiple Choices"}
	StatusMovedPermanently   = StatusCodeItem{301, "Moved Permanently"}
	StatusMovedTemporarily   = StatusCodeItem{302, "Moved Temporarily"}
	StatusUseProxy           = StatusCodeItem{305, "Use Proxy"}
	StatusAlternativeService = StatusCodeItem{380, "Alternative Service"}

	// 4xx - 客户端错误
	StatusBadRequest                  = StatusCodeItem{400, "Bad Request"}
	StatusUnauthorized                = StatusCodeItem{401, "Unauthorized"}
	StatusPaymentRequired             = StatusCodeItem{402, "Payment Required"}
	StatusForbidden                   = StatusCodeItem{403, "Forbidden"}
	StatusNotFound                    = StatusCodeItem{404, "Not Found"}
	StatusMethodNotAllowed            = StatusCodeItem{405, "Method Not Allowed"}
	StatusNotAcceptable               = StatusCodeItem{406, "Not Acceptable"}
	StatusProxyAuthenticationRequired = StatusCodeItem{407, "Proxy Authentication Required"}
	StatusRequestTimeout              = StatusCodeItem{408, "Request Timeout"}
	StatusGone                        = StatusCodeItem{410, "Gone"}
	StatusRequestEntityTooLarge       = StatusCodeItem{413, "Request Entity Too Large"}
	StatusRequestURITooLong           = StatusCodeItem{414, "Request-URI Too Long"}
	StatusUnsupportedMediaType        = StatusCodeItem{415, "Unsupported Media Type"}
	StatusUnsupportedURIScheme        = StatusCodeItem{416, "Unsupported URI Scheme"}
	StatusBadExtension                = StatusCodeItem{420, "Bad Extension"}
	StatusExtensionRequired           = StatusCodeItem{421, "Extension Required"}
	StatusIntervalTooBrief            = StatusCodeItem{423, "Interval Too Brief"}
	StatusNoResponse                  = StatusCodeItem{480, "No Response"}
	StatusCallTransactionDoesNotExist = StatusCodeItem{481, "Call/Transaction Does Not Exist"}
	StatusLoopDetected                = StatusCodeItem{482, "Loop Detected"}
	StatusTooManyHops                 = StatusCodeItem{483, "Too Many Hops"}
	StatusAddressIncomplete           = StatusCodeItem{484, "Address Incomplete"}
	StatusAmbigious                   = StatusCodeItem{485, "Ambiguous"}
	StatusBusyHere                    = StatusCodeItem{486, "Busy Here"}
	StatusRequestTerminated           = StatusCodeItem{487, "Request Terminated"}
	StatusNotAcceptableHere           = StatusCodeItem{488, "Not Acceptable Here"}
	StatusRequestPending              = StatusCodeItem{491, "Request Pending"}
	StatusUndecipherable              = StatusCodeItem{493, "Undecipherable"}

	// 5xx - 服务器错误
	StatusServerInternalError = StatusCodeItem{500, "Server Internal Error"}
	StatusNotImplemented      = StatusCodeItem{501, "Not Implemented"}
	StatusBadGateway          = StatusCodeItem{502, "Bad Gateway"}
	StatusServiceUnavailable  = StatusCodeItem{503, "Service Unavailable"}
	StatusServerTimeout       = StatusCodeItem{504, "Server Timeout"}
	StatusVersionNotSupported = StatusCodeItem{505, "Version Not Supported"}
	StatusMessageTooLarge     = StatusCodeItem{513, "Message Too Large"}

	// 6xx - 全局错误
	StatusBusyEverywhere       = StatusCodeItem{600, "Busy Everywhere"}
	StatusDecline              = StatusCodeItem{603, "Decline"}
	StatusDoesNotExistAnywhere = StatusCodeItem{604, "Does Not Exist Anywhere"}
	StatusUnacceptable         = StatusCodeItem{606, "Not Acceptable"}
)
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值