github.com/EagleQL/Xray-core@v1.4.3/transport/internet/udp/hub.go (about)

     1  package udp
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/xtls/xray-core/common/buf"
     7  	"github.com/xtls/xray-core/common/net"
     8  	"github.com/xtls/xray-core/common/protocol/udp"
     9  	"github.com/xtls/xray-core/transport/internet"
    10  )
    11  
    12  type HubOption func(h *Hub)
    13  
    14  func HubCapacity(capacity int) HubOption {
    15  	return func(h *Hub) {
    16  		h.capacity = capacity
    17  	}
    18  }
    19  
    20  func HubReceiveOriginalDestination(r bool) HubOption {
    21  	return func(h *Hub) {
    22  		h.recvOrigDest = r
    23  	}
    24  }
    25  
    26  type Hub struct {
    27  	conn         *net.UDPConn
    28  	cache        chan *udp.Packet
    29  	capacity     int
    30  	recvOrigDest bool
    31  }
    32  
    33  func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, options ...HubOption) (*Hub, error) {
    34  	hub := &Hub{
    35  		capacity:     256,
    36  		recvOrigDest: false,
    37  	}
    38  	for _, opt := range options {
    39  		opt(hub)
    40  	}
    41  
    42  	var sockopt *internet.SocketConfig
    43  	if streamSettings != nil {
    44  		sockopt = streamSettings.SocketSettings
    45  	}
    46  	if sockopt != nil && sockopt.ReceiveOriginalDestAddress {
    47  		hub.recvOrigDest = true
    48  	}
    49  
    50  	udpConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{
    51  		IP:   address.IP(),
    52  		Port: int(port),
    53  	}, sockopt)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	newError("listening UDP on ", address, ":", port).WriteToLog()
    58  	hub.conn = udpConn.(*net.UDPConn)
    59  	hub.cache = make(chan *udp.Packet, hub.capacity)
    60  
    61  	go hub.start()
    62  	return hub, nil
    63  }
    64  
    65  // Close implements net.Listener.
    66  func (h *Hub) Close() error {
    67  	h.conn.Close()
    68  	return nil
    69  }
    70  
    71  func (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) {
    72  	return h.conn.WriteToUDP(payload, &net.UDPAddr{
    73  		IP:   dest.Address.IP(),
    74  		Port: int(dest.Port),
    75  	})
    76  }
    77  
    78  func (h *Hub) start() {
    79  	c := h.cache
    80  	defer close(c)
    81  
    82  	oobBytes := make([]byte, 256)
    83  
    84  	for {
    85  		buffer := buf.New()
    86  		var noob int
    87  		var addr *net.UDPAddr
    88  		rawBytes := buffer.Extend(buf.Size)
    89  
    90  		n, noob, _, addr, err := ReadUDPMsg(h.conn, rawBytes, oobBytes)
    91  		if err != nil {
    92  			newError("failed to read UDP msg").Base(err).WriteToLog()
    93  			buffer.Release()
    94  			break
    95  		}
    96  		buffer.Resize(0, int32(n))
    97  
    98  		if buffer.IsEmpty() {
    99  			buffer.Release()
   100  			continue
   101  		}
   102  
   103  		payload := &udp.Packet{
   104  			Payload: buffer,
   105  			Source:  net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)),
   106  		}
   107  		if h.recvOrigDest && noob > 0 {
   108  			payload.Target = RetrieveOriginalDest(oobBytes[:noob])
   109  			if payload.Target.IsValid() {
   110  				newError("UDP original destination: ", payload.Target).AtDebug().WriteToLog()
   111  			} else {
   112  				newError("failed to read UDP original destination").WriteToLog()
   113  			}
   114  		}
   115  
   116  		select {
   117  		case c <- payload:
   118  		default:
   119  			buffer.Release()
   120  			payload.Payload = nil
   121  		}
   122  	}
   123  }
   124  
   125  // Addr implements net.Listener.
   126  func (h *Hub) Addr() net.Addr {
   127  	return h.conn.LocalAddr()
   128  }
   129  
   130  func (h *Hub) Receive() <-chan *udp.Packet {
   131  	return h.cache
   132  }