ws2.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. remoteIp net.IP
  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. // Get real remote address from proxy headers
  53. remoteIp := r.Header.Get("X-Real-IP")
  54. if remoteIp == "" {
  55. // X-Forwarded-For can contain a list of comma-separated IPs; the first is the original client
  56. forwarded := r.Header.Get("X-Forwarded-For")
  57. if forwarded != "" {
  58. remoteIp = strings.Split(forwarded, ",")[0]
  59. remoteIp = strings.TrimSpace(remoteIp)
  60. }
  61. }
  62. // Fallback to standard RemoteAddr if no proxy headers exist
  63. if remoteIp == "" {
  64. remoteIp = r.RemoteAddr
  65. }
  66. conn, err := upgrader.Upgrade(w, r, nil)
  67. if err != nil {
  68. log.Println("[ws2 Server Upgrade ERROR]", err)
  69. return
  70. }
  71. if ci == nil {
  72. ws := &Ws2{
  73. cf: cf,
  74. conn: conn,
  75. }
  76. fn(ws)
  77. return
  78. }
  79. var eiv []byte
  80. var div []byte
  81. if ci.IvLen > 0 {
  82. // 服务端 IV
  83. eiv = make([]byte, ci.IvLen)
  84. _, err = rand.Read(eiv)
  85. if err != nil {
  86. log.Println("[ws2 Server rand.Read ERROR]", err)
  87. return
  88. }
  89. // 发送 IV
  90. conn.SetWriteDeadline(time.Now().Add(time.Duration(cf.WriteWait) * time.Millisecond))
  91. if err := conn.WriteMessage(websocket.BinaryMessage, eiv); err != nil {
  92. log.Println("[ws2 Server conn.Write ERROR]", err)
  93. return
  94. }
  95. // 读取 IV
  96. err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(cf.ReadWait)))
  97. if err != nil {
  98. log.Println("[ws2 Server SetReadDeadline ERROR]", err)
  99. return
  100. }
  101. _, div, err = conn.ReadMessage()
  102. if err != nil {
  103. log.Println("[ws2 Server ReadFull ERROR]", err)
  104. conn.Close()
  105. return
  106. }
  107. }
  108. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  109. if err != nil {
  110. log.Println("[ws2 NewCipher ERROR]", err)
  111. return
  112. }
  113. ws := &Ws2{
  114. cf: cf,
  115. conn: conn,
  116. cipher: cipher,
  117. remoteIp: util.StrToIP(remoteIp),
  118. }
  119. fn(ws)
  120. })
  121. if bind != "" {
  122. go func() (err error) {
  123. defer func() {
  124. if err != nil {
  125. log.Fatal(err)
  126. }
  127. }()
  128. log.Printf("Listening and serving Websocket on %s\n", bind)
  129. // 暂时使用全局的方式,后面有需求再修改
  130. // 而且还没有 https 方式的绑定
  131. // 需要在前端增加其他的服务进行转换
  132. err = http.ListenAndServe(bind, nil)
  133. return
  134. }()
  135. }
  136. return
  137. }
  138. // 客户端,新建一个连接
  139. func Dial(cf *config.Config, scheme string, addr string, path string, hash string) (conn.Connect, error) {
  140. u := url.URL{Scheme: scheme, Host: addr, Path: path}
  141. // 没有加密的情况
  142. if hash == "" {
  143. conn, _, err := (&websocket.Dialer{
  144. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  145. }).Dial(u.String(), nil)
  146. if err != nil {
  147. return nil, err
  148. }
  149. ws := &Ws2{
  150. cf: cf,
  151. conn: conn,
  152. }
  153. return ws, nil
  154. }
  155. i := strings.Index(hash, ":")
  156. if i <= 0 {
  157. return nil, errors.New("hash is invalid")
  158. }
  159. encryptMethod := hash[0:i]
  160. encryptKey := hash[i+1:]
  161. ci, ok := util.CipherMethod[encryptMethod]
  162. if !ok {
  163. return nil, errors.New("Unsupported encryption method: " + encryptMethod)
  164. }
  165. conn, _, err := (&websocket.Dialer{
  166. HandshakeTimeout: time.Duration(time.Millisecond * time.Duration(cf.ConnectTimeout)),
  167. }).Dial(u.String(), nil)
  168. if err != nil {
  169. return nil, err
  170. }
  171. var eiv []byte
  172. var div []byte
  173. if ci.IvLen > 0 {
  174. // 客户端 IV
  175. eiv = make([]byte, ci.IvLen)
  176. _, err = rand.Read(eiv)
  177. if err != nil {
  178. log.Println("[ws2 Client rand.Read ERROR]", err)
  179. return nil, err
  180. }
  181. // 发送 IV
  182. conn.SetWriteDeadline(time.Now().Add(time.Duration(cf.WriteWait) * time.Millisecond))
  183. if err := conn.WriteMessage(websocket.BinaryMessage, eiv); err != nil {
  184. log.Println("[ws2 Client conn.Write ERROR]", err)
  185. return nil, err
  186. }
  187. // 读取 IV
  188. err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(cf.ReadWait)))
  189. if err != nil {
  190. log.Println("[ws2 Client SetReadDeadline ERROR]", err)
  191. return nil, err
  192. }
  193. _, div, err = conn.ReadMessage()
  194. if err != nil {
  195. log.Println("[ws2 Client ReadFull ERROR]", err)
  196. return nil, err
  197. }
  198. }
  199. cipher, err := util.NewCipher(ci, encryptKey, eiv, div)
  200. if err != nil {
  201. log.Println("[ws2 NewCipher ERROR]", err)
  202. return nil, err
  203. }
  204. ws := &Ws2{
  205. cf: cf,
  206. conn: conn,
  207. cipher: cipher,
  208. compress: true,
  209. }
  210. return ws, nil
  211. }
  212. // 发送数据到网络
  213. func (c *Ws2) WriteRawPackage(buf []byte, recycle bool) (err error) {
  214. if recycle {
  215. defer pool.Put(buf)
  216. }
  217. if c.cipher != nil {
  218. c.cipher.Encrypt(buf, buf)
  219. }
  220. c.conn.SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(c.cf.WriteWait)))
  221. return c.conn.WriteMessage(websocket.BinaryMessage, buf)
  222. }
  223. // 从连接中读取数据包
  224. // recycle 指示是否需要手动将缓存放回内存池
  225. func (c *Ws2) ReadRawPackage(deadline int) (buf []byte, recycle bool, err error) {
  226. err = c.conn.SetReadDeadline(time.Now().Add(time.Millisecond * time.Duration(deadline)))
  227. if err != nil {
  228. return
  229. }
  230. _, buf, err = c.conn.ReadMessage()
  231. if err != nil {
  232. return
  233. }
  234. if c.cipher != nil {
  235. c.cipher.Decrypt(buf, buf)
  236. }
  237. return
  238. }
  239. // 发送Auth信息
  240. // 建立连接后第一个发送的消息
  241. func (c *Ws2) WriteAuthInfo(channel string, auth []byte) (err error) {
  242. buf := conn.AuthPackageEncode(PROTO, VERSION, channel, auth, c.compress)
  243. return c.WriteRawPackage(buf, true)
  244. }
  245. // 获取Auth信息
  246. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  247. func (c *Ws2) ReadAuthInfo() (proto string, version uint8, channel string, auth []byte, err error) {
  248. msg, recycle, err := c.ReadRawPackage(c.cf.ReadWait)
  249. if err != nil {
  250. return
  251. }
  252. var compress bool
  253. proto, version, compress, channel, auth, err = conn.AuthPackageDecode(msg, recycle)
  254. if err != nil {
  255. return
  256. }
  257. if proto != PROTO && proto != PROTO_STL {
  258. err = fmt.Errorf("wrong proto: want %s, get %s", PROTO, proto)
  259. return
  260. }
  261. if version != VERSION {
  262. err = fmt.Errorf("require version %d, get version: %d", VERSION, version)
  263. return
  264. }
  265. c.compress = compress
  266. return
  267. }
  268. // 发送请求数据包到网络
  269. func (c *Ws2) WriteRequest(id uint16, cmd string, data []byte) error {
  270. buf := conn.RequestPackageEncode(id, cmd, data, c.compress, c.cf)
  271. return c.WriteRawPackage(buf, true)
  272. }
  273. // 发送响应数据包到网络
  274. // 网络格式:[id, stateCode, data]
  275. func (c *Ws2) WriteResponse(id uint16, state uint8, data []byte) error {
  276. buf := conn.ResponsePackageEncode(id, state, data, c.compress, c.cf)
  277. return c.WriteRawPackage(buf, true)
  278. }
  279. // 发送ping包
  280. func (c *Ws2) WritePing(id uint16) error {
  281. buf := conn.PingPackageEncode(id)
  282. return c.WriteRawPackage(buf, true)
  283. }
  284. // 获取信息
  285. func (c *Ws2) ReadMessage(deadline int) (msgType conn.MsgType, id uint16, cmd string, state uint8, data []byte, err error) {
  286. var msg []byte
  287. var recycle bool
  288. msg, recycle, err = c.ReadRawPackage(deadline)
  289. if err != nil {
  290. return
  291. }
  292. return conn.PackageDecode(msg, recycle, c.compress, c.cf)
  293. }
  294. // 获取远程的地址
  295. func (c *Ws2) RemoteIP() net.IP {
  296. if c.remoteIp != nil {
  297. return c.remoteIp
  298. }
  299. return util.AddrToIP(c.conn.RemoteAddr())
  300. }
  301. // 获取本地的地址
  302. func (c *Ws2) LocalIP() net.IP {
  303. return util.AddrToIP(c.conn.LocalAddr())
  304. }
  305. func (c *Ws2) Close() error {
  306. return c.conn.Close()
  307. }