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 }