forked from ejoy/goscon
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebsocket.go
More file actions
126 lines (103 loc) · 2.45 KB
/
websocket.go
File metadata and controls
126 lines (103 loc) · 2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"errors"
"io"
"net"
"time"
"github.com/gobwas/ws"
"github.com/xjdrew/glog"
)
var ErrOverMaxLength = errors.New("websocket header length over max_header_length")
type websocketConn struct {
*net.TCPConn
readTimeout time.Duration
upgraded bool
length int64
offset int64
mask *[4]byte
}
func readMaskData(conn *websocketConn, buf []byte, remain int64) (n int, err error) {
sz := int64(len(buf))
if sz > remain {
sz = remain
}
b := buf[:sz]
n, err = io.ReadFull(conn.TCPConn, b)
if err != nil {
return
}
glog.Infof("1 b=%s", b)
ws.Cipher(b, *conn.mask, int(conn.offset))
conn.offset += sz
glog.Infof("2 b=%s", b)
return
}
func (conn *websocketConn) Read(b []byte) (int, error) {
if conn.readTimeout > 0 {
conn.SetReadDeadline(time.Now().Add(conn.readTimeout))
}
if !conn.upgraded {
_, err := ws.Upgrade(conn.TCPConn)
if err != nil {
return 0, err
}
conn.upgraded = true
if glog.V(1) {
glog.Infof("upgrade websocket connection: addr=%s", conn.RemoteAddr())
}
}
remain := conn.length - conn.offset
if remain > 0 {
return readMaskData(conn, b, remain)
}
header, err := ws.ReadHeader(conn.TCPConn)
if err != nil {
return 0, err
}
if header.OpCode == ws.OpClose {
return 0, io.EOF
}
conn.length = header.Length
conn.offset = 0
conn.mask = &header.Mask
return readMaskData(conn, b, header.Length)
}
func (conn *websocketConn) Write(b []byte) (int, error) {
f := ws.NewBinaryFrame(b)
err := ws.WriteFrame(conn.TCPConn, f)
if err != nil {
return 0, err
}
return len(b), nil
}
// WebsocketListener .
type WebsocketListener struct {
net.Listener
}
// Accept .
func (l *WebsocketListener) Accept() (conn net.Conn, err error) {
c, err := l.Listener.Accept()
if err != nil {
return
}
keepalive := configItemBool("websocket_option.keepalive")
keepaliveInterval := configItemTime("websocket_option.keepalive_interval")
readTimeout := configItemTime("websocket_option.read_timeout")
t := c.(*net.TCPConn)
t.SetKeepAlive(keepalive)
t.SetKeepAlivePeriod(keepaliveInterval)
// t.SetLinger(0)
if glog.V(1) {
glog.Infof("accept new websocket connection: addr=%s", c.RemoteAddr())
}
conn = &websocketConn{t, readTimeout, false, 0, 0, nil}
return
}
// NewWebsocketListener creates a new WebsocketListener
func NewWebsocketListener(laddr string) (*WebsocketListener, error) {
ln, err := net.Listen("tcp", laddr)
if err != nil {
return nil, err
}
return &WebsocketListener{ln}, nil
}