ws2.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. package ws2
  2. import (
  3. "crypto/rand"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "log"
  8. "net"
  9. "net/http"
  10. "net/url"
  11. "strings"
  12. "time"
  13. "git.me9.top/git/tinymq/config"
  14. "git.me9.top/git/tinymq/conn"
  15. "git.me9.top/git/tinymq/util"
  16. "git.me9.top/git/tinymq/util/pool"
  17. "github.com/gorilla/websocket"
  18. )
  19. const PROTO string = "ws"
  20. const PROTO_STL string = "wss"
  21. const VERSION uint8 = 2
  22. type Ws2 struct {
  23. cf *config.Config
  24. conn *websocket.Conn
  25. cipher *util.Cipher // 记录当前的加解密类,可以保证在没有ssl的情况下数据安全
  26. compress bool // 是否启用压缩
  27. }
  28. var upgrader = websocket.Upgrader{
  29. CheckOrigin: func(r *http.Request) bool {
  30. return true // 允许任何Origin跨站访问
  31. },
  32. } // use default options
  33. // websocket 服务
  34. // 如果有绑定参数,则进行绑定操作代码
  35. func Server(cf *config.Config, bind string, path string, hash string, fn conn.ServerConnectFunc) (err error) {
  36. var ci *util.CipherInfo
  37. var encryptKey string
  38. if hash != "" {
  39. i := strings.Index(hash, ":")
  40. if i <= 0 {
  41. return errors.New("hash is invalid")
  42. }
  43. encryptMethod := hash[0:i]
  44. encryptKey = hash[i+1:]
  45. if c, ok := util.CipherMethod[encryptMethod]; ok {
  46. ci = c
  47. } else {
  48. return errors.New("Unsupported encryption method: " + encryptMethod)
  49. }
  50. }
  51. http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
  52. conn, err := upgrader.Upgrade(w, r, nil)
  53. if err != nil {
  54. log.Println("[ws2 Server Upgrade ERROR]", err)
  55. return
  56. }
  57. if ci == nil {
  58. ws := &Ws2{
  59. cf: cf,
  60. conn: conn,
  61. }
  62. fn(ws)
  63. return
  64. }
  65. var eiv []byte
  66. var div []byte
  67. if ci.IvLen > 0 {
  68. // 服务端 IV
  69. eiv = make([]byte, ci.IvLen)
  70. _, err = rand.Read(eiv)
  71. if err != nil {
  72. log.Println("[ws2 Server rand.Read ERROR]", err)
  73. return
  74. }
  75. // 发送 IV
  76. conn.SetWriteDeadline(time.Now().Add(time.Duration(cf.WriteWait) * time.Millisecond))
  77. if err := conn.WriteMessage(websocket.BinaryMessage, eiv); err != nil {
  78. log.Println("[ws2 Server conn.Write ERROR]", err)
  79. return
  80. }
  81. // 读取 IV
  82. err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(cf.ReadWait)))
  83. if err != nil {
  84. log.Println("[ws2 Server SetReadDeadline ERROR]", err)
  85. return
  86. }
  87. _, div, err = conn.ReadMessage()
  88. if err != nil {
  89. log.Println("[ws2 Server ReadFull ERROR]", err)
  90. conn.Close()
  91. return
  92. }
  93. }
  94. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  95. if err != nil {
  96. log.Println("[ws2 NewCipher ERROR]", err)
  97. return
  98. }
  99. ws := &Ws2{
  100. cf: cf,
  101. conn: conn,
  102. cipher: cipher,
  103. }
  104. fn(ws)
  105. })
  106. if bind != "" {
  107. go func() (err error) {
  108. defer func() {
  109. if err != nil {
  110. log.Fatal(err)
  111. }
  112. }()
  113. log.Printf("Listening and serving Websocket on %s\n", bind)
  114. // 暂时使用全局的方式,后面有需求再修改
  115. // 而且还没有 https 方式的绑定
  116. // 需要在前端增加其他的服务进行转换
  117. err = http.ListenAndServe(bind, nil)
  118. return
  119. }()
  120. }
  121. return
  122. }
  123. // 客户端,新建一个连接
  124. func Dial(cf *config.Config, scheme string, addr string, path string, hash string) (conn.Connect, error) {
  125. u := url.URL{Scheme: scheme, Host: addr, Path: path}
  126. // 没有加密的情况
  127. if hash == "" {
  128. conn, _, err := (&websocket.Dialer{
  129. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  130. }).Dial(u.String(), nil)
  131. if err != nil {
  132. return nil, err
  133. }
  134. ws := &Ws2{
  135. cf: cf,
  136. conn: conn,
  137. }
  138. return ws, nil
  139. }
  140. i := strings.Index(hash, ":")
  141. if i <= 0 {
  142. return nil, errors.New("hash is invalid")
  143. }
  144. encryptMethod := hash[0:i]
  145. encryptKey := hash[i+1:]
  146. ci, ok := util.CipherMethod[encryptMethod]
  147. if !ok {
  148. return nil, errors.New("Unsupported encryption method: " + encryptMethod)
  149. }
  150. conn, _, err := (&websocket.Dialer{
  151. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  152. }).Dial(u.String(), nil)
  153. if err != nil {
  154. return nil, err
  155. }
  156. var eiv []byte
  157. var div []byte
  158. if ci.IvLen > 0 {
  159. // 客户端 IV
  160. eiv = make([]byte, ci.IvLen)
  161. _, err = rand.Read(eiv)
  162. if err != nil {
  163. log.Println("[ws2 Client rand.Read ERROR]", err)
  164. return nil, err
  165. }
  166. // 发送 IV
  167. conn.SetWriteDeadline(time.Now().Add(time.Duration(cf.WriteWait) * time.Millisecond))
  168. if err := conn.WriteMessage(websocket.BinaryMessage, eiv); err != nil {
  169. log.Println("[ws2 Client conn.Write ERROR]", err)
  170. return nil, err
  171. }
  172. // 读取 IV
  173. err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(cf.ReadWait)))
  174. if err != nil {
  175. log.Println("[ws2 Client SetReadDeadline ERROR]", err)
  176. return nil, err
  177. }
  178. _, div, err = conn.ReadMessage()
  179. if err != nil {
  180. log.Println("[ws2 Client ReadFull ERROR]", err)
  181. return nil, err
  182. }
  183. }
  184. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  185. if err != nil {
  186. log.Println("[ws2 NewCipher ERROR]", err)
  187. return nil, err
  188. }
  189. ws := &Ws2{
  190. cf: cf,
  191. conn: conn,
  192. cipher: cipher,
  193. compress: true,
  194. }
  195. return ws, nil
  196. }
  197. // 发送数据到网络
  198. // 如果有加密函数的话会直接修改源数据
  199. func (c *Ws2) WriteRawPackage(buf []byte, recycle bool) (err error) {
  200. if recycle {
  201. defer pool.Put(buf)
  202. }
  203. if c.cipher != nil {
  204. c.cipher.Encrypt(buf, buf)
  205. }
  206. c.conn.SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(c.cf.WriteWait)))
  207. return c.conn.WriteMessage(websocket.BinaryMessage, buf)
  208. }
  209. // 从连接中读取数据包
  210. // recycle 指示是否需要手动将缓存放回内存池
  211. func (c *Ws2) ReadRawPackage(deadline int) (msg []byte, recycle bool, err error) {
  212. err = c.conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(deadline)))
  213. if err != nil {
  214. return
  215. }
  216. _, msg, err = c.conn.ReadMessage()
  217. return
  218. }
  219. // 发送Auth信息
  220. // 建立连接后第一个发送的消息
  221. func (c *Ws2) WriteAuthInfo(channel string, auth []byte) (err error) {
  222. protoLen := len(PROTO)
  223. if protoLen > 0xFF {
  224. return errors.New("length of protocol over")
  225. }
  226. channelLen := len(channel)
  227. if channelLen > 0xFFFF {
  228. return errors.New("length of channel over")
  229. }
  230. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  231. dlen := 2 + 1 + protoLen + 1 + 1 + 2 + channelLen + len(auth)
  232. index := 0
  233. // buf := make([]byte, dlen)
  234. buf := pool.Get(dlen)
  235. binary.BigEndian.PutUint16(buf[index:index+2], config.ID_AUTH)
  236. index += 2
  237. buf[index] = byte(protoLen)
  238. index++
  239. copy(buf[index:index+protoLen], []byte(PROTO))
  240. index += protoLen
  241. buf[index] = VERSION
  242. index++
  243. if c.compress {
  244. buf[index] = 0x01
  245. } else {
  246. buf[index] = 0
  247. }
  248. index++
  249. binary.BigEndian.PutUint16(buf[index:index+2], uint16(channelLen))
  250. index += 2
  251. copy(buf[index:index+channelLen], []byte(channel))
  252. index += channelLen
  253. copy(buf[index:], auth)
  254. return c.WriteRawPackage(buf, true)
  255. }
  256. // 获取Auth信息
  257. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  258. func (c *Ws2) ReadAuthInfo() (proto string, version uint8, channel string, auth []byte, err error) {
  259. defer func() {
  260. if r := recover(); r != nil {
  261. err = fmt.Errorf("recovered from panic: %v", r)
  262. return
  263. }
  264. }()
  265. // 由于这里返回的数据都不需要回收,故不做判断处理
  266. msg, _, err := c.ReadRawPackage(c.cf.ReadWait)
  267. // err = c.conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(c.cf.ReadWait)))
  268. // if err != nil {
  269. // return
  270. // }
  271. // _, msg, err := c.conn.ReadMessage()
  272. if err != nil {
  273. return
  274. }
  275. msgLen := len(msg)
  276. if msgLen < 9 {
  277. err = errors.New("wrong message length")
  278. return
  279. }
  280. // 将读出来的数据进行解密
  281. if c.cipher != nil {
  282. c.cipher.Decrypt(msg, msg)
  283. }
  284. index := 0
  285. id := binary.BigEndian.Uint16(msg[index : index+2])
  286. if id != config.ID_AUTH {
  287. err = fmt.Errorf("wrong message id: %d", id)
  288. return
  289. }
  290. index += 2
  291. protoLen := int(msg[index])
  292. if protoLen < 2 {
  293. err = errors.New("wrong proto length")
  294. return
  295. }
  296. index++
  297. proto = string(msg[index : index+protoLen])
  298. if proto != PROTO {
  299. err = fmt.Errorf("wrong proto: %s", proto)
  300. return
  301. }
  302. index += protoLen
  303. version = msg[index]
  304. if version != VERSION {
  305. err = fmt.Errorf("require version %d, get version: %d", VERSION, version)
  306. return
  307. }
  308. index++
  309. c.compress = (msg[index] & 0x01) != 0
  310. index++
  311. channelLen := int(binary.BigEndian.Uint16(msg[index : index+2]))
  312. if channelLen < 2 {
  313. err = errors.New("wrong channel length")
  314. return
  315. }
  316. index += 2
  317. channel = string(msg[index : index+channelLen])
  318. index += channelLen
  319. auth = msg[index:]
  320. return
  321. }
  322. // 发送请求数据包到网络
  323. func (c *Ws2) WriteRequest(id uint16, cmd string, data []byte) error {
  324. // 为了区分请求还是响应包,命令字符串不能超过127个字节,如果超过则报错
  325. cmdLen := len(cmd)
  326. if cmdLen > 0x7F {
  327. return errors.New("length of command more than 0x7F")
  328. }
  329. dlen := len(data)
  330. if c.compress && dlen > 0 {
  331. compressedData, ok, _ := util.CompressData(data)
  332. ddlen := 2 + 1 + cmdLen + 1 + len(compressedData)
  333. // buf := make([]byte, ddlen) // 申请内存
  334. buf := pool.Get(ddlen)
  335. index := 0
  336. binary.BigEndian.PutUint16(buf[index:index+2], id)
  337. index += 2
  338. buf[index] = byte(cmdLen)
  339. index++
  340. copy(buf[index:], cmd)
  341. index += cmdLen
  342. if ok {
  343. buf[index] = 0x01
  344. if c.cf.PrintMsg {
  345. log.Println("[CompressData]", len(data), "->", len(compressedData))
  346. }
  347. } else {
  348. buf[index] = 0
  349. }
  350. index++
  351. copy(buf[index:], compressedData)
  352. return c.WriteRawPackage(buf, true)
  353. } else {
  354. ddlen := 2 + 1 + cmdLen + dlen
  355. buf := pool.Get(ddlen)
  356. binary.BigEndian.PutUint16(buf[0:2], id)
  357. buf[2] = byte(cmdLen)
  358. copy(buf[3:], cmd)
  359. copy(buf[3+cmdLen:], data)
  360. return c.WriteRawPackage(buf, true)
  361. }
  362. }
  363. // 发送响应数据包到网络
  364. // 网络格式:[id, stateCode, data]
  365. func (c *Ws2) WriteResponse(id uint16, state uint8, data []byte) error {
  366. dlen := len(data)
  367. if c.compress && dlen > 0 {
  368. compressedData, ok, _ := util.CompressData(data)
  369. ddlen := 2 + 1 + 1 + len(compressedData)
  370. buf := pool.Get(ddlen)
  371. binary.BigEndian.PutUint16(buf[0:2], id)
  372. buf[2] = state | 0x80
  373. if ok {
  374. buf[3] = 0x01
  375. if c.cf.PrintMsg {
  376. log.Println("[CompressData]", len(data), "->", len(compressedData))
  377. }
  378. } else {
  379. buf[3] = 0
  380. }
  381. copy(buf[4:], compressedData)
  382. return c.WriteRawPackage(buf, true)
  383. } else {
  384. ddlen := 2 + 1 + dlen
  385. buf := pool.Get(ddlen)
  386. binary.BigEndian.PutUint16(buf[0:2], id)
  387. buf[2] = state | 0x80
  388. copy(buf[3:], data)
  389. return c.WriteRawPackage(buf, true)
  390. }
  391. }
  392. // 发送ping包
  393. func (c *Ws2) WritePing(id uint16) error {
  394. buf := pool.Get(2)
  395. binary.BigEndian.PutUint16(buf[0:2], id)
  396. return c.WriteRawPackage(buf, true)
  397. }
  398. // 获取信息
  399. func (c *Ws2) ReadMessage(deadline int) (msgType conn.MsgType, id uint16, cmd string, state uint8, data []byte, err error) {
  400. msg, _, err := c.ReadRawPackage(deadline)
  401. // err = c.conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(deadline)))
  402. // if err != nil {
  403. // return
  404. // }
  405. // _, msg, err := c.conn.ReadMessage()
  406. if err != nil {
  407. return
  408. }
  409. msgLen := len(msg)
  410. if msgLen < 2 {
  411. err = errors.New("message length less than 2")
  412. return
  413. }
  414. // 将读出来的数据进行解密
  415. if c.cipher != nil {
  416. c.cipher.Decrypt(msg, msg)
  417. }
  418. id = binary.BigEndian.Uint16(msg[0:2])
  419. // ping信息
  420. if msgLen == 2 {
  421. msgType = conn.PingMsg
  422. return
  423. }
  424. if id > config.ID_MAX {
  425. err = fmt.Errorf("wrong message id: %d", id)
  426. return
  427. }
  428. cmdx := msg[2]
  429. if (cmdx & 0x80) == 0 {
  430. // 请求包
  431. msgType = conn.RequestMsg
  432. cmdLen := int(cmdx)
  433. cmd = string(msg[3 : cmdLen+3])
  434. data = msg[cmdLen+3:]
  435. } else {
  436. // 响应数据包
  437. msgType = conn.ResponseMsg
  438. state = cmdx & 0x7F
  439. data = msg[3:]
  440. }
  441. dataLen := len(data)
  442. if c.compress && dataLen > 1 {
  443. var ok bool
  444. data, ok, err = util.UncompressData(data)
  445. if ok && c.cf.PrintMsg {
  446. log.Println("[UncompressData]", dataLen, "->", len(data))
  447. }
  448. }
  449. return
  450. }
  451. // 获取远程的地址
  452. func (c *Ws2) RemoteIP() net.IP {
  453. return util.AddrToIP(c.conn.RemoteAddr())
  454. }
  455. // 获取本地的地址
  456. func (c *Ws2) LocalIP() net.IP {
  457. return util.AddrToIP(c.conn.LocalAddr())
  458. }
  459. func (c *Ws2) Close() error {
  460. return c.conn.Close()
  461. }