package udpnat import ( "io" "net" "os" "time" "github.com/sagernet/sing/common/buf" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/pipe" ) type Conn interface { N.PacketConn SetHandler(handler N.UDPHandlerEx) } var _ Conn = (*natConn)(nil) type natConn struct { writer N.PacketWriter localAddr M.Socksaddr handler N.UDPHandlerEx packetChan chan *N.PacketBuffer doneChan chan struct{} readDeadline pipe.Deadline readWaitOptions N.ReadWaitOptions } func (c *natConn) ReadPacket(buffer *buf.Buffer) (addr M.Socksaddr, err error) { select { case p := <-c.packetChan: _, err = buffer.ReadOnceFrom(p.Buffer) destination := p.Destination p.Buffer.Release() N.PutPacketBuffer(p) return destination, err case <-c.doneChan: return M.Socksaddr{}, io.ErrClosedPipe case <-c.readDeadline.Wait(): return M.Socksaddr{}, os.ErrDeadlineExceeded } } func (c *natConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { return c.writer.WritePacket(buffer, destination) } func (c *natConn) SetHandler(handler N.UDPHandlerEx) { select { case <-c.doneChan: default: } c.handler = handler c.readWaitOptions = N.NewReadWaitOptions(c.writer, handler) fetch: for { select { case packet := <-c.packetChan: c.handler.NewPacketEx(packet.Buffer, packet.Destination) N.PutPacketBuffer(packet) continue fetch default: break fetch } } } func (c *natConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { c.readWaitOptions = options return false } func (c *natConn) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { select { case packet := <-c.packetChan: buffer = c.readWaitOptions.Copy(packet.Buffer) destination = packet.Destination N.PutPacketBuffer(packet) return case <-c.doneChan: return nil, M.Socksaddr{}, io.ErrClosedPipe case <-c.readDeadline.Wait(): return nil, M.Socksaddr{}, os.ErrDeadlineExceeded } } func (c *natConn) Close() error { select { case <-c.doneChan: default: close(c.doneChan) } return nil } func (c *natConn) LocalAddr() net.Addr { return c.localAddr } func (c *natConn) RemoteAddr() net.Addr { return M.Socksaddr{} } func (c *natConn) SetDeadline(t time.Time) error { return os.ErrInvalid } func (c *natConn) SetReadDeadline(t time.Time) error { c.readDeadline.Set(t) return nil } func (c *natConn) SetWriteDeadline(t time.Time) error { return os.ErrInvalid } func (c *natConn) Upstream() any { return c.writer }