github.com/kelleygo/clashcore@v1.0.2/common/net/deadline/packet_sing.go (about) 1 package deadline 2 3 import ( 4 "os" 5 "runtime" 6 7 "github.com/kelleygo/clashcore/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 }