github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/pipe/pipe_wait.go (about)

     1  package pipe
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  	"os"
     7  
     8  	"github.com/sagernet/sing/common/buf"
     9  	N "github.com/sagernet/sing/common/network"
    10  )
    11  
    12  var _ N.ReadWaiter = (*pipe)(nil)
    13  
    14  func (p *pipe) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) {
    15  	p.readWaitOptions = options
    16  	return false
    17  }
    18  
    19  func (p *pipe) WaitReadBuffer() (buffer *buf.Buffer, err error) {
    20  	buffer, err = p.waitReadBuffer()
    21  	if err != nil && err != io.EOF && err != io.ErrClosedPipe {
    22  		err = &net.OpError{Op: "read", Net: "pipe", Err: err}
    23  	}
    24  	return
    25  }
    26  
    27  func (p *pipe) waitReadBuffer() (buffer *buf.Buffer, err error) {
    28  	switch {
    29  	case isClosedChan(p.localDone):
    30  		return nil, io.ErrClosedPipe
    31  	case isClosedChan(p.remoteDone):
    32  		return nil, io.EOF
    33  	case isClosedChan(p.readDeadline.wait()):
    34  		return nil, os.ErrDeadlineExceeded
    35  	}
    36  	select {
    37  	case bw := <-p.rdRx:
    38  		buffer = p.readWaitOptions.NewBuffer()
    39  		var nr int
    40  		nr, err = buffer.Write(bw)
    41  		if err != nil {
    42  			buffer.Release()
    43  			return
    44  		}
    45  		p.readWaitOptions.PostReturn(buffer)
    46  		p.rdTx <- nr
    47  		return
    48  	case <-p.localDone:
    49  		return nil, io.ErrClosedPipe
    50  	case <-p.remoteDone:
    51  		return nil, io.EOF
    52  	case <-p.readDeadline.wait():
    53  		return nil, os.ErrDeadlineExceeded
    54  	}
    55  }