github.com/v2fly/v2ray-core/v4@v4.45.2/transport/internet/websocket/connection.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package websocket 5 6 import ( 7 "context" 8 "io" 9 "net" 10 "time" 11 12 "github.com/gorilla/websocket" 13 14 "github.com/v2fly/v2ray-core/v4/common/buf" 15 "github.com/v2fly/v2ray-core/v4/common/errors" 16 "github.com/v2fly/v2ray-core/v4/common/serial" 17 ) 18 19 var _ buf.Writer = (*connection)(nil) 20 21 // connection is a wrapper for net.Conn over WebSocket connection. 22 type connection struct { 23 conn *websocket.Conn 24 reader io.Reader 25 remoteAddr net.Addr 26 27 shouldWait bool 28 delayedDialFinish context.Context 29 finishedDial context.CancelFunc 30 dialer DelayedDialer 31 } 32 33 type DelayedDialer interface { 34 Dial(earlyData []byte) (*websocket.Conn, error) 35 } 36 37 func newConnection(conn *websocket.Conn, remoteAddr net.Addr) *connection { 38 return &connection{ 39 conn: conn, 40 remoteAddr: remoteAddr, 41 } 42 } 43 44 func newConnectionWithEarlyData(conn *websocket.Conn, remoteAddr net.Addr, earlyData io.Reader) *connection { 45 return &connection{ 46 conn: conn, 47 remoteAddr: remoteAddr, 48 reader: earlyData, 49 } 50 } 51 52 func newConnectionWithDelayedDial(dialer DelayedDialer) *connection { 53 delayedDialContext, CancellFunc := context.WithCancel(context.Background()) 54 return &connection{ 55 shouldWait: true, 56 delayedDialFinish: delayedDialContext, 57 finishedDial: CancellFunc, 58 dialer: dialer, 59 } 60 } 61 62 func newRelayedConnectionWithDelayedDial(dialer DelayedDialerForwarded) *connectionForwarder { 63 delayedDialContext, CancellFunc := context.WithCancel(context.Background()) 64 return &connectionForwarder{ 65 shouldWait: true, 66 delayedDialFinish: delayedDialContext, 67 finishedDial: CancellFunc, 68 dialer: dialer, 69 } 70 } 71 72 func newRelayedConnection(conn io.ReadWriteCloser) *connectionForwarder { 73 return &connectionForwarder{ 74 ReadWriteCloser: conn, 75 shouldWait: false, 76 } 77 } 78 79 // Read implements net.Conn.Read() 80 func (c *connection) Read(b []byte) (int, error) { 81 for { 82 reader, err := c.getReader() 83 if err != nil { 84 return 0, err 85 } 86 87 nBytes, err := reader.Read(b) 88 if errors.Cause(err) == io.EOF { 89 c.reader = nil 90 continue 91 } 92 return nBytes, err 93 } 94 } 95 96 func (c *connection) getReader() (io.Reader, error) { 97 if c.shouldWait { 98 <-c.delayedDialFinish.Done() 99 if c.conn == nil { 100 return nil, newError("unable to read delayed dial websocket connection as it do not exist") 101 } 102 } 103 if c.reader != nil { 104 return c.reader, nil 105 } 106 107 _, reader, err := c.conn.NextReader() 108 if err != nil { 109 return nil, err 110 } 111 c.reader = reader 112 return reader, nil 113 } 114 115 // Write implements io.Writer. 116 func (c *connection) Write(b []byte) (int, error) { 117 if c.shouldWait { 118 var err error 119 c.conn, err = c.dialer.Dial(b) 120 c.finishedDial() 121 if err != nil { 122 return 0, newError("Unable to proceed with delayed write").Base(err) 123 } 124 c.remoteAddr = c.conn.RemoteAddr() 125 c.shouldWait = false 126 return len(b), nil 127 } 128 if err := c.conn.WriteMessage(websocket.BinaryMessage, b); err != nil { 129 return 0, err 130 } 131 return len(b), nil 132 } 133 134 func (c *connection) WriteMultiBuffer(mb buf.MultiBuffer) error { 135 mb = buf.Compact(mb) 136 mb, err := buf.WriteMultiBuffer(c, mb) 137 buf.ReleaseMulti(mb) 138 return err 139 } 140 141 func (c *connection) Close() error { 142 if c.shouldWait { 143 <-c.delayedDialFinish.Done() 144 if c.conn == nil { 145 return newError("unable to close delayed dial websocket connection as it do not exist") 146 } 147 } 148 var errors []interface{} 149 if err := c.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5)); err != nil { 150 errors = append(errors, err) 151 } 152 if err := c.conn.Close(); err != nil { 153 errors = append(errors, err) 154 } 155 if len(errors) > 0 { 156 return newError("failed to close connection").Base(newError(serial.Concat(errors...))) 157 } 158 return nil 159 } 160 161 func (c *connection) LocalAddr() net.Addr { 162 if c.shouldWait { 163 <-c.delayedDialFinish.Done() 164 if c.conn == nil { 165 newError("websocket transport is not materialized when LocalAddr() is called").AtWarning().WriteToLog() 166 return &net.UnixAddr{ 167 Name: "@placeholder", 168 Net: "unix", 169 } 170 } 171 } 172 return c.conn.LocalAddr() 173 } 174 175 func (c *connection) RemoteAddr() net.Addr { 176 return c.remoteAddr 177 } 178 179 func (c *connection) SetDeadline(t time.Time) error { 180 if err := c.SetReadDeadline(t); err != nil { 181 return err 182 } 183 return c.SetWriteDeadline(t) 184 } 185 186 func (c *connection) SetReadDeadline(t time.Time) error { 187 if c.shouldWait { 188 <-c.delayedDialFinish.Done() 189 if c.conn == nil { 190 newError("websocket transport is not materialized when SetReadDeadline() is called").AtWarning().WriteToLog() 191 return nil 192 } 193 } 194 return c.conn.SetReadDeadline(t) 195 } 196 197 func (c *connection) SetWriteDeadline(t time.Time) error { 198 if c.shouldWait { 199 <-c.delayedDialFinish.Done() 200 if c.conn == nil { 201 newError("websocket transport is not materialized when SetWriteDeadline() is called").AtWarning().WriteToLog() 202 return nil 203 } 204 } 205 return c.conn.SetWriteDeadline(t) 206 }