ws2.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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/conn/util"
  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. return
  90. }
  91. }
  92. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  93. if err != nil {
  94. log.Println("[ws2 NewCipher ERROR]", err)
  95. return
  96. }
  97. ws := &Ws2{
  98. cf: cf,
  99. conn: conn,
  100. cipher: cipher,
  101. }
  102. fn(ws)
  103. })
  104. if bind != "" {
  105. go func() (err error) {
  106. defer func() {
  107. if err != nil {
  108. log.Fatal(err)
  109. }
  110. }()
  111. log.Printf("Listening and serving Websocket on %s\n", bind)
  112. // 暂时使用全局的方式,后面有需求再修改
  113. // 而且还没有 https 方式的绑定
  114. // 需要在前端增加其他的服务进行转换
  115. err = http.ListenAndServe(bind, nil)
  116. return
  117. }()
  118. }
  119. return
  120. }
  121. // 客户端,新建一个连接
  122. func Dial(cf *config.Config, scheme string, addr string, path string, hash string) (conn.Connect, error) {
  123. u := url.URL{Scheme: scheme, Host: addr, Path: path}
  124. // 没有加密的情况
  125. if hash == "" {
  126. conn, _, err := (&websocket.Dialer{
  127. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  128. }).Dial(u.String(), nil)
  129. if err != nil {
  130. return nil, err
  131. }
  132. ws := &Ws2{
  133. cf: cf,
  134. conn: conn,
  135. }
  136. return ws, nil
  137. }
  138. i := strings.Index(hash, ":")
  139. if i <= 0 {
  140. return nil, errors.New("hash is invalid")
  141. }
  142. encryptMethod := hash[0:i]
  143. encryptKey := hash[i+1:]
  144. ci, ok := util.CipherMethod[encryptMethod]
  145. if !ok {
  146. return nil, errors.New("Unsupported encryption method: " + encryptMethod)
  147. }
  148. conn, _, err := (&websocket.Dialer{
  149. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  150. }).Dial(u.String(), nil)
  151. if err != nil {
  152. return nil, err
  153. }
  154. var eiv []byte
  155. var div []byte
  156. if ci.IvLen > 0 {
  157. // 客户端 IV
  158. eiv = make([]byte, ci.IvLen)
  159. _, err = rand.Read(eiv)
  160. if err != nil {
  161. log.Println("[ws2 Client rand.Read ERROR]", err)
  162. return nil, err
  163. }
  164. // 发送 IV
  165. conn.SetWriteDeadline(time.Now().Add(time.Duration(cf.WriteWait) * time.Millisecond))
  166. if err := conn.WriteMessage(websocket.BinaryMessage, eiv); err != nil {
  167. log.Println("[ws2 Client conn.Write ERROR]", err)
  168. return nil, err
  169. }
  170. // 读取 IV
  171. err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(cf.ReadWait)))
  172. if err != nil {
  173. log.Println("[ws2 Client SetReadDeadline ERROR]", err)
  174. return nil, err
  175. }
  176. _, div, err = conn.ReadMessage()
  177. if err != nil {
  178. log.Println("[ws2 Client ReadFull ERROR]", err)
  179. return nil, err
  180. }
  181. }
  182. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  183. if err != nil {
  184. log.Println("[ws2 NewCipher ERROR]", err)
  185. return nil, err
  186. }
  187. ws := &Ws2{
  188. cf: cf,
  189. conn: conn,
  190. cipher: cipher,
  191. compress: true,
  192. }
  193. return ws, nil
  194. }
  195. // 发送数据到网络
  196. // 如果有加密函数的话会直接修改源数据
  197. func (c *Ws2) writeMessage(buf []byte) (err error) {
  198. if c.cipher != nil {
  199. c.cipher.Encrypt(buf, buf)
  200. }
  201. c.conn.SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(c.cf.WriteWait)))
  202. return c.conn.WriteMessage(websocket.BinaryMessage, buf)
  203. }
  204. // 发送Auth信息
  205. // 建立连接后第一个发送的消息
  206. func (c *Ws2) WriteAuthInfo(channel string, auth []byte) (err error) {
  207. protoLen := len(PROTO)
  208. if protoLen > 0xFF {
  209. return errors.New("length of protocol over")
  210. }
  211. channelLen := len(channel)
  212. if channelLen > 0xFFFF {
  213. return errors.New("length of channel over")
  214. }
  215. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  216. dlen := 2 + 1 + protoLen + 1 + 1 + 2 + channelLen + len(auth)
  217. index := 0
  218. buf := make([]byte, dlen)
  219. binary.BigEndian.PutUint16(buf[index:index+2], config.ID_AUTH)
  220. index += 2
  221. buf[index] = byte(protoLen)
  222. index++
  223. copy(buf[index:index+protoLen], []byte(PROTO))
  224. index += protoLen
  225. buf[index] = VERSION
  226. index++
  227. if c.compress {
  228. buf[index] = 0x01
  229. } else {
  230. buf[index] = 0
  231. }
  232. index++
  233. binary.BigEndian.PutUint16(buf[index:index+2], uint16(channelLen))
  234. index += 2
  235. copy(buf[index:index+channelLen], []byte(channel))
  236. index += channelLen
  237. copy(buf[index:], auth)
  238. return c.writeMessage(buf)
  239. }
  240. // 获取Auth信息
  241. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  242. func (c *Ws2) ReadAuthInfo() (proto string, version uint8, channel string, auth []byte, err error) {
  243. defer func() {
  244. if r := recover(); r != nil {
  245. err = fmt.Errorf("recovered from panic: %v", r)
  246. return
  247. }
  248. }()
  249. err = c.conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(c.cf.ReadWait)))
  250. if err != nil {
  251. return
  252. }
  253. _, msg, err := c.conn.ReadMessage()
  254. if err != nil {
  255. return
  256. }
  257. msgLen := len(msg)
  258. if msgLen < 9 {
  259. err = errors.New("wrong message length")
  260. return
  261. }
  262. // 将读出来的数据进行解密
  263. if c.cipher != nil {
  264. c.cipher.Decrypt(msg, msg)
  265. }
  266. index := 0
  267. id := binary.BigEndian.Uint16(msg[index : index+2])
  268. if id != config.ID_AUTH {
  269. err = fmt.Errorf("wrong message id: %d", id)
  270. return
  271. }
  272. index += 2
  273. protoLen := int(msg[index])
  274. if protoLen < 2 {
  275. err = errors.New("wrong proto length")
  276. return
  277. }
  278. index++
  279. proto = string(msg[index : index+protoLen])
  280. if proto != PROTO {
  281. err = fmt.Errorf("wrong proto: %s", proto)
  282. return
  283. }
  284. index += protoLen
  285. version = msg[index]
  286. if version != VERSION {
  287. err = fmt.Errorf("require version %d, get version: %d", VERSION, version)
  288. return
  289. }
  290. index++
  291. c.compress = (msg[index] & 0x01) != 0
  292. index++
  293. channelLen := int(binary.BigEndian.Uint16(msg[index : index+2]))
  294. if channelLen < 2 {
  295. err = errors.New("wrong channel length")
  296. return
  297. }
  298. index += 2
  299. channel = string(msg[index : index+channelLen])
  300. index += channelLen
  301. auth = msg[index:]
  302. return
  303. }
  304. // 发送请求数据包到网络
  305. func (c *Ws2) WriteRequest(id uint16, cmd string, data []byte) error {
  306. // 为了区分请求还是响应包,命令字符串不能超过127个字节,如果超过则报错
  307. cmdLen := len(cmd)
  308. if cmdLen > 0x7F {
  309. return errors.New("length of command more than 0x7F")
  310. }
  311. dlen := len(data)
  312. if c.compress && dlen > 0 {
  313. compressedData, ok := util.CompressData(data)
  314. ddlen := 2 + 1 + cmdLen + 1 + len(compressedData)
  315. buf := make([]byte, ddlen) // 申请内存
  316. index := 0
  317. binary.BigEndian.PutUint16(buf[index:index+2], id)
  318. index += 2
  319. buf[index] = byte(cmdLen)
  320. index++
  321. copy(buf[index:], cmd)
  322. index += cmdLen
  323. if ok {
  324. buf[index] = 0x01
  325. if c.cf.PrintMsg {
  326. log.Println("[CompressData]", len(data), "->", len(compressedData))
  327. }
  328. } else {
  329. buf[index] = 0
  330. }
  331. index++
  332. copy(buf[index:], compressedData)
  333. return c.writeMessage(buf)
  334. } else {
  335. ddlen := 2 + 1 + cmdLen + dlen
  336. buf := make([]byte, ddlen) // 申请内存
  337. binary.BigEndian.PutUint16(buf[0:2], id)
  338. buf[2] = byte(cmdLen)
  339. copy(buf[3:], cmd)
  340. copy(buf[3+cmdLen:], data)
  341. return c.writeMessage(buf)
  342. }
  343. }
  344. // 发送响应数据包到网络
  345. // 网络格式:[id, stateCode, data]
  346. func (c *Ws2) WriteResponse(id uint16, state uint8, data []byte) error {
  347. dlen := len(data)
  348. if c.compress && dlen > 0 {
  349. compressedData, ok := util.CompressData(data)
  350. ddlen := 2 + 1 + 1 + len(compressedData)
  351. buf := make([]byte, ddlen)
  352. binary.BigEndian.PutUint16(buf[0:2], id)
  353. buf[2] = state | 0x80
  354. if ok {
  355. buf[3] = 0x01
  356. if c.cf.PrintMsg {
  357. log.Println("[CompressData]", len(data), "->", len(compressedData))
  358. }
  359. } else {
  360. buf[3] = 0
  361. }
  362. copy(buf[4:], compressedData)
  363. return c.writeMessage(buf)
  364. } else {
  365. ddlen := 2 + 1 + dlen
  366. buf := make([]byte, ddlen)
  367. binary.BigEndian.PutUint16(buf[0:2], id)
  368. buf[2] = state | 0x80
  369. copy(buf[3:], data)
  370. return c.writeMessage(buf)
  371. }
  372. }
  373. // 发送ping包
  374. func (c *Ws2) WritePing(id uint16) error {
  375. buf := make([]byte, 2)
  376. binary.BigEndian.PutUint16(buf[0:2], id)
  377. return c.writeMessage(buf)
  378. }
  379. // 获取信息
  380. func (c *Ws2) ReadMessage(deadline int) (msgType conn.MsgType, id uint16, cmd string, state uint8, data []byte, err error) {
  381. err = c.conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(deadline)))
  382. if err != nil {
  383. return
  384. }
  385. _, msg, err := c.conn.ReadMessage()
  386. if err != nil {
  387. return
  388. }
  389. msgLen := len(msg)
  390. if msgLen < 2 {
  391. err = errors.New("message length less than 2")
  392. return
  393. }
  394. // 将读出来的数据进行解密
  395. if c.cipher != nil {
  396. c.cipher.Decrypt(msg, msg)
  397. }
  398. id = binary.BigEndian.Uint16(msg[0:2])
  399. // ping信息
  400. if msgLen == 2 {
  401. msgType = conn.PingMsg
  402. return
  403. }
  404. if id > config.ID_MAX {
  405. err = fmt.Errorf("wrong message id: %d", id)
  406. return
  407. }
  408. cmdx := msg[2]
  409. if (cmdx & 0x80) == 0 {
  410. // 请求包
  411. msgType = conn.RequestMsg
  412. cmdLen := int(cmdx)
  413. cmd = string(msg[3 : cmdLen+3])
  414. data = msg[cmdLen+3:]
  415. } else {
  416. // 响应数据包
  417. msgType = conn.ResponseMsg
  418. state = cmdx & 0x7F
  419. data = msg[3:]
  420. }
  421. if c.compress && len(data) > 1 {
  422. data, _ = util.UncompressData(data)
  423. }
  424. return
  425. }
  426. // 获取远程的地址
  427. func (c *Ws2) RemoteAddr() net.Addr {
  428. return c.conn.RemoteAddr()
  429. }
  430. // 获取本地的地址
  431. func (c *Ws2) LocalAddr() net.Addr {
  432. return c.conn.LocalAddr()
  433. }
  434. func (c *Ws2) Close() error {
  435. return c.conn.Close()
  436. }