github.com/TugasAkhir-QUIC/quic-go@v0.0.2-0.20240215011318-d20e25a9054c/send_conn.go (about) 1 package quic 2 3 import ( 4 "net" 5 6 "github.com/TugasAkhir-QUIC/quic-go/internal/protocol" 7 "github.com/TugasAkhir-QUIC/quic-go/internal/utils" 8 ) 9 10 // A sendConn allows sending using a simple Write() on a non-connected packet conn. 11 type sendConn interface { 12 Write(b []byte, gsoSize uint16, ecn protocol.ECN) error 13 Close() error 14 LocalAddr() net.Addr 15 RemoteAddr() net.Addr 16 17 capabilities() connCapabilities 18 } 19 20 type sconn struct { 21 rawConn 22 23 localAddr net.Addr 24 remoteAddr net.Addr 25 26 logger utils.Logger 27 28 packetInfoOOB []byte 29 // If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled. 30 gotGSOError bool 31 // Used to catch the error sometimes returned by the first sendmsg call on Linux, 32 // see https://github.com/golang/go/issues/63322. 33 wroteFirstPacket bool 34 } 35 36 var _ sendConn = &sconn{} 37 38 func newSendConn(c rawConn, remote net.Addr, info packetInfo, logger utils.Logger) *sconn { 39 localAddr := c.LocalAddr() 40 if info.addr.IsValid() { 41 if udpAddr, ok := localAddr.(*net.UDPAddr); ok { 42 addrCopy := *udpAddr 43 addrCopy.IP = info.addr.AsSlice() 44 localAddr = &addrCopy 45 } 46 } 47 48 oob := info.OOB() 49 // increase oob slice capacity, so we can add the UDP_SEGMENT and ECN control messages without allocating 50 l := len(oob) 51 oob = append(oob, make([]byte, 64)...)[:l] 52 return &sconn{ 53 rawConn: c, 54 localAddr: localAddr, 55 remoteAddr: remote, 56 packetInfoOOB: oob, 57 logger: logger, 58 } 59 } 60 61 func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error { 62 err := c.writePacket(p, c.remoteAddr, c.packetInfoOOB, gsoSize, ecn) 63 if err != nil && isGSOError(err) { 64 // disable GSO for future calls 65 c.gotGSOError = true 66 if c.logger.Debug() { 67 c.logger.Debugf("GSO failed when sending to %s", c.remoteAddr) 68 } 69 // send out the packets one by one 70 for len(p) > 0 { 71 l := len(p) 72 if l > int(gsoSize) { 73 l = int(gsoSize) 74 } 75 if err := c.writePacket(p[:l], c.remoteAddr, c.packetInfoOOB, 0, ecn); err != nil { 76 return err 77 } 78 p = p[l:] 79 } 80 return nil 81 } 82 return err 83 } 84 85 func (c *sconn) writePacket(p []byte, addr net.Addr, oob []byte, gsoSize uint16, ecn protocol.ECN) error { 86 _, err := c.WritePacket(p, addr, oob, gsoSize, ecn) 87 if err != nil && !c.wroteFirstPacket && isPermissionError(err) { 88 _, err = c.WritePacket(p, addr, oob, gsoSize, ecn) 89 } 90 c.wroteFirstPacket = true 91 return err 92 } 93 94 func (c *sconn) capabilities() connCapabilities { 95 capabilities := c.rawConn.capabilities() 96 if capabilities.GSO { 97 capabilities.GSO = !c.gotGSOError 98 } 99 return capabilities 100 } 101 102 func (c *sconn) RemoteAddr() net.Addr { return c.remoteAddr } 103 func (c *sconn) LocalAddr() net.Addr { return c.localAddr }