Source file src/net/net.go

Documentation: net

     1  // Copyright 2009 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  /*
     6  Package net provides a portable interface for network I/O, including
     7  TCP/IP, UDP, domain name resolution, and Unix domain sockets.
     8  
     9  Although the package provides access to low-level networking
    10  primitives, most clients will need only the basic interface provided
    11  by the Dial, Listen, and Accept functions and the associated
    12  Conn and Listener interfaces. The crypto/tls package uses
    13  the same interfaces and similar Dial and Listen functions.
    14  
    15  The Dial function connects to a server:
    16  
    17  	conn, err := net.Dial("tcp", "golang.org:80")
    18  	if err != nil {
    19  		// handle error
    20  	}
    21  	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
    22  	status, err := bufio.NewReader(conn).ReadString('\n')
    23  	// ...
    24  
    25  The Listen function creates servers:
    26  
    27  	ln, err := net.Listen("tcp", ":8080")
    28  	if err != nil {
    29  		// handle error
    30  	}
    31  	for {
    32  		conn, err := ln.Accept()
    33  		if err != nil {
    34  			// handle error
    35  		}
    36  		go handleConnection(conn)
    37  	}
    38  
    39  Name Resolution
    40  
    41  The method for resolving domain names, whether indirectly with functions like Dial
    42  or directly with functions like LookupHost and LookupAddr, varies by operating system.
    43  
    44  On Unix systems, the resolver has two options for resolving names.
    45  It can use a pure Go resolver that sends DNS requests directly to the servers
    46  listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C
    47  library routines such as getaddrinfo and getnameinfo.
    48  
    49  By default the pure Go resolver is used, because a blocked DNS request consumes
    50  only a goroutine, while a blocked C call consumes an operating system thread.
    51  When cgo is available, the cgo-based resolver is used instead under a variety of
    52  conditions: on systems that do not let programs make direct DNS requests (OS X),
    53  when the LOCALDOMAIN environment variable is present (even if empty),
    54  when the RES_OPTIONS or HOSTALIASES environment variable is non-empty,
    55  when the ASR_CONFIG environment variable is non-empty (OpenBSD only),
    56  when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the
    57  Go resolver does not implement, and when the name being looked up ends in .local
    58  or is an mDNS name.
    59  
    60  The resolver decision can be overridden by setting the netdns value of the
    61  GODEBUG environment variable (see package runtime) to go or cgo, as in:
    62  
    63  	export GODEBUG=netdns=go    # force pure Go resolver
    64  	export GODEBUG=netdns=cgo   # force cgo resolver
    65  
    66  The decision can also be forced while building the Go source tree
    67  by setting the netgo or netcgo build tag.
    68  
    69  A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver
    70  to print debugging information about its decisions.
    71  To force a particular resolver while also printing debugging information,
    72  join the two settings by a plus sign, as in GODEBUG=netdns=go+1.
    73  
    74  On Plan 9, the resolver always accesses /net/cs and /net/dns.
    75  
    76  On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
    77  
    78  */
    79  package net
    80  
    81  import (
    82  	"context"
    83  	"errors"
    84  	"internal/poll"
    85  	"io"
    86  	"os"
    87  	"sync"
    88  	"syscall"
    89  	"time"
    90  )
    91  
    92  // netGo and netCgo contain the state of the build tags used
    93  // to build this binary, and whether cgo is available.
    94  // conf.go mirrors these into conf for easier testing.
    95  var (
    96  	netGo  bool // set true in cgo_stub.go for build tag "netgo" (or no cgo)
    97  	netCgo bool // set true in conf_netcgo.go for build tag "netcgo"
    98  )
    99  
   100  // Addr represents a network end point address.
   101  //
   102  // The two methods Network and String conventionally return strings
   103  // that can be passed as the arguments to Dial, but the exact form
   104  // and meaning of the strings is up to the implementation.
   105  type Addr interface {
   106  	Network() string // name of the network (for example, "tcp", "udp")
   107  	String() string  // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80")
   108  }
   109  
   110  // Conn is a generic stream-oriented network connection.
   111  //
   112  // Multiple goroutines may invoke methods on a Conn simultaneously.
   113  type Conn interface {
   114  	// Read reads data from the connection.
   115  	// Read can be made to time out and return an Error with Timeout() == true
   116  	// after a fixed time limit; see SetDeadline and SetReadDeadline.
   117  	Read(b []byte) (n int, err error)
   118  
   119  	// Write writes data to the connection.
   120  	// Write can be made to time out and return an Error with Timeout() == true
   121  	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
   122  	Write(b []byte) (n int, err error)
   123  
   124  	// Close closes the connection.
   125  	// Any blocked Read or Write operations will be unblocked and return errors.
   126  	Close() error
   127  
   128  	// LocalAddr returns the local network address.
   129  	LocalAddr() Addr
   130  
   131  	// RemoteAddr returns the remote network address.
   132  	RemoteAddr() Addr
   133  
   134  	// SetDeadline sets the read and write deadlines associated
   135  	// with the connection. It is equivalent to calling both
   136  	// SetReadDeadline and SetWriteDeadline.
   137  	//
   138  	// A deadline is an absolute time after which I/O operations
   139  	// fail with a timeout (see type Error) instead of
   140  	// blocking. The deadline applies to all future and pending
   141  	// I/O, not just the immediately following call to Read or
   142  	// Write. After a deadline has been exceeded, the connection
   143  	// can be refreshed by setting a deadline in the future.
   144  	//
   145  	// An idle timeout can be implemented by repeatedly extending
   146  	// the deadline after successful Read or Write calls.
   147  	//
   148  	// A zero value for t means I/O operations will not time out.
   149  	//
   150  	// Note that if a TCP connection has keep-alive turned on,
   151  	// which is the default unless overridden by Dialer.KeepAlive
   152  	// or ListenConfig.KeepAlive, then a keep-alive failure may
   153  	// also return a timeout error. On Unix systems a keep-alive
   154  	// failure on I/O can be detected using
   155  	// errors.Is(err, syscall.ETIMEDOUT).
   156  	SetDeadline(t time.Time) error
   157  
   158  	// SetReadDeadline sets the deadline for future Read calls
   159  	// and any currently-blocked Read call.
   160  	// A zero value for t means Read will not time out.
   161  	SetReadDeadline(t time.Time) error
   162  
   163  	// SetWriteDeadline sets the deadline for future Write calls
   164  	// and any currently-blocked Write call.
   165  	// Even if write times out, it may return n > 0, indicating that
   166  	// some of the data was successfully written.
   167  	// A zero value for t means Write will not time out.
   168  	SetWriteDeadline(t time.Time) error
   169  }
   170  
   171  type conn struct {
   172  	fd *netFD
   173  }
   174  
   175  func (c *conn) ok() bool { return c != nil && c.fd != nil }
   176  
   177  // Implementation of the Conn interface.
   178  
   179  // Read implements the Conn Read method.
   180  func (c *conn) Read(b []byte) (int, error) {
   181  	if !c.ok() {
   182  		return 0, syscall.EINVAL
   183  	}
   184  	n, err := c.fd.Read(b)
   185  	if err != nil && err != io.EOF {
   186  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   187  	}
   188  	return n, err
   189  }
   190  
   191  // Write implements the Conn Write method.
   192  func (c *conn) Write(b []byte) (int, error) {
   193  	if !c.ok() {
   194  		return 0, syscall.EINVAL
   195  	}
   196  	n, err := c.fd.Write(b)
   197  	if err != nil {
   198  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   199  	}
   200  	return n, err
   201  }
   202  
   203  // Close closes the connection.
   204  func (c *conn) Close() error {
   205  	if !c.ok() {
   206  		return syscall.EINVAL
   207  	}
   208  	err := c.fd.Close()
   209  	if err != nil {
   210  		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   211  	}
   212  	return err
   213  }
   214  
   215  // LocalAddr returns the local network address.
   216  // The Addr returned is shared by all invocations of LocalAddr, so
   217  // do not modify it.
   218  func (c *conn) LocalAddr() Addr {
   219  	if !c.ok() {
   220  		return nil
   221  	}
   222  	return c.fd.laddr
   223  }
   224  
   225  // RemoteAddr returns the remote network address.
   226  // The Addr returned is shared by all invocations of RemoteAddr, so
   227  // do not modify it.
   228  func (c *conn) RemoteAddr() Addr {
   229  	if !c.ok() {
   230  		return nil
   231  	}
   232  	return c.fd.raddr
   233  }
   234  
   235  // SetDeadline implements the Conn SetDeadline method.
   236  func (c *conn) SetDeadline(t time.Time) error {
   237  	if !c.ok() {
   238  		return syscall.EINVAL
   239  	}
   240  	if err := c.fd.SetDeadline(t); err != nil {
   241  		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
   242  	}
   243  	return nil
   244  }
   245  
   246  // SetReadDeadline implements the Conn SetReadDeadline method.
   247  func (c *conn) SetReadDeadline(t time.Time) error {
   248  	if !c.ok() {
   249  		return syscall.EINVAL
   250  	}
   251  	if err := c.fd.SetReadDeadline(t); err != nil {
   252  		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
   253  	}
   254  	return nil
   255  }
   256  
   257  // SetWriteDeadline implements the Conn SetWriteDeadline method.
   258  func (c *conn) SetWriteDeadline(t time.Time) error {
   259  	if !c.ok() {
   260  		return syscall.EINVAL
   261  	}
   262  	if err := c.fd.SetWriteDeadline(t); err != nil {
   263  		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
   264  	}
   265  	return nil
   266  }
   267  
   268  // SetReadBuffer sets the size of the operating system's
   269  // receive buffer associated with the connection.
   270  func (c *conn) SetReadBuffer(bytes int) error {
   271  	if !c.ok() {
   272  		return syscall.EINVAL
   273  	}
   274  	if err := setReadBuffer(c.fd, bytes); err != nil {
   275  		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
   276  	}
   277  	return nil
   278  }
   279  
   280  // SetWriteBuffer sets the size of the operating system's
   281  // transmit buffer associated with the connection.
   282  func (c *conn) SetWriteBuffer(bytes int) error {
   283  	if !c.ok() {
   284  		return syscall.EINVAL
   285  	}
   286  	if err := setWriteBuffer(c.fd, bytes); err != nil {
   287  		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
   288  	}
   289  	return nil
   290  }
   291  
   292  // File returns a copy of the underlying os.File.
   293  // It is the caller's responsibility to close f when finished.
   294  // Closing c does not affect f, and closing f does not affect c.
   295  //
   296  // The returned os.File's file descriptor is different from the connection's.
   297  // Attempting to change properties of the original using this duplicate
   298  // may or may not have the desired effect.
   299  func (c *conn) File() (f *os.File, err error) {
   300  	f, err = c.fd.dup()
   301  	if err != nil {
   302  		err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   303  	}
   304  	return
   305  }
   306  
   307  // PacketConn is a generic packet-oriented network connection.
   308  //
   309  // Multiple goroutines may invoke methods on a PacketConn simultaneously.
   310  type PacketConn interface {
   311  	// ReadFrom reads a packet from the connection,
   312  	// copying the payload into p. It returns the number of
   313  	// bytes copied into p and the return address that
   314  	// was on the packet.
   315  	// It returns the number of bytes read (0 <= n <= len(p))
   316  	// and any error encountered. Callers should always process
   317  	// the n > 0 bytes returned before considering the error err.
   318  	// ReadFrom can be made to time out and return
   319  	// an Error with Timeout() == true after a fixed time limit;
   320  	// see SetDeadline and SetReadDeadline.
   321  	ReadFrom(p []byte) (n int, addr Addr, err error)
   322  
   323  	// WriteTo writes a packet with payload p to addr.
   324  	// WriteTo can be made to time out and return
   325  	// an Error with Timeout() == true after a fixed time limit;
   326  	// see SetDeadline and SetWriteDeadline.
   327  	// On packet-oriented connections, write timeouts are rare.
   328  	WriteTo(p []byte, addr Addr) (n int, err error)
   329  
   330  	// Close closes the connection.
   331  	// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
   332  	Close() error
   333  
   334  	// LocalAddr returns the local network address.
   335  	LocalAddr() Addr
   336  
   337  	// SetDeadline sets the read and write deadlines associated
   338  	// with the connection. It is equivalent to calling both
   339  	// SetReadDeadline and SetWriteDeadline.
   340  	//
   341  	// A deadline is an absolute time after which I/O operations
   342  	// fail with a timeout (see type Error) instead of
   343  	// blocking. The deadline applies to all future and pending
   344  	// I/O, not just the immediately following call to ReadFrom or
   345  	// WriteTo. After a deadline has been exceeded, the connection
   346  	// can be refreshed by setting a deadline in the future.
   347  	//
   348  	// An idle timeout can be implemented by repeatedly extending
   349  	// the deadline after successful ReadFrom or WriteTo calls.
   350  	//
   351  	// A zero value for t means I/O operations will not time out.
   352  	SetDeadline(t time.Time) error
   353  
   354  	// SetReadDeadline sets the deadline for future ReadFrom calls
   355  	// and any currently-blocked ReadFrom call.
   356  	// A zero value for t means ReadFrom will not time out.
   357  	SetReadDeadline(t time.Time) error
   358  
   359  	// SetWriteDeadline sets the deadline for future WriteTo calls
   360  	// and any currently-blocked WriteTo call.
   361  	// Even if write times out, it may return n > 0, indicating that
   362  	// some of the data was successfully written.
   363  	// A zero value for t means WriteTo will not time out.
   364  	SetWriteDeadline(t time.Time) error
   365  }
   366  
   367  var listenerBacklogCache struct {
   368  	sync.Once
   369  	val int
   370  }
   371  
   372  // listenerBacklog is a caching wrapper around maxListenerBacklog.
   373  func listenerBacklog() int {
   374  	listenerBacklogCache.Do(func() { listenerBacklogCache.val = maxListenerBacklog() })
   375  	return listenerBacklogCache.val
   376  }
   377  
   378  // A Listener is a generic network listener for stream-oriented protocols.
   379  //
   380  // Multiple goroutines may invoke methods on a Listener simultaneously.
   381  type Listener interface {
   382  	// Accept waits for and returns the next connection to the listener.
   383  	Accept() (Conn, error)
   384  
   385  	// Close closes the listener.
   386  	// Any blocked Accept operations will be unblocked and return errors.
   387  	Close() error
   388  
   389  	// Addr returns the listener's network address.
   390  	Addr() Addr
   391  }
   392  
   393  // An Error represents a network error.
   394  type Error interface {
   395  	error
   396  	Timeout() bool   // Is the error a timeout?
   397  	Temporary() bool // Is the error temporary?
   398  }
   399  
   400  // Various errors contained in OpError.
   401  var (
   402  	// For connection setup operations.
   403  	errNoSuitableAddress = errors.New("no suitable address found")
   404  
   405  	// For connection setup and write operations.
   406  	errMissingAddress = errors.New("missing address")
   407  
   408  	// For both read and write operations.
   409  	errCanceled         = errors.New("operation was canceled")
   410  	ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
   411  )
   412  
   413  // mapErr maps from the context errors to the historical internal net
   414  // error values.
   415  //
   416  // TODO(bradfitz): get rid of this after adjusting tests and making
   417  // context.DeadlineExceeded implement net.Error?
   418  func mapErr(err error) error {
   419  	switch err {
   420  	case context.Canceled:
   421  		return errCanceled
   422  	case context.DeadlineExceeded:
   423  		return poll.ErrTimeout
   424  	default:
   425  		return err
   426  	}
   427  }
   428  
   429  // OpError is the error type usually returned by functions in the net
   430  // package. It describes the operation, network type, and address of
   431  // an error.
   432  type OpError struct {
   433  	// Op is the operation which caused the error, such as
   434  	// "read" or "write".
   435  	Op string
   436  
   437  	// Net is the network type on which this error occurred,
   438  	// such as "tcp" or "udp6".
   439  	Net string
   440  
   441  	// For operations involving a remote network connection, like
   442  	// Dial, Read, or Write, Source is the corresponding local
   443  	// network address.
   444  	Source Addr
   445  
   446  	// Addr is the network address for which this error occurred.
   447  	// For local operations, like Listen or SetDeadline, Addr is
   448  	// the address of the local endpoint being manipulated.
   449  	// For operations involving a remote network connection, like
   450  	// Dial, Read, or Write, Addr is the remote address of that
   451  	// connection.
   452  	Addr Addr
   453  
   454  	// Err is the error that occurred during the operation.
   455  	Err error
   456  }
   457  
   458  func (e *OpError) Unwrap() error { return e.Err }
   459  
   460  func (e *OpError) Error() string {
   461  	if e == nil {
   462  		return "<nil>"
   463  	}
   464  	s := e.Op
   465  	if e.Net != "" {
   466  		s += " " + e.Net
   467  	}
   468  	if e.Source != nil {
   469  		s += " " + e.Source.String()
   470  	}
   471  	if e.Addr != nil {
   472  		if e.Source != nil {
   473  			s += "->"
   474  		} else {
   475  			s += " "
   476  		}
   477  		s += e.Addr.String()
   478  	}
   479  	s += ": " + e.Err.Error()
   480  	return s
   481  }
   482  
   483  var (
   484  	// aLongTimeAgo is a non-zero time, far in the past, used for
   485  	// immediate cancellation of dials.
   486  	aLongTimeAgo = time.Unix(1, 0)
   487  
   488  	// nonDeadline and noCancel are just zero values for
   489  	// readability with functions taking too many parameters.
   490  	noDeadline = time.Time{}
   491  	noCancel   = (chan struct{})(nil)
   492  )
   493  
   494  type timeout interface {
   495  	Timeout() bool
   496  }
   497  
   498  func (e *OpError) Timeout() bool {
   499  	if ne, ok := e.Err.(*os.SyscallError); ok {
   500  		t, ok := ne.Err.(timeout)
   501  		return ok && t.Timeout()
   502  	}
   503  	t, ok := e.Err.(timeout)
   504  	return ok && t.Timeout()
   505  }
   506  
   507  type temporary interface {
   508  	Temporary() bool
   509  }
   510  
   511  func (e *OpError) Temporary() bool {
   512  	// Treat ECONNRESET and ECONNABORTED as temporary errors when
   513  	// they come from calling accept. See issue 6163.
   514  	if e.Op == "accept" && isConnError(e.Err) {
   515  		return true
   516  	}
   517  
   518  	if ne, ok := e.Err.(*os.SyscallError); ok {
   519  		t, ok := ne.Err.(temporary)
   520  		return ok && t.Temporary()
   521  	}
   522  	t, ok := e.Err.(temporary)
   523  	return ok && t.Temporary()
   524  }
   525  
   526  // A ParseError is the error type of literal network address parsers.
   527  type ParseError struct {
   528  	// Type is the type of string that was expected, such as
   529  	// "IP address", "CIDR address".
   530  	Type string
   531  
   532  	// Text is the malformed text string.
   533  	Text string
   534  }
   535  
   536  func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }
   537  
   538  type AddrError struct {
   539  	Err  string
   540  	Addr string
   541  }
   542  
   543  func (e *AddrError) Error() string {
   544  	if e == nil {
   545  		return "<nil>"
   546  	}
   547  	s := e.Err
   548  	if e.Addr != "" {
   549  		s = "address " + e.Addr + ": " + s
   550  	}
   551  	return s
   552  }
   553  
   554  func (e *AddrError) Timeout() bool   { return false }
   555  func (e *AddrError) Temporary() bool { return false }
   556  
   557  type UnknownNetworkError string
   558  
   559  func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
   560  func (e UnknownNetworkError) Timeout() bool   { return false }
   561  func (e UnknownNetworkError) Temporary() bool { return false }
   562  
   563  type InvalidAddrError string
   564  
   565  func (e InvalidAddrError) Error() string   { return string(e) }
   566  func (e InvalidAddrError) Timeout() bool   { return false }
   567  func (e InvalidAddrError) Temporary() bool { return false }
   568  
   569  // DNSConfigError represents an error reading the machine's DNS configuration.
   570  // (No longer used; kept for compatibility.)
   571  type DNSConfigError struct {
   572  	Err error
   573  }
   574  
   575  func (e *DNSConfigError) Unwrap() error   { return e.Err }
   576  func (e *DNSConfigError) Error() string   { return "error reading DNS config: " + e.Err.Error() }
   577  func (e *DNSConfigError) Timeout() bool   { return false }
   578  func (e *DNSConfigError) Temporary() bool { return false }
   579  
   580  // Various errors contained in DNSError.
   581  var (
   582  	errNoSuchHost = errors.New("no such host")
   583  )
   584  
   585  // DNSError represents a DNS lookup error.
   586  type DNSError struct {
   587  	Err         string // description of the error
   588  	Name        string // name looked for
   589  	Server      string // server used
   590  	IsTimeout   bool   // if true, timed out; not all timeouts set this
   591  	IsTemporary bool   // if true, error is temporary; not all errors set this
   592  	IsNotFound  bool   // if true, host could not be found
   593  }
   594  
   595  func (e *DNSError) Error() string {
   596  	if e == nil {
   597  		return "<nil>"
   598  	}
   599  	s := "lookup " + e.Name
   600  	if e.Server != "" {
   601  		s += " on " + e.Server
   602  	}
   603  	s += ": " + e.Err
   604  	return s
   605  }
   606  
   607  // Timeout reports whether the DNS lookup is known to have timed out.
   608  // This is not always known; a DNS lookup may fail due to a timeout
   609  // and return a DNSError for which Timeout returns false.
   610  func (e *DNSError) Timeout() bool { return e.IsTimeout }
   611  
   612  // Temporary reports whether the DNS error is known to be temporary.
   613  // This is not always known; a DNS lookup may fail due to a temporary
   614  // error and return a DNSError for which Temporary returns false.
   615  func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary }
   616  
   617  type writerOnly struct {
   618  	io.Writer
   619  }
   620  
   621  // Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
   622  // applicable.
   623  func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
   624  	// Use wrapper to hide existing r.ReadFrom from io.Copy.
   625  	return io.Copy(writerOnly{w}, r)
   626  }
   627  
   628  // Limit the number of concurrent cgo-using goroutines, because
   629  // each will block an entire operating system thread. The usual culprit
   630  // is resolving many DNS names in separate goroutines but the DNS
   631  // server is not responding. Then the many lookups each use a different
   632  // thread, and the system or the program runs out of threads.
   633  
   634  var threadLimit chan struct{}
   635  
   636  var threadOnce sync.Once
   637  
   638  func acquireThread() {
   639  	threadOnce.Do(func() {
   640  		threadLimit = make(chan struct{}, concurrentThreadsLimit())
   641  	})
   642  	threadLimit <- struct{}{}
   643  }
   644  
   645  func releaseThread() {
   646  	<-threadLimit
   647  }
   648  
   649  // buffersWriter is the interface implemented by Conns that support a
   650  // "writev"-like batch write optimization.
   651  // writeBuffers should fully consume and write all chunks from the
   652  // provided Buffers, else it should report a non-nil error.
   653  type buffersWriter interface {
   654  	writeBuffers(*Buffers) (int64, error)
   655  }
   656  
   657  // Buffers contains zero or more runs of bytes to write.
   658  //
   659  // On certain machines, for certain types of connections, this is
   660  // optimized into an OS-specific batch write operation (such as
   661  // "writev").
   662  type Buffers [][]byte
   663  
   664  var (
   665  	_ io.WriterTo = (*Buffers)(nil)
   666  	_ io.Reader   = (*Buffers)(nil)
   667  )
   668  
   669  func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
   670  	if wv, ok := w.(buffersWriter); ok {
   671  		return wv.writeBuffers(v)
   672  	}
   673  	for _, b := range *v {
   674  		nb, err := w.Write(b)
   675  		n += int64(nb)
   676  		if err != nil {
   677  			v.consume(n)
   678  			return n, err
   679  		}
   680  	}
   681  	v.consume(n)
   682  	return n, nil
   683  }
   684  
   685  func (v *Buffers) Read(p []byte) (n int, err error) {
   686  	for len(p) > 0 && len(*v) > 0 {
   687  		n0 := copy(p, (*v)[0])
   688  		v.consume(int64(n0))
   689  		p = p[n0:]
   690  		n += n0
   691  	}
   692  	if len(*v) == 0 {
   693  		err = io.EOF
   694  	}
   695  	return
   696  }
   697  
   698  func (v *Buffers) consume(n int64) {
   699  	for len(*v) > 0 {
   700  		ln0 := int64(len((*v)[0]))
   701  		if ln0 > n {
   702  			(*v)[0] = (*v)[0][n:]
   703  			return
   704  		}
   705  		n -= ln0
   706  		*v = (*v)[1:]
   707  	}
   708  }
   709  

View as plain text