github.com/metacubex/mihomo@v1.18.5/common/net/deadline/packet_sing.go (about)

     1  package deadline
     2  
     3  import (
     4  	"os"
     5  	"runtime"
     6  
     7  	"github.com/metacubex/mihomo/common/net/packet"
     8  
     9  	"github.com/sagernet/sing/common/buf"
    10  	"github.com/sagernet/sing/common/bufio"
    11  	M "github.com/sagernet/sing/common/metadata"
    12  	N "github.com/sagernet/sing/common/network"
    13  )
    14  
    15  type SingPacketConn struct {
    16  	*NetPacketConn
    17  	singPacketConn
    18  }
    19  
    20  var _ packet.SingPacketConn = (*SingPacketConn)(nil)
    21  
    22  func NewSingPacketConn(pc packet.SingPacketConn) packet.SingPacketConn {
    23  	return NewNetPacketConn(pc).(packet.SingPacketConn)
    24  }
    25  
    26  type EnhanceSingPacketConn struct {
    27  	*EnhancePacketConn
    28  	singPacketConn
    29  }
    30  
    31  func NewEnhanceSingPacketConn(pc packet.EnhanceSingPacketConn) packet.EnhanceSingPacketConn {
    32  	return NewNetPacketConn(pc).(packet.EnhanceSingPacketConn)
    33  }
    34  
    35  var _ packet.EnhanceSingPacketConn = (*EnhanceSingPacketConn)(nil)
    36  
    37  type singReadResult struct {
    38  	buffer      *buf.Buffer
    39  	destination M.Socksaddr
    40  	err         error
    41  }
    42  
    43  type singPacketConn struct {
    44  	netPacketConn  *NetPacketConn
    45  	singPacketConn packet.SingPacketConn
    46  }
    47  
    48  func (c *singPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
    49  FOR:
    50  	for {
    51  		select {
    52  		case result := <-c.netPacketConn.resultCh:
    53  			if result != nil {
    54  				if result, ok := result.(*singReadResult); ok {
    55  					destination = result.destination
    56  					err = result.err
    57  					n, _ := buffer.Write(result.buffer.Bytes())
    58  					result.buffer.Advance(n)
    59  					if result.buffer.IsEmpty() {
    60  						result.buffer.Release()
    61  					}
    62  					c.netPacketConn.resultCh <- nil // finish cache read
    63  					return
    64  				}
    65  				c.netPacketConn.resultCh <- result // another type of read
    66  				runtime.Gosched()                  // allowing other goroutines to run
    67  				continue FOR
    68  			} else {
    69  				c.netPacketConn.resultCh <- nil
    70  				break FOR
    71  			}
    72  		case <-c.netPacketConn.pipeDeadline.wait():
    73  			return M.Socksaddr{}, os.ErrDeadlineExceeded
    74  		}
    75  	}
    76  
    77  	if c.netPacketConn.disablePipe.Load() {
    78  		return c.singPacketConn.ReadPacket(buffer)
    79  	} else if c.netPacketConn.deadline.Load().IsZero() {
    80  		c.netPacketConn.inRead.Store(true)
    81  		defer c.netPacketConn.inRead.Store(false)
    82  		destination, err = c.singPacketConn.ReadPacket(buffer)
    83  		return
    84  	}
    85  
    86  	<-c.netPacketConn.resultCh
    87  	go c.pipeReadPacket(buffer.FreeLen())
    88  
    89  	return c.ReadPacket(buffer)
    90  }
    91  
    92  func (c *singPacketConn) pipeReadPacket(pLen int) {
    93  	buffer := buf.NewSize(pLen)
    94  	destination, err := c.singPacketConn.ReadPacket(buffer)
    95  	result := &singReadResult{}
    96  	result.destination = destination
    97  	result.err = err
    98  	c.netPacketConn.resultCh <- result
    99  }
   100  
   101  func (c *singPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
   102  	return c.singPacketConn.WritePacket(buffer, destination)
   103  }
   104  
   105  func (c *singPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) {
   106  	prw, isReadWaiter := bufio.CreatePacketReadWaiter(c.singPacketConn)
   107  	if isReadWaiter {
   108  		return &singPacketReadWaiter{
   109  			netPacketConn:    c.netPacketConn,
   110  			packetReadWaiter: prw,
   111  		}, true
   112  	}
   113  	return nil, false
   114  }
   115  
   116  var _ N.PacketReadWaiter = (*singPacketReadWaiter)(nil)
   117  
   118  type singPacketReadWaiter struct {
   119  	netPacketConn    *NetPacketConn
   120  	packetReadWaiter N.PacketReadWaiter
   121  }
   122  
   123  type singWaitReadResult singReadResult
   124  
   125  func (c *singPacketReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) {
   126  	return c.packetReadWaiter.InitializeReadWaiter(options)
   127  }
   128  
   129  func (c *singPacketReadWaiter) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) {
   130  FOR:
   131  	for {
   132  		select {
   133  		case result := <-c.netPacketConn.resultCh:
   134  			if result != nil {
   135  				if result, ok := result.(*singWaitReadResult); ok {
   136  					buffer = result.buffer
   137  					destination = result.destination
   138  					err = result.err
   139  					c.netPacketConn.resultCh <- nil // finish cache read
   140  					return
   141  				}
   142  				c.netPacketConn.resultCh <- result // another type of read
   143  				runtime.Gosched()                  // allowing other goroutines to run
   144  				continue FOR
   145  			} else {
   146  				c.netPacketConn.resultCh <- nil
   147  				break FOR
   148  			}
   149  		case <-c.netPacketConn.pipeDeadline.wait():
   150  			return nil, M.Socksaddr{}, os.ErrDeadlineExceeded
   151  		}
   152  	}
   153  
   154  	if c.netPacketConn.disablePipe.Load() {
   155  		return c.packetReadWaiter.WaitReadPacket()
   156  	} else if c.netPacketConn.deadline.Load().IsZero() {
   157  		c.netPacketConn.inRead.Store(true)
   158  		defer c.netPacketConn.inRead.Store(false)
   159  		return c.packetReadWaiter.WaitReadPacket()
   160  	}
   161  
   162  	<-c.netPacketConn.resultCh
   163  	go c.pipeWaitReadPacket()
   164  
   165  	return c.WaitReadPacket()
   166  }
   167  
   168  func (c *singPacketReadWaiter) pipeWaitReadPacket() {
   169  	buffer, destination, err := c.packetReadWaiter.WaitReadPacket()
   170  	result := &singWaitReadResult{}
   171  	result.buffer = buffer
   172  	result.destination = destination
   173  	result.err = err
   174  	c.netPacketConn.resultCh <- result
   175  }
   176  
   177  func (c *singPacketReadWaiter) Upstream() any {
   178  	return c.packetReadWaiter
   179  }