首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >GoSIP 功能简介与技术解读:用 Go 实现 RFC 3261 的 SIP 栈

GoSIP 功能简介与技术解读:用 Go 实现 RFC 3261 的 SIP 栈

原创
作者头像
Openskeye
发布2026-05-09 15:31:26
发布2026-05-09 15:31:26
920
举报

## GoSIP 功能简介与技术解读:用 Go 实现 RFC 3261 的 SIP 栈

`ghettovoice/gosip` 是一个用 Go 编写的 SIP(Session Initiation Protocol)协议栈实现,目标覆盖 RFC 3261 的关键能力:消息模型、解析/构建、事务状态机、传输层,以及面向业务的 Server 编程接口。

协议标准参考:RFC 3261([IETF](https://tools.ietf.org/html/rfc3261))

项目地址:[`ghettovoice/gosip`](https://github.com/ghettovoice/gosip)

---

## 1. 总体架构:Server 分层编排 + 传输/事务/消息解耦

从源码目录和模块划分(`server.go`、`transport/`、`transaction/`、`sip/`)可以把 gosip 抽象成四层:

- **Server(应用编排层)**

- 负责接收传输/事务层上报的请求或 ACK

- 按 `RequestMethod` 路由到业务注册的 handler

- 提供 `Request(...)` / `RequestWithContext(...)` 这种“发起请求并等待响应”的 API

- 提供 `Respond(...)` / `RespondOnRequest(...)` 回包能力

- **Transport(传输层)**

- 支持 UDP/TCP/TLS/WS/WSS 等网络协议

- 负责监听、发送与消息解析产出 `sip.Message`

- **Transaction(事务状态机层)**

- 实现 SIP Transaction Layer(客户端事务、服务器事务)

- 使用 FSM + RFC 定时器管理重传、超时、ACK/CANCEL 相关流程

- 对外暴露统一的通道/接口(`Requests()`、`Acks()`、`Responses()`、`Errors()`)

- **SIP(消息模型层)**

- 定义 `sip.Message`、`sip.Request`、`sip.Response` 等接口与数据结构

- 实现报文构建器(`sip/builder.go`)与解析器(`sip/parser/*`)

- 提供 Digest 等认证能力(`sip/auth.go`)

这种解耦的好处是:你可以在不改业务逻辑的前提下,替换传输实现或复用事务/消息模型。

---

## 2. Server:路由请求、发起请求、上下文等待响应

### 2.1 `OnRequest`:按方法注册回调

Server 在创建时会初始化传输层与事务层(`transport.Layer` 与 `transaction.Layer`)。

业务侧通过:

- `OnRequest(method, handler)` 注册回调

当事务层上报新请求时,Server 会在 `handleRequest` 中按 `req.Method()` 查表路由到对应 handler。

若找不到 handler:

- 对非 ACK 请求:自动构造 `405 Method Not Allowed` 并回包

- 对 ACK:跳过响应阶段(ACK 场景没有完整事务响应)

### 2.2 发起请求:`RequestWithContext`

Server 提供:

- `Request(req)`:返回 `sip.ClientTransaction`

- `RequestWithContext(ctx, request, options...)`:返回最终 `sip.Response`(支持等待与取消)

在 `RequestWithContext` 中,Server 会:

- 创建 client transaction

- 启动 goroutine 监听:

- `tx.Responses()`:区分 provisional / success / failure

- `tx.Errors()`:事务错误上报

- 将 ctx.Done() 作为取消信号,触发 `tx.Cancel()`

此外还支持:

- `ResponseHandler`:每个收到的响应都可回调

- `Authorizer`:如果遇到 `401/407`,基于 Authorizer 进行认证并重试请求

### 2.3 自动补齐头字段

Server 的发送/回包前会执行 `appendAutoHeaders`,用于补齐例如:

- 缺少 `User-Agent`:追加默认 UA

- 缺少 `Server`:追加默认 Server header

- 对部分方法(如 `INVITE/REGISTER/OPTIONS/REFER/NOTIFY`)补齐 `Allow` 与 `Supported`(取决于已注册 handlers 与 extensions)

- 缺少 `Content-Length`:保证 body 长度一致

---

## 3. SIP 消息模型:线程安全的 headers + 明确的 request/response 接口

`sip/` 包里的关键点包括:

- `sip.Message` 抽象统一了:

- `StartLine()` / `String()` / `Body()` / `SetBody()`

- headers 管理(`AppendHeader/PrependHeader/ReplaceHeaders/...`)

- 常用 getter(如 `CallID`、`Via`、`From`、`To`、`CSeq`、`Content-Length` 等)

- `sip.Request`:

- 提供 `Method()`、`Recipient()`、`IsInvite()`、`IsAck()`、`IsCancel()` 等

- `StartLine()` 会按 request line 规则组装:`METHOD recipient SIP/2.0`

- `Transport()` 会结合 `Via`、Route、URI 参数、MTU 规则进行推断(例如 UDP 太大可能切换到 TCP)

- `Source()/Destination()` 会从 Via/Route/URI 推断端点信息

- `sip.Response`:

- 提供 `StatusCode()`、`Reason()`、`Previous()`(保存 provisional responses)

- `StartLine()` 输出为 status line:`SIP/2.0 200 OK`

- `IsProvisional/IsSuccess/...` 用于分类响应

headers 的内部实现通过锁保证并发安全,同时维护 header 输出顺序(`headerOrder`)。

---

## 4. 报文构建与解析:Builder + PacketParser(支持 packet 与 streamed)

### 4.1 Builder:`sip/builder.go`

`RequestBuilder` 提供链式构建请求:

- 默认生成 `Call-ID`、`CSeq`、`User-Agent`、`Max-Forwards`

- 支持设置:

- transport、host、method、recipient、body、call-id、via

- From/To/Contact/Expires/User-Agent 等标准头

- Accept/Require/Supported/Route 等能力头

- 以统一方式输出规范 SIP 报文

### 4.2 Parser:`sip/parser/*`

解析器核心是 `Parser` 接口(`Write` 入队、`ParseHeader` 注册自定义 header parser、`Stop/Reset` 控制状态)。

`PacketParser` 会:

- 通过双 CRLF 定位 body 起点并判断 body 长度

- 解析 start line(request 或 response)

- 解析 headers:

- 支持 header fold(续行行首为空白字符)

- 维护 header 解析策略:对已注册的 headerName 使用对应 parser,否则使用 `GenericHeader` 封装

- 解析 body:

- 校验长度与 `Content-Length` 一致

- 返回 `BrokenMessageError` 等结构化错误(便于上层处理)

流式解析(`streamed` 模式)则依赖 `Content-Length`,用于 TCP 等无法可靠识别消息边界的场景。

---

## 5. Transaction:客户端事务与服务器事务(FSM + RFC 定时器)

事务层是 gosip 最核心、也最“贴 RFC”的部分。

### 5.1 事务接口

事务层对外统一暴露:

- 客户端事务:`ClientTx` / `Responses()` / `Cancel()` / `OnAck/OnCancel`

- 服务器事务:`ServerTx` / `Respond(res)` / `Acks()` / `Cancels()`

事务层内部通过 `MakeClientTxKey` / `MakeServerTxKey` 生成交易匹配 key,用于关联重传、ACK、CANCEL 与最终响应。

### 5.2 FSM 状态与输入

客户端事务在 `client_tx.go` 中会:

- 初始化 FSM(`initFSM`)

- 设置定时器:

- 不可靠传输启动 Timer A(request 重传)

- 通用启动 Timer B(超时)

- reliable transport 则按 RFC 规则调整

- 在 `Receive` 时把 response 归类为:

- 1xx / 2xx / 300+,分别映射到不同 FSM 输入

服务器事务在 `server_tx.go` 中会:

- 根据 origin 是否 INVITE 选择不同 FSM 初始化策略

- 为 INVITE 触发 Timer 1xx,定时返回 `100 Trying`

- 在 `Receive` 中处理:

- 与 origin 方法匹配的 request

- ACK 与 CANCEL 的输入映射

这些行为让上层业务只需要关注 `Respond()`,无需关心重传/超时的复杂性。

---

## 6. Transport:网络协议适配层(UDP/TCP/…)

transport 层提供统一接口:

- `Listen(network, addr, options...)`

- `Send(msg)`

- `Messages()`:上送解析后的 `sip.Message` 给事务层

- `Errors()`:网络/连接错误上报

- `IsReliable()`、`IsStreamed()`:给事务层决定定时器策略

在 `transport/layer.go` 中,按网络名选择协议实现:

- `udp` -> `NewUdpProtocol`

- `tcp` -> `NewTcpProtocol`

- `tls/ws/wss` 等对应实现

### 6.1 发送时的 Via rewrite 与 DNS SRV

`Send(msg)` 中对 request 会执行:

- rewrite Via 的 `sent-by`:

- Transport 改写为实际 transport

- Host 改写为本机 IP

- 端口推断(如果未填,基于监听端口集合补齐或使用默认端口)

- 如果目的 host 不是 IP,会做 DNS SRV lookup(`LookupSRV("sip", proto, target.Host)`),选择合适的地址与端口后发送

### 6.2 UDP 与 TCP 的差异

- UDP:

- `udpProtocol.Listen()` 创建 UDP conn 并放入 ConnectionPool

- `Send()` 遍历 pool 按端口匹配连接并写入 `msg.String()`

- TCP:

- 通过 ListenerPool 和 ConnectionPool 管理监听器与连接

- 通过新连接事件 pipePools() 把连接交给连接池服务

---

## 7. 认证能力:Digest(MD5)与挑战应答重试

`sip/auth.go` 提供 Digest 认证(当前实现支持 Digest + MD5)。

核心包括:

- 从响应 header 中解析 challenge:`AuthFromValue(value)`

- 计算 response:`CalcResponse()`(按 RFC 2617 Digest 组合)

- `AuthorizeRequest(request, response, user, password)`:

- 处理 401(WWW-Authenticate)与 407(Proxy-Authenticate)

- 生成/注入 `Authorization` 或 `Proxy-Authorization`

配合 Server 的 `RequestWithContext` 重试逻辑,使认证流程在栈内部闭环。

---

## 8. 请求处理主线

```mermaid

sequenceDiagram

participant UA as 用户代码/业务 handler

participant Server as gosip.Server

participant Transport as transport.Layer

participant Parser as sip.Parser

participant Tx as transaction.Layer

participant ClientTx as sip.ClientTransaction / ServerTx

UA->>Server: OnRequest(method, handler)

Transport->>Parser: Parse SIP bytes

Parser-->>Transport: sip.Message

Transport-->>Tx: Messages channel

Tx-->>Server: Requests()/Acks()

Server->>UA: handler(req, tx)

UA->>Server: Respond(res) / RespondOnRequest(...)

Server->>Tx: tx.Respond(res)

Tx->>Transport: tpl.Send(res)

```

---

## 9. 适用场景

凭借上述模块化设计,gosip 常见用途包括:

- 实现 SIP UA(发起 INVITE/处理响应、ACK/CANCEL)

- 实现 Registrar/Proxy/Options/Refer/Notify 等方法型服务端能力(使用 `OnRequest`)

- 需要事务状态机正确性的 SIP 中继/代理场景

- 需要 Digest 认证闭环的部署(Server + Authorizer)

---

## 10. 总结

gosip 的价值在于:

- **分层清晰**:Server/Transport/Transaction/SIP 解耦,便于扩展与复用

- **事务状态机工程化**:FSM + RFC 定时器把复杂 SIP 行为内聚到栈内部

- **消息模型完备**:Request/Response 与 header 操作具备线程安全与可扩展性

- **解析/构建可用**:Builder + Parser 覆盖常见报文处理路径

- **认证闭环**:Digest 认证与挑战重试在栈内完成

如果你在项目里需要一个“可以直接写 SIP 业务代码”的工程化栈,gosip 是一个很值得研究并快速落地的选择。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档