1package quic
2
3import (
4	"io"
5	"net"
6	"syscall"
7	"time"
8
9	"github.com/lucas-clemente/quic-go/internal/protocol"
10	"github.com/lucas-clemente/quic-go/internal/utils"
11)
12
13type connection interface {
14	ReadPacket() (*receivedPacket, error)
15	WritePacket(b []byte, addr net.Addr, oob []byte) (int, error)
16	LocalAddr() net.Addr
17	io.Closer
18}
19
20// If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will read the ECN bits from the IP header.
21// In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets.
22type OOBCapablePacketConn interface {
23	net.PacketConn
24	SyscallConn() (syscall.RawConn, error)
25	ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
26	WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
27}
28
29var _ OOBCapablePacketConn = &net.UDPConn{}
30
31func wrapConn(pc net.PacketConn) (connection, error) {
32	c, ok := pc.(OOBCapablePacketConn)
33	if !ok {
34		utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.")
35		return &basicConn{PacketConn: pc}, nil
36	}
37	return newConn(c)
38}
39
40type basicConn struct {
41	net.PacketConn
42}
43
44var _ connection = &basicConn{}
45
46func (c *basicConn) ReadPacket() (*receivedPacket, error) {
47	buffer := getPacketBuffer()
48	// The packet size should not exceed protocol.MaxPacketBufferSize bytes
49	// If it does, we only read a truncated packet, which will then end up undecryptable
50	buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
51	n, addr, err := c.PacketConn.ReadFrom(buffer.Data)
52	if err != nil {
53		return nil, err
54	}
55	return &receivedPacket{
56		remoteAddr: addr,
57		rcvTime:    time.Now(),
58		data:       buffer.Data[:n],
59		buffer:     buffer,
60	}, nil
61}
62
63func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte) (n int, err error) {
64	return c.PacketConn.WriteTo(b, addr)
65}
66