github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/net/pipe.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package net
     6  
     7  import (
     8  	"io"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  // pipeDeadline is an abstraction for handling timeouts.
    14  type pipeDeadline struct {
    15  	mu     sync.Mutex // Guards timer and cancel
    16  	timer  *time.Timer
    17  	cancel chan struct{} // Must be non-nil
    18  }
    19  
    20  func makePipeDeadline() pipeDeadline {
    21  	return pipeDeadline{cancel: make(chan struct{})}
    22  }
    23  
    24  // set sets the point in time when the deadline will time out.
    25  // A timeout event is signaled by closing the channel returned by waiter.
    26  // Once a timeout has occurred, the deadline can be refreshed by specifying a
    27  // t value in the future.
    28  //
    29  // A zero value for t prevents timeout.
    30  func (d *pipeDeadline) set(t time.Time) {
    31  	d.mu.Lock()
    32  	defer d.mu.Unlock()
    33  
    34  	if d.timer != nil && !d.timer.Stop() {
    35  		<-d.cancel // Wait for the timer callback to finish and close cancel
    36  	}
    37  	d.timer = nil
    38  
    39  	// Time is zero, then there is no deadline.
    40  	closed := isClosedChan(d.cancel)
    41  	if t.IsZero() {
    42  		if closed {
    43  			d.cancel = make(chan struct{})
    44  		}
    45  		return
    46  	}
    47  
    48  	// Time in the future, setup a timer to cancel in the future.
    49  	if dur := time.Until(t); dur > 0 {
    50  		if closed {
    51  			d.cancel = make(chan struct{})
    52  		}
    53  		d.timer = time.AfterFunc(dur, func() {
    54  			close(d.cancel)
    55  		})
    56  		return
    57  	}
    58  
    59  	// Time in the past, so close immediately.
    60  	if !closed {
    61  		close(d.cancel)
    62  	}
    63  }
    64  
    65  // wait returns a channel that is closed when the deadline is exceeded.
    66  func (d *pipeDeadline) wait() chan struct{} {
    67  	d.mu.Lock()
    68  	defer d.mu.Unlock()
    69  	return d.cancel
    70  }
    71  
    72  func isClosedChan(c <-chan struct{}) bool {
    73  	select {
    74  	case <-c:
    75  		return true
    76  	default:
    77  		return false
    78  	}
    79  }
    80  
    81  type pipeError struct {
    82  	errStr  string
    83  	timeout bool
    84  }
    85  
    86  func (pe pipeError) Error() string   { return pe.errStr }
    87  func (pe pipeError) Timeout() bool   { return pe.timeout }
    88  func (pe pipeError) Temporary() bool { return pe.timeout }
    89  
    90  var (
    91  	errDeadline = pipeError{"deadline exceeded", true}
    92  	errClosed   = pipeError{"closed connection", false}
    93  )
    94  
    95  type pipeAddr struct{}
    96  
    97  func (pipeAddr) Network() string { return "pipe" }
    98  func (pipeAddr) String() string  { return "pipe" }
    99  
   100  type pipe struct {
   101  	wrMu sync.Mutex // Serialize Write operations
   102  
   103  	// Used by local Read to interact with remote Write.
   104  	// Successful receive on rdRx is always followed by send on rdTx.
   105  	rdRx <-chan []byte
   106  	rdTx chan<- int
   107  
   108  	// Used by local Write to interact with remote Read.
   109  	// Successful send on wrTx is always followed by receive on wrRx.
   110  	wrTx chan<- []byte
   111  	wrRx <-chan int
   112  
   113  	once       sync.Once // Protects closing localDone
   114  	localDone  chan struct{}
   115  	remoteDone <-chan struct{}
   116  
   117  	readDeadline  pipeDeadline
   118  	writeDeadline pipeDeadline
   119  }
   120  
   121  // Pipe creates a synchronous, in-memory, full duplex
   122  // network connection; both ends implement the Conn interface.
   123  // Reads on one end are matched with writes on the other,
   124  // copying data directly between the two; there is no internal
   125  // buffering.
   126  func Pipe() (Conn, Conn) {
   127  	cb1 := make(chan []byte)
   128  	cb2 := make(chan []byte)
   129  	cn1 := make(chan int)
   130  	cn2 := make(chan int)
   131  	done1 := make(chan struct{})
   132  	done2 := make(chan struct{})
   133  
   134  	p1 := &pipe{
   135  		rdRx: cb1, rdTx: cn1,
   136  		wrTx: cb2, wrRx: cn2,
   137  		localDone: done1, remoteDone: done2,
   138  		readDeadline:  makePipeDeadline(),
   139  		writeDeadline: makePipeDeadline(),
   140  	}
   141  	p2 := &pipe{
   142  		rdRx: cb2, rdTx: cn2,
   143  		wrTx: cb1, wrRx: cn1,
   144  		localDone: done2, remoteDone: done1,
   145  		readDeadline:  makePipeDeadline(),
   146  		writeDeadline: makePipeDeadline(),
   147  	}
   148  	return p1, p2
   149  }
   150  
   151  func (*pipe) LocalAddr() Addr  { return pipeAddr{} }
   152  func (*pipe) RemoteAddr() Addr { return pipeAddr{} }
   153  
   154  func (p *pipe) Read(b []byte) (int, error) {
   155  	n, err := p.read(b)
   156  	if err != nil && err != io.EOF {
   157  		err = &OpError{Op: "read", Net: "pipe", Err: err}
   158  	}
   159  	return n, err
   160  }
   161  
   162  func (p *pipe) read(b []byte) (n int, err error) {
   163  	switch {
   164  	case isClosedChan(p.localDone):
   165  		return 0, errClosed
   166  	case isClosedChan(p.remoteDone):
   167  		return 0, io.EOF
   168  	case isClosedChan(p.readDeadline.wait()):
   169  		return 0, errDeadline
   170  	}
   171  
   172  	select {
   173  	case bw := <-p.rdRx:
   174  		nr := copy(b, bw)
   175  		p.rdTx <- nr
   176  		return nr, nil
   177  	case <-p.localDone:
   178  		return 0, errClosed
   179  	case <-p.remoteDone:
   180  		return 0, io.EOF
   181  	case <-p.readDeadline.wait():
   182  		return 0, errDeadline
   183  	}
   184  }
   185  
   186  func (p *pipe) Write(b []byte) (int, error) {
   187  	n, err := p.write(b)
   188  	if err != nil {
   189  		err = &OpError{Op: "write", Net: "pipe", Err: err}
   190  	}
   191  	return n, err
   192  }
   193  
   194  func (p *pipe) write(b []byte) (n int, err error) {
   195  	switch {
   196  	case isClosedChan(p.localDone):
   197  		return 0, errClosed
   198  	case isClosedChan(p.remoteDone):
   199  		return 0, errClosed
   200  	case isClosedChan(p.writeDeadline.wait()):
   201  		return 0, errDeadline
   202  	}
   203  
   204  	p.wrMu.Lock() // Ensure entirety of b is written together
   205  	defer p.wrMu.Unlock()
   206  	for once := true; once || len(b) > 0; once = false {
   207  		select {
   208  		case p.wrTx <- b:
   209  			nw := <-p.wrRx
   210  			b = b[nw:]
   211  			n += nw
   212  		case <-p.localDone:
   213  			return n, errClosed
   214  		case <-p.remoteDone:
   215  			return n, errClosed
   216  		case <-p.writeDeadline.wait():
   217  			return n, errDeadline
   218  		}
   219  	}
   220  	return n, nil
   221  }
   222  
   223  func (p *pipe) SetDeadline(t time.Time) error {
   224  	if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
   225  		return &OpError{Op: "set", Net: "pipe", Err: errClosed}
   226  	}
   227  	p.readDeadline.set(t)
   228  	p.writeDeadline.set(t)
   229  	return nil
   230  }
   231  
   232  func (p *pipe) SetReadDeadline(t time.Time) error {
   233  	if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
   234  		return &OpError{Op: "set", Net: "pipe", Err: errClosed}
   235  	}
   236  	p.readDeadline.set(t)
   237  	return nil
   238  }
   239  
   240  func (p *pipe) SetWriteDeadline(t time.Time) error {
   241  	if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
   242  		return &OpError{Op: "set", Net: "pipe", Err: errClosed}
   243  	}
   244  	p.writeDeadline.set(t)
   245  	return nil
   246  }
   247  
   248  func (p *pipe) Close() error {
   249  	p.once.Do(func() { close(p.localDone) })
   250  	return nil
   251  }