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  	// The Error method panics if the error is nil.
   456  	Err error
   457  }
   458  
   459  func (e *OpError) Unwrap() error { return e.Err }
   460  
   461  func (e *OpError) Error() string {
   462  	if e == nil {
   463  		return "<nil>"
   464  	}
   465  	s := e.Op
   466  	if e.Net != "" {
   467  		s += " " + e.Net
   468  	}
   469  	if e.Source != nil {
   470  		s += " " + e.Source.String()
   471  	}
   472  	if e.Addr != nil {
   473  		if e.Source != nil {
   474  			s += "->"
   475  		} else {
   476  			s += " "
   477  		}
   478  		s += e.Addr.String()
   479  	}
   480  	s += ": " + e.Err.Error()
   481  	return s
   482  }
   483  
   484  var (
   485  	// aLongTimeAgo is a non-zero time, far in the past, used for
   486  	// immediate cancellation of dials.
   487  	aLongTimeAgo = time.Unix(1, 0)
   488  
   489  	// nonDeadline and noCancel are just zero values for
   490  	// readability with functions taking too many parameters.
   491  	noDeadline = time.Time{}
   492  	noCancel   = (chan struct{})(nil)
   493  )
   494  
   495  type timeout interface {
   496  	Timeout() bool
   497  }
   498  
   499  func (e *OpError) Timeout() bool {
   500  	if ne, ok := e.Err.(*os.SyscallError); ok {
   501  		t, ok := ne.Err.(timeout)
   502  		return ok && t.Timeout()
   503  	}
   504  	t, ok := e.Err.(timeout)
   505  	return ok && t.Timeout()
   506  }
   507  
   508  type temporary interface {
   509  	Temporary() bool
   510  }
   511  
   512  func (e *OpError) Temporary() bool {
   513  	// Treat ECONNRESET and ECONNABORTED as temporary errors when
   514  	// they come from calling accept. See issue 6163.
   515  	if e.Op == "accept" && isConnError(e.Err) {
   516  		return true
   517  	}
   518  
   519  	if ne, ok := e.Err.(*os.SyscallError); ok {
   520  		t, ok := ne.Err.(temporary)
   521  		return ok && t.Temporary()
   522  	}
   523  	t, ok := e.Err.(temporary)
   524  	return ok && t.Temporary()
   525  }
   526  
   527  // A ParseError is the error type of literal network address parsers.
   528  type ParseError struct {
   529  	// Type is the type of string that was expected, such as
   530  	// "IP address", "CIDR address".
   531  	Type string
   532  
   533  	// Text is the malformed text string.
   534  	Text string
   535  }
   536  
   537  func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }
   538  
   539  type AddrError struct {
   540  	Err  string
   541  	Addr string
   542  }
   543  
   544  func (e *AddrError) Error() string {
   545  	if e == nil {
   546  		return "<nil>"
   547  	}
   548  	s := e.Err
   549  	if e.Addr != "" {
   550  		s = "address " + e.Addr + ": " + s
   551  	}
   552  	return s
   553  }
   554  
   555  func (e *AddrError) Timeout() bool   { return false }
   556  func (e *AddrError) Temporary() bool { return false }
   557  
   558  type UnknownNetworkError string
   559  
   560  func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
   561  func (e UnknownNetworkError) Timeout() bool   { return false }
   562  func (e UnknownNetworkError) Temporary() bool { return false }
   563  
   564  type InvalidAddrError string
   565  
   566  func (e InvalidAddrError) Error() string   { return string(e) }
   567  func (e InvalidAddrError) Timeout() bool   { return false }
   568  func (e InvalidAddrError) Temporary() bool { return false }
   569  
   570  // DNSConfigError represents an error reading the machine's DNS configuration.
   571  // (No longer used; kept for compatibility.)
   572  type DNSConfigError struct {
   573  	Err error
   574  }
   575  
   576  func (e *DNSConfigError) Unwrap() error   { return e.Err }
   577  func (e *DNSConfigError) Error() string   { return "error reading DNS config: " + e.Err.Error() }
   578  func (e *DNSConfigError) Timeout() bool   { return false }
   579  func (e *DNSConfigError) Temporary() bool { return false }
   580  
   581  // Various errors contained in DNSError.
   582  var (
   583  	errNoSuchHost = errors.New("no such host")
   584  )
   585  
   586  // DNSError represents a DNS lookup error.
   587  type DNSError struct {
   588  	Err         string // description of the error
   589  	Name        string // name looked for
   590  	Server      string // server used
   591  	IsTimeout   bool   // if true, timed out; not all timeouts set this
   592  	IsTemporary bool   // if true, error is temporary; not all errors set this
   593  	IsNotFound  bool   // if true, host could not be found
   594  }
   595  
   596  func (e *DNSError) Error() string {
   597  	if e == nil {
   598  		return "<nil>"
   599  	}
   600  	s := "lookup " + e.Name
   601  	if e.Server != "" {
   602  		s += " on " + e.Server
   603  	}
   604  	s += ": " + e.Err
   605  	return s
   606  }
   607  
   608  // Timeout reports whether the DNS lookup is known to have timed out.
   609  // This is not always known; a DNS lookup may fail due to a timeout
   610  // and return a DNSError for which Timeout returns false.
   611  func (e *DNSError) Timeout() bool { return e.IsTimeout }
   612  
   613  // Temporary reports whether the DNS error is known to be temporary.
   614  // This is not always known; a DNS lookup may fail due to a temporary
   615  // error and return a DNSError for which Temporary returns false.
   616  func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary }
   617  
   618  type writerOnly struct {
   619  	io.Writer
   620  }
   621  
   622  // Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
   623  // applicable.
   624  func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
   625  	// Use wrapper to hide existing r.ReadFrom from io.Copy.
   626  	return io.Copy(writerOnly{w}, r)
   627  }
   628  
   629  // Limit the number of concurrent cgo-using goroutines, because
   630  // each will block an entire operating system thread. The usual culprit
   631  // is resolving many DNS names in separate goroutines but the DNS
   632  // server is not responding. Then the many lookups each use a different
   633  // thread, and the system or the program runs out of threads.
   634  
   635  var threadLimit chan struct{}
   636  
   637  var threadOnce sync.Once
   638  
   639  func acquireThread() {
   640  	threadOnce.Do(func() {
   641  		threadLimit = make(chan struct{}, concurrentThreadsLimit())
   642  	})
   643  	threadLimit <- struct{}{}
   644  }
   645  
   646  func releaseThread() {
   647  	<-threadLimit
   648  }
   649  
   650  // buffersWriter is the interface implemented by Conns that support a
   651  // "writev"-like batch write optimization.
   652  // writeBuffers should fully consume and write all chunks from the
   653  // provided Buffers, else it should report a non-nil error.
   654  type buffersWriter interface {
   655  	writeBuffers(*Buffers) (int64, error)
   656  }
   657  
   658  // Buffers contains zero or more runs of bytes to write.
   659  //
   660  // On certain machines, for certain types of connections, this is
   661  // optimized into an OS-specific batch write operation (such as
   662  // "writev").
   663  type Buffers [][]byte
   664  
   665  var (
   666  	_ io.WriterTo = (*Buffers)(nil)
   667  	_ io.Reader   = (*Buffers)(nil)
   668  )
   669  
   670  func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
   671  	if wv, ok := w.(buffersWriter); ok {
   672  		return wv.writeBuffers(v)
   673  	}
   674  	for _, b := range *v {
   675  		nb, err := w.Write(b)
   676  		n += int64(nb)
   677  		if err != nil {
   678  			v.consume(n)
   679  			return n, err
   680  		}
   681  	}
   682  	v.consume(n)
   683  	return n, nil
   684  }
   685  
   686  func (v *Buffers) Read(p []byte) (n int, err error) {
   687  	for len(p) > 0 && len(*v) > 0 {
   688  		n0 := copy(p, (*v)[0])
   689  		v.consume(int64(n0))
   690  		p = p[n0:]
   691  		n += n0
   692  	}
   693  	if len(*v) == 0 {
   694  		err = io.EOF
   695  	}
   696  	return
   697  }
   698  
   699  func (v *Buffers) consume(n int64) {
   700  	for len(*v) > 0 {
   701  		ln0 := int64(len((*v)[0]))
   702  		if ln0 > n {
   703  			(*v)[0] = (*v)[0][n:]
   704  			return
   705  		}
   706  		n -= ln0
   707  		*v = (*v)[1:]
   708  	}
   709  }
   710  

View as plain text