ws2.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package ws2
  2. import (
  3. "crypto/rand"
  4. "errors"
  5. "fmt"
  6. "log"
  7. "net"
  8. "net/http"
  9. "net/url"
  10. "strings"
  11. "time"
  12. "git.me9.top/git/tinymq/config"
  13. "git.me9.top/git/tinymq/conn"
  14. "git.me9.top/git/tinymq/util"
  15. "git.me9.top/git/tinymq/util/pool"
  16. "github.com/gorilla/websocket"
  17. )
  18. const PROTO string = "ws"
  19. const PROTO_STL string = "wss"
  20. const VERSION uint8 = 2
  21. type Ws2 struct {
  22. cf *config.Config
  23. conn *websocket.Conn
  24. cipher *util.Cipher // 记录当前的加解密类,可以保证在没有ssl的情况下数据安全
  25. compress bool // 是否启用压缩
  26. }
  27. var upgrader = websocket.Upgrader{
  28. CheckOrigin: func(r *http.Request) bool {
  29. return true // 允许任何Origin跨站访问
  30. },
  31. } // use default options
  32. // websocket 服务
  33. // 如果有绑定参数,则进行绑定操作代码
  34. func Server(cf *config.Config, bind string, path string, hash string, fn conn.ServerConnectFunc) (err error) {
  35. var ci *util.CipherInfo
  36. var encryptKey string
  37. if hash != "" {
  38. i := strings.Index(hash, ":")
  39. if i <= 0 {
  40. return errors.New("hash is invalid")
  41. }
  42. encryptMethod := hash[0:i]
  43. encryptKey = hash[i+1:]
  44. if c, ok := util.CipherMethod[encryptMethod]; ok {
  45. ci = c
  46. } else {
  47. return errors.New("Unsupported encryption method: " + encryptMethod)
  48. }
  49. }
  50. http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
  51. conn, err := upgrader.Upgrade(w, r, nil)
  52. if err != nil {
  53. log.Println("[ws2 Server Upgrade ERROR]", err)
  54. return
  55. }
  56. if ci == nil {
  57. ws := &Ws2{
  58. cf: cf,
  59. conn: conn,
  60. }
  61. fn(ws)
  62. return
  63. }
  64. var eiv []byte
  65. var div []byte
  66. if ci.IvLen > 0 {
  67. // 服务端 IV
  68. eiv = make([]byte, ci.IvLen)
  69. _, err = rand.Read(eiv)
  70. if err != nil {
  71. log.Println("[ws2 Server rand.Read ERROR]", err)
  72. return
  73. }
  74. // 发送 IV
  75. conn.SetWriteDeadline(time.Now().Add(time.Duration(cf.WriteWait) * time.Millisecond))
  76. if err := conn.WriteMessage(websocket.BinaryMessage, eiv); err != nil {
  77. log.Println("[ws2 Server conn.Write ERROR]", err)
  78. return
  79. }
  80. // 读取 IV
  81. err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(cf.ReadWait)))
  82. if err != nil {
  83. log.Println("[ws2 Server SetReadDeadline ERROR]", err)
  84. return
  85. }
  86. _, div, err = conn.ReadMessage()
  87. if err != nil {
  88. log.Println("[ws2 Server ReadFull ERROR]", err)
  89. conn.Close()
  90. return
  91. }
  92. }
  93. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  94. if err != nil {
  95. log.Println("[ws2 NewCipher ERROR]", err)
  96. return
  97. }
  98. ws := &Ws2{
  99. cf: cf,
  100. conn: conn,
  101. cipher: cipher,
  102. }
  103. fn(ws)
  104. })
  105. if bind != "" {
  106. go func() (err error) {
  107. defer func() {
  108. if err != nil {
  109. log.Fatal(err)
  110. }
  111. }()
  112. log.Printf("Listening and serving Websocket on %s\n", bind)
  113. // 暂时使用全局的方式,后面有需求再修改
  114. // 而且还没有 https 方式的绑定
  115. // 需要在前端增加其他的服务进行转换
  116. err = http.ListenAndServe(bind, nil)
  117. return
  118. }()
  119. }
  120. return
  121. }
  122. // 客户端,新建一个连接
  123. func Dial(cf *config.Config, scheme string, addr string, path string, hash string) (conn.Connect, error) {
  124. u := url.URL{Scheme: scheme, Host: addr, Path: path}
  125. // 没有加密的情况
  126. if hash == "" {
  127. conn, _, err := (&websocket.Dialer{
  128. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  129. }).Dial(u.String(), nil)
  130. if err != nil {
  131. return nil, err
  132. }
  133. ws := &Ws2{
  134. cf: cf,
  135. conn: conn,
  136. }
  137. return ws, nil
  138. }
  139. i := strings.Index(hash, ":")
  140. if i <= 0 {
  141. return nil, errors.New("hash is invalid")
  142. }
  143. encryptMethod := hash[0:i]
  144. encryptKey := hash[i+1:]
  145. ci, ok := util.CipherMethod[encryptMethod]
  146. if !ok {
  147. return nil, errors.New("Unsupported encryption method: " + encryptMethod)
  148. }
  149. conn, _, err := (&websocket.Dialer{
  150. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  151. }).Dial(u.String(), nil)
  152. if err != nil {
  153. return nil, err
  154. }
  155. var eiv []byte
  156. var div []byte
  157. if ci.IvLen > 0 {
  158. // 客户端 IV
  159. eiv = make([]byte, ci.IvLen)
  160. _, err = rand.Read(eiv)
  161. if err != nil {
  162. log.Println("[ws2 Client rand.Read ERROR]", err)
  163. return nil, err
  164. }
  165. // 发送 IV
  166. conn.SetWriteDeadline(time.Now().Add(time.Duration(cf.WriteWait) * time.Millisecond))
  167. if err := conn.WriteMessage(websocket.BinaryMessage, eiv); err != nil {
  168. log.Println("[ws2 Client conn.Write ERROR]", err)
  169. return nil, err
  170. }
  171. // 读取 IV
  172. err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(cf.ReadWait)))
  173. if err != nil {
  174. log.Println("[ws2 Client SetReadDeadline ERROR]", err)
  175. return nil, err
  176. }
  177. _, div, err = conn.ReadMessage()
  178. if err != nil {
  179. log.Println("[ws2 Client ReadFull ERROR]", err)
  180. return nil, err
  181. }
  182. }
  183. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  184. if err != nil {
  185. log.Println("[ws2 NewCipher ERROR]", err)
  186. return nil, err
  187. }
  188. ws := &Ws2{
  189. cf: cf,
  190. conn: conn,
  191. cipher: cipher,
  192. compress: true,
  193. }
  194. return ws, nil
  195. }
  196. // 发送数据到网络
  197. func (c *Ws2) WriteRawPackage(buf []byte, recycle bool) (err error) {
  198. if recycle {
  199. defer pool.Put(buf)
  200. }
  201. if c.cipher != nil {
  202. c.cipher.Encrypt(buf, buf)
  203. }
  204. c.conn.SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(c.cf.WriteWait)))
  205. return c.conn.WriteMessage(websocket.BinaryMessage, buf)
  206. }
  207. // 从连接中读取数据包
  208. // recycle 指示是否需要手动将缓存放回内存池
  209. func (c *Ws2) ReadRawPackage(deadline int) (buf []byte, recycle bool, err error) {
  210. err = c.conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(deadline)))
  211. if err != nil {
  212. return
  213. }
  214. _, buf, err = c.conn.ReadMessage()
  215. if err != nil {
  216. return
  217. }
  218. if c.cipher != nil {
  219. c.cipher.Decrypt(buf, buf)
  220. }
  221. return
  222. }
  223. // 发送Auth信息
  224. // 建立连接后第一个发送的消息
  225. func (c *Ws2) WriteAuthInfo(channel string, auth []byte) (err error) {
  226. buf := conn.AuthPackageEncode(PROTO, VERSION, channel, auth, c.compress)
  227. return c.WriteRawPackage(buf, true)
  228. }
  229. // 获取Auth信息
  230. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  231. func (c *Ws2) ReadAuthInfo() (proto string, version uint8, channel string, auth []byte, err error) {
  232. msg, recycle, err := c.ReadRawPackage(c.cf.ReadWait)
  233. if err != nil {
  234. return
  235. }
  236. var compress bool
  237. proto, version, compress, channel, auth, err = conn.AuthPackageDecode(msg, recycle)
  238. if err != nil {
  239. return
  240. }
  241. if proto != PROTO && proto != PROTO_STL {
  242. err = fmt.Errorf("wrong proto: %s", proto)
  243. return
  244. }
  245. if version != VERSION {
  246. err = fmt.Errorf("require version %d, get version: %d", VERSION, version)
  247. return
  248. }
  249. c.compress = compress
  250. return
  251. }
  252. // 发送请求数据包到网络
  253. func (c *Ws2) WriteRequest(id uint16, cmd string, data []byte) error {
  254. buf := conn.RequestPackageEncode(id, cmd, data, c.compress, c.cf)
  255. return c.WriteRawPackage(buf, true)
  256. }
  257. // 发送响应数据包到网络
  258. // 网络格式:[id, stateCode, data]
  259. func (c *Ws2) WriteResponse(id uint16, state uint8, data []byte) error {
  260. buf := conn.ResponsePackageEncode(id, state, data, c.compress, c.cf)
  261. return c.WriteRawPackage(buf, true)
  262. }
  263. // 发送ping包
  264. func (c *Ws2) WritePing(id uint16) error {
  265. buf := conn.PingPackageEncode(id)
  266. return c.WriteRawPackage(buf, true)
  267. }
  268. // 获取信息
  269. func (c *Ws2) ReadMessage(deadline int) (msgType conn.MsgType, id uint16, cmd string, state uint8, data []byte, err error) {
  270. var msg []byte
  271. var recycle bool
  272. msg, recycle, err = c.ReadRawPackage(deadline)
  273. if err != nil {
  274. return
  275. }
  276. return conn.PackageDecode(msg, recycle, c.compress, c.cf)
  277. }
  278. // 获取远程的地址
  279. func (c *Ws2) RemoteIP() net.IP {
  280. return util.AddrToIP(c.conn.RemoteAddr())
  281. }
  282. // 获取本地的地址
  283. func (c *Ws2) LocalIP() net.IP {
  284. return util.AddrToIP(c.conn.LocalAddr())
  285. }
  286. func (c *Ws2) Close() error {
  287. return c.conn.Close()
  288. }