├── utils ├── string.go └── sip.go ├── transaction ├── errors.go ├── fsm_ist.go ├── README.md ├── config.go ├── utils.go ├── fsm_nist.go ├── fsm_nict.go ├── fsm_ict.go ├── core.go └── transaction.go ├── .gitignore ├── transport ├── README.md ├── transport.go ├── example.go ├── udp_server.go ├── tcp_client.go ├── udp_client.go └── tcp_server.go ├── tu ├── README.md ├── server.go ├── common.go └── client.go ├── go.mod ├── sip ├── body.go ├── demo.go ├── status.go ├── head_test.go ├── README.md ├── message.go └── head.go ├── README.md ├── main.go └── go.sum /utils/string.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "encoding/json" 4 | 5 | func ToJSONString(v interface{}) string { 6 | b, _ := json.Marshal(v) 7 | return string(b) 8 | } 9 | 10 | func ToPrettyString(v interface{}) string { 11 | b, _ := json.MarshalIndent(v, "", " ") 12 | return string(b) 13 | } 14 | -------------------------------------------------------------------------------- /transaction/errors.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | //transaction 的错误定义 8 | var ( 9 | ErrorSyntax = errors.New("message syntax error") 10 | ErrorCheck = errors.New("message check failed") 11 | ErrorParse = errors.New("message parse failed") 12 | ErrorUnknown = errors.New("message unknown") 13 | ) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | vendor/ 16 | ./build 17 | 18 | .idea/ 19 | 20 | .DS_Store 21 | 22 | -------------------------------------------------------------------------------- /transport/README.md: -------------------------------------------------------------------------------- 1 | 2 | #### 介绍 3 | 4 | transport 包括客户端和服务器端,仅实现tcp和udp的传输层,不负责具体消息的解析和处理。不负责粘包、半包、消息解析、心跳处理、状态管理等工作。 5 | 6 | 比如设备关闭或者离线,要修改缓存状态、数据库状态、发送离线通知、执行离线回调等等,都在上层处理。tcp server 和 udp server、tcp client 和 udp client , 消息的接收和发送都在外面处理。 7 | 8 | tcp是流传输,需要注意粘包和半包的处理。在上层处理tcp包的时候,可以尝试使用 ring buffer 9 | 10 | 11 | #### usage 12 | 13 | 参考 example.go 14 | 15 | #### TODO 16 | 17 | - sip协议的传输层,TCP和UDP有所不同,比如重传以及超时的错误信息等。所以需要在 transaction上面,处理消息重传、错误上报等。具体参考RFC3261。 18 | 19 | -------------------------------------------------------------------------------- /tu/README.md: -------------------------------------------------------------------------------- 1 | 2 | Transaction User(TU)事务用户:在transaction 层之上的协议层。TU包括了UAC core、UAS core,和proxy core。 3 | tu处理业务逻辑,并对事物层进行操作。 4 | 5 | #### 类型 6 | 7 | SIP服务器典型有以下几类: 8 | 9 | a. 注册服务器 -即只管Register消息,这里相当于location也在这里了 10 | 11 | b. 重定向服务器 -给ua回一条302后,转给其它的服务器,这样保证全系统统一接入 12 | 13 | c. 代理服务器 -只做proxy,即对SIP消息转发 14 | 15 | d. 媒体服务器-只做rtp包相关处理,即media server 16 | 17 | e. B2BUA - 这个里包实际一般是可以含以上几种服务器类型 18 | 19 | 暂时仅处理gb28181 相关 20 | 21 | #### TU 22 | 23 | tu负责根据应用层需求,发起操作。 24 | 比如注册到sip服务器、发起会话、取消会话等。 -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module gogb28181 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/abiosoft/ishell v2.0.0+incompatible 7 | github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect 8 | github.com/chzyer/logex v1.1.10 // indirect 9 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect 10 | github.com/fatih/color v1.9.0 // indirect 11 | github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect 12 | github.com/stretchr/testify v1.6.1 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /sip/body.go: -------------------------------------------------------------------------------- 1 | package sip 2 | 3 | //sip message body 4 | //xml解析的字段 5 | const ( 6 | MESSAGE_CATALOG = "Catalog" 7 | MESSAGE_DEVICE_INFO = "DeviceInfo" 8 | MESSAGE_BROADCAST = "Broadcast" 9 | MESSAGE_DEVICE_STATUS = "DeviceStatus" 10 | MESSAGE_KEEP_ALIVE = "Keepalive" 11 | MESSAGE_MOBILE_POSITION = "MobilePosition" 12 | MESSAGE_MOBILE_POSITION_INTERVAL = "Interval" 13 | 14 | ELEMENT_DEVICE_ID = "DeviceID" 15 | ELEMENT_DEVICE_LIST = "DeviceList" 16 | ELEMENT_NAME = "Name" 17 | ELEMENT_STATUS = "Status" 18 | ) 19 | -------------------------------------------------------------------------------- /transaction/fsm_ist.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | func ist_rcv_invite(t *Transaction, e *EventObj) error { 4 | return nil 5 | } 6 | func osip_ist_timeout_g_event(t *Transaction, e *EventObj) error { 7 | return nil 8 | } 9 | func osip_ist_timeout_h_event(t *Transaction, e *EventObj) error { 10 | return nil 11 | } 12 | func ist_snd_1xx(t *Transaction, e *EventObj) error { 13 | return nil 14 | } 15 | func ist_snd_2xx(t *Transaction, e *EventObj) error { 16 | return nil 17 | } 18 | func ist_snd_3456xx(t *Transaction, e *EventObj) error { 19 | return nil 20 | } 21 | func ist_rcv_ack(t *Transaction, e *EventObj) error { 22 | return nil 23 | } 24 | func osip_ist_timeout_i_event(t *Transaction, e *EventObj) error { 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### Usage 2 | 3 | 运行程序,进入交互试shell,输入要打开的子应用: 4 | 5 | 有如下几个子应用: 6 | 传输层:tcps、tcpc、udps、udpc 7 | TU层:uas 和 uac 8 | 9 | ``` 10 | ➜ gogb28181 go run main.go 11 | gb28181 test 12 | >>> help 13 | 14 | Commands: 15 | clear clear the screen 16 | exit exit the program 17 | help display help 18 | tcpc tcp client 19 | tcps tcp server 20 | uac sip user agent client 21 | uas sip user agent server 22 | udpc udp client 23 | udps udp server 24 | 25 | ``` 26 | 27 | 28 | 29 | #### 说明1 30 | 31 | 对比了很多sip库的实现,有的与标准sip差距太大,有的实现的太复杂。osip2比较容易懂。所以这个代码参考(抄袭)的osip2 和 exosip2的相关实现。比如状态机的对应管理连函数名都没改。 32 | 33 | 34 | #### 说明2 35 | 36 | 这是一个gb28181的golang实现。仅实现了部分基础库。 37 | 38 | 39 | 1、sip标准兼容性 40 | 41 | sip协议的实现github上其实有好几个go库了,但都实现的过于复杂了。所以我这边重新造了个轮子,毕竟go造轮子太简单了。 42 | 43 | ``` 44 | Implementations MUST be able to process multiple header field rows with the same name in any combination of the 45 | single-value-per-line or comma-separated value forms. 46 | ``` 47 | 上面是RFC3261的内容。 48 | 因为gb28181对于sip的使用也是很初级的(我的理解),并且后续扩展的话也很方便。 49 | 我们这个sip包里面并没有完全实现RFC,很多header字段没有支持、且header字段不处理多值的情况。 50 | 51 | -------------------------------------------------------------------------------- /tu/server.go: -------------------------------------------------------------------------------- 1 | package tu 2 | 3 | import ( 4 | "gogb28181/transaction" 5 | "sync" 6 | ) 7 | 8 | //TODO:参考http服务,使用者仅需要根据需要实现某些handler,替换某些header fileds or body信息。其他的处理都由库来实现。 9 | type Server struct { 10 | *transaction.Core //SIP transaction manager 11 | registers sync.Map //管理所有已经注册的设备端 12 | //routers:TODO:消息路由,应用层可以处理消息体,或者针对某些消息的callback 13 | } 14 | 15 | //提供config参数 16 | func NewServer(config *transaction.Config) *Server { 17 | return &Server{ 18 | Core: transaction.NewCore(config), 19 | registers: sync.Map{}, 20 | } 21 | } 22 | 23 | //运行一个sip server 24 | func RunServer() { 25 | config := &transaction.Config{ 26 | SipIP: "192.168.1.102", 27 | SipPort: 5060, 28 | SipNetwork: "UDP", 29 | Serial: "34020000002000000001", 30 | Realm: "3402000000", 31 | AckTimeout: 10, 32 | 33 | RegisterValidity: 3600, 34 | RegisterInterval: 60, 35 | HeartbeatInterval: 60, 36 | HeartbeatRetry: 3, 37 | 38 | AudioEnable: true, 39 | WaitKeyFrame: true, 40 | MediaPortMin: 58200, 41 | MediaPortMax: 58300, 42 | MediaIdleTimeout: 30, 43 | } 44 | s := NewServer(config) 45 | 46 | s.Start() 47 | 48 | select {} 49 | } 50 | -------------------------------------------------------------------------------- /utils/sip.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "runtime" 7 | "time" 8 | ) 9 | 10 | func RandNum16String(n int) string { 11 | numbers16 := "0123456789abcdef" 12 | return randStringBySoure(numbers16, n) 13 | } 14 | 15 | func RandNumString(n int) string { 16 | numbers := "0123456789" 17 | return randStringBySoure(numbers, n) 18 | } 19 | 20 | func RandString(n int) string { 21 | letterBytes := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 22 | return randStringBySoure(letterBytes, n) 23 | } 24 | 25 | // https://github.com/kpbird/golang_random_string 26 | func randStringBySoure(src string, n int) string { 27 | randomness := make([]byte, n) 28 | 29 | rand.Seed(time.Now().UnixNano()) 30 | _, err := rand.Read(randomness) 31 | if err != nil { 32 | panic(err) 33 | } 34 | 35 | l := len(src) 36 | 37 | // fill output 38 | output := make([]byte, n) 39 | for pos := range output { 40 | random := randomness[pos] 41 | randomPos := random % uint8(l) 42 | output[pos] = src[randomPos] 43 | } 44 | 45 | return string(output) 46 | } 47 | 48 | func PrintStack() { 49 | var buf [4096]byte 50 | n := runtime.Stack(buf[:], false) 51 | fmt.Printf("==> %s\n", string(buf[:n])) 52 | } 53 | -------------------------------------------------------------------------------- /transaction/README.md: -------------------------------------------------------------------------------- 1 | #### 事物 2 | transaction事务是SIP的基本组成部分。 3 | 一个事务是客户发送的一个请求事务(通过通讯层)发送到一个服务器事务,连同服务器事务的所有的该请求的应答发送回客户端事务。 4 | 事务层处理应用服务层的重发,匹配请求的应答,以及应用服务层的超时。 5 | 任何一个用户代理客户端(user agent client UAC)完成的事情都是由一组事务构成的。 6 | 用户代理包含一个事务层,来实现有状态的代理服务器。 7 | 事务层包含一个客户元素(可以认为是一个客户事务)和一个服务器元素(可以认为是一个服务器事务),他们都可以用一个有限状态机来处理特定的请求。 8 | 9 | 在状态机层面,事物分为ict、ist、nict、nist四种。 10 | 但底层事物方面,仅根据 method 等信息,分支处理。 11 | 12 | #### 关于事物管理 13 | 14 | 事物在map里面管理,事物ID的选择是要和事物匹配相关。 15 | 16 | ``` 17 | 客户端事件的匹配 18 | 19 | 当客户端中的传输层收到响应时,它必须确定哪个客户端事务将处理该响应,以便可以进行17.1.1和17.1.2节的处理。头域 Via 字段中的branch参数用于匹配规则。 一个匹配的响应应该满足下面两个条件: 20 | 1.如果响应的头域 Via头字段中的branch参数值与创建事务的请求的头域 Via头字段中的branch参数值相同。 21 | 2.如果CSeq标头字段中的method参数与创建事务的请求的方法匹配。(由于CANCEL请求会创建新的事务,但共享相同的branch参数值。所以仅用branch参数是不够的) 22 | 23 | 24 | 服务端事物匹配 25 | 26 | 首先要检查请求中的Via头域的branch参数。如果他以”z9hG4bk”开头,那么这个请求一定是由客户端事务根据本规范产生的。因此,branch参数在该客户端发出的所有的事务中都是唯一的。根据下列规则我们可以判定请求是否和事务匹配: 27 | 28 | 1、 请求的Via头域的branch参数和创建本事务的请求的Via头域的branch参数一样,并且: 29 | 2、 请求的Via头域的send-by参数和创建本事务的请求的Via头域的send-by参数一样(可能存在来自不同客户端的branch参数的意外或恶意重复,所以将 send-by 值用作匹配的一部分),并且: 30 | 3、 请求的方法与创建事务的方法匹配,但ACK除外,在ACK中,创建事务的请求的方法为INVITE。 31 | ``` 32 | 33 | 所以,根据匹配规则,事物的ID 使用 branch,然后在匹配逻辑里面,再做条件判断。而因为branch可能会重复,所以如果使用map来简化transaction的管理,key的取值应该: 34 | 35 | 客户端事物: branch+method 36 | 服务端事物: branch + sendby + method,method中ack还要除外。所以只能用branch + sendby 37 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/abiosoft/ishell" 5 | "gogb28181/transport" 6 | "gogb28181/tu" 7 | ) 8 | 9 | func main() { 10 | // create new shell. 11 | // by default, new shell includes 'exit', 'help' and 'clear' commands. 12 | shell := ishell.New() 13 | 14 | // display welcome info. 15 | shell.Println("gb28181 test") 16 | 17 | // simulate an authentication 18 | shell.AddCmd(&ishell.Cmd{ 19 | Name: "tcps", 20 | Help: "tcp server", 21 | Func: func(c *ishell.Context) { 22 | transport.RunServerTCP() 23 | }, 24 | }) 25 | 26 | shell.AddCmd(&ishell.Cmd{ 27 | Name: "tcpc", 28 | Help: "tcp client", 29 | Func: func(c *ishell.Context) { 30 | transport.RunClientTCP() 31 | }, 32 | }) 33 | // simulate an authentication 34 | shell.AddCmd(&ishell.Cmd{ 35 | Name: "udps", 36 | Help: "udp server", 37 | Func: func(c *ishell.Context) { 38 | transport.RunServerUDP() 39 | }, 40 | }) 41 | 42 | shell.AddCmd(&ishell.Cmd{ 43 | Name: "udpc", 44 | Help: "udp client", 45 | Func: func(c *ishell.Context) { 46 | transport.RunClientUDP() 47 | }, 48 | }) 49 | 50 | //======================================= 51 | shell.AddCmd(&ishell.Cmd{ 52 | Name: "uas", 53 | Help: "sip user agent server", 54 | Func: func(c *ishell.Context) { 55 | tu.RunServer() 56 | }, 57 | }) 58 | shell.AddCmd(&ishell.Cmd{ 59 | Name: "uac", 60 | Help: "sip user agent client", 61 | Func: func(c *ishell.Context) { 62 | tu.RunClient() 63 | }, 64 | }) 65 | 66 | //======================================= 67 | // run shell 68 | shell.Run() 69 | } 70 | -------------------------------------------------------------------------------- /sip/demo.go: -------------------------------------------------------------------------------- 1 | package sip 2 | 3 | import "fmt" 4 | 5 | func DemoMessage() { 6 | registerStr := `REGISTER sip:34020000002000000001@3402000000 SIP/2.0 7 | Via: SIP/2.0/UDP 192.168.1.64:5060;rport;branch=z9hG4bK385701375 8 | From: ;tag=1840661473 9 | To: 10 | Call-ID: 418133739 11 | CSeq: 1 REGISTER 12 | Contact: 13 | Max-Forwards: 70 14 | User-Agent: IP Camera 15 | Expires: 3600 16 | Content-Length: 0` 17 | 18 | fmt.Println("input:") 19 | fmt.Println(registerStr) 20 | msg, err := Decode([]byte(registerStr)) 21 | if err != nil { 22 | fmt.Println("decode message failed:", err.Error()) 23 | return 24 | } 25 | out, err := Encode(msg) 26 | if err != nil { 27 | fmt.Println("encode message failed:", err.Error()) 28 | return 29 | } 30 | fmt.Println("=====================================") 31 | fmt.Println("output:") 32 | fmt.Println(string(out)) 33 | } 34 | 35 | func DemoVIA() { 36 | str1 := "SIP / 2.0 / UDP first.example.com: 4000;ttl=16 ;maddr=224.2.0.1 ;branch=z9hG4bKa7c6a8dlze.1" 37 | str2 := "SIP/2.0/UDP 192.168.1.64:5060;rport;received=192.168.1.64;branch=z9hG4bK1000615294" 38 | 39 | var err error 40 | v1 := &Via{} 41 | err = v1.Parse(str1) 42 | if err != nil { 43 | fmt.Println("error:", err.Error()) 44 | return 45 | } 46 | fmt.Printf("result:%v\n", v1.String()) 47 | 48 | v2 := &Via{} 49 | err = v2.Parse(str2) 50 | if err != nil { 51 | fmt.Println("error:", err.Error()) 52 | return 53 | } 54 | fmt.Printf("result:%v\n", v2.String()) 55 | 56 | } 57 | -------------------------------------------------------------------------------- /transaction/config.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | //SIP服务器静态配置信息 4 | 5 | /* 6 | # sip监听udp端口 7 | listen 5060; 8 | 9 | # SIP server ID(SIP服务器ID). 10 | # 设备端配置编号需要与该值一致,否则无法注册 11 | serial 34020000002000000001; 12 | 13 | # SIP server domain(SIP服务器域) 14 | realm 3402000000; 15 | 16 | # 服务端发送ack后,接收回应的超时时间,单位为秒 17 | # 如果指定时间没有回应,认为失败 18 | ack_timeout 30; 19 | 20 | # 设备心跳维持时间,如果指定时间内(秒)没有接收一个心跳 21 | # 认为设备离线 22 | keepalive_timeout 120; 23 | 24 | # 注册之后是否自动给设备端发送invite 25 | # on: 是 off 不是,需要通过api控制 26 | auto_play on; 27 | # 设备将流发送的端口,是否固定 28 | # on 发送流到多路复用端口 如9000 29 | # off 自动从rtp_mix_port - rtp_max_port 之间的值中 30 | # 选一个可以用的端口 31 | invite_port_fixed on; 32 | 33 | # 向设备或下级域查询设备列表的间隔,单位(秒) 34 | # 默认60秒 35 | query_catalog_interval 60; 36 | */ 37 | 38 | type Config struct { 39 | //sip服务器的配置 40 | SipNetwork string //传输协议,默认UDP,可选TCP 41 | SipIP string //sip 服务器公网IP 42 | SipPort uint16 //sip 服务器端口,默认 5060 43 | Serial string //sip 服务器 id, 默认 34020000002000000001 44 | Realm string //sip 服务器域,默认 3402000000 45 | 46 | AckTimeout uint16 //sip 服务应答超时,单位秒 47 | RegisterValidity int //注册有效期,单位秒,默认 3600 48 | RegisterInterval int //注册间隔,单位秒,默认 60 49 | HeartbeatInterval int //心跳间隔,单位秒,默认 60 50 | HeartbeatRetry int //心跳超时次数,默认 3 51 | 52 | //媒体服务器配置 53 | MediaIP string //媒体服务器地址 54 | MediaPort uint16 //媒体服务器端口 55 | MediaPortMin uint16 56 | MediaPortMax uint16 57 | MediaIdleTimeout uint16 //推流超时时间,超过则断开链接,让设备重连 58 | AudioEnable bool //是否开启音频 59 | WaitKeyFrame bool //是否等待关键帧,如果等待,则在收到第一个关键帧之前,忽略所有媒体流 60 | } 61 | -------------------------------------------------------------------------------- /transport/transport.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "net" 5 | "time" 6 | ) 7 | 8 | /* 9 | transport层仅实现数据的读写,连接的关闭 10 | 11 | TCP和UDP的区别 12 | 13 | - TCP面向链接,在服务关闭的时候,要先close掉所有客户端连接。所以使用一个map简单做session管理,key 是 remote address。 14 | - udp不需要管理session。 15 | */ 16 | 17 | //transport server and client interface 18 | //对于面向连接的服务,需要有两个关闭接口:Close and CloseOne 19 | //非面向连接的服务,不必实现 20 | //TODO:心跳管理,使用timewheel 21 | 22 | type ITransport interface { 23 | Name() string 24 | ReadPacketChan() <-chan *Packet //读消息,消息处理器需在循环中阻塞读取 25 | WritePacket(packet *Packet) //写消息 26 | Start() error //开启连接,阻塞接收消息 27 | Close() error //关闭连接 28 | IsReliable() bool //是否可靠传输 29 | } 30 | 31 | type IServer interface { 32 | ITransport 33 | CloseOne(addr string) //对于关闭某个客户端连接,比如没有鉴权的非法链接,心跳超时等 34 | IsKeepalive() bool //persistent connection or not 35 | } 36 | 37 | //transport 需要实现的接口如下 38 | type IClient interface { 39 | ITransport 40 | LocalAddr() net.Addr //本地地址 41 | RemoteAddr() net.Addr //远程地址 42 | Heartbeat(packet *Packet) //客户端需要定期发送心跳包到服务器端 43 | } 44 | 45 | type Packet struct { 46 | Type string //消息类型,预留字段,对于客户端主动关闭等消息的上报、心跳超时等。如果为空,则仅透传消息。 47 | Addr net.Addr 48 | Data []byte 49 | } 50 | 51 | //对于面向连接的(UDP或者TCP都可以面向连接,维持心跳即可),必须有session 52 | type Connection struct { 53 | Addr net.Addr 54 | Conn net.Conn 55 | Online bool 56 | ReconnectCount int64 //重连次数 57 | } 58 | 59 | func (s *Connection) Close() { 60 | //TODO:处理session的关闭,修改缓存状态、数据库状态、发送离线通知、执行离线回调等等 61 | } 62 | 63 | //通讯统计 64 | type Statistic struct { 65 | startTime time.Time 66 | stopTime time.Time 67 | recvCount int64 68 | sendCount int64 69 | errCount int64 70 | } 71 | -------------------------------------------------------------------------------- /tu/common.go: -------------------------------------------------------------------------------- 1 | package tu 2 | 3 | import ( 4 | "fmt" 5 | "gogb28181/sip" 6 | "gogb28181/utils" 7 | ) 8 | 9 | //根据参数构建各种消息 10 | //参数来自于session/transaction等会话管理器 11 | /* 12 | method:请求方法 13 | transport:UDP/TCP 14 | sipSerial: sip server ID 15 | sipRealm: sip domain 16 | username: 用户名/设备序列号 17 | srcIP: 源IP 18 | srcPort:源端口 19 | expires: 过期时间 20 | cseq:消息序列号,当前对话递增 21 | */ 22 | //构建消息:以客户端(可能是IPC,也可能是SIP Server)的角度 23 | func BuildMessageRequest(method sip.Method, transport, sipSerial, sipRealm, username string, srcIP string, srcPort uint16, expires, cseq int) *sip.Message { 24 | server := fmt.Sprintf("%s@%s", sipSerial, sipRealm) 25 | client := fmt.Sprintf("%s@%s", username, sipRealm) 26 | 27 | msg := &sip.Message{ 28 | Mode: sip.SIP_MESSAGE_REQUEST, 29 | MaxForwards: 70, 30 | UserAgent: "IPC", 31 | Expires: expires, 32 | ContentLength: 0, 33 | } 34 | msg.StartLine = &sip.StartLine{ 35 | Method: method, 36 | Uri: sip.NewURI(server), 37 | } 38 | msg.Via = &sip.Via{ 39 | Transport: transport, 40 | Host: client, 41 | } 42 | msg.Via.Params = map[string]string{ 43 | "branch": randBranch(), 44 | "rport": "-1", //only key,no-value 45 | } 46 | msg.From = &sip.Contact{ 47 | Uri: sip.NewURI(client), 48 | Params: nil, 49 | } 50 | msg.From.Params = map[string]string{ 51 | "tag": utils.RandNumString(10), 52 | } 53 | msg.To = &sip.Contact{ 54 | Uri: sip.NewURI(client), 55 | } 56 | msg.CallID = utils.RandNumString(8) 57 | msg.CSeq = &sip.CSeq{ 58 | ID: uint32(cseq), 59 | Method: method, 60 | } 61 | 62 | msg.Contact = &sip.Contact{ 63 | Uri: sip.NewURI(fmt.Sprintf("%s@%s:%d", username, srcIP, srcPort)), 64 | } 65 | return msg 66 | } 67 | 68 | //z9hG4bK + 10个随机数字 69 | func randBranch() string { 70 | return fmt.Sprintf("z9hG4bK%s", utils.RandNumString(8)) 71 | } 72 | -------------------------------------------------------------------------------- /transport/example.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "fmt" 5 | "gogb28181/utils" 6 | "os" 7 | "time" 8 | ) 9 | 10 | //默认端口:TCP/UDP是5060,5061是在TCP上的TLS 11 | //对于服务器监听UDP的任何端口和界面,都必须在TCP上也进行同样的监听。这是因为可能消息还需要通过TCP进行传输,比如消息过大的情况。 12 | const SipHost string = "127.0.0.1" 13 | const SipPort uint16 = 5060 14 | 15 | func RunServerTCP() { 16 | tcp := NewTCPServer(SipPort, true) 17 | go PacketHandler(tcp) 18 | go func() { 19 | _ = tcp.Start() 20 | }() 21 | 22 | select {} 23 | } 24 | 25 | //测试通讯,客户端先发一条消息 26 | func RunClientTCP() { 27 | c := NewTCPClient(SipHost, SipPort) 28 | go PacketHandler(c) 29 | go func() { 30 | _ = c.Start() 31 | }() 32 | 33 | //发送测试数据 34 | fmt.Println("send test data") 35 | go func() { 36 | for { 37 | c.WritePacket(&Packet{Data: []byte("from client : " + time.Now().String())}) 38 | time.Sleep(2 * time.Second) 39 | } 40 | }() 41 | select {} 42 | } 43 | func PacketHandler(s ITransport) { 44 | defer func() { 45 | if err := recover(); err != nil { 46 | fmt.Println("packet handler panic: ", err) 47 | utils.PrintStack() 48 | os.Exit(1) 49 | } 50 | }() 51 | 52 | fmt.Println("PacketHandler ========== ", s.Name()) 53 | 54 | ch := s.ReadPacketChan() 55 | //阻塞读取消息 56 | for { 57 | select { 58 | case p := <-ch: 59 | fmt.Println("packet content:", string(p.Data)) 60 | //TODO:message parse 61 | } 62 | } 63 | } 64 | 65 | //====================================================================== 66 | 67 | func RunServerUDP() { 68 | udp := NewUDPServer(SipPort) 69 | 70 | go PacketHandler(udp) 71 | go func() { 72 | _ = udp.Start() 73 | }() 74 | 75 | select {} 76 | } 77 | 78 | func RunClientUDP() { 79 | c := NewUDPClient(SipHost, SipPort) 80 | go PacketHandler(c) 81 | go func() { 82 | _ = c.Start() 83 | }() 84 | //发送测试数据 85 | go func() { 86 | for { 87 | time.Sleep(1 * time.Second) 88 | c.WritePacket(&Packet{ 89 | Data: []byte("hello " + time.Now().String())}) 90 | } 91 | }() 92 | 93 | select {} 94 | } 95 | -------------------------------------------------------------------------------- /transport/udp_server.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | ) 8 | 9 | type UDPServer struct { 10 | Statistic 11 | addr string 12 | Conn *net.UDPConn 13 | ReadChan chan *Packet 14 | WriteChan chan *Packet 15 | done chan struct{} 16 | Keepalive bool 17 | //Sessions sync.Map // key is remote-addr的string , value:*Connection。UDP不需要 18 | } 19 | 20 | func NewUDPServer(port uint16) IServer { 21 | addrStr := fmt.Sprintf(":%d", port) 22 | 23 | return &UDPServer{ 24 | addr: addrStr, 25 | ReadChan: make(chan *Packet, 10), 26 | WriteChan: make(chan *Packet, 10), 27 | done: make(chan struct{}), 28 | } 29 | } 30 | 31 | func (s *UDPServer) IsReliable() bool { 32 | return false 33 | } 34 | 35 | func (s *UDPServer) Name() string { 36 | return fmt.Sprintf("udp client to:%s", s.addr) 37 | } 38 | 39 | func (s *UDPServer) IsKeepalive() bool { 40 | return s.Keepalive 41 | } 42 | 43 | func (s *UDPServer) Start() error { 44 | addr, err := net.ResolveUDPAddr("udp", s.addr) 45 | if err != nil { 46 | fmt.Println("Can't resolve address: ", err) 47 | return err 48 | } 49 | 50 | conn, err := net.ListenUDP("udp", addr) 51 | if err != nil { 52 | fmt.Println("Error listenUDP :", err) 53 | os.Exit(1) 54 | } 55 | defer func() { 56 | _ = conn.Close() 57 | }() 58 | 59 | s.Conn = conn 60 | 61 | fmt.Println("start udp server at: ", s.addr) 62 | 63 | //心跳线程 64 | if s.Keepalive { 65 | //TODO:start heartbeat thread 66 | } 67 | //写线程 68 | go func() { 69 | for { 70 | select { 71 | case p := <-s.WriteChan: 72 | _, _ = s.Conn.WriteTo(p.Data, p.Addr) 73 | case <-s.done: 74 | return 75 | } 76 | } 77 | }() 78 | 79 | //读线程 80 | for { 81 | data := make([]byte, 4096) 82 | n, remoteAddr, err := conn.ReadFromUDP(data) 83 | if err != nil { 84 | fmt.Println("failed to read UDP msg because of ", err.Error()) 85 | continue 86 | } 87 | s.ReadChan <- &Packet{ 88 | Addr: remoteAddr, 89 | Data: data[:n], 90 | } 91 | } 92 | } 93 | func (s *UDPServer) ReadPacketChan() <-chan *Packet { 94 | return s.ReadChan 95 | } 96 | func (s *UDPServer) WritePacket(packet *Packet) { 97 | s.WriteChan <- packet 98 | } 99 | 100 | func (s *UDPServer) Close() error { 101 | //所有session离线和关闭处理 102 | return nil 103 | } 104 | func (s *UDPServer) CloseOne(addr string) { 105 | //处理某设备离线 106 | } 107 | -------------------------------------------------------------------------------- /tu/client.go: -------------------------------------------------------------------------------- 1 | package tu 2 | 3 | import ( 4 | "fmt" 5 | "gogb28181/transaction" 6 | ) 7 | 8 | //sip server和client的配置,可以得到sip URI:sip 9 | //格式:user:password@host:port;uri-parameters?headers 10 | //在这些URI里边包含了足够的信息来发起和维持到这个资源的一个通讯会话。 11 | //client静态配置 12 | type ClientStatic struct { 13 | LocalIP string //设备本地IP 14 | LocalPort uint16 //客户端SIP端口 15 | Username string //SIP用户名,一般是取通道ID,默认 34020000001320000001 16 | AuthID string //SIP用户认证ID,一般是通道ID, 默认 34020000001320000001 17 | Password string //密码 18 | } 19 | 20 | //client运行时信息 21 | type ClientRuntime struct { 22 | RemoteAddress string //设备的公网的IP和端口,格式x.x.x.x:x 23 | Online bool //在线状态 24 | Branch string //branch 25 | Cseq int //消息序列号,发送消息递增, uint32 26 | FromTag string //from tag 27 | ToTag string //to tag 28 | Received string //remote ip 29 | Rport string //remote port 30 | } 31 | 32 | type Client struct { 33 | *transaction.Core //transaction manager 34 | static *ClientStatic //静态配置 35 | runtime *ClientRuntime //运行时信息 36 | } 37 | 38 | //config:sip信令服务器配置 39 | //static:sip客户端配置 40 | func NewClient(config *transaction.Config, static *ClientStatic) *Client { 41 | return &Client{ 42 | Core: transaction.NewCore(config), 43 | static: static, 44 | runtime: &ClientRuntime{}, 45 | } 46 | } 47 | 48 | 49 | //TODO:对于一个TU,开启之后 50 | //运行一个sip client 51 | func RunClient() { 52 | config := &transaction.Config{ 53 | SipIP: "192.168.1.102", 54 | SipPort: 5060, 55 | SipNetwork: "UDP", 56 | Serial: "34020000002000000001", 57 | Realm: "3402000000", 58 | AckTimeout: 10, 59 | 60 | RegisterValidity: 3600, 61 | RegisterInterval: 60, 62 | HeartbeatInterval: 60, 63 | HeartbeatRetry: 3, 64 | 65 | AudioEnable: true, 66 | WaitKeyFrame: true, 67 | MediaPortMin: 58200, 68 | MediaPortMax: 58300, 69 | MediaIdleTimeout: 30, 70 | } 71 | static := &ClientStatic{ 72 | LocalIP: "192.168.1.65", 73 | LocalPort: 5060, 74 | Username: "34020000001320000001", 75 | AuthID: "34020000001320000001", 76 | Password: "123456", 77 | } 78 | c := NewClient(config, static) 79 | 80 | go c.Start() 81 | 82 | //TODO:先发起注册 83 | //TODO:build sip message 84 | msg := BuildMessageRequest("", "", "", "", "", "", 85 | 0, 0, 0) 86 | resp := c.SendMessage(msg) 87 | if resp.Code != 0 { 88 | fmt.Println("request failed") 89 | } 90 | fmt.Println("response: ", resp.Data) 91 | 92 | select {} 93 | } 94 | -------------------------------------------------------------------------------- /sip/status.go: -------------------------------------------------------------------------------- 1 | package sip 2 | 3 | import "fmt" 4 | 5 | //transaction sip error 6 | var errorMap = map[int]string{ 7 | //1xx 8 | 100: "Trying", 9 | 180: "Ringing", 10 | 181: "Call Is Being Forwarded", 11 | 182: "Queued", 12 | 183: "Session Progress", 13 | 199: "Early Dialog Terminated", 14 | //2xx 15 | 200: "OK", 16 | 202: "Accepted", 17 | 204: "No Notification", 18 | //3xx 19 | 300: "Multiple Choices", 20 | 301: "Moved Permanently", 21 | 302: "Moved Temporarily", 22 | 305: "Use Proxy", 23 | 380: "Alternative Service", 24 | //4xx 25 | 400: "Bad Request", 26 | 401: "Unauthorized", 27 | 402: "Payment Required", 28 | 403: "Forbidden", 29 | 404: "Not Found", 30 | 405: "Method Not Allowed", 31 | 406: "Not Acceptable", 32 | 407: "Proxy Authentication Required", 33 | 408: "Request Timeout", 34 | 409: "Conflict", 35 | 410: "Gone", 36 | 411: "Length Required", 37 | 412: "Conditional Request Failed", 38 | 413: "Request Entity Too Large", 39 | 414: "Request-URI Too Long", 40 | 415: "Unsupported Media Type", 41 | 416: "Unsupported URI Scheme", 42 | 417: "Unknown Resource-Priority", 43 | 420: "Bad Extension", 44 | 421: "Extension Required", 45 | 422: "Session Interval Too Small", 46 | 423: "Interval Too Brief", 47 | 424: "Bad Location Information", 48 | 428: "Use Identity Header", 49 | 429: "Provide Referrer Identity", 50 | 430: "Flow Failed", 51 | 433: "Anonymity Disallowed", 52 | 436: "Bad Identity Info", 53 | 437: "Unsupported Credential", 54 | 438: "Invalid Identity Header", 55 | 439: "First Hop Lacks Outbound Support", 56 | 440: "Max-Breadth Exceeded", 57 | 469: "Bad Info Package", 58 | 470: "Consent Needed", 59 | 480: "Temporarily Unavailable", 60 | 481: "Call/Transaction Does Not Exist", 61 | 482: "Loop Detected", 62 | 483: "Too Many Hops", 63 | 484: "Address Incomplete", 64 | 485: "Ambiguous", 65 | 486: "Busy Here", 66 | 487: "Request Terminated", 67 | 488: "Not Acceptable Here", 68 | 489: "Bad Event", 69 | 491: "Request Pending", 70 | 493: "Undecipherable", 71 | 494: "Security Agreement Required", 72 | //5xx 73 | 500: "Server Internal Error", 74 | 501: "Not Implemented", 75 | 502: "Bad Gateway", 76 | 503: "Service Unavailable", 77 | 504: "Server Time-out", 78 | 505: "Version Not Supported", 79 | 513: "Message Too Large", 80 | 580: "Precondition Failure", 81 | //6xx 82 | 600: "Busy Everywhere", 83 | 603: "Decline", 84 | 604: "Does Not Exist Anywhere", 85 | 606: "Not Acceptable", 86 | 607: "Unwanted", 87 | 687: "Dialog Terminated", 88 | } 89 | 90 | func DumpError(code int) string { 91 | if code == 0{ 92 | return "invalid status reason for request" 93 | } 94 | return fmt.Sprintf("%d %s", code, errorMap[code]) 95 | } 96 | 97 | -------------------------------------------------------------------------------- /transport/tcp_client.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | type TCPClient struct { 9 | Statistic 10 | host string 11 | port uint16 12 | conn net.Conn 13 | readChan chan *Packet 14 | writeChan chan *Packet 15 | remoteAddr net.Addr 16 | localAddr net.Addr 17 | done chan struct{} 18 | } 19 | 20 | func NewTCPClient(host string, port uint16) IClient { 21 | return &TCPClient{ 22 | host: host, 23 | port: port, 24 | readChan: make(chan *Packet, 10), 25 | writeChan: make(chan *Packet, 10), 26 | done: make(chan struct{}), 27 | } 28 | } 29 | 30 | func (c *TCPClient) IsReliable() bool { 31 | return true 32 | } 33 | 34 | func (c *TCPClient) Name() string { 35 | return fmt.Sprintf("tcp client to:%s", fmt.Sprintf("%s:%d", c.host, c.port)) 36 | } 37 | 38 | func (c *TCPClient) LocalAddr() net.Addr { 39 | return c.localAddr 40 | } 41 | 42 | func (c *TCPClient) RemoteAddr() net.Addr { 43 | return c.remoteAddr 44 | } 45 | 46 | func (c *TCPClient) Start() error { 47 | conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", c.host, c.port)) 48 | if err != nil { 49 | fmt.Println("dial tcp server failed :", err.Error()) 50 | return err 51 | }else{ 52 | fmt.Println("start tcp client") 53 | } 54 | 55 | c.conn = conn 56 | c.remoteAddr = conn.RemoteAddr() 57 | c.localAddr = conn.LocalAddr() 58 | 59 | //开启写线程 60 | go func() { 61 | for { 62 | select { 63 | case p := <-c.writeChan: 64 | _, err := c.conn.Write(p.Data) 65 | if err != nil { 66 | fmt.Println("client write failed:", err.Error()) 67 | _ = c.Close() 68 | return 69 | } 70 | case <-c.done: 71 | return 72 | } 73 | } 74 | }() 75 | 76 | fmt.Println("start tcp client") 77 | fmt.Printf("remote addr: %s, local addr: %s\n", conn.RemoteAddr().String(), conn.LocalAddr().String()) 78 | 79 | //读线程,阻塞 80 | for { 81 | buf := make([]byte, 2048) 82 | n, err := conn.Read(buf) 83 | if err != nil { 84 | fmt.Println("tcp client read error:", err.Error()) 85 | return err 86 | } 87 | c.readChan <- &Packet{ 88 | Addr: c.remoteAddr, 89 | Data: buf[:n], 90 | } 91 | } 92 | } 93 | 94 | func (c *TCPClient) ReadPacketChan() <-chan *Packet { 95 | return c.readChan 96 | } 97 | 98 | func (c *TCPClient) WritePacket(packet *Packet) { 99 | c.writeChan <- packet 100 | } 101 | 102 | func (c *TCPClient) Close() error { 103 | close(c.done) 104 | return c.conn.Close() 105 | } 106 | 107 | //外部定期调用此接口,实现心跳 108 | func (c *TCPClient) Heartbeat(p *Packet) { 109 | if p == nil { 110 | p = &Packet{ 111 | Data: []byte("ping"), 112 | } 113 | } 114 | c.WritePacket(p) 115 | } 116 | -------------------------------------------------------------------------------- /transport/udp_client.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | ) 8 | 9 | type UDPClient struct { 10 | Statistic 11 | host string 12 | port uint16 13 | conn *net.UDPConn 14 | readChan chan *Packet 15 | writeChan chan *Packet 16 | done chan struct{} 17 | remoteAddr net.Addr 18 | localAddr net.Addr 19 | } 20 | 21 | func NewUDPClient(host string, port uint16) IClient { 22 | return &UDPClient{ 23 | host: host, 24 | port: port, 25 | readChan: make(chan *Packet, 10), 26 | writeChan: make(chan *Packet, 10), 27 | done: make(chan struct{}), 28 | } 29 | } 30 | 31 | func (c *UDPClient) IsReliable() bool { 32 | return false 33 | } 34 | 35 | func (c *UDPClient) Name() string { 36 | return fmt.Sprintf("udp client to:%s", fmt.Sprintf("%s:%d", c.host, c.port)) 37 | } 38 | func (c *UDPClient) LocalAddr() net.Addr { 39 | return c.localAddr 40 | } 41 | 42 | func (c *UDPClient) RemoteAddr() net.Addr { 43 | return c.remoteAddr 44 | } 45 | 46 | func (c *UDPClient) Start() error { 47 | addrStr := fmt.Sprintf("%s:%d", c.host, c.port) 48 | addr, err := net.ResolveUDPAddr("udp", addrStr) 49 | if err != nil { 50 | fmt.Println("Can't resolve address: ", err) 51 | os.Exit(1) 52 | } 53 | 54 | conn, err := net.DialUDP("udp", nil, addr) 55 | if err != nil { 56 | fmt.Println("Can't dial: ", err) 57 | os.Exit(1) 58 | } 59 | defer conn.Close() 60 | 61 | c.remoteAddr = conn.RemoteAddr() 62 | c.localAddr = conn.LocalAddr() 63 | 64 | fmt.Println("udp client remote addr:", conn.RemoteAddr().String()) 65 | fmt.Println("udp client local addr:", conn.LocalAddr().String()) 66 | 67 | //写线程 68 | go func() { 69 | for { 70 | select { 71 | case p := <-c.writeChan: 72 | _, err = conn.Write(p.Data) 73 | if err != nil { 74 | fmt.Println("udp client write failed:", err.Error()) 75 | continue 76 | } 77 | case <-c.done: 78 | return 79 | } 80 | } 81 | }() 82 | 83 | for { 84 | buf := make([]byte, 4096) 85 | n, err := conn.Read(buf) 86 | if err != nil { 87 | fmt.Println("failed to read UDP msg because of ", err) 88 | os.Exit(1) 89 | } 90 | 91 | c.readChan <- &Packet{ 92 | Addr: c.remoteAddr, 93 | Data: buf[:n], 94 | } 95 | } 96 | } 97 | 98 | func (c *UDPClient) ReadPacketChan() <-chan *Packet { 99 | return c.readChan 100 | } 101 | 102 | func (c *UDPClient) WritePacket(packet *Packet) { 103 | c.writeChan <- packet 104 | } 105 | 106 | func (c *UDPClient) Close() error { 107 | close(c.done) 108 | return c.conn.Close() 109 | } 110 | 111 | //外部定期调用此接口,实现心跳 112 | func (c *UDPClient) Heartbeat(p *Packet) { 113 | if p == nil { 114 | p = &Packet{ 115 | Data: []byte("ping"), 116 | } 117 | } 118 | c.WritePacket(p) 119 | } 120 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw= 2 | github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg= 3 | github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db h1:CjPUSXOiYptLbTdr1RceuZgSFDQ7U15ITERUGrUORx8= 4 | github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530= 5 | github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= 6 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 7 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= 8 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 9 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 10 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 11 | github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= 12 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 13 | github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BMXYYRWTLOJKlh+lOBt6nUQgXAfB7oVIQt5cNreqSLI= 14 | github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M= 15 | github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= 16 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 17 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 18 | github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= 19 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 20 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 21 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 22 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 23 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 24 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 25 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 26 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= 27 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 28 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 29 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 30 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 31 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 32 | -------------------------------------------------------------------------------- /transaction/utils.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "gogb28181/sip" 5 | "fmt" 6 | "net" 7 | "strings" 8 | ) 9 | 10 | //=====================================================sip message utils 11 | //The branch ID parameter in the Via header field values serves as a transaction identifier, 12 | //and is used by proxies to detect loops. 13 | //The branch parameter in the topmost Via header field of the request 14 | // is examined. If it is present and begins with the magic cookie 15 | // "z9hG4bK", the request was generated by a client transaction 16 | // compliant to this specification. 17 | //参考RFC3261 18 | func getMessageTransactionID(m *sip.Message) string { 19 | if m.GetMethod() == sip.ACK { 20 | //TODO:在匹配服务端事物的ACK中,创建事务的请求的方法为INVITE。所以ACK消息匹配事物的时候需要注意???? 21 | } 22 | return string(m.GetMethod()) + "_" + m.GetBranch() 23 | } 24 | 25 | //根据收到的响应的消息的状态码,获取事件 26 | func getInComingMessageEvent(m *sip.Message) Event { 27 | //request:根据请求方法来确认事件 28 | if m.IsRequest() { 29 | method := m.GetMethod() 30 | if method == sip.INVITE { 31 | return RCV_REQINVITE 32 | } else if method == sip.ACK { 33 | return RCV_REQACK 34 | } else { 35 | return RCV_REQUEST 36 | } 37 | } 38 | 39 | //response:根据状态码来确认事件 40 | status := m.StartLine.Code 41 | if status >= 100 && status < 200 { 42 | return RCV_STATUS_1XX 43 | } 44 | 45 | if status >= 200 && status < 300 { 46 | return RCV_STATUS_2XX 47 | } 48 | if status >= 300 { 49 | return RCV_STATUS_3456XX 50 | } 51 | 52 | return UNKNOWN_EVT 53 | } 54 | 55 | //根据发出的响应的消息的状态码,获取事件 56 | func getOutGoingMessageEvent(m *sip.Message) Event { 57 | //request:get event by method 58 | if m.IsRequest() { 59 | method := m.GetMethod() 60 | if method == sip.INVITE { 61 | return SND_REQINVITE 62 | } else if method == sip.ACK { 63 | return SND_REQACK 64 | } else { 65 | return SND_REQUEST 66 | } 67 | } 68 | 69 | //response:get event by status 70 | status := m.StartLine.Code 71 | if status >= 100 && status < 200 { 72 | return SND_STATUS_1XX 73 | } 74 | 75 | if status >= 200 && status < 300 { 76 | return SND_STATUS_2XX 77 | } 78 | if status >= 300 { 79 | return SND_STATUS_3456XX 80 | } 81 | 82 | return UNKNOWN_EVT 83 | } 84 | 85 | func checkMessage(msg *sip.Message) error { 86 | //TODO:sip消息解析成功之后,检查必要元素,如果失败,则返回 ErrorCheckMessage 87 | 88 | //检查头域字段:callID via startline 等 89 | //检查seq、method等 90 | //不可以有router? 91 | //是否根据消息是接收还是发送检查? 92 | return nil 93 | } 94 | 95 | //fix via header,add send-by info, 96 | func fixReceiveMessageViaParams(msg *sip.Message, addr net.Addr) { 97 | rport := msg.Via.Params["rport"] 98 | if rport == "" || rport == "0" || rport == "-1" { 99 | arr := strings.Split(addr.String(), ":") 100 | if len(arr) == 2 { 101 | msg.Via.Params["rport"] = arr[1] 102 | if msg.Via.Host != arr[0] { 103 | msg.Via.Params["received"] = arr[0] 104 | } 105 | } else { 106 | //TODO:数据报的地址错误?? 107 | fmt.Println("packet handle > invalid addr :", addr.String()) 108 | } 109 | } else { 110 | fmt.Println("sip message has have send-by info:", msg.Via.GetSendBy()) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /sip/head_test.go: -------------------------------------------------------------------------------- 1 | package sip 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestContact(t *testing.T) { 9 | str1 := "\"Mr.Watson\" ;q=0.7; expires=3600,\"Mr.Watson\" "; 10 | //str1 := `"Mr.Watson" ;q=0.7;` 11 | c := &Contact{} 12 | err := c.Parse(str1) 13 | if err != nil { 14 | t.Error(err) 15 | return 16 | } 17 | fmt.Println("source:", str1) 18 | fmt.Println("result:", c.String()) 19 | } 20 | 21 | func TestVia(t *testing.T) { 22 | str1 := "SIP / 2.0 / UDP first.example.com: 4000;ttl=16 ;maddr=224.2.0.1 ;branch=z9hG4bKa7c6a8dlze.1" 23 | str2 := "SIP/2.0/UDP 192.168.1.64:5060;rport;received=192.168.1.64;branch=z9hG4bK1000615294" 24 | 25 | var err error 26 | v1 := &Via{} 27 | err = v1.Parse(str1) 28 | if err != nil { 29 | fmt.Println("error:", err.Error()) 30 | return 31 | } 32 | fmt.Printf("source:%v\n", str1) 33 | fmt.Printf("result:%v\n", v1.String()) 34 | 35 | v2 := &Via{} 36 | err = v2.Parse(str2) 37 | if err != nil { 38 | fmt.Println("error:", err.Error()) 39 | return 40 | } 41 | fmt.Printf("source:%v\n", str2) 42 | fmt.Printf("result:%v\n", v2.String()) 43 | 44 | } 45 | 46 | func TestMessage1(t *testing.T) { 47 | str1 := `REGISTER sip:34020000002000000001@3402000000 SIP/2.0 48 | Via: SIP/2.0/UDP 192.168.1.64:5060;rport;branch=z9hG4bK385701375 49 | From: ;tag=1840661473 50 | To: 51 | Call-ID: 418133739 52 | CSeq: 1 REGISTER 53 | Contact: 54 | Max-Forwards: 70 55 | User-Agent: IP Camera 56 | Expires: 3600 57 | Content-Length: 0` 58 | 59 | fmt.Println("input:") 60 | fmt.Println(str1) 61 | msg, err := Decode([]byte(str1)) 62 | if err != nil { 63 | fmt.Println("decode message failed:", err.Error()) 64 | return 65 | } 66 | out, err := Encode(msg) 67 | if err != nil { 68 | fmt.Println("encode message failed:", err.Error()) 69 | return 70 | } 71 | fmt.Println("=====================================") 72 | fmt.Println("output:") 73 | fmt.Println(string(out)) 74 | } 75 | 76 | func TestMessage2(t *testing.T) { 77 | str1 := `SIP/2.0 200 OK 78 | Via: SIP/2.0/UDP 192.168.1.151:5060;rport=5060;branch=SrsGbB56116414 79 | From: ;tag=SrsGbF72006729 80 | To: ;tag=416442565 81 | Call-ID: 202093500940 82 | CSeq: 101 INVITE 83 | Contact: 84 | Content-Type: application/sdp 85 | User-Agent: IP Camera 86 | Content-Length: 185 87 | 88 | v=0 89 | o=34020000001320000001 1835 1835 IN IP4 192.168.1.64 90 | s=Play 91 | c=IN IP4 192.168.1.64 92 | t=0 0 93 | m=video 15060 RTP/AVP 96 94 | a=sendonly 95 | a=rtpmap:96 PS/90000 96 | a=filesize:0 97 | y=0009093131` 98 | 99 | fmt.Println("input:") 100 | fmt.Println(str1) 101 | msg, err := Decode([]byte(str1)) 102 | if err != nil { 103 | fmt.Println("decode message failed:", err.Error()) 104 | return 105 | } 106 | out, err := Encode(msg) 107 | if err != nil { 108 | fmt.Println("encode message failed:", err.Error()) 109 | return 110 | } 111 | fmt.Println("=====================================") 112 | fmt.Println("output:") 113 | fmt.Println(string(out)) 114 | } 115 | -------------------------------------------------------------------------------- /transaction/fsm_nist.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | /* 9 | |Request received 10 | |pass to TU 11 | V 12 | +-----------+ 13 | | | 14 | | Trying |-------------+ 15 | | | | 16 | +-----------+ |200-699 from TU 17 | | |send response 18 | |1xx from TU | 19 | |send response | 20 | | | 21 | Request V 1xx from TU | 22 | send response+-----------+send response| 23 | +--------| |--------+ | 24 | | | Proceeding| | | 25 | +------->| |<-------+ | 26 | +<--------------| | | 27 | |Trnsprt Err +-----------+ | 28 | |Inform TU | | 29 | | | | 30 | | |200-699 from TU | 31 | | |send response | 32 | | Request V | 33 | | send response+-----------+ | 34 | | +--------| | | 35 | | | | Completed |<------------+ 36 | | +------->| | 37 | +<--------------| | 38 | |Trnsprt Err +-----------+ 39 | |Inform TU | 40 | | |Timer J fires 41 | | |- 42 | | | 43 | | V 44 | | +-----------+ 45 | | | | 46 | +-------------->| Terminated| 47 | | | 48 | +-----------+ 49 | 50 | Figure 8: non-INVITE server transaction 51 | 52 | */ 53 | 54 | func nist_rcv_request(t *Transaction, e *EventObj) error { 55 | fmt.Println("rcv request: ", e.msg.GetMethod()) 56 | fmt.Println("transaction state: ", t.state.String()) 57 | if t.state != NIST_PRE_TRYING { 58 | fmt.Println("rcv request retransmission,do response") 59 | if t.lastResponse != nil { 60 | err := t.SipSend(t.lastResponse) 61 | if err != nil { 62 | //transport error 63 | return err 64 | } 65 | } 66 | return nil 67 | } else { 68 | t.origRequest = e.msg 69 | t.state = NIST_TRYING 70 | t.isReliable = e.msg.IsReliable() 71 | } 72 | 73 | return nil 74 | } 75 | 76 | func nist_snd_1xx(t *Transaction, e *EventObj) error { 77 | t.lastResponse = e.msg 78 | err := t.SipSend(t.lastResponse) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | t.state = NIST_PROCEEDING 84 | return nil 85 | } 86 | 87 | func nist_snd_23456xx(t *Transaction, e *EventObj) error { 88 | t.lastResponse = e.msg 89 | err := t.SipSend(t.lastResponse) 90 | if err != nil { 91 | return err 92 | } 93 | if t.state != NIST_COMPLETED { 94 | if !t.isReliable { 95 | t.timerJ = time.AfterFunc(T1*64, func() { 96 | t.event <- &EventObj{ 97 | evt: TIMEOUT_J, 98 | tid: t.id, 99 | } 100 | }) 101 | } 102 | } 103 | 104 | t.state = NIST_COMPLETED 105 | return nil 106 | } 107 | func osip_nist_timeout_j_event(t *Transaction, e *EventObj) error { 108 | t.Terminate() 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /sip/README.md: -------------------------------------------------------------------------------- 1 | 2 | #### SIP消息 3 | 4 | ``` 5 | SIP-message = Request / Response 6 | Request = Request-Line 7 | *( message-header ) 8 | CRLF 9 | [ message-body ] 10 | ``` 11 | 12 | #### SIP消息头域 13 | 14 | ``` 15 | message-header = (Accept 16 | / Accept-Encoding 17 | / Accept-Language 18 | / Alert-Info 19 | / Allow 20 | / Authentication-Info 21 | / Authorization 22 | / Call-ID 23 | / Call-Info 24 | / Contact 25 | / Content-Disposition 26 | / Content-Encoding 27 | / Content-Language 28 | / Content-Length 29 | / Content-Type 30 | / CSeq 31 | / Date 32 | / Error-Info 33 | / Expires 34 | / From 35 | / In-Reply-To 36 | / Max-Forwards 37 | / MIME-Version 38 | / Min-Expires 39 | / Organization 40 | / Priority 41 | / Proxy-Authenticate 42 | / Proxy-Authorization 43 | / Proxy-Require 44 | / Record-Route 45 | / Reply-To 46 | / Require 47 | / Retry-After 48 | / Route 49 | / Server 50 | / Subject 51 | / Supported 52 | / Timestamp 53 | / To 54 | / Unsupported 55 | / User-Agent 56 | / Via 57 | / Warning 58 | / WWW-Authenticate 59 | / extension-header) CRLF 60 | ``` 61 | 62 | 63 | #### SIP 响应状态码 64 | 65 | ``` 66 | Informational = "100" ; Trying 67 | / "180" ; Ringing 68 | / "181" ; Call Is Being Forwarded 69 | / "182" ; Queued 70 | / "183" ; Session Progress 71 | Success = "200" ; OK 72 | 73 | Redirection = "300" ; Multiple Choices 74 | / "301" ; Moved Permanently 75 | / "302" ; Moved Temporarily 76 | / "305" ; Use Proxy 77 | / "380" ; Alternative Service 78 | 79 | Client-Error = "400" ; Bad Request 80 | / "401" ; Unauthorized 81 | / "402" ; Payment Required 82 | / "403" ; Forbidden 83 | / "404" ; Not Found 84 | / "405" ; Method Not Allowed 85 | / "406" ; Not Acceptable 86 | / "407" ; Proxy Authentication Required 87 | / "408" ; Request Timeout 88 | / "410" ; Gone 89 | / "413" ; Request Entity Too Large 90 | / "414" ; Request-URI Too Large 91 | / "415" ; Unsupported Media Type 92 | / "416" ; Unsupported URI Scheme 93 | / "420" ; Bad Extension 94 | / "421" ; Extension Required 95 | / "423" ; Interval Too Brief 96 | / "480" ; Temporarily not available 97 | / "481" ; Call Leg/Transaction Does Not Exist 98 | / "482" ; Loop Detected 99 | / "483" ; Too Many Hops 100 | / "484" ; Address Incomplete 101 | / "485" ; Ambiguous 102 | / "486" ; Busy Here 103 | / "487" ; Request Terminated 104 | / "488" ; Not Acceptable Here 105 | / "491" ; Request Pending 106 | / "493" ; Undecipherable 107 | 108 | Server-Error = "500" ; Internal Server Error 109 | / "501" ; Not Implemented 110 | / "502" ; Bad Gateway 111 | / "503" ; Service Unavailable 112 | / "504" ; Server Time-out 113 | / "505" ; SIP Version not supported 114 | / "513" ; Message Too Large 115 | Global-Failure = "600" ; Busy Everywhere 116 | / "603" ; Decline 117 | / "604" ; Does not exist anywhere 118 | / "606" ; Not Acceptable 119 | 120 | ``` -------------------------------------------------------------------------------- /transport/tcp_server.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | type TCPServer struct { 12 | Statistic 13 | addr string 14 | listener net.Listener 15 | readChan chan *Packet 16 | writeChan chan *Packet 17 | done chan struct{} 18 | Keepalive bool 19 | sessions sync.Map //key 是 remote-addr , value:*Connection。 20 | } 21 | 22 | func NewTCPServer(port uint16, keepalive bool) IServer { 23 | tcpAddr := fmt.Sprintf(":%d", port) 24 | 25 | return &TCPServer{ 26 | addr: tcpAddr, 27 | Keepalive: keepalive, 28 | readChan: make(chan *Packet, 10), 29 | writeChan: make(chan *Packet, 10), 30 | done: make(chan struct{}), 31 | } 32 | } 33 | 34 | func (s *TCPServer) IsReliable() bool { 35 | return true 36 | } 37 | 38 | func (s *TCPServer) Name() string { 39 | return fmt.Sprintf("tcp server at:%s", s.addr) 40 | } 41 | func (s *TCPServer) IsKeepalive() bool { 42 | return s.Keepalive 43 | } 44 | 45 | func (s *TCPServer) Start() error { 46 | //监听端口 47 | //开启tcp连接线程 48 | var err error 49 | s.listener, err = net.Listen("tcp", s.addr) 50 | //s.listener, err = tls.Listen("tcp", s.tcpAddr, tlsConfig) 51 | if err != nil { 52 | fmt.Println("TCP Listen failed:", err) 53 | return err 54 | } 55 | defer s.listener.Close() 56 | 57 | fmt.Println("start tcp server at: ", s.addr) 58 | 59 | //心跳线程 60 | if s.Keepalive { 61 | //TODO:start heartbeat thread 62 | } 63 | //写线程 64 | go func() { 65 | for { 66 | select { 67 | case p := <-s.writeChan: 68 | val, ok := s.sessions.Load(p.Addr.String()) 69 | if !ok { 70 | return 71 | } 72 | c := val.(*Connection) 73 | _, _ = c.Conn.Write(p.Data) 74 | case <-s.done: 75 | return 76 | } 77 | 78 | } 79 | }() 80 | 81 | //读线程 82 | for { 83 | conn, err := s.listener.Accept() 84 | if err != nil { 85 | var tempDelay time.Duration // how long to sleep on accept failure 86 | fmt.Println("accept err :", err.Error()) 87 | // 重连。参考http server 88 | if ne, ok := err.(net.Error); ok && ne.Temporary() { 89 | if tempDelay == 0 { 90 | tempDelay = 5 * time.Millisecond 91 | } else { 92 | tempDelay *= 2 93 | } 94 | 95 | if max := 1 * time.Second; tempDelay > max { 96 | tempDelay = max 97 | } 98 | 99 | time.Sleep(tempDelay) 100 | continue 101 | } 102 | fmt.Println("accept error, retry failed & exit.") 103 | return err 104 | } 105 | 106 | // conn.SetReadDeadline(time.Now().Add(600 * time.Second)) 107 | session := &Connection{Conn: conn, Addr: conn.RemoteAddr()} 108 | address := session.Addr.String() 109 | s.sessions.Store(address, session) 110 | 111 | fmt.Println(fmt.Sprintf("new tcp client remoteAddr: %v", address)) 112 | go s.handlerSession(session) 113 | } 114 | } 115 | 116 | func (s *TCPServer) handlerSession(c *Connection) { 117 | addrStr := c.Addr.String() 118 | 119 | //recovery from panic 120 | defer func() { 121 | s.CloseOne(addrStr) 122 | if err := recover(); err != nil { 123 | fmt.Println("client receiver handler panic: ", err) 124 | } 125 | }() 126 | 127 | buf := make([]byte, 2048) 128 | for { 129 | n, err := c.Conn.Read(buf) 130 | switch { 131 | case err == nil: 132 | p := &Packet{ 133 | Addr: c.Addr, 134 | Data: buf[:n], 135 | } 136 | s.readChan <- p 137 | case err == io.EOF: 138 | fmt.Println(fmt.Sprintf("io.EOF,client close --- remoteAddr: %v", c.Addr)) 139 | return 140 | case err != nil: 141 | fmt.Println("client other err: ", err) 142 | fmt.Println(fmt.Sprintf("client other err --- remoteAddr: %v", addrStr)) 143 | return 144 | } 145 | } 146 | } 147 | 148 | func (s *TCPServer) CloseOne(addr string) { 149 | val, ok := s.sessions.Load(addr) 150 | if !ok { 151 | return 152 | } 153 | c := val.(*Connection) 154 | _ = c.Conn.Close() 155 | s.sessions.Delete(addr) 156 | } 157 | 158 | func (s *TCPServer) ReadPacketChan() <-chan *Packet { 159 | return s.readChan 160 | } 161 | func (s *TCPServer) WritePacket(packet *Packet) { 162 | s.writeChan <- packet 163 | } 164 | 165 | func (s *TCPServer) Close() error { 166 | //TODO:TCP服务退出之前,需要先close掉所有客户端的连接 167 | s.sessions.Range(func(key, value interface{}) bool { 168 | c := value.(*Connection) 169 | _ = c.Conn.Close() 170 | s.sessions.Delete(key) 171 | return true 172 | }) 173 | return nil 174 | } 175 | -------------------------------------------------------------------------------- /transaction/fsm_nict.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | /* 9 | 非invite事物的状态机: 10 | 11 | |Request from TU 12 | |send request 13 | Timer E V 14 | send request +-----------+ 15 | +---------| |-------------------+ 16 | | | Trying | Timer F | 17 | +-------->| | or Transport Err.| 18 | +-----------+ inform TU | 19 | 200-699 | | | 20 | resp. to TU | |1xx | 21 | +---------------+ |resp. to TU | 22 | | | | 23 | | Timer E V Timer F | 24 | | send req +-----------+ or Transport Err. | 25 | | +---------| | inform TU | 26 | | | |Proceeding |------------------>| 27 | | +-------->| |-----+ | 28 | | +-----------+ |1xx | 29 | | | ^ |resp to TU | 30 | | 200-699 | +--------+ | 31 | | resp. to TU | | 32 | | | | 33 | | V | 34 | | +-----------+ | 35 | | | | | 36 | | | Completed | | 37 | | | | | 38 | | +-----------+ | 39 | | ^ | | 40 | | | | Timer K | 41 | +--------------+ | - | 42 | | | 43 | V | 44 | NOTE: +-----------+ | 45 | | | | 46 | transitions | Terminated|<------------------+ 47 | labeled with | | 48 | the event +-----------+ 49 | over the action 50 | to take 51 | 52 | Figure 6: non-INVITE client transaction 53 | */ 54 | func nict_snd_request(t *Transaction, e *EventObj) error { 55 | msg := e.msg 56 | fmt.Println("nict request:", msg.GetMethod()) 57 | 58 | t.origRequest = msg 59 | t.state = NICT_TRYING 60 | 61 | err := t.SipSend(msg) 62 | if err != nil { 63 | t.Terminate() 64 | return err 65 | } 66 | 67 | //发送出去之后,开启 timer 68 | if msg.IsReliable() { 69 | //stop timer E in reliable transport 70 | fmt.Println("Reliabel") 71 | } else { 72 | fmt.Println("Not Reliable") 73 | //发送定时器 74 | t.timerE = NewSipTimer(T1, T2, func() { 75 | t.event <- &EventObj{ 76 | evt: TIMEOUT_E, 77 | tid: t.id, 78 | } 79 | }) 80 | } 81 | 82 | //事物定时器 83 | t.timerF = time.AfterFunc(TimeF, func() { 84 | t.event <- &EventObj{ 85 | evt: TIMEOUT_F, 86 | tid: t.id, 87 | } 88 | }) 89 | 90 | return nil 91 | } 92 | 93 | //事物超时 94 | func osip_nict_timeout_f_event(t *Transaction, e *EventObj) error { 95 | t.Terminate() 96 | return nil 97 | } 98 | 99 | func osip_nict_timeout_e_event(t *Transaction, e *EventObj) error { 100 | if t.state == NICT_TRYING { 101 | //reset timer 102 | t.timerE.Reset(t.timerE.timeout * 2) 103 | } else { 104 | //in PROCEEDING STATE, TIMER is always T2 105 | t.timerE.Reset(T2) 106 | } 107 | 108 | //resend origin request 109 | err := t.SipSend(t.origRequest) 110 | if err != nil { 111 | t.Terminate() 112 | return err 113 | } 114 | 115 | return nil 116 | } 117 | 118 | func nict_rcv_1xx(t *Transaction, e *EventObj) error { 119 | t.lastResponse = e.msg 120 | t.state = NICT_PROCEEDING 121 | 122 | //重置发送定时器 123 | t.timerE.Reset(T2) 124 | 125 | return nil 126 | } 127 | 128 | func nict_rcv_23456xx(t *Transaction, e *EventObj) error { 129 | t.lastResponse = e.msg 130 | t.state = NICT_COMPLETED 131 | 132 | if e.msg.IsReliable() { 133 | //不设置timerK 134 | } else { 135 | t.timerK = time.AfterFunc(T4, func() { 136 | t.event <- &EventObj{ 137 | evt: TIMEOUT_K, 138 | tid: t.id, 139 | } 140 | }) 141 | } 142 | 143 | return nil 144 | } 145 | 146 | func osip_nict_timeout_k_event(t *Transaction, e *EventObj) error { 147 | t.Terminate() 148 | return nil 149 | } 150 | -------------------------------------------------------------------------------- /transaction/fsm_ict.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "gogb28181/sip" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | /* 10 | |INVITE from TU 11 | Timer A fires |INVITE sent 12 | Reset A, V Timer B fires 13 | INVITE sent +-----------+ or Transport Err. 14 | +---------| |---------------+inform TU 15 | | | Calling | | 16 | +-------->| |-------------->| 17 | +-----------+ 2xx | 18 | | | 2xx to TU | 19 | | |1xx | 20 | 300-699 +---------------+ |1xx to TU | 21 | ACK sent | | | 22 | resp. to TU | 1xx V | 23 | | 1xx to TU -----------+ | 24 | | +---------| | | 25 | | | |Proceeding |-------------->| 26 | | +-------->| | 2xx | 27 | | +-----------+ 2xx to TU | 28 | | 300-699 | | 29 | | ACK sent, | | 30 | | resp. to TU| | 31 | | | | NOTE: 32 | | 300-699 V | 33 | | ACK sent +-----------+Transport Err. | transitions 34 | | +---------| |Inform TU | labeled with 35 | | | | Completed |-------------->| the event 36 | | +-------->| | | over the action 37 | | +-----------+ | to take 38 | | ^ | | 39 | | | | Timer D fires | 40 | +--------------+ | - | 41 | | | 42 | V | 43 | +-----------+ | 44 | | | | 45 | | Terminated|<--------------+ 46 | | | 47 | +-----------+ 48 | 49 | Figure 5: INVITE client transaction 50 | */ 51 | func ict_snd_invite(t *Transaction, e *EventObj) error { 52 | msg := e.msg 53 | 54 | t.isReliable = msg.IsReliable() 55 | t.origRequest = msg 56 | t.state = ICT_CALLING 57 | 58 | //发送出去之后,开启 timer 59 | if msg.IsReliable() { 60 | //stop timer E in reliable transport 61 | fmt.Println("Reliabel") 62 | } else { 63 | fmt.Println("Not Reliable") 64 | //发送定时器,每次加倍,没有上限? 65 | t.timerA = NewSipTimer(T1, 0, func() { 66 | t.event <- &EventObj{ 67 | evt: TIMEOUT_A, 68 | tid: t.id, 69 | } 70 | }) 71 | } 72 | 73 | //事物定时器 74 | t.timerB = time.AfterFunc(TimeB, func() { 75 | t.event <- &EventObj{ 76 | evt: TIMEOUT_B, 77 | tid: t.id, 78 | } 79 | }) 80 | 81 | return nil 82 | } 83 | 84 | func osip_ict_timeout_a_event(t *Transaction, e *EventObj) error { 85 | err := t.SipSend(t.origRequest) 86 | if err != nil { 87 | //发送失败 88 | t.Terminate() 89 | return err 90 | } 91 | t.timerA.Reset(t.timerA.timeout * 2) 92 | 93 | return nil 94 | } 95 | 96 | func osip_ict_timeout_b_event(t *Transaction, e *EventObj) error { 97 | t.Terminate() 98 | return nil 99 | } 100 | 101 | func ict_rcv_1xx(t *Transaction, e *EventObj) error { 102 | t.lastResponse = e.msg 103 | t.state = ICT_PROCEEDING 104 | return nil 105 | } 106 | func ict_rcv_2xx(t *Transaction, e *EventObj) error { 107 | t.lastResponse = e.msg 108 | 109 | t.Terminate() 110 | 111 | return nil 112 | } 113 | func ict_rcv_3456xx(t *Transaction, e *EventObj) error { 114 | t.lastResponse = e.msg 115 | 116 | if t.state != ICT_COMPLETED { 117 | /* not a retransmission */ 118 | /* automatic handling of ack! */ 119 | ack := ict_create_ack(t, e.msg) 120 | t.ack = ack 121 | _ = t.SipSend(t.ack) 122 | t.Terminate() 123 | } 124 | 125 | /* start timer D (length is set to MAX (64*DEFAULT_T1 or 32000) */ 126 | t.timerD = time.AfterFunc(TimeD, func() { 127 | t.event <- &EventObj{ 128 | evt: TIMEOUT_D, 129 | tid: t.id, 130 | } 131 | }) 132 | 133 | t.state = ICT_COMPLETED 134 | 135 | return nil 136 | } 137 | 138 | func ict_create_ack(t *Transaction, resp *sip.Message) *sip.Message { 139 | 140 | return nil 141 | } 142 | 143 | func ict_retransmit_ack(t *Transaction, e *EventObj) error { 144 | if t.ack == nil { 145 | /* ??? we should make a new ACK and send it!!! */ 146 | return nil 147 | } 148 | 149 | err := t.SipSend(t.ack) 150 | if err != nil { 151 | return err 152 | } 153 | t.state = ICT_COMPLETED 154 | return nil 155 | } 156 | 157 | func osip_ict_timeout_d_event(t *Transaction, e *EventObj) error { 158 | t.Terminate() 159 | return nil 160 | } 161 | -------------------------------------------------------------------------------- /sip/message.go: -------------------------------------------------------------------------------- 1 | package sip 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | //Content-Type: Application/MANSCDP+xml 11 | //Content-Type: Application/SDP 12 | //Call-ID: 202081530679 13 | //Max-Forwards: 70 14 | //User-Agent: SRS/4.0.32(Leo) 15 | //Subject: 34020000001320000001:0009093128,34020000002000000001:0 16 | //Content-Length: 164 17 | 18 | type Message struct { 19 | Mode Mode //0:REQUEST, 1:RESPONSE 20 | 21 | StartLine *StartLine 22 | Via *Via //Via 23 | From *Contact //From 24 | To *Contact //To 25 | CallID string //Call-ID 26 | CSeq *CSeq //CSeq 27 | Contact *Contact //Contact 28 | Authorization string //Authorization 29 | MaxForwards int //Max-Forwards 30 | UserAgent string //User-Agent 31 | Subject string //Subject 32 | ContentType string //Content-Type 33 | Expires int //Expires 34 | ContentLength int //Content-Length 35 | 36 | Body string 37 | } 38 | 39 | func (m *Message) GetMode() Mode { 40 | return m.Mode 41 | } 42 | 43 | func (m *Message) IsRequest() bool { 44 | return m.Mode == SIP_MESSAGE_REQUEST 45 | } 46 | 47 | func (m *Message) IsResponse() bool { 48 | return m.Mode == SIP_MESSAGE_RESPONSE 49 | } 50 | 51 | func (m *Message) GetMethod() Method { 52 | return m.CSeq.Method 53 | } 54 | 55 | //此消息是否使用可靠传输 56 | func (m *Message) IsReliable() bool { 57 | protocol := strings.ToUpper(m.Via.Transport) 58 | return "TCP" == protocol || "TLS" == protocol || "SCTP" == protocol 59 | } 60 | 61 | //response code 62 | func (m *Message) GetStatusCode() int { 63 | return m.StartLine.Code 64 | } 65 | 66 | //response code and reason 67 | func (m *Message) GetReason() string { 68 | return DumpError(m.StartLine.Code) 69 | } 70 | 71 | func (m *Message) GetBranch() string { 72 | if m.Via == nil { 73 | panic("invalid via") 74 | } 75 | if m.Via.Params == nil { 76 | panic("invalid via params") 77 | } 78 | 79 | b, ok := m.Via.Params["branch"] 80 | if !ok { 81 | panic("invalid via paramas branch") 82 | } 83 | 84 | return b 85 | } 86 | 87 | //构建响应消息的时候,会使用请求消息的 source 和 destination 88 | //请求消息的source,格式: host:port 89 | func (m *Message) Source() string { 90 | if m.Mode == SIP_MESSAGE_RESPONSE { 91 | fmt.Println("only for request message") 92 | return "" 93 | } 94 | 95 | if m.Via == nil { 96 | fmt.Println("invalid request message") 97 | return "" 98 | } 99 | 100 | var ( 101 | host, port string 102 | via = m.Via 103 | ) 104 | 105 | if received, ok := via.Params["received"]; ok && received != "" { 106 | host = received 107 | } else { 108 | host = via.Host 109 | } 110 | 111 | if rport, ok := via.Params["rport"]; ok && rport != "-1" && rport != "0" && rport != "" { 112 | port = rport 113 | } else if via.Port != "" { 114 | port = via.Port 115 | } else { 116 | //如果port为空,则上层构建消息的时候,根据sip服务的默认端口来选择 117 | } 118 | return fmt.Sprintf("%v:%v", host, port) 119 | } 120 | 121 | //目标地址:这个应该是用于通过route头域实现proxy这样的功能,暂时不支持 122 | func (m *Message) Destination() string { 123 | //TODO: 124 | return "" 125 | } 126 | 127 | //======================================================================================================= 128 | 129 | func Decode(data []byte) (msg *Message, err error) { 130 | msg = &Message{} 131 | 132 | content := string(data) 133 | content = strings.Trim(content, CRLFCRLF) 134 | msgArr := strings.Split(content, CRLFCRLF) 135 | //第一部分:header 136 | //第二部分:body 137 | if len(msgArr) == 0 { 138 | fmt.Println("invalid sip message:", data) 139 | err = errors.New("invalid sip message") 140 | return 141 | } 142 | 143 | headStr := strings.TrimSpace(msgArr[0]) 144 | if len(msgArr) > 1 { 145 | msg.Body = strings.TrimSpace(msgArr[1]) 146 | } 147 | 148 | headStr = strings.Trim(headStr, CRLF) 149 | headArr := strings.Split(headStr, CRLF) 150 | for i, line := range headArr { 151 | //fmt.Printf("%02d --- %s ---- %d\n", i, line, len(line)) 152 | if i == 0 { 153 | firstline := strings.Trim(line, " ") 154 | tmp := strings.Split(firstline, " ") 155 | if len(tmp) != 3 { 156 | fmt.Println("parse first line failed:", firstline) 157 | err = errors.New("invalid first line") 158 | return 159 | } 160 | 161 | if strings.HasPrefix(firstline, VERSION) { 162 | //status line 163 | //SIP/2.0 200 OK 164 | var num int64 165 | num, err = strconv.ParseInt(tmp[1], 10, 64) 166 | if err != nil { 167 | return 168 | } 169 | msg.Mode = SIP_MESSAGE_RESPONSE 170 | msg.StartLine = &StartLine{ 171 | raw: firstline, 172 | Version: VERSION, 173 | Code: int(num), 174 | phrase: tmp[2], 175 | } 176 | } else { 177 | //request line 178 | //REGISTER sip:34020000002000000001@3402000000 SIP/2.0 179 | //MESSAGE sip:34020000002000000001@3402000000 SIP/2.0 180 | msg.Mode = SIP_MESSAGE_REQUEST 181 | msg.StartLine = &StartLine{ 182 | raw: firstline, 183 | Method: Method(tmp[0]), 184 | Version: VERSION, 185 | } 186 | msg.StartLine.Uri, err = parseURI(tmp[1]) 187 | if err != nil { 188 | return 189 | } 190 | } 191 | continue 192 | } 193 | 194 | pos := strings.IndexByte(line, ':') 195 | if pos == -1 { 196 | continue 197 | } 198 | k := strings.ToLower(strings.TrimSpace(line[:pos])) 199 | v := strings.TrimSpace(line[pos+1:]) 200 | //fmt.Printf("%02d ---k = %s , v = %s\n", i, k, v) 201 | 202 | if len(v) == 0 { 203 | continue 204 | } 205 | 206 | switch k { 207 | case "via": 208 | //Via: SIP/2.0/UDP 192.168.1.64:5060;rport;branch=z9hG4bK385701375 209 | msg.Via = &Via{} 210 | err = msg.Via.Parse(v) 211 | if err != nil { 212 | return 213 | } 214 | 215 | case "from": 216 | msg.From = &Contact{} 217 | err = msg.From.Parse(v) 218 | if err != nil { 219 | return 220 | } 221 | 222 | case "to": 223 | msg.To = &Contact{} 224 | err = msg.To.Parse(v) 225 | if err != nil { 226 | return 227 | } 228 | 229 | case "call-id": 230 | msg.CallID = v 231 | 232 | case "cseq": 233 | //CSeq: 2 REGISTER 234 | msg.CSeq = &CSeq{} 235 | err = msg.CSeq.Parse(v) 236 | if err != nil { 237 | return 238 | } 239 | 240 | case "contact": 241 | msg.Contact = &Contact{} 242 | err = msg.Contact.Parse(v) 243 | if err != nil { 244 | return 245 | } 246 | 247 | case "max-forwards": 248 | n, err := strconv.ParseInt(v, 10, 64) 249 | if err != nil { 250 | fmt.Printf("parse head faield: %s,%s\n", k, v) 251 | return nil, err 252 | } 253 | msg.MaxForwards = int(n) 254 | 255 | case "user-agent": 256 | msg.UserAgent = v 257 | 258 | case "expires": 259 | n, err := strconv.ParseInt(v, 10, 64) 260 | if err != nil { 261 | fmt.Printf("parse head faield: %s,%s\n", k, v) 262 | return nil, err 263 | } 264 | msg.Expires = int(n) 265 | 266 | case "content-length": 267 | n, err := strconv.ParseInt(v, 10, 64) 268 | if err != nil { 269 | fmt.Printf("parse head faield: %s,%s\n", k, v) 270 | return nil, err 271 | } 272 | msg.ContentLength = int(n) 273 | 274 | case "authorization": 275 | msg.Authorization = v 276 | 277 | case "content-type": 278 | msg.ContentType = v 279 | default: 280 | fmt.Printf("invalid sip head: %s,%s\n", k, v) 281 | } 282 | } 283 | return 284 | } 285 | 286 | func Encode(msg *Message) ([]byte, error) { 287 | sb := strings.Builder{} 288 | sb.WriteString(msg.StartLine.String()) 289 | sb.WriteString(CRLF) 290 | 291 | if msg.Via != nil { 292 | sb.WriteString("Via: ") 293 | sb.WriteString(msg.Via.String()) 294 | sb.WriteString(CRLF) 295 | } 296 | 297 | if msg.From != nil { 298 | sb.WriteString("From: ") 299 | sb.WriteString(msg.From.String()) 300 | sb.WriteString(CRLF) 301 | } 302 | 303 | if msg.To != nil { 304 | sb.WriteString("To: ") 305 | sb.WriteString(msg.To.String()) 306 | sb.WriteString(CRLF) 307 | } 308 | 309 | if msg.CallID != "" { 310 | sb.WriteString("Call-ID: ") 311 | sb.WriteString(msg.CallID) 312 | sb.WriteString(CRLF) 313 | } 314 | if msg.CSeq != nil { 315 | sb.WriteString("CSeq: ") 316 | sb.WriteString(msg.CSeq.String()) 317 | sb.WriteString(CRLF) 318 | } 319 | 320 | if msg.Contact != nil { 321 | sb.WriteString("Contact: ") 322 | sb.WriteString(msg.Contact.String()) 323 | sb.WriteString(CRLF) 324 | } 325 | 326 | if msg.UserAgent != "" { 327 | sb.WriteString("User-Agent: ") 328 | sb.WriteString(msg.UserAgent) 329 | sb.WriteString(CRLF) 330 | } 331 | 332 | if msg.ContentType != "" { 333 | sb.WriteString("Content-Type: ") 334 | sb.WriteString(msg.ContentType) 335 | sb.WriteString(CRLF) 336 | } 337 | 338 | if msg.Expires != 0 { 339 | sb.WriteString("Expires: ") 340 | sb.WriteString(strconv.Itoa(msg.Expires)) 341 | sb.WriteString(CRLF) 342 | } 343 | 344 | if msg.IsRequest() { 345 | //request only 346 | 347 | sb.WriteString("Max-Forwards: ") 348 | sb.WriteString(strconv.Itoa(msg.MaxForwards)) 349 | sb.WriteString(CRLF) 350 | 351 | if msg.Authorization != "" { 352 | sb.WriteString("Authorization: ") 353 | sb.WriteString(msg.Authorization) 354 | sb.WriteString(CRLF) 355 | } 356 | } else { 357 | //response only 358 | } 359 | 360 | sb.WriteString("Content-Length: ") 361 | sb.WriteString(strconv.Itoa(msg.ContentLength)) 362 | 363 | sb.WriteString(CRLFCRLF) 364 | 365 | if msg.Body != "" { 366 | sb.WriteString(msg.Body) 367 | } 368 | 369 | return []byte( sb.String()), nil 370 | } 371 | -------------------------------------------------------------------------------- /transaction/core.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "gogb28181/sip" 7 | "gogb28181/transport" 8 | "gogb28181/utils" 9 | "os" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | //Core: transactions manager 15 | //管理所有 transactions,以及相关全局参数、运行状态机 16 | type Core struct { 17 | ctx context.Context //上下文 18 | handlers map[State]map[Event]Handler //每个状态都可以处理有限个事件。不必加锁。 19 | transactions map[string]*Transaction //管理所有 transactions,key:tid,value:transaction 20 | mutex sync.Mutex //transactions的锁 21 | removeTa chan string //要删除transaction的时候,通过chan传递tid 22 | tp transport.ITransport //transport 23 | config *Config //sip server配置信息 24 | } 25 | 26 | //初始化一个 Core,需要能响应请求,也要能发起请求 27 | //client 发起请求 28 | //server 响应请求 29 | //TODO:根据角色,增加相关配置信息 30 | //TODO:通过context管理子线程 31 | //TODO:单元测试 32 | func NewCore(config *Config) *Core { 33 | core := &Core{ 34 | handlers: make(map[State]map[Event]Handler), 35 | transactions: make(map[string]*Transaction), 36 | mutex: sync.Mutex{}, 37 | removeTa: make(chan string, 10), 38 | config: config, 39 | tp: transport.NewUDPClient(config.SipIP, config.SipPort), 40 | } 41 | 42 | //可以放一些全局参数在ctx 43 | core.ctx = context.Background() 44 | 45 | //填充fsm 46 | core.addICTHandler() 47 | core.addISTHandler() 48 | core.addNICTHandler() 49 | core.addNISTHandler() 50 | 51 | return core 52 | } 53 | 54 | //add transaction to core 55 | func (c *Core) AddTransaction(ta *Transaction) { 56 | c.mutex.Lock() 57 | c.transactions[ta.id] = ta 58 | c.mutex.Unlock() 59 | } 60 | 61 | //delete transaction 62 | func (c *Core) DelTransaction(tid string) { 63 | c.mutex.Lock() 64 | delete(c.transactions, tid) 65 | c.mutex.Unlock() 66 | } 67 | 68 | //创建事件:根据接收到的消息创建消息事件 69 | func (c *Core) NewInComingMessageEvent(m *sip.Message) *EventObj { 70 | return &EventObj{ 71 | evt: getInComingMessageEvent(m), 72 | tid: getMessageTransactionID(m), 73 | msg: m, 74 | } 75 | } 76 | 77 | //创建事件:根据发出的消息创建消息事件 78 | func (c *Core) NewOutGoingMessageEvent(m *sip.Message) *EventObj { 79 | return &EventObj{ 80 | evt: getOutGoingMessageEvent(m), 81 | tid: getMessageTransactionID(m), 82 | msg: m, 83 | } 84 | } 85 | 86 | //创建事物 87 | //填充此事物的参数:via、from、to、callID、cseq 88 | func (c *Core) initTransaction(ctx context.Context, obj *EventObj) *Transaction { 89 | m := obj.msg 90 | 91 | //ack要么属于一个invite事物,要么由TU层直接管理,不通过事物管理。 92 | if m.GetMethod() == sip.ACK { 93 | fmt.Println("ack nerver create transaction") 94 | return nil 95 | } 96 | ta := &Transaction{ 97 | id: obj.tid, 98 | core: c, 99 | ctx: ctx, 100 | done: make(chan struct{}), 101 | event: make(chan *EventObj, 10), //带缓冲的event channel 102 | response: make(chan *Response), 103 | startAt: time.Now(), 104 | endAt: time.Now().Add(1000000 * time.Hour), 105 | } 106 | //填充其他transaction的信息 107 | ta.via = m.Via 108 | ta.from = m.From 109 | ta.to = m.To 110 | ta.callID = m.CallID 111 | ta.cseq = m.CSeq 112 | ta.origRequest = m 113 | 114 | return ta 115 | } 116 | 117 | //状态机初始化:ICT 118 | func (c *Core) addICTHandler() { 119 | c.addHandler(ICT_PRE_CALLING, SND_REQINVITE, ict_snd_invite) 120 | c.addHandler(ICT_CALLING, TIMEOUT_A, osip_ict_timeout_a_event) 121 | c.addHandler(ICT_CALLING, TIMEOUT_B, osip_ict_timeout_b_event) 122 | c.addHandler(ICT_CALLING, RCV_STATUS_1XX, ict_rcv_1xx) 123 | c.addHandler(ICT_CALLING, RCV_STATUS_2XX, ict_rcv_2xx) 124 | c.addHandler(ICT_CALLING, RCV_STATUS_3456XX, ict_rcv_3456xx) 125 | c.addHandler(ICT_PROCEEDING, RCV_STATUS_1XX, ict_rcv_1xx) 126 | c.addHandler(ICT_PROCEEDING, RCV_STATUS_2XX, ict_rcv_2xx) 127 | c.addHandler(ICT_PROCEEDING, RCV_STATUS_3456XX, ict_rcv_3456xx) 128 | c.addHandler(ICT_COMPLETED, RCV_STATUS_3456XX, ict_retransmit_ack) 129 | c.addHandler(ICT_COMPLETED, TIMEOUT_D, osip_ict_timeout_d_event) 130 | } 131 | 132 | //状态机初始化:IST 133 | func (c *Core) addISTHandler() { 134 | c.addHandler(IST_PRE_PROCEEDING, RCV_REQINVITE, ist_rcv_invite) 135 | c.addHandler(IST_PROCEEDING, RCV_REQINVITE, ist_rcv_invite) 136 | c.addHandler(IST_COMPLETED, RCV_REQINVITE, ist_rcv_invite) 137 | c.addHandler(IST_COMPLETED, TIMEOUT_G, osip_ist_timeout_g_event) 138 | c.addHandler(IST_COMPLETED, TIMEOUT_H, osip_ist_timeout_h_event) 139 | c.addHandler(IST_PROCEEDING, SND_STATUS_1XX, ist_snd_1xx) 140 | c.addHandler(IST_PROCEEDING, SND_STATUS_2XX, ist_snd_2xx) 141 | c.addHandler(IST_PROCEEDING, SND_STATUS_3456XX, ist_snd_3456xx) 142 | c.addHandler(IST_COMPLETED, RCV_REQACK, ist_rcv_ack) 143 | c.addHandler(IST_CONFIRMED, RCV_REQACK, ist_rcv_ack) 144 | c.addHandler(IST_CONFIRMED, TIMEOUT_I, osip_ist_timeout_i_event) 145 | } 146 | 147 | //状态机初始化:NICT 148 | func (c *Core) addNICTHandler() { 149 | c.addHandler(NICT_PRE_TRYING, SND_REQUEST, nict_snd_request) 150 | c.addHandler(NICT_TRYING, TIMEOUT_F, osip_nict_timeout_f_event) 151 | c.addHandler(NICT_TRYING, TIMEOUT_E, osip_nict_timeout_e_event) 152 | c.addHandler(NICT_TRYING, RCV_STATUS_1XX, nict_rcv_1xx) 153 | c.addHandler(NICT_TRYING, RCV_STATUS_2XX, nict_rcv_23456xx) 154 | c.addHandler(NICT_TRYING, RCV_STATUS_3456XX, nict_rcv_23456xx) 155 | c.addHandler(NICT_PROCEEDING, TIMEOUT_F, osip_nict_timeout_f_event) 156 | c.addHandler(NICT_PROCEEDING, TIMEOUT_E, osip_nict_timeout_e_event) 157 | c.addHandler(NICT_PROCEEDING, RCV_STATUS_1XX, nict_rcv_1xx) 158 | c.addHandler(NICT_PROCEEDING, RCV_STATUS_2XX, nict_rcv_23456xx) 159 | c.addHandler(NICT_PROCEEDING, RCV_STATUS_3456XX, nict_rcv_23456xx) 160 | c.addHandler(NICT_COMPLETED, TIMEOUT_K, osip_nict_timeout_k_event) 161 | } 162 | 163 | //状态机初始化:NIST 164 | func (c *Core) addNISTHandler() { 165 | c.addHandler(NIST_PRE_TRYING, RCV_REQUEST, nist_rcv_request) 166 | c.addHandler(NIST_TRYING, SND_STATUS_1XX, nist_snd_1xx) 167 | c.addHandler(NIST_TRYING, SND_STATUS_2XX, nist_snd_23456xx) 168 | c.addHandler(NIST_TRYING, SND_STATUS_3456XX, nist_snd_23456xx) 169 | c.addHandler(NIST_PROCEEDING, SND_STATUS_1XX, nist_snd_1xx) 170 | c.addHandler(NIST_PROCEEDING, SND_STATUS_2XX, nist_snd_23456xx) 171 | c.addHandler(NIST_PROCEEDING, SND_STATUS_3456XX, nist_snd_23456xx) 172 | c.addHandler(NIST_PROCEEDING, RCV_REQUEST, nist_rcv_request) 173 | c.addHandler(NIST_COMPLETED, TIMEOUT_J, osip_nist_timeout_j_event) 174 | c.addHandler(NIST_COMPLETED, RCV_REQUEST, nist_rcv_request) 175 | } 176 | 177 | //状态机初始化:根据state 匹配到对应的状态机 178 | func (c *Core) addHandler(state State, event Event, handler Handler) { 179 | m := c.handlers 180 | 181 | if state >= DIALOG_CLOSE { 182 | fmt.Println("invalid state:", state) 183 | return 184 | } 185 | 186 | if event >= UNKNOWN_EVT { 187 | fmt.Println("invalid event:", event) 188 | return 189 | } 190 | 191 | if _, ok := m[state]; !ok { 192 | m[state] = make(map[Event]Handler) 193 | } 194 | 195 | if _, ok := m[state][event]; ok { 196 | fmt.Printf("state:%d,event:%d, has been exist\n", state, event) 197 | } else { 198 | m[state][event] = handler 199 | } 200 | } 201 | 202 | func (c *Core) Start() { 203 | go c.Handler() 204 | 205 | c.tp.Start() 206 | } 207 | 208 | func (c *Core) Handler() { 209 | defer func() { 210 | if err := recover(); err != nil { 211 | fmt.Println("packet handler panic: ", err) 212 | utils.PrintStack() 213 | os.Exit(1) 214 | } 215 | }() 216 | 217 | ch := c.tp.ReadPacketChan() 218 | //阻塞读取消息 219 | for { 220 | fmt.Println("PacketHandler ========== SIP Client") 221 | select { 222 | case tid := <-c.removeTa: 223 | c.DelTransaction(tid) 224 | case p := <-ch: 225 | err := c.HandleReceiveMessage(p) 226 | if err != nil { 227 | fmt.Println("handler sip response message failed:", err.Error()) 228 | continue 229 | } 230 | } 231 | } 232 | } 233 | 234 | //发送消息:发送请求或者响应 235 | //发送消息仅负责发送。报错有两种:1、发送错误。2、发送了但是超时没有收到响应 236 | //如果发送成功,如何判断是否收到响应?没有收到响应要重传 237 | //所以一个transaction 有read和wriet的chan。 238 | //发送的时候写 write chan 239 | //接收的时候读取 read chan 240 | //发送之后,就开启timer,超时重传,还要记录和修改每次超时时间。不超时的话,记得删掉timer 241 | //发送 register 消息 242 | func (c *Core) SendMessage(msg *sip.Message) *Response { 243 | methond := msg.GetMethod() 244 | fmt.Println("send message:", methond) 245 | 246 | e := c.NewOutGoingMessageEvent(msg) 247 | 248 | //匹配事物 249 | ta, ok := c.transactions[e.tid] 250 | if !ok { 251 | //新的请求 252 | ta = c.initTransaction(c.ctx, e) 253 | 254 | //如果是sip 消息事件,则将消息缓存,填充typo和state 255 | if msg.IsRequest() { 256 | //as uac 257 | if msg.GetMethod() == sip.INVITE || msg.GetMethod() == sip.ACK { 258 | ta.typo = FSM_ICT 259 | ta.state = ICT_PRE_CALLING 260 | } else { 261 | ta.typo = FSM_NICT 262 | ta.state = NICT_PRE_TRYING 263 | } 264 | } else { 265 | //as uas:send response 266 | 267 | } 268 | 269 | c.AddTransaction(ta) 270 | } 271 | 272 | //把event推到transaction 273 | ta.event <- e 274 | 275 | //等待事件结束,并返回 276 | return <-ta.response 277 | } 278 | 279 | //接收到的消息处理 280 | //收到消息有两种:1、请求消息 2、响应消息 281 | //请求消息则直接响应处理。 282 | //响应消息则需要匹配到请求,让请求的transaction来处理。 283 | //TODO:参考srs和osip的流程,以及文档,做最终处理。需要将逻辑分成两层:TU 层和 transaction 层 284 | func (c *Core) HandleReceiveMessage(p *transport.Packet) (err error) { 285 | fmt.Println("packet content:", string(p.Data)) 286 | var msg *sip.Message 287 | msg, err = sip.Decode(p.Data) 288 | if err != nil { 289 | fmt.Println("parse sip message failed:", err.Error()) 290 | return ErrorParse 291 | } 292 | 293 | //这里不处理超过MTU的包,不处理半包 294 | err = checkMessage(msg) 295 | if err != nil { 296 | return err 297 | } 298 | 299 | fmt.Println("receive message:", msg.GetMethod()) 300 | 301 | e := c.NewInComingMessageEvent(msg) 302 | 303 | //一般应该是uas对于接收到的request做预处理 304 | if msg.IsRequest() { 305 | fixReceiveMessageViaParams(msg, p.Addr) 306 | } else { 307 | //TODO:对于uac,收到response消息,是否要检查 rport 和 received 呢?因为uas可能对此做了修改 308 | } 309 | //TODO:CANCEL、BYE 和 ACK 需要特殊处理,使用事物或者直接由TU层处理 310 | //查找transaction 311 | ta, ok := c.transactions[e.tid] 312 | if !ok { 313 | if msg.IsRequest() { 314 | if msg.GetMethod() == sip.ACK { 315 | //TODO:this should be a ACK for 2xx (but could be a late ACK!) 316 | return 317 | } 318 | ta = c.initTransaction(c.ctx, e) 319 | //as uas 320 | if msg.GetMethod() == sip.INVITE { 321 | ta.typo = FSM_IST 322 | ta.state = IST_PRE_PROCEEDING 323 | } else { 324 | ta.typo = FSM_NIST 325 | ta.state = NIST_PRE_TRYING 326 | } 327 | 328 | //构建transaction之后 329 | if msg.GetMethod() == sip.CANCEL { 330 | //TODO:CANCEL处理 331 | /* special handling for CANCEL */ 332 | /* in the new spec, if the CANCEL has a Via branch, then it 333 | is the same as the one in the original INVITE */ 334 | return 335 | } 336 | c.AddTransaction(ta) 337 | } else { 338 | //as uac 339 | //无法匹配事物的响应,只能是 INVITE 的响应?? 340 | if msg.GetMethod() != sip.INVITE { 341 | return ErrorUnknown //此消息无法处理 342 | } 343 | 344 | if msg.GetStatusCode() < 200 || msg.GetStatusCode() > 299 { 345 | //非成功的响应 346 | return nil 347 | } 348 | 349 | } 350 | } 351 | 352 | //把event推到transaction 353 | ta.event <- e 354 | 355 | //TODO:TU层处理:根据需要,创建,或者匹配 Dialog 356 | //通过tag匹配到call和dialog 357 | //处理是否要重传ack 358 | return 359 | } 360 | -------------------------------------------------------------------------------- /transaction/transaction.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "context" 5 | "gogb28181/sip" 6 | "gogb28181/transport" 7 | "fmt" 8 | "net" 9 | "time" 10 | ) 11 | 12 | //状态机之状态 13 | type State int 14 | 15 | const ( 16 | /* STATES for invite client transaction */ 17 | ICT_PRE_CALLING State = iota 18 | ICT_CALLING 19 | ICT_PROCEEDING 20 | ICT_COMPLETED 21 | ICT_TERMINATED 22 | 23 | /* STATES for invite server transaction */ 24 | IST_PRE_PROCEEDING 25 | IST_PROCEEDING 26 | IST_COMPLETED 27 | IST_CONFIRMED 28 | IST_TERMINATED 29 | 30 | /* STATES for NON-invite client transaction */ 31 | NICT_PRE_TRYING 32 | NICT_TRYING 33 | NICT_PROCEEDING 34 | NICT_COMPLETED 35 | NICT_TERMINATED 36 | 37 | /* STATES for NON-invite server transaction */ 38 | NIST_PRE_TRYING 39 | NIST_TRYING 40 | NIST_PROCEEDING 41 | NIST_COMPLETED 42 | NIST_TERMINATED 43 | 44 | /* STATES for dialog */ 45 | DIALOG_EARLY 46 | DIALOG_CONFIRMED 47 | DIALOG_CLOSE 48 | ) 49 | 50 | var stateMap = map[State]string{ 51 | ICT_PRE_CALLING: "ICT_PRE_CALLING", 52 | ICT_CALLING: "ICT_CALLING", 53 | ICT_PROCEEDING: "ICT_PROCEEDING", 54 | ICT_COMPLETED: "ICT_COMPLETED", 55 | ICT_TERMINATED: "ICT_TERMINATED", 56 | IST_PRE_PROCEEDING: "IST_PRE_PROCEEDING", 57 | IST_PROCEEDING: "IST_PROCEEDING", 58 | IST_COMPLETED: "IST_COMPLETED", 59 | IST_CONFIRMED: "IST_CONFIRMED", 60 | IST_TERMINATED: "IST_TERMINATED", 61 | NICT_PRE_TRYING: "NICT_PRE_TRYING", 62 | NICT_TRYING: "NICT_TRYING", 63 | NICT_PROCEEDING: "NICT_PROCEEDING", 64 | NICT_COMPLETED: "NICT_COMPLETED", 65 | NICT_TERMINATED: "NICT_TERMINATED", 66 | NIST_PRE_TRYING: "NIST_PRE_TRYING", 67 | NIST_TRYING: "NIST_TRYING", 68 | NIST_PROCEEDING: "NIST_PROCEEDING", 69 | NIST_COMPLETED: "NIST_COMPLETED", 70 | NIST_TERMINATED: "NIST_TERMINATED", 71 | DIALOG_EARLY: "DIALOG_EARLY", 72 | DIALOG_CONFIRMED: "DIALOG_CONFIRMED", 73 | DIALOG_CLOSE: "DIALOG_CLOSE", 74 | } 75 | 76 | func (s State) String() string { 77 | return stateMap[s] 78 | } 79 | 80 | //状态机之事件 81 | type Event int 82 | 83 | const ( 84 | /* TIMEOUT EVENTS for ICT */ 85 | TIMEOUT_A Event = iota /**< Timer A */ 86 | TIMEOUT_B /**< Timer B */ 87 | TIMEOUT_D /**< Timer D */ 88 | 89 | /* TIMEOUT EVENTS for NICT */ 90 | TIMEOUT_E /**< Timer E */ 91 | TIMEOUT_F /**< Timer F */ 92 | TIMEOUT_K /**< Timer K */ 93 | 94 | /* TIMEOUT EVENTS for IST */ 95 | TIMEOUT_G /**< Timer G */ 96 | TIMEOUT_H /**< Timer H */ 97 | TIMEOUT_I /**< Timer I */ 98 | 99 | /* TIMEOUT EVENTS for NIST */ 100 | TIMEOUT_J /**< Timer J */ 101 | 102 | /* FOR INCOMING MESSAGE */ 103 | RCV_REQINVITE /**< Event is an incoming INVITE request */ 104 | RCV_REQACK /**< Event is an incoming ACK request */ 105 | RCV_REQUEST /**< Event is an incoming NON-INVITE and NON-ACK request */ 106 | RCV_STATUS_1XX /**< Event is an incoming informational response */ 107 | RCV_STATUS_2XX /**< Event is an incoming 2XX response */ 108 | RCV_STATUS_3456XX /**< Event is an incoming final response (not 2XX) */ 109 | 110 | /* FOR OUTGOING MESSAGE */ 111 | SND_REQINVITE /**< Event is an outgoing INVITE request */ 112 | SND_REQACK /**< Event is an outgoing ACK request */ 113 | SND_REQUEST /**< Event is an outgoing NON-INVITE and NON-ACK request */ 114 | SND_STATUS_1XX /**< Event is an outgoing informational response */ 115 | SND_STATUS_2XX /**< Event is an outgoing 2XX response */ 116 | SND_STATUS_3456XX /**< Event is an outgoing final response (not 2XX) */ 117 | 118 | KILL_TRANSACTION /**< Event to 'kill' the transaction before termination */ 119 | UNKNOWN_EVT /**< Max event */ 120 | ) 121 | 122 | var eventMap = map[Event]string{ 123 | TIMEOUT_A: "TIMEOUT_A", 124 | TIMEOUT_B: "TIMEOUT_B", 125 | TIMEOUT_D: "TIMEOUT_D", 126 | TIMEOUT_E: "TIMEOUT_E", 127 | TIMEOUT_F: "TIMEOUT_F", 128 | TIMEOUT_K: "TIMEOUT_K", 129 | TIMEOUT_G: "TIMEOUT_G", 130 | TIMEOUT_H: "TIMEOUT_H", 131 | TIMEOUT_I: "TIMEOUT_I", 132 | TIMEOUT_J: "TIMEOUT_J", 133 | RCV_REQINVITE: "RCV_REQINVITE", 134 | RCV_REQACK: "RCV_REQACK", 135 | RCV_REQUEST: "RCV_REQUEST", 136 | RCV_STATUS_1XX: "RCV_STATUS_1XX", 137 | RCV_STATUS_2XX: "RCV_STATUS_2XX", 138 | RCV_STATUS_3456XX: "RCV_STATUS_3456XX", 139 | SND_REQINVITE: "SND_REQINVITE", 140 | SND_REQACK: "SND_REQACK", 141 | SND_REQUEST: "SND_REQUEST", 142 | SND_STATUS_1XX: "SND_STATUS_1XX", 143 | SND_STATUS_2XX: "SND_STATUS_2XX", 144 | SND_STATUS_3456XX: "SND_STATUS_3456XX", 145 | KILL_TRANSACTION: "KILL_TRANSACTION", 146 | UNKNOWN_EVT: "UNKNOWN_EVT", 147 | } 148 | 149 | func (e Event) String() string { 150 | return eventMap[e] 151 | } 152 | 153 | //incoming SIP MESSAGE 154 | func (e Event) IsIncomingMessage() bool { 155 | return e >= RCV_REQINVITE && e <= RCV_STATUS_3456XX 156 | } 157 | 158 | //incoming SIP REQUEST 159 | func (e Event) IsIncomingRequest() bool { 160 | return e == RCV_REQINVITE || e == RCV_REQACK || e == RCV_REQUEST 161 | } 162 | 163 | //incoming SIP RESPONSE 164 | func (e Event) IsIncomingResponse() bool { 165 | return e == RCV_STATUS_1XX || e == RCV_STATUS_2XX || e == RCV_STATUS_3456XX 166 | } 167 | 168 | //outgoing SIP MESSAGE 169 | func (e Event) IsOutgoingMessage() bool { 170 | return e >= SND_REQINVITE && e <= SND_REQINVITE 171 | } 172 | 173 | //outgoing SIP REQUEST 174 | func (e Event) IsOutgoingRequest() bool { 175 | return e == SND_REQINVITE || e == SND_REQACK || e == SND_REQUEST 176 | } 177 | 178 | //outgoing SIP RESPONSE 179 | func (e Event) IsOutgoingResponse() bool { 180 | return e == SND_STATUS_1XX || e == SND_STATUS_2XX || e == SND_STATUS_3456XX 181 | } 182 | 183 | //a SIP MESSAGE 184 | func (e Event) IsSipMessage() bool { 185 | return e >= RCV_REQINVITE && e <= SND_STATUS_3456XX 186 | } 187 | 188 | type EventObj struct { 189 | evt Event // event type 190 | tid string // transaction id 191 | msg *sip.Message 192 | } 193 | 194 | //状态机类型 195 | type FSMType int 196 | 197 | const ( 198 | FSM_ICT FSMType = iota /**< Invite Client (outgoing) Transaction */ 199 | FSM_IST /**< Invite Server (incoming) Transaction */ 200 | FSM_NICT /**< Non-Invite Client (outgoing) Transaction */ 201 | FSM_NIST /**< Non-Invite Server (incoming) Transaction */ 202 | FSM_UNKNOWN /**< Invalid Transaction */ 203 | ) 204 | 205 | var typeMap = map[FSMType]string{ 206 | FSM_ICT: "FSM_ICT", 207 | FSM_IST: "FSM_IST", 208 | FSM_NICT: "FSM_NICT", 209 | FSM_NIST: "FSM_NIST", 210 | FSM_UNKNOWN: "FSM_UNKNOWN", 211 | } 212 | 213 | func (t FSMType) String() string { 214 | return typeMap[t] 215 | } 216 | 217 | //对外将sip通讯封装成请求和响应 218 | //TODO:可参考http的request和response,屏蔽sip协议细节 219 | type Request struct { 220 | data *sip.Message 221 | } 222 | 223 | //Code = 0,则响应正常 224 | //Code != 0,打印错误提示信息 Message 225 | type Response struct { 226 | Code int 227 | Message string 228 | Data *sip.Message 229 | } 230 | 231 | type Handler func(t *Transaction, e *EventObj) error //操作 232 | 233 | type Header map[string]string 234 | 235 | // timer相关基础常量、方法等定义 236 | const ( 237 | T1 = 100 * time.Millisecond 238 | T2 = 4 * time.Second 239 | T4 = 5 * time.Second 240 | TimeA = T1 241 | TimeB = 64 * T1 242 | TimeD = 32 * time.Second 243 | TimeE = T1 244 | TimeF = 64 * T1 245 | TimeG = T1 246 | TimeH = 64 * T1 247 | TimeI = T4 248 | TimeJ = 64 * T1 249 | TimeK = T4 250 | Time1xx = 100 * time.Millisecond 251 | ) 252 | 253 | //TODO:是否要管理当前 transaction 的多次请求和响应的message? 254 | //TODO:是否要管理当前 transaction 的头域 255 | //TODO:多种transaction在一个struct里面管理不太方便,暂时写在一起,后期重构分开,并使用interface 解耦 256 | 257 | //是否需要tp layer? 258 | type Transaction struct { 259 | ctx context.Context //线程管理、其他参数 260 | id string //transaction ID 261 | isReliable bool //是否可靠传输 262 | core *Core //全局参数 263 | typo FSMType //状态机类型 264 | done chan struct{} //主动退出 265 | 266 | state State //当前状态 267 | event chan *EventObj //输入的事件,带缓冲 268 | response chan *Response //输出的响应 269 | startAt time.Time //开始时间 270 | endAt time.Time //结束时间 271 | 272 | //messages []*sip.Message //传输的消息缓存,origin request/last response/request ack... 273 | //header Header //创建事物的消息头域参数:Via From To CallID CSeq 274 | via *sip.Via 275 | from *sip.Contact 276 | to *sip.Contact 277 | callID string 278 | cseq *sip.CSeq 279 | origRequest *sip.Message //Initial request 280 | lastResponse *sip.Message //Last response,可能是临时的,也可能是最终的 281 | ack *sip.Message //ack request sent 282 | 283 | //timer for ict 284 | timerA *SipTimer 285 | timerB *time.Timer 286 | timerD *time.Timer 287 | 288 | //timer for nict 289 | timerE *SipTimer 290 | timerF *time.Timer 291 | timerK *time.Timer 292 | 293 | //timer for ist 294 | timerG *time.Timer 295 | timerH *time.Timer 296 | timerI *time.Timer 297 | 298 | //timer for nist 299 | timerJ *time.Timer 300 | } 301 | 302 | type SipTimer struct { 303 | tm *time.Timer 304 | timeout time.Duration //当前超时时间 305 | max time.Duration //最大超时时间 306 | } 307 | 308 | func NewSipTimer(d, max time.Duration, f func()) *SipTimer { 309 | return &SipTimer{ 310 | tm: time.AfterFunc(d, f), 311 | timeout: d, 312 | max: max, 313 | } 314 | } 315 | 316 | func (t *SipTimer) Reset(d time.Duration) { 317 | t.timeout = d 318 | if t.timeout > t.max && t.max != 0 { 319 | t.timeout = t.max 320 | } 321 | t.tm.Reset(t.timeout) 322 | } 323 | 324 | func (ta *Transaction) SetState(s State) { 325 | ta.state = s 326 | } 327 | 328 | func (ta *Transaction) GetTid() string { 329 | return ta.id 330 | } 331 | 332 | //每一个transaction至少有一个状态机线程运行 333 | //TODO:如果是一个uac的transaction,则把最后响应的消息返回(通过response chan) 334 | //transaction有很多消息需要传递到TU,也接收来自TU的消息。 335 | func (ta *Transaction) Run() { 336 | for { 337 | select { 338 | case e := <-ta.event: 339 | //根据event调用对应的handler 340 | fmt.Println("fsm run event:", e.evt.String()) 341 | core := ta.core 342 | state := ta.state 343 | evtHandlers, ok1 := core.handlers[state] 344 | if !ok1 { 345 | fmt.Println("invalid state:", ta.state.String()) 346 | return 347 | } 348 | f, ok2 := evtHandlers[e.evt] 349 | if !ok2 { 350 | fmt.Println("invalid handler for this event:", e.evt.String()) 351 | return 352 | } 353 | fmt.Printf("state:%s, event:%s\n", state.String(), e.evt.String()) 354 | err := f(ta, e) 355 | if err != nil { 356 | fmt.Printf("transaction run failed, state:%s, event:%s\n", state.String(), e.evt.String()) 357 | } 358 | 359 | case <-ta.done: 360 | fmt.Println("fsm exit") 361 | return 362 | 363 | case <-ta.ctx.Done(): 364 | fmt.Println("fsm killed") 365 | return 366 | } 367 | } 368 | } 369 | 370 | //Terminated:事物的终止 371 | //TODO:check调用时机 372 | func (ta *Transaction) Terminate() { 373 | 374 | ta.state = NICT_TERMINATED 375 | 376 | switch ta.typo { 377 | case FSM_ICT: 378 | ta.state = ICT_TERMINATED 379 | case FSM_NICT: 380 | ta.state = NICT_TERMINATED 381 | case FSM_IST: 382 | ta.state = IST_TERMINATED 383 | case FSM_NIST: 384 | ta.state = NIST_TERMINATED 385 | } 386 | 387 | //关掉事物的线程 388 | close(ta.done) 389 | 390 | //TODO:某些timer需要检查并关掉,并且设置为nil 391 | 392 | //remove ta from core 393 | ta.core.removeTa <- ta.id 394 | } 395 | 396 | //根据sip消息,解析出目标服务器地址,发送消息 397 | func (ta *Transaction) SipSend(msg *sip.Message) error { 398 | err := checkMessage(msg) 399 | if err != nil { 400 | return err 401 | } 402 | viaParams := msg.Via.Params 403 | 404 | //host 405 | var host, port string 406 | var ok1, ok2 bool 407 | if host, ok1 = viaParams["maddr"]; !ok1 { 408 | if host, ok2 = viaParams["received"]; !ok2 { 409 | host = msg.Via.Host 410 | } 411 | } 412 | //port 413 | port = viaParams["rport"] 414 | if port == "" || port == "0" || port == "-1" { 415 | port = msg.Via.Port 416 | } 417 | 418 | if port == "" { 419 | port = "5060" 420 | } 421 | 422 | addr := fmt.Sprintf("%s:%s", host, port) 423 | fmt.Println("dest addr:", addr) 424 | 425 | var err1, err2 error 426 | pkt := &transport.Packet{} 427 | pkt.Data, err1 = sip.Encode(msg) 428 | 429 | if msg.Via.Transport == "UDP" { 430 | pkt.Addr, err2 = net.ResolveUDPAddr("udp", addr) 431 | } else { 432 | pkt.Addr, err2 = net.ResolveTCPAddr("tcp", addr) 433 | } 434 | 435 | if err1 != nil { 436 | return err1 437 | } 438 | 439 | if err2 != nil { 440 | return err2 441 | } 442 | ta.core.tp.WritePacket(pkt) 443 | 444 | return nil 445 | } 446 | -------------------------------------------------------------------------------- /sip/head.go: -------------------------------------------------------------------------------- 1 | package sip 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | //换行符号: 11 | //linux,unix : \r\n 12 | //windows : \n 13 | //Mac OS : \r 14 | const ( 15 | VERSION = "SIP/2.0" // sip version 16 | //CRLF = "\r\n" // 0x0D0A 17 | //CRLFCRLF = "\r\n\r\n" // 0x0D0A0D0A 18 | 19 | CRLF = "\n" // 0x0D 20 | CRLFCRLF = "\n\n" // 0x0D0D 21 | ) 22 | 23 | //SIP消息类型:请求or响应 24 | type Mode int 25 | 26 | const ( 27 | SIP_MESSAGE_REQUEST Mode = 0 28 | SIP_MESSAGE_RESPONSE Mode = 1 29 | ) 30 | 31 | //sip request method 32 | type Method string 33 | 34 | const ( 35 | ACK Method = "ACK" 36 | BYE Method = "BYE" 37 | CANCEL Method = "CANCEL" 38 | INVITE Method = "INVITE" 39 | OPTIONS Method = "OPTIONS" 40 | REGISTER Method = "REGISTER" 41 | NOTIFY Method = "NOTIFY" 42 | SUBSCRIBE Method = "SUBSCRIBE" 43 | MESSAGE Method = "MESSAGE" 44 | REFER Method = "REFER" 45 | INFO Method = "INFO" 46 | PRACK Method = "PRACK" 47 | UPDATE Method = "UPDATE" 48 | PUBLISH Method = "PUBLISH" 49 | ) 50 | 51 | //startline 52 | //MESSAGE sip:34020000001320000001@3402000000 SIP/2.0 53 | //SIP/2.0 200 OK 54 | type StartLine struct { 55 | raw string //原始内容 56 | 57 | //request line: method uri version 58 | Method Method 59 | Uri URI //Request-URI:请求的服务地址,不能包含空白字符或者控制字符,并且禁止用”<>”括上。 60 | Version string 61 | 62 | //status line: version code phrase 63 | Code int //status code 64 | phrase string 65 | } 66 | 67 | func (l *StartLine) String() string { 68 | if l.Version == "" { 69 | l.Version = "SIP/2.0" 70 | } 71 | var result string 72 | if l.Method == "" { 73 | result = fmt.Sprintf("%s %d %s", l.Version, l.Code, l.phrase) 74 | } else { 75 | result = fmt.Sprintf("%s %s %s", l.Method, l.Uri.String(), l.Version) 76 | } 77 | l.raw = result 78 | return l.raw 79 | } 80 | 81 | //To From Referto Contact 82 | //From: ;tag=575945878 83 | //To: 84 | //Contact: 85 | //Contact: ;expires=0 86 | type Contact struct { 87 | raw string //原始内容 88 | 89 | Nickname string //可以没有 90 | Uri URI // 91 | 92 | //header params 93 | Params map[string]string // include tag/q/expires 94 | } 95 | 96 | func (c *Contact) String() string { 97 | sb := strings.Builder{} 98 | 99 | if c.Nickname != "" { 100 | sb.WriteByte('"') 101 | sb.WriteString(c.Nickname) 102 | sb.WriteByte('"') 103 | sb.WriteByte(' ') 104 | } 105 | urlStr := c.Uri.String() 106 | if strings.ContainsAny(urlStr, ",?:") { 107 | urlStr = fmt.Sprintf("<%s>", urlStr) 108 | } 109 | sb.WriteString(urlStr) 110 | 111 | if c.Params != nil { 112 | for k, v := range c.Params { 113 | sb.WriteString(";") 114 | sb.WriteString(k) 115 | sb.WriteString("=") 116 | sb.WriteString(v) 117 | } 118 | } 119 | 120 | c.raw = sb.String() 121 | return c.raw 122 | } 123 | 124 | func (c *Contact) Parse(str string) (err error) { 125 | c.raw = str 126 | 127 | if str == "*" { 128 | c.Uri.host = "*" 129 | return 130 | } 131 | 132 | n0 := strings.IndexByte(str, '"') 133 | if n0 != -1 { 134 | str = str[n0+1:] 135 | n1 := strings.IndexByte(str, '"') 136 | if n1 == -1 { 137 | return errors.New("parse nickname failed") 138 | } 139 | c.Nickname = str[:n1] 140 | str = strings.TrimSpace(str[n1+1:]) 141 | } 142 | 143 | if len(str) == 0 { 144 | return 145 | } 146 | 147 | var uriDone = false 148 | if strings.ContainsAny(str, "<>") { 149 | n2 := strings.IndexByte(str, '<') 150 | n3 := strings.IndexByte(str, '>') 151 | if n2 == -1 || n3 == -1 { 152 | err = errors.New("parse contact-uri failed") 153 | return 154 | } 155 | c.Uri, err = parseURI(str[n2+1 : n3]) 156 | if err != nil { 157 | return 158 | } 159 | uriDone = true 160 | str = strings.TrimSpace(str[n3+1:]) 161 | } 162 | 163 | if len(str) == 0 { 164 | return 165 | } 166 | 167 | str = strings.Trim(str, ";") 168 | arr1 := strings.Split(str, ";") 169 | for idx, one := range arr1 { 170 | //如果上面没有通过<>解析出来uri,则用分号split的第一个元素,就是uri字符串 171 | if !uriDone && idx == 0 { 172 | c.Uri, err = parseURI(one) 173 | if err != nil { 174 | return 175 | } 176 | 177 | continue 178 | } 179 | if c.Params == nil { 180 | c.Params = make(map[string]string) 181 | } 182 | arr2 := strings.Split(one, "=") 183 | k, v := arr2[0], arr2[1] 184 | c.Params[k] = v 185 | } 186 | 187 | return 188 | } 189 | 190 | //Via: SIP/2.0/UDP 192.168.1.64:5060;rport=49243;received=27.38.49.149;branch=z9hG4bK879576192 191 | //Params: 192 | //Received : IPv4address / IPv6address 193 | //RPort : 0-not found, -1-no-value, other-value 194 | //Branch : branch参数的值必须用magic cookie "z9hG4bK" 作为开头 195 | 196 | /* 197 | Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm) 198 | via-parm = sent-protocol LWS sent-by *( SEMI via-params ) 199 | via-params = via-ttl / via-maddr 200 | / via-received / via-branch 201 | / via-extension 202 | via-ttl = "ttl" EQUAL ttl 203 | via-maddr = "maddr" EQUAL host 204 | via-received = "received" EQUAL (IPv4address / IPv6address) 205 | via-branch = "branch" EQUAL token 206 | via-extension = generic-param 207 | sent-protocol = protocol-name SLASH protocol-version 208 | SLASH transport 209 | protocol-name = "SIP" / token 210 | protocol-version = token 211 | transport = "UDP" / "TCP" / "TLS" / "SCTP" 212 | / other-transport 213 | sent-by = host [ COLON port ] 214 | ttl = 1*3DIGIT ; 0 to 255 215 | */ 216 | type Via struct { 217 | raw string // 原始内容 218 | Version string // sip version: default to SIP/2.0 219 | Transport string // UDP,TCP ,TLS , SCTP 220 | Host string // sent-by : host:port 221 | Port string // 222 | //header params 223 | Params map[string]string // include branch/rport/received/ttl/maddr 224 | } 225 | 226 | func (v *Via) GetBranch() string { 227 | return v.Params["branch"] 228 | } 229 | 230 | func (v *Via) GetSendBy() string { 231 | var host, port string 232 | 233 | sb := strings.Builder{} 234 | received := v.Params["received"] 235 | rport := v.Params["rport"] 236 | 237 | if received != "" { 238 | host = received 239 | } else { 240 | host = v.Host 241 | } 242 | 243 | if rport != "" && rport != "0" && rport != "-1" { 244 | port = rport 245 | } else if v.Port != "" { 246 | port = v.Port 247 | } else { 248 | if strings.ToUpper(v.Transport) == "UDP" { 249 | port = "5060" 250 | } else { 251 | port = "5061" 252 | } 253 | } 254 | 255 | sb.WriteString(host) 256 | sb.WriteString(":") 257 | sb.WriteString(port) 258 | 259 | return sb.String() 260 | } 261 | func (v *Via) String() string { 262 | sb := strings.Builder{} 263 | if v.Version == "" { 264 | v.Version = "SIP/2.0" 265 | } 266 | 267 | if v.Transport == "" { 268 | v.Transport = "UDP" 269 | } 270 | 271 | sb.WriteString(v.Version) 272 | sb.WriteString("/") 273 | sb.WriteString(v.Transport) 274 | sb.WriteString(" ") 275 | sb.WriteString(v.Host) 276 | if v.Port != "" { 277 | sb.WriteString(":") 278 | sb.WriteString(v.Port) 279 | } 280 | 281 | if v.Params != nil { 282 | for k, v := range v.Params { 283 | sb.WriteString(";") 284 | sb.WriteString(k) 285 | if v == "-1" { 286 | //rport 值为-1的时候,没有值 287 | continue 288 | } 289 | sb.WriteString("=") 290 | sb.WriteString(v) 291 | } 292 | } 293 | 294 | v.raw = sb.String() 295 | return v.raw 296 | } 297 | 298 | //注意via允许以下这种添加空白 299 | //Via: SIP / 2.0 / UDP first.example.com: 4000;ttl=16 ;maddr=224.2.0.1 ;branch=z9hG4bKa7c6a8dlze.1 300 | //Via: SIP/2.0/UDP 192.168.1.64:5060;rport=5060;received=192.168.1.64;branch=z9hG4bK1000615294 301 | func (v *Via) Parse(str string) (err error) { 302 | v.raw = str 303 | 304 | str = strings.Trim(str, ";") 305 | arr1 := strings.Split(str, ";") 306 | part1 := strings.TrimSpace(arr1[0]) //SIP / 2.0 / UDP first.example.com: 4000 307 | 308 | v.Host, v.Port = "", "" 309 | if n1 := strings.IndexByte(part1, ':'); n1 != -1 { 310 | v.Port = strings.TrimSpace(part1[n1+1:]) 311 | part1 = strings.TrimSpace(part1[:n1]) 312 | } 313 | 314 | n2 := strings.LastIndexByte(part1, ' ') 315 | if n2 == -1 { 316 | v.Host = part1 //error? 317 | } else { 318 | v.Host = strings.TrimSpace(part1[n2+1:]) 319 | 320 | //解析protocol、version和transport,SIP / 2.0 / UDP 321 | part2 := part1[:n2] 322 | arr2 := strings.Split(part2, "/") 323 | if len(arr2) != 3 { 324 | err = errors.New("parse contait part1.1 failed:" + part2) 325 | return 326 | } 327 | v.Version = fmt.Sprintf("%s/%s", strings.TrimSpace(arr2[0]), strings.TrimSpace(arr2[1])) 328 | v.Transport = strings.TrimSpace(arr2[2]) 329 | } 330 | 331 | //必须有参数 332 | v.Params = make(map[string]string) 333 | for i, one := range arr1 { 334 | if i == 0 { 335 | //arr[0]已经处理 336 | continue 337 | } 338 | one = strings.TrimSpace(one) 339 | arr2 := strings.Split(one, "=") 340 | //rport 这个参数可能没有 value。 -1:no-value, other-value 341 | if len(arr2) == 1 { 342 | if arr2[0] == "rport" { 343 | v.Params["rport"] = "-1" 344 | continue 345 | } else { 346 | fmt.Println("invalid param:", one) 347 | continue 348 | } 349 | } 350 | 351 | k, val := arr2[0], arr2[1] 352 | v.Params[k] = val 353 | } 354 | 355 | return 356 | } 357 | 358 | //CSeq: 101 INVITE 359 | //CSeq: 2 REGISTER 360 | type CSeq struct { 361 | raw string //原始内容 362 | ID uint32 363 | Method Method 364 | } 365 | 366 | func (c *CSeq) String() string { 367 | c.raw = fmt.Sprintf("%d %s", c.ID, c.Method) 368 | return c.raw 369 | } 370 | 371 | func (c *CSeq) Parse(str string) error { 372 | c.raw = str 373 | arr1 := strings.Split(str, " ") 374 | n, err := strconv.ParseInt(arr1[0], 10, 64) 375 | if err != nil { 376 | fmt.Println("parse cseq faield:", str) 377 | return err 378 | } 379 | c.ID = uint32(n) 380 | c.Method = Method(arr1[1]) 381 | return nil 382 | } 383 | 384 | //sip:user:password@domain;uri-parameters?headers 385 | /* 386 | RFC3261 387 | SIP-URI = "sip:" [ userinfo ] hostport 388 | uri-parameters [ headers ] 389 | SIPS-URI = "sips:" [ userinfo ] hostport 390 | uri-parameters [ headers ] 391 | userinfo = ( user / telephone-subscriber ) [ ":" password ] "@" 392 | user = 1*( unreserved / escaped / user-unreserved ) 393 | user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/" 394 | password = *( unreserved / escaped / 395 | "&" / "=" / "+" / "$" / "," ) 396 | hostport = host [ ":" port ] 397 | host = hostname / IPv4address / IPv6reference 398 | hostname = *( domainlabel "." ) toplabel [ "." ] 399 | domainlabel = alphanum 400 | / alphanum *( alphanum / "-" ) alphanum 401 | toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum 402 | 403 | IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT 404 | IPv6reference = "[" IPv6address "]" 405 | IPv6address = hexpart [ ":" IPv4address ] 406 | hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ] 407 | hexseq = hex4 *( ":" hex4) 408 | hex4 = 1*4HEXDIG 409 | port = 1*DIGIT 410 | 411 | uri-parameters = *( ";" uri-parameter) 412 | uri-parameter = transport-param / user-param / method-param 413 | / ttl-param / maddr-param / lr-param / other-param 414 | transport-param = "transport=" 415 | ( "udp" / "tcp" / "sctp" / "tls" 416 | / other-transport) 417 | other-transport = token 418 | user-param = "user=" ( "phone" / "ip" / other-user) 419 | other-user = token 420 | method-param = "method=" Method 421 | ttl-param = "ttl=" ttl 422 | maddr-param = "maddr=" host 423 | lr-param = "lr" 424 | other-param = pname [ "=" pvalue ] 425 | pname = 1*paramchar 426 | pvalue = 1*paramchar 427 | paramchar = param-unreserved / unreserved / escaped 428 | param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$" 429 | 430 | headers = "?" header *( "&" header ) 431 | header = hname "=" hvalue 432 | hname = 1*( hnv-unreserved / unreserved / escaped ) 433 | hvalue = *( hnv-unreserved / unreserved / escaped ) 434 | hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$" 435 | */ 436 | type URI struct { 437 | scheme string // sip sips 438 | host string // userinfo@domain or userinfo@ip:port 439 | method string // uri和method有关? 440 | params map[string]string // include branch/maddr/received/ttl/rport 441 | headers map[string]string // include branch/maddr/received/ttl/rport 442 | } 443 | 444 | func (u *URI) String() string { 445 | if u.scheme == "" { 446 | u.scheme = "sip" 447 | } 448 | sb := strings.Builder{} 449 | sb.WriteString(u.scheme) 450 | sb.WriteString(":") 451 | sb.WriteString(u.host) 452 | if u.params != nil { 453 | for k, v := range u.params { 454 | sb.WriteString(";") 455 | sb.WriteString(k) 456 | sb.WriteString("=") 457 | sb.WriteString(v) 458 | } 459 | } 460 | 461 | if u.headers != nil { 462 | sb.WriteString("?") 463 | for k, v := range u.headers { 464 | sb.WriteString("&") 465 | sb.WriteString(k) 466 | sb.WriteString("=") 467 | sb.WriteString(v) 468 | } 469 | } 470 | 471 | return sb.String() 472 | } 473 | 474 | //对于gb28181,request-uri 不带参数 475 | func NewURI(host string) URI { 476 | return URI{ 477 | scheme: "sip", 478 | host: host, 479 | } 480 | } 481 | func parseURI(str string) (ret URI, err error) { 482 | ret = URI{} 483 | 484 | //解析scheme 485 | str = strings.TrimSpace(str) 486 | n1 := strings.IndexByte(str, ':') 487 | if n1 == -1 { 488 | err = errors.New("invalid sheme") 489 | return 490 | } 491 | ret.scheme = str[:n1] 492 | str = str[n1+1:] 493 | if len(str) == 0 { 494 | return 495 | } 496 | 497 | //解析host 498 | n2 := strings.IndexByte(str, ';') 499 | if n2 == -1 { 500 | ret.host = str 501 | return 502 | } 503 | ret.host = str[:n2] 504 | 505 | str = str[n2+1:] 506 | if len(str) == 0 { 507 | return 508 | } 509 | 510 | //解析params and headers 511 | var paramStr, headerStr = "", "" 512 | n3 := strings.IndexByte(str, '?') 513 | if n3 == -1 { 514 | paramStr = str 515 | } else { 516 | paramStr = str[:n3] 517 | headerStr = str[n3+1:] 518 | } 519 | 520 | //k1=v1;k2=v2 521 | if paramStr != "" { 522 | ret.params = make(map[string]string) 523 | paramStr = strings.Trim(paramStr, ";") 524 | arr1 := strings.Split(paramStr, ";") 525 | for _, one := range arr1 { 526 | tmp := strings.Split(one, "=") 527 | k, v := tmp[0], tmp[1] 528 | ret.params[k] = v 529 | } 530 | } 531 | 532 | //k1=v1&k2=v2 533 | if headerStr != "" { 534 | ret.headers = make(map[string]string) 535 | arr2 := strings.Split(paramStr, "&") 536 | for _, one := range arr2 { 537 | tmp := strings.Split(one, "=") 538 | k, v := tmp[0], tmp[1] 539 | ret.headers[k] = v 540 | } 541 | } 542 | 543 | return 544 | } 545 | --------------------------------------------------------------------------------