google.golang.org/grpc@v1.72.2/test/bufconn/bufconn.go (about)

     1  /*
     2   *
     3   * Copyright 2017 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  // Package bufconn provides a net.Conn implemented by a buffer and related
    20  // dialing and listening functionality.
    21  package bufconn
    22  
    23  import (
    24  	"context"
    25  	"fmt"
    26  	"io"
    27  	"net"
    28  	"sync"
    29  	"time"
    30  )
    31  
    32  // Listener implements a net.Listener that creates local, buffered net.Conns
    33  // via its Accept and Dial method.
    34  type Listener struct {
    35  	mu   sync.Mutex
    36  	sz   int
    37  	ch   chan net.Conn
    38  	done chan struct{}
    39  }
    40  
    41  // Implementation of net.Error providing timeout
    42  type netErrorTimeout struct {
    43  	error
    44  }
    45  
    46  func (e netErrorTimeout) Timeout() bool   { return true }
    47  func (e netErrorTimeout) Temporary() bool { return false }
    48  
    49  var errClosed = fmt.Errorf("closed")
    50  var errTimeout net.Error = netErrorTimeout{error: fmt.Errorf("i/o timeout")}
    51  
    52  // Listen returns a Listener that can only be contacted by its own Dialers and
    53  // creates buffered connections between the two.
    54  func Listen(sz int) *Listener {
    55  	return &Listener{sz: sz, ch: make(chan net.Conn), done: make(chan struct{})}
    56  }
    57  
    58  // Accept blocks until Dial is called, then returns a net.Conn for the server
    59  // half of the connection.
    60  func (l *Listener) Accept() (net.Conn, error) {
    61  	select {
    62  	case <-l.done:
    63  		return nil, errClosed
    64  	case c := <-l.ch:
    65  		return c, nil
    66  	}
    67  }
    68  
    69  // Close stops the listener.
    70  func (l *Listener) Close() error {
    71  	l.mu.Lock()
    72  	defer l.mu.Unlock()
    73  	select {
    74  	case <-l.done:
    75  		// Already closed.
    76  	default:
    77  		close(l.done)
    78  	}
    79  	return nil
    80  }
    81  
    82  // Addr reports the address of the listener.
    83  func (l *Listener) Addr() net.Addr { return addr{} }
    84  
    85  // Dial creates an in-memory full-duplex network connection, unblocks Accept by
    86  // providing it the server half of the connection, and returns the client half
    87  // of the connection.
    88  func (l *Listener) Dial() (net.Conn, error) {
    89  	return l.DialContext(context.Background())
    90  }
    91  
    92  // DialContext creates an in-memory full-duplex network connection, unblocks Accept by
    93  // providing it the server half of the connection, and returns the client half
    94  // of the connection.  If ctx is Done, returns ctx.Err()
    95  func (l *Listener) DialContext(ctx context.Context) (net.Conn, error) {
    96  	p1, p2 := newPipe(l.sz), newPipe(l.sz)
    97  	select {
    98  	case <-ctx.Done():
    99  		return nil, ctx.Err()
   100  	case <-l.done:
   101  		return nil, errClosed
   102  	case l.ch <- &conn{p1, p2}:
   103  		return &conn{p2, p1}, nil
   104  	}
   105  }
   106  
   107  type pipe struct {
   108  	mu sync.Mutex
   109  
   110  	// buf contains the data in the pipe.  It is a ring buffer of fixed capacity,
   111  	// with r and w pointing to the offset to read and write, respectively.
   112  	//
   113  	// Data is read between [r, w) and written to [w, r), wrapping around the end
   114  	// of the slice if necessary.
   115  	//
   116  	// The buffer is empty if r == len(buf), otherwise if r == w, it is full.
   117  	//
   118  	// w and r are always in the range [0, cap(buf)) and [0, len(buf)].
   119  	buf  []byte
   120  	w, r int
   121  
   122  	wwait sync.Cond
   123  	rwait sync.Cond
   124  
   125  	// Indicate that a write/read timeout has occurred
   126  	wtimedout bool
   127  	rtimedout bool
   128  
   129  	wtimer *time.Timer
   130  	rtimer *time.Timer
   131  
   132  	closed      bool
   133  	writeClosed bool
   134  }
   135  
   136  func newPipe(sz int) *pipe {
   137  	p := &pipe{buf: make([]byte, 0, sz)}
   138  	p.wwait.L = &p.mu
   139  	p.rwait.L = &p.mu
   140  
   141  	p.wtimer = time.AfterFunc(0, func() {})
   142  	p.rtimer = time.AfterFunc(0, func() {})
   143  	return p
   144  }
   145  
   146  func (p *pipe) empty() bool {
   147  	return p.r == len(p.buf)
   148  }
   149  
   150  func (p *pipe) full() bool {
   151  	return p.r < len(p.buf) && p.r == p.w
   152  }
   153  
   154  func (p *pipe) Read(b []byte) (n int, err error) {
   155  	p.mu.Lock()
   156  	defer p.mu.Unlock()
   157  	// Block until p has data.
   158  	for {
   159  		if p.closed {
   160  			return 0, io.ErrClosedPipe
   161  		}
   162  		if !p.empty() {
   163  			break
   164  		}
   165  		if p.writeClosed {
   166  			return 0, io.EOF
   167  		}
   168  		if p.rtimedout {
   169  			return 0, errTimeout
   170  		}
   171  
   172  		p.rwait.Wait()
   173  	}
   174  	wasFull := p.full()
   175  
   176  	n = copy(b, p.buf[p.r:len(p.buf)])
   177  	p.r += n
   178  	if p.r == cap(p.buf) {
   179  		p.r = 0
   180  		p.buf = p.buf[:p.w]
   181  	}
   182  
   183  	// Signal a blocked writer, if any
   184  	if wasFull {
   185  		p.wwait.Signal()
   186  	}
   187  
   188  	return n, nil
   189  }
   190  
   191  func (p *pipe) Write(b []byte) (n int, err error) {
   192  	p.mu.Lock()
   193  	defer p.mu.Unlock()
   194  	if p.closed {
   195  		return 0, io.ErrClosedPipe
   196  	}
   197  	for len(b) > 0 {
   198  		// Block until p is not full.
   199  		for {
   200  			if p.closed || p.writeClosed {
   201  				return 0, io.ErrClosedPipe
   202  			}
   203  			if !p.full() {
   204  				break
   205  			}
   206  			if p.wtimedout {
   207  				return 0, errTimeout
   208  			}
   209  
   210  			p.wwait.Wait()
   211  		}
   212  		wasEmpty := p.empty()
   213  
   214  		end := cap(p.buf)
   215  		if p.w < p.r {
   216  			end = p.r
   217  		}
   218  		x := copy(p.buf[p.w:end], b)
   219  		b = b[x:]
   220  		n += x
   221  		p.w += x
   222  		if p.w > len(p.buf) {
   223  			p.buf = p.buf[:p.w]
   224  		}
   225  		if p.w == cap(p.buf) {
   226  			p.w = 0
   227  		}
   228  
   229  		// Signal a blocked reader, if any.
   230  		if wasEmpty {
   231  			p.rwait.Signal()
   232  		}
   233  	}
   234  	return n, nil
   235  }
   236  
   237  func (p *pipe) Close() error {
   238  	p.mu.Lock()
   239  	defer p.mu.Unlock()
   240  	p.closed = true
   241  	// Signal all blocked readers and writers to return an error.
   242  	p.rwait.Broadcast()
   243  	p.wwait.Broadcast()
   244  	return nil
   245  }
   246  
   247  func (p *pipe) closeWrite() error {
   248  	p.mu.Lock()
   249  	defer p.mu.Unlock()
   250  	p.writeClosed = true
   251  	// Signal all blocked readers and writers to return an error.
   252  	p.rwait.Broadcast()
   253  	p.wwait.Broadcast()
   254  	return nil
   255  }
   256  
   257  type conn struct {
   258  	io.Reader
   259  	io.Writer
   260  }
   261  
   262  func (c *conn) Close() error {
   263  	err1 := c.Reader.(*pipe).Close()
   264  	err2 := c.Writer.(*pipe).closeWrite()
   265  	if err1 != nil {
   266  		return err1
   267  	}
   268  	return err2
   269  }
   270  
   271  func (c *conn) SetDeadline(t time.Time) error {
   272  	c.SetReadDeadline(t)
   273  	c.SetWriteDeadline(t)
   274  	return nil
   275  }
   276  
   277  func (c *conn) SetReadDeadline(t time.Time) error {
   278  	p := c.Reader.(*pipe)
   279  	p.mu.Lock()
   280  	defer p.mu.Unlock()
   281  	p.rtimer.Stop()
   282  	p.rtimedout = false
   283  	if !t.IsZero() {
   284  		p.rtimer = time.AfterFunc(time.Until(t), func() {
   285  			p.mu.Lock()
   286  			defer p.mu.Unlock()
   287  			p.rtimedout = true
   288  			p.rwait.Broadcast()
   289  		})
   290  	}
   291  	return nil
   292  }
   293  
   294  func (c *conn) SetWriteDeadline(t time.Time) error {
   295  	p := c.Writer.(*pipe)
   296  	p.mu.Lock()
   297  	defer p.mu.Unlock()
   298  	p.wtimer.Stop()
   299  	p.wtimedout = false
   300  	if !t.IsZero() {
   301  		p.wtimer = time.AfterFunc(time.Until(t), func() {
   302  			p.mu.Lock()
   303  			defer p.mu.Unlock()
   304  			p.wtimedout = true
   305  			p.wwait.Broadcast()
   306  		})
   307  	}
   308  	return nil
   309  }
   310  
   311  func (*conn) LocalAddr() net.Addr  { return addr{} }
   312  func (*conn) RemoteAddr() net.Addr { return addr{} }
   313  
   314  type addr struct{}
   315  
   316  func (addr) Network() string { return "bufconn" }
   317  func (addr) String() string  { return "bufconn" }