sys_conn.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package quic
  2. import (
  3. "net"
  4. "os"
  5. "strconv"
  6. "strings"
  7. "syscall"
  8. "time"
  9. "github.com/Psiphon-Labs/quic-go/internal/protocol"
  10. "github.com/Psiphon-Labs/quic-go/internal/utils"
  11. )
  12. // OOBCapablePacketConn is a connection that allows the reading of ECN bits from the IP header.
  13. // If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will use it.
  14. // In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets.
  15. type OOBCapablePacketConn interface {
  16. net.PacketConn
  17. SyscallConn() (syscall.RawConn, error)
  18. SetReadBuffer(int) error
  19. ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
  20. WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
  21. }
  22. var _ OOBCapablePacketConn = &net.UDPConn{}
  23. // [Psiphon]
  24. var logger = utils.DefaultLogger
  25. func wrapConn(pc net.PacketConn) (rawConn, error) {
  26. if err := setReceiveBuffer(pc); err != nil {
  27. if !strings.Contains(err.Error(), "use of closed network connection") {
  28. setBufferWarningOnce.Do(func() {
  29. if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
  30. return
  31. }
  32. // [Psiphon]
  33. // Do not emit alert to stderr
  34. // log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
  35. logger.Errorf("%s. See https://github.com/Psiphon-Labs/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
  36. })
  37. }
  38. }
  39. if err := setSendBuffer(pc); err != nil {
  40. if !strings.Contains(err.Error(), "use of closed network connection") {
  41. setBufferWarningOnce.Do(func() {
  42. if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
  43. return
  44. }
  45. // [Psiphon]
  46. // Do not emit alert to stderr
  47. // log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
  48. logger.Errorf("%s. See https://github.com/Psiphon-Labs/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
  49. })
  50. }
  51. }
  52. conn, ok := pc.(interface {
  53. SyscallConn() (syscall.RawConn, error)
  54. })
  55. var supportsDF bool
  56. if ok {
  57. rawConn, err := conn.SyscallConn()
  58. if err != nil {
  59. return nil, err
  60. }
  61. // only set DF on UDP sockets
  62. if _, ok := pc.LocalAddr().(*net.UDPAddr); ok {
  63. var err error
  64. supportsDF, err = setDF(rawConn)
  65. if err != nil {
  66. return nil, err
  67. }
  68. }
  69. }
  70. c, ok := pc.(OOBCapablePacketConn)
  71. if !ok {
  72. utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.")
  73. return &basicConn{PacketConn: pc, supportsDF: supportsDF}, nil
  74. }
  75. return newConn(c, supportsDF)
  76. }
  77. // The basicConn is the most trivial implementation of a rawConn.
  78. // It reads a single packet from the underlying net.PacketConn.
  79. // It is used when
  80. // * the net.PacketConn is not a OOBCapablePacketConn, and
  81. // * when the OS doesn't support OOB.
  82. type basicConn struct {
  83. net.PacketConn
  84. supportsDF bool
  85. }
  86. var _ rawConn = &basicConn{}
  87. func (c *basicConn) ReadPacket() (receivedPacket, error) {
  88. buffer := getPacketBuffer()
  89. // The packet size should not exceed protocol.MaxPacketBufferSize bytes
  90. // If it does, we only read a truncated packet, which will then end up undecryptable
  91. buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
  92. n, addr, err := c.PacketConn.ReadFrom(buffer.Data)
  93. if err != nil {
  94. return receivedPacket{}, err
  95. }
  96. return receivedPacket{
  97. remoteAddr: addr,
  98. rcvTime: time.Now(),
  99. data: buffer.Data[:n],
  100. buffer: buffer,
  101. }, nil
  102. }
  103. func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte, gsoSize uint16, ecn protocol.ECN) (n int, err error) {
  104. if gsoSize != 0 {
  105. panic("cannot use GSO with a basicConn")
  106. }
  107. if ecn != protocol.ECNUnsupported {
  108. panic("cannot use ECN with a basicConn")
  109. }
  110. return c.PacketConn.WriteTo(b, addr)
  111. }
  112. func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} }