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  }