github.com/kelleygo/clashcore@v1.0.2/common/net/deadline/pipe_sing.go (about) 1 package deadline 2 3 import ( 4 "io" 5 "net" 6 "os" 7 "sync" 8 "time" 9 10 "github.com/sagernet/sing/common/buf" 11 N "github.com/sagernet/sing/common/network" 12 ) 13 14 type pipeAddr struct{} 15 16 func (pipeAddr) Network() string { return "pipe" } 17 func (pipeAddr) String() string { return "pipe" } 18 19 type pipe struct { 20 wrMu sync.Mutex // Serialize Write operations 21 22 // Used by local Read to interact with remote Write. 23 // Successful receive on rdRx is always followed by send on rdTx. 24 rdRx <-chan []byte 25 rdTx chan<- int 26 27 // Used by local Write to interact with remote Read. 28 // Successful send on wrTx is always followed by receive on wrRx. 29 wrTx chan<- []byte 30 wrRx <-chan int 31 32 once sync.Once // Protects closing localDone 33 localDone chan struct{} 34 remoteDone <-chan struct{} 35 36 readDeadline pipeDeadline 37 writeDeadline pipeDeadline 38 39 readWaitOptions N.ReadWaitOptions 40 } 41 42 // Pipe creates a synchronous, in-memory, full duplex 43 // network connection; both ends implement the Conn interface. 44 // Reads on one end are matched with writes on the other, 45 // copying data directly between the two; there is no internal 46 // buffering. 47 func Pipe() (net.Conn, net.Conn) { 48 cb1 := make(chan []byte) 49 cb2 := make(chan []byte) 50 cn1 := make(chan int) 51 cn2 := make(chan int) 52 done1 := make(chan struct{}) 53 done2 := make(chan struct{}) 54 55 p1 := &pipe{ 56 rdRx: cb1, rdTx: cn1, 57 wrTx: cb2, wrRx: cn2, 58 localDone: done1, remoteDone: done2, 59 readDeadline: makePipeDeadline(), 60 writeDeadline: makePipeDeadline(), 61 } 62 p2 := &pipe{ 63 rdRx: cb2, rdTx: cn2, 64 wrTx: cb1, wrRx: cn1, 65 localDone: done2, remoteDone: done1, 66 readDeadline: makePipeDeadline(), 67 writeDeadline: makePipeDeadline(), 68 } 69 return p1, p2 70 } 71 72 func (*pipe) LocalAddr() net.Addr { return pipeAddr{} } 73 func (*pipe) RemoteAddr() net.Addr { return pipeAddr{} } 74 75 func (p *pipe) Read(b []byte) (int, error) { 76 n, err := p.read(b) 77 if err != nil && err != io.EOF && err != io.ErrClosedPipe { 78 err = &net.OpError{Op: "read", Net: "pipe", Err: err} 79 } 80 return n, err 81 } 82 83 func (p *pipe) read(b []byte) (n int, err error) { 84 switch { 85 case isClosedChan(p.localDone): 86 return 0, io.ErrClosedPipe 87 case isClosedChan(p.remoteDone): 88 return 0, io.EOF 89 case isClosedChan(p.readDeadline.wait()): 90 return 0, os.ErrDeadlineExceeded 91 } 92 93 select { 94 case bw := <-p.rdRx: 95 nr := copy(b, bw) 96 p.rdTx <- nr 97 return nr, nil 98 case <-p.localDone: 99 return 0, io.ErrClosedPipe 100 case <-p.remoteDone: 101 return 0, io.EOF 102 case <-p.readDeadline.wait(): 103 return 0, os.ErrDeadlineExceeded 104 } 105 } 106 107 func (p *pipe) Write(b []byte) (int, error) { 108 n, err := p.write(b) 109 if err != nil && err != io.ErrClosedPipe { 110 err = &net.OpError{Op: "write", Net: "pipe", Err: err} 111 } 112 return n, err 113 } 114 115 func (p *pipe) write(b []byte) (n int, err error) { 116 switch { 117 case isClosedChan(p.localDone): 118 return 0, io.ErrClosedPipe 119 case isClosedChan(p.remoteDone): 120 return 0, io.ErrClosedPipe 121 case isClosedChan(p.writeDeadline.wait()): 122 return 0, os.ErrDeadlineExceeded 123 } 124 125 p.wrMu.Lock() // Ensure entirety of b is written together 126 defer p.wrMu.Unlock() 127 for once := true; once || len(b) > 0; once = false { 128 select { 129 case p.wrTx <- b: 130 nw := <-p.wrRx 131 b = b[nw:] 132 n += nw 133 case <-p.localDone: 134 return n, io.ErrClosedPipe 135 case <-p.remoteDone: 136 return n, io.ErrClosedPipe 137 case <-p.writeDeadline.wait(): 138 return n, os.ErrDeadlineExceeded 139 } 140 } 141 return n, nil 142 } 143 144 func (p *pipe) SetDeadline(t time.Time) error { 145 if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) { 146 return io.ErrClosedPipe 147 } 148 p.readDeadline.set(t) 149 p.writeDeadline.set(t) 150 return nil 151 } 152 153 func (p *pipe) SetReadDeadline(t time.Time) error { 154 if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) { 155 return io.ErrClosedPipe 156 } 157 p.readDeadline.set(t) 158 return nil 159 } 160 161 func (p *pipe) SetWriteDeadline(t time.Time) error { 162 if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) { 163 return io.ErrClosedPipe 164 } 165 p.writeDeadline.set(t) 166 return nil 167 } 168 169 func (p *pipe) Close() error { 170 p.once.Do(func() { close(p.localDone) }) 171 return nil 172 } 173 174 var _ N.ReadWaiter = (*pipe)(nil) 175 176 func (p *pipe) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { 177 p.readWaitOptions = options 178 return false 179 } 180 181 func (p *pipe) WaitReadBuffer() (buffer *buf.Buffer, err error) { 182 buffer, err = p.waitReadBuffer() 183 if err != nil && err != io.EOF && err != io.ErrClosedPipe { 184 err = &net.OpError{Op: "read", Net: "pipe", Err: err} 185 } 186 return 187 } 188 189 func (p *pipe) waitReadBuffer() (buffer *buf.Buffer, err error) { 190 switch { 191 case isClosedChan(p.localDone): 192 return nil, io.ErrClosedPipe 193 case isClosedChan(p.remoteDone): 194 return nil, io.EOF 195 case isClosedChan(p.readDeadline.wait()): 196 return nil, os.ErrDeadlineExceeded 197 } 198 select { 199 case bw := <-p.rdRx: 200 buffer = p.readWaitOptions.NewBuffer() 201 var nr int 202 nr, err = buffer.Write(bw) 203 if err != nil { 204 buffer.Release() 205 return 206 } 207 p.readWaitOptions.PostReturn(buffer) 208 p.rdTx <- nr 209 return 210 case <-p.localDone: 211 return nil, io.ErrClosedPipe 212 case <-p.remoteDone: 213 return nil, io.EOF 214 case <-p.readDeadline.wait(): 215 return nil, os.ErrDeadlineExceeded 216 } 217 } 218 219 func IsPipe(conn any) bool { 220 _, ok := conn.(*pipe) 221 return ok 222 }