send_conn.go 2.6 KB

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