github.com/searKing/golang/go@v1.2.117/net/tcp/conn.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package tcp 6 7 import ( 8 "context" 9 "errors" 10 "io" 11 "net" 12 "runtime" 13 "sync/atomic" 14 "time" 15 16 "github.com/searKing/golang/go/x/dispatch" 17 ) 18 19 // maxInt64 is the effective "infinite" value for the Server and 20 // Transport's byte-limiting readers. 21 const maxInt64 = 1<<63 - 1 22 23 // aLongTimeAgo is a non-zero time, far in the past, used for 24 // immediate cancelation of network operations. 25 var aLongTimeAgo = time.Unix(1, 0) 26 27 // A conn represents the server side of an HTTP connection. 28 type conn struct { 29 // server is the server on which the connection arrived. 30 // Immutable; never nil. 31 server *Server 32 33 // cancelCtx cancels the connection-level context. 34 cancelCtx context.CancelFunc 35 36 // rwc is the underlying network connection. 37 // This is never wrapped by other types and is the value given out 38 // to CloseNotifier callers. It is usually of type *net.TCPConn or 39 // *tls.Conn. 40 rwc net.Conn 41 42 // remoteAddr is rwc.RemoteAddr().String(). It is not populated synchronously 43 // inside the Listener's Accept goroutine, as some implementations block. 44 // It is populated immediately inside the (*conn).serve goroutine. 45 // This is the value of a onMsgHandle's (*Request).RemoteAddr. 46 remoteAddr string 47 48 // werr is set to the first write error to rwc. 49 // It is set via checkConnErrorWriter{w}, where bufw writes. 50 werr error 51 52 // r is bufr's read source. It's a wrapper around rwc that provides 53 // io.LimitedReader-style limiting (while reading request headers) 54 // and functionality to support CloseNotifier. See *connReader docs. 55 r *connReader 56 w *checkConnErrorWriter 57 58 curState struct{ atomic uint64 } // packed (unixtime<<8|uint8(ConnState)) 59 } 60 61 func (c *conn) finalFlush() { 62 } 63 64 // Close the connection. 65 func (c *conn) close() error { 66 err := c.server.onCloseHandler.OnClose(c.w, c.r) 67 c.rwc.Close() 68 c.r.abortPendingRead() 69 return err 70 } 71 72 // rstAvoidanceDelay is the amount of time we sleep after closing the 73 // write side of a TCP connection before closing the entire socket. 74 // By sleeping, we increase the chances that the client sees our FIN 75 // and processes its final data before they process the subsequent RST 76 // from closing a connection with known unread data. 77 // This RST seems to occur mostly on BSD systems. (And Windows?) 78 // This timeout is somewhat arbitrary (~latency around the planet). 79 const rstAvoidanceDelay = 500 * time.Millisecond 80 81 type closeWriter interface { 82 CloseWrite() error 83 } 84 85 var _ closeWriter = (*net.TCPConn)(nil) 86 87 // closeWrite flushes any outstanding data and sends a FIN packet (if 88 // client is connected via TCP), signalling that we're done. We then 89 // pause for a bit, hoping the client processes it before any 90 // subsequent RST. 91 // 92 // See https://golang.org/issue/3595 93 func (c *conn) closeWriteAndWait() { 94 c.finalFlush() 95 if tcp, ok := c.rwc.(closeWriter); ok { 96 tcp.CloseWrite() 97 } 98 time.Sleep(rstAvoidanceDelay) 99 } 100 101 func (c *conn) setState(nc net.Conn, state ConnState) { 102 srv := c.server 103 switch state { 104 case StateNew: 105 srv.trackConn(c, true) 106 case StateHijacked, StateClosed: 107 srv.trackConn(c, false) 108 } 109 if state > 0xff || state < 0 { 110 panic("internal error") 111 } 112 packedState := uint64(time.Now().Unix()<<8) | uint64(state) 113 atomic.StoreUint64(&c.curState.atomic, packedState) 114 if hook := srv.ConnState; hook != nil { 115 hook(nc, state) 116 } 117 } 118 119 func (c *conn) getState() (state ConnState, unixSec int64) { 120 packedState := atomic.LoadUint64(&c.curState.atomic) 121 return ConnState(packedState & 0xff), int64(packedState >> 8) 122 } 123 124 // ErrAbortHandler is a sentinel panic value to abort a handler. 125 // While any panic from OnHandshake aborts the response to the client, 126 // panicking with ErrAbortHandler also suppresses logging of a stack 127 // trace to the server's error log. 128 var ErrAbortHandler = errors.New("net/tcp: abort onMsgHandle") 129 var errTooLarge = errors.New("tcp: read too large") 130 131 // isCommonNetReadError reports whether err is a common error 132 // encountered during reading a request off the network when the 133 // client has gone away or had its read fail somehow. This is used to 134 // determine which logs are interesting enough to log about. 135 func isCommonNetReadError(err error) bool { 136 if err == io.EOF { 137 return true 138 } 139 if neterr, ok := err.(net.Error); ok && neterr.Timeout() { 140 return true 141 } 142 if oe, ok := err.(*net.OpError); ok && oe.Op == "read" { 143 return true 144 } 145 return false 146 } 147 148 // onMsgRead next request from connection. 149 func (c *conn) readRequest(ctx context.Context) (req any, err error) { 150 151 var ( 152 wholeReqDeadline time.Time // or zero if none 153 hdrDeadline time.Time // or zero if none 154 ) 155 t0 := time.Now() 156 if d := c.server.readTimeout(); d != 0 { 157 hdrDeadline = t0.Add(d) 158 } 159 if d := c.server.ReadTimeout; d != 0 { 160 wholeReqDeadline = t0.Add(d) 161 } 162 c.rwc.SetReadDeadline(hdrDeadline) 163 if d := c.server.WriteTimeout; d != 0 { 164 defer func() { 165 c.rwc.SetWriteDeadline(time.Now().Add(d)) 166 }() 167 } 168 169 c.r.setReadLimit(c.server.initialReadLimitSize()) 170 req, err = c.server.onMsgReadHandler.OnMsgRead(c.r) 171 if err != nil { 172 if c.r.hitReadLimit() { 173 return nil, errTooLarge 174 } 175 return nil, err 176 } 177 178 c.r.setInfiniteReadLimit() 179 180 // Adjust the read deadline if necessary. 181 if !hdrDeadline.Equal(wholeReqDeadline) { 182 c.rwc.SetReadDeadline(wholeReqDeadline) 183 } 184 185 return req, nil 186 } 187 188 // Serve a new connection. 189 func (c *conn) serve(ctx context.Context) { 190 c.remoteAddr = c.rwc.RemoteAddr().String() 191 ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr()) 192 // handle close 193 defer func() { 194 if err := recover(); err != nil && err != ErrAbortHandler { 195 const size = 64 << 10 196 buf := make([]byte, size) 197 buf = buf[:runtime.Stack(buf, false)] 198 c.server.logf("tcp: panic serving %v: %v\n%s", c.remoteAddr, err, buf) 199 } 200 c.server.CheckError(c.w, c.r, c.close()) 201 c.setState(c.rwc, StateClosed) 202 }() 203 204 // TCP from here on. 205 // cancel after this connection is handled 206 ctx, cancelCtx := context.WithCancel(ctx) 207 c.cancelCtx = cancelCtx 208 defer cancelCtx() 209 210 // wrap original conn itself with buffer 211 c.r = &connReader{conn: c} 212 c.w = &checkConnErrorWriter{c: c} 213 214 // read and handle the msg 215 dispatch.NewDispatch(dispatch.ReaderFunc(func(ctx context.Context) (any, error) { 216 msg, err := c.readRequest(ctx) 217 if c.r.remain != c.server.initialReadLimitSize() { 218 // If we read any bytes off the wire, we're active. 219 c.setState(c.rwc, StateActive) 220 } 221 if err = c.server.CheckError(c.w, c.r, err); err != nil { 222 if isCommonNetReadError(err) { 223 return nil, err // don't reply 224 } 225 // otherwise, close socket's Write channel and wait for a monment 226 c.closeWriteAndWait() 227 return nil, err 228 } 229 return msg, nil 230 }), dispatch.HandlerFunc(func(ctx context.Context, msg any) error { 231 return c.server.CheckError(c.w, c.r, c.server.onMsgHandleHandler.OnMsgHandle(c.w, msg)) 232 })).WithContext(ctx).Start() 233 // after onMsgHandle, read all left data 234 c.r.startBackgroundRead() 235 } 236 237 // checkConnErrorWriter writes to c.rwc and records any write errors to c.werr. 238 // It only contains one field (and a pointer field at that), so it 239 // fits in an interface value without an extra allocation. 240 type checkConnErrorWriter struct { 241 c *conn 242 } 243 244 func (w checkConnErrorWriter) Write(p []byte) (n int, err error) { 245 n, err = w.c.rwc.Write(p) 246 if err != nil && w.c.werr == nil { 247 w.c.werr = err 248 w.c.cancelCtx() 249 } 250 return 251 }