Source file src/net/net.go
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 On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS 50 request consumes 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. 58 59 On all systems (except Plan 9), when the cgo resolver is being used 60 this package applies a concurrent cgo lookup limit to prevent the system 61 from running out of system threads. Currently, it is limited to 500 concurrent lookups. 62 63 The resolver decision can be overridden by setting the netdns value of the 64 GODEBUG environment variable (see package runtime) to go or cgo, as in: 65 66 export GODEBUG=netdns=go # force pure Go resolver 67 export GODEBUG=netdns=cgo # force native resolver (cgo, win32) 68 69 The decision can also be forced while building the Go source tree 70 by setting the netgo or netcgo build tag. 71 72 A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver 73 to print debugging information about its decisions. 74 To force a particular resolver while also printing debugging information, 75 join the two settings by a plus sign, as in GODEBUG=netdns=go+1. 76 77 On macOS, if Go code that uses the net package is built with 78 -buildmode=c-archive, linking the resulting archive into a C program 79 requires passing -lresolv when linking the C code. 80 81 On Plan 9, the resolver always accesses /net/cs and /net/dns. 82 83 On Windows, in Go 1.18.x and earlier, the resolver always used C 84 library functions, such as GetAddrInfo and DnsQuery. 85 */ 86 package net 87 88 import ( 89 "context" 90 "errors" 91 "internal/poll" 92 "io" 93 "os" 94 "sync" 95 "syscall" 96 "time" 97 ) 98 99 // Addr represents a network end point address. 100 // 101 // The two methods [Addr.Network] and [Addr.String] conventionally return strings 102 // that can be passed as the arguments to [Dial], but the exact form 103 // and meaning of the strings is up to the implementation. 104 type Addr interface { 105 Network() string // name of the network (for example, "tcp", "udp") 106 String() string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80") 107 } 108 109 // Conn is a generic stream-oriented network connection. 110 // 111 // Multiple goroutines may invoke methods on a Conn simultaneously. 112 type Conn interface { 113 // Read reads data from the connection. 114 // Read can be made to time out and return an error after a fixed 115 // time limit; see SetDeadline and SetReadDeadline. 116 Read(b []byte) (n int, err error) 117 118 // Write writes data to the connection. 119 // Write can be made to time out and return an error after a fixed 120 // time limit; see SetDeadline and SetWriteDeadline. 121 Write(b []byte) (n int, err error) 122 123 // Close closes the connection. 124 // Any blocked Read or Write operations will be unblocked and return errors. 125 Close() error 126 127 // LocalAddr returns the local network address, if known. 128 LocalAddr() Addr 129 130 // RemoteAddr returns the remote network address, if known. 131 RemoteAddr() Addr 132 133 // SetDeadline sets the read and write deadlines associated 134 // with the connection. It is equivalent to calling both 135 // SetReadDeadline and SetWriteDeadline. 136 // 137 // A deadline is an absolute time after which I/O operations 138 // fail instead of blocking. The deadline applies to all future 139 // and pending I/O, not just the immediately following call to 140 // Read or Write. After a deadline has been exceeded, the 141 // connection can be refreshed by setting a deadline in the future. 142 // 143 // If the deadline is exceeded a call to Read or Write or to other 144 // I/O methods will return an error that wraps os.ErrDeadlineExceeded. 145 // This can be tested using errors.Is(err, os.ErrDeadlineExceeded). 146 // The error's Timeout method will return true, but note that there 147 // are other possible errors for which the Timeout method will 148 // return true even if the deadline has not been exceeded. 149 // 150 // An idle timeout can be implemented by repeatedly extending 151 // the deadline after successful Read or Write calls. 152 // 153 // A zero value for t means I/O operations will not time out. 154 SetDeadline(t time.Time) error 155 156 // SetReadDeadline sets the deadline for future Read calls 157 // and any currently-blocked Read call. 158 // A zero value for t means Read will not time out. 159 SetReadDeadline(t time.Time) error 160 161 // SetWriteDeadline sets the deadline for future Write calls 162 // and any currently-blocked Write call. 163 // Even if write times out, it may return n > 0, indicating that 164 // some of the data was successfully written. 165 // A zero value for t means Write will not time out. 166 SetWriteDeadline(t time.Time) error 167 } 168 169 type conn struct { 170 fd *netFD 171 } 172 173 func (c *conn) ok() bool { return c != nil && c.fd != nil } 174 175 // Implementation of the Conn interface. 176 177 // Read implements the Conn Read method. 178 func (c *conn) Read(b []byte) (int, error) { 179 if !c.ok() { 180 return 0, syscall.EINVAL 181 } 182 n, err := c.fd.Read(b) 183 if err != nil && err != io.EOF { 184 err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 185 } 186 return n, err 187 } 188 189 // Write implements the Conn Write method. 190 func (c *conn) Write(b []byte) (int, error) { 191 if !c.ok() { 192 return 0, syscall.EINVAL 193 } 194 n, err := c.fd.Write(b) 195 if err != nil { 196 err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 197 } 198 return n, err 199 } 200 201 // Close closes the connection. 202 func (c *conn) Close() error { 203 if !c.ok() { 204 return syscall.EINVAL 205 } 206 err := c.fd.Close() 207 if err != nil { 208 err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 209 } 210 return err 211 } 212 213 // LocalAddr returns the local network address. 214 // The Addr returned is shared by all invocations of LocalAddr, so 215 // do not modify it. 216 func (c *conn) LocalAddr() Addr { 217 if !c.ok() { 218 return nil 219 } 220 return c.fd.laddr 221 } 222 223 // RemoteAddr returns the remote network address. 224 // The Addr returned is shared by all invocations of RemoteAddr, so 225 // do not modify it. 226 func (c *conn) RemoteAddr() Addr { 227 if !c.ok() { 228 return nil 229 } 230 return c.fd.raddr 231 } 232 233 // SetDeadline implements the Conn SetDeadline method. 234 func (c *conn) SetDeadline(t time.Time) error { 235 if !c.ok() { 236 return syscall.EINVAL 237 } 238 if err := c.fd.SetDeadline(t); err != nil { 239 return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} 240 } 241 return nil 242 } 243 244 // SetReadDeadline implements the Conn SetReadDeadline method. 245 func (c *conn) SetReadDeadline(t time.Time) error { 246 if !c.ok() { 247 return syscall.EINVAL 248 } 249 if err := c.fd.SetReadDeadline(t); err != nil { 250 return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} 251 } 252 return nil 253 } 254 255 // SetWriteDeadline implements the Conn SetWriteDeadline method. 256 func (c *conn) SetWriteDeadline(t time.Time) error { 257 if !c.ok() { 258 return syscall.EINVAL 259 } 260 if err := c.fd.SetWriteDeadline(t); err != nil { 261 return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} 262 } 263 return nil 264 } 265 266 // SetReadBuffer sets the size of the operating system's 267 // receive buffer associated with the connection. 268 func (c *conn) SetReadBuffer(bytes int) error { 269 if !c.ok() { 270 return syscall.EINVAL 271 } 272 if err := setReadBuffer(c.fd, bytes); err != nil { 273 return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} 274 } 275 return nil 276 } 277 278 // SetWriteBuffer sets the size of the operating system's 279 // transmit buffer associated with the connection. 280 func (c *conn) SetWriteBuffer(bytes int) error { 281 if !c.ok() { 282 return syscall.EINVAL 283 } 284 if err := setWriteBuffer(c.fd, bytes); err != nil { 285 return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} 286 } 287 return nil 288 } 289 290 // File returns a copy of the underlying [os.File]. 291 // It is the caller's responsibility to close f when finished. 292 // Closing c does not affect f, and closing f does not affect c. 293 // 294 // The returned os.File's file descriptor is different from the connection's. 295 // Attempting to change properties of the original using this duplicate 296 // may or may not have the desired effect. 297 func (c *conn) File() (f *os.File, err error) { 298 f, err = c.fd.dup() 299 if err != nil { 300 err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 301 } 302 return 303 } 304 305 // PacketConn is a generic packet-oriented network connection. 306 // 307 // Multiple goroutines may invoke methods on a PacketConn simultaneously. 308 type PacketConn interface { 309 // ReadFrom reads a packet from the connection, 310 // copying the payload into p. It returns the number of 311 // bytes copied into p and the return address that 312 // was on the packet. 313 // It returns the number of bytes read (0 <= n <= len(p)) 314 // and any error encountered. Callers should always process 315 // the n > 0 bytes returned before considering the error err. 316 // ReadFrom can be made to time out and return an error after a 317 // fixed time limit; see SetDeadline and SetReadDeadline. 318 ReadFrom(p []byte) (n int, addr Addr, err error) 319 320 // WriteTo writes a packet with payload p to addr. 321 // WriteTo can be made to time out and return an Error after a 322 // fixed time limit; see SetDeadline and SetWriteDeadline. 323 // On packet-oriented connections, write timeouts are rare. 324 WriteTo(p []byte, addr Addr) (n int, err error) 325 326 // Close closes the connection. 327 // Any blocked ReadFrom or WriteTo operations will be unblocked and return errors. 328 Close() error 329 330 // LocalAddr returns the local network address, if known. 331 LocalAddr() Addr 332 333 // SetDeadline sets the read and write deadlines associated 334 // with the connection. It is equivalent to calling both 335 // SetReadDeadline and SetWriteDeadline. 336 // 337 // A deadline is an absolute time after which I/O operations 338 // fail instead of blocking. The deadline applies to all future 339 // and pending I/O, not just the immediately following call to 340 // Read or Write. After a deadline has been exceeded, the 341 // connection can be refreshed by setting a deadline in the future. 342 // 343 // If the deadline is exceeded a call to Read or Write or to other 344 // I/O methods will return an error that wraps os.ErrDeadlineExceeded. 345 // This can be tested using errors.Is(err, os.ErrDeadlineExceeded). 346 // The error's Timeout method will return true, but note that there 347 // are other possible errors for which the Timeout method will 348 // return true even if the deadline has not been exceeded. 349 // 350 // An idle timeout can be implemented by repeatedly extending 351 // the deadline after successful ReadFrom or WriteTo calls. 352 // 353 // A zero value for t means I/O operations will not time out. 354 SetDeadline(t time.Time) error 355 356 // SetReadDeadline sets the deadline for future ReadFrom calls 357 // and any currently-blocked ReadFrom call. 358 // A zero value for t means ReadFrom will not time out. 359 SetReadDeadline(t time.Time) error 360 361 // SetWriteDeadline sets the deadline for future WriteTo calls 362 // and any currently-blocked WriteTo call. 363 // Even if write times out, it may return n > 0, indicating that 364 // some of the data was successfully written. 365 // A zero value for t means WriteTo will not time out. 366 SetWriteDeadline(t time.Time) error 367 } 368 369 var listenerBacklogCache struct { 370 sync.Once 371 val int 372 } 373 374 // listenerBacklog is a caching wrapper around maxListenerBacklog. 375 func listenerBacklog() int { 376 listenerBacklogCache.Do(func() { listenerBacklogCache.val = maxListenerBacklog() }) 377 return listenerBacklogCache.val 378 } 379 380 // A Listener is a generic network listener for stream-oriented protocols. 381 // 382 // Multiple goroutines may invoke methods on a Listener simultaneously. 383 type Listener interface { 384 // Accept waits for and returns the next connection to the listener. 385 Accept() (Conn, error) 386 387 // Close closes the listener. 388 // Any blocked Accept operations will be unblocked and return errors. 389 Close() error 390 391 // Addr returns the listener's network address. 392 Addr() Addr 393 } 394 395 // An Error represents a network error. 396 type Error interface { 397 error 398 Timeout() bool // Is the error a timeout? 399 400 // Deprecated: Temporary errors are not well-defined. 401 // Most "temporary" errors are timeouts, and the few exceptions are surprising. 402 // Do not use this method. 403 Temporary() bool 404 } 405 406 // Various errors contained in OpError. 407 var ( 408 // For connection setup operations. 409 errNoSuitableAddress = errors.New("no suitable address found") 410 411 // For connection setup and write operations. 412 errMissingAddress = errors.New("missing address") 413 414 // For both read and write operations. 415 errCanceled = canceledError{} 416 ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection") 417 ) 418 419 // canceledError lets us return the same error string we have always 420 // returned, while still being Is context.Canceled. 421 type canceledError struct{} 422 423 func (canceledError) Error() string { return "operation was canceled" } 424 425 func (canceledError) Is(err error) bool { return err == context.Canceled } 426 427 // mapErr maps from the context errors to the historical internal net 428 // error values. 429 func mapErr(err error) error { 430 switch err { 431 case context.Canceled: 432 return errCanceled 433 case context.DeadlineExceeded: 434 return errTimeout 435 default: 436 return err 437 } 438 } 439 440 // OpError is the error type usually returned by functions in the net 441 // package. It describes the operation, network type, and address of 442 // an error. 443 type OpError struct { 444 // Op is the operation which caused the error, such as 445 // "read" or "write". 446 Op string 447 448 // Net is the network type on which this error occurred, 449 // such as "tcp" or "udp6". 450 Net string 451 452 // For operations involving a remote network connection, like 453 // Dial, Read, or Write, Source is the corresponding local 454 // network address. 455 Source Addr 456 457 // Addr is the network address for which this error occurred. 458 // For local operations, like Listen or SetDeadline, Addr is 459 // the address of the local endpoint being manipulated. 460 // For operations involving a remote network connection, like 461 // Dial, Read, or Write, Addr is the remote address of that 462 // connection. 463 Addr Addr 464 465 // Err is the error that occurred during the operation. 466 // The Error method panics if the error is nil. 467 Err error 468 } 469 470 func (e *OpError) Unwrap() error { return e.Err } 471 472 func (e *OpError) Error() string { 473 if e == nil { 474 return "<nil>" 475 } 476 s := e.Op 477 if e.Net != "" { 478 s += " " + e.Net 479 } 480 if e.Source != nil { 481 s += " " + e.Source.String() 482 } 483 if e.Addr != nil { 484 if e.Source != nil { 485 s += "->" 486 } else { 487 s += " " 488 } 489 s += e.Addr.String() 490 } 491 s += ": " + e.Err.Error() 492 return s 493 } 494 495 var ( 496 // aLongTimeAgo is a non-zero time, far in the past, used for 497 // immediate cancellation of dials. 498 aLongTimeAgo = time.Unix(1, 0) 499 500 // noDeadline and noCancel are just zero values for 501 // readability with functions taking too many parameters. 502 noDeadline = time.Time{} 503 noCancel = (chan struct{})(nil) 504 ) 505 506 type timeout interface { 507 Timeout() bool 508 } 509 510 func (e *OpError) Timeout() bool { 511 if ne, ok := e.Err.(*os.SyscallError); ok { 512 t, ok := ne.Err.(timeout) 513 return ok && t.Timeout() 514 } 515 t, ok := e.Err.(timeout) 516 return ok && t.Timeout() 517 } 518 519 type temporary interface { 520 Temporary() bool 521 } 522 523 func (e *OpError) Temporary() bool { 524 // Treat ECONNRESET and ECONNABORTED as temporary errors when 525 // they come from calling accept. See issue 6163. 526 if e.Op == "accept" && isConnError(e.Err) { 527 return true 528 } 529 530 if ne, ok := e.Err.(*os.SyscallError); ok { 531 t, ok := ne.Err.(temporary) 532 return ok && t.Temporary() 533 } 534 t, ok := e.Err.(temporary) 535 return ok && t.Temporary() 536 } 537 538 // A ParseError is the error type of literal network address parsers. 539 type ParseError struct { 540 // Type is the type of string that was expected, such as 541 // "IP address", "CIDR address". 542 Type string 543 544 // Text is the malformed text string. 545 Text string 546 } 547 548 func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text } 549 550 func (e *ParseError) Timeout() bool { return false } 551 func (e *ParseError) Temporary() bool { return false } 552 553 type AddrError struct { 554 Err string 555 Addr string 556 } 557 558 func (e *AddrError) Error() string { 559 if e == nil { 560 return "<nil>" 561 } 562 s := e.Err 563 if e.Addr != "" { 564 s = "address " + e.Addr + ": " + s 565 } 566 return s 567 } 568 569 func (e *AddrError) Timeout() bool { return false } 570 func (e *AddrError) Temporary() bool { return false } 571 572 type UnknownNetworkError string 573 574 func (e UnknownNetworkError) Error() string { return "unknown network " + string(e) } 575 func (e UnknownNetworkError) Timeout() bool { return false } 576 func (e UnknownNetworkError) Temporary() bool { return false } 577 578 type InvalidAddrError string 579 580 func (e InvalidAddrError) Error() string { return string(e) } 581 func (e InvalidAddrError) Timeout() bool { return false } 582 func (e InvalidAddrError) Temporary() bool { return false } 583 584 // errTimeout exists to return the historical "i/o timeout" string 585 // for context.DeadlineExceeded. See mapErr. 586 // It is also used when Dialer.Deadline is exceeded. 587 // error.Is(errTimeout, context.DeadlineExceeded) returns true. 588 // 589 // TODO(iant): We could consider changing this to os.ErrDeadlineExceeded 590 // in the future, if we make 591 // 592 // errors.Is(os.ErrDeadlineExceeded, context.DeadlineExceeded) 593 // 594 // return true. 595 var errTimeout error = &timeoutError{} 596 597 type timeoutError struct{} 598 599 func (e *timeoutError) Error() string { return "i/o timeout" } 600 func (e *timeoutError) Timeout() bool { return true } 601 func (e *timeoutError) Temporary() bool { return true } 602 603 func (e *timeoutError) Is(err error) bool { 604 return err == context.DeadlineExceeded 605 } 606 607 // DNSConfigError represents an error reading the machine's DNS configuration. 608 // (No longer used; kept for compatibility.) 609 type DNSConfigError struct { 610 Err error 611 } 612 613 func (e *DNSConfigError) Unwrap() error { return e.Err } 614 func (e *DNSConfigError) Error() string { return "error reading DNS config: " + e.Err.Error() } 615 func (e *DNSConfigError) Timeout() bool { return false } 616 func (e *DNSConfigError) Temporary() bool { return false } 617 618 // Various errors contained in DNSError. 619 var ( 620 errNoSuchHost = errors.New("no such host") 621 ) 622 623 // DNSError represents a DNS lookup error. 624 type DNSError struct { 625 Err string // description of the error 626 Name string // name looked for 627 Server string // server used 628 IsTimeout bool // if true, timed out; not all timeouts set this 629 IsTemporary bool // if true, error is temporary; not all errors set this 630 631 // IsNotFound is set to true when the requested name does not 632 // contain any records of the requested type (data not found), 633 // or the name itself was not found (NXDOMAIN). 634 IsNotFound bool 635 } 636 637 func (e *DNSError) Error() string { 638 if e == nil { 639 return "<nil>" 640 } 641 s := "lookup " + e.Name 642 if e.Server != "" { 643 s += " on " + e.Server 644 } 645 s += ": " + e.Err 646 return s 647 } 648 649 // Timeout reports whether the DNS lookup is known to have timed out. 650 // This is not always known; a DNS lookup may fail due to a timeout 651 // and return a [DNSError] for which Timeout returns false. 652 func (e *DNSError) Timeout() bool { return e.IsTimeout } 653 654 // Temporary reports whether the DNS error is known to be temporary. 655 // This is not always known; a DNS lookup may fail due to a temporary 656 // error and return a [DNSError] for which Temporary returns false. 657 func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary } 658 659 // errClosed exists just so that the docs for ErrClosed don't mention 660 // the internal package poll. 661 var errClosed = poll.ErrNetClosing 662 663 // ErrClosed is the error returned by an I/O call on a network 664 // connection that has already been closed, or that is closed by 665 // another goroutine before the I/O is completed. This may be wrapped 666 // in another error, and should normally be tested using 667 // errors.Is(err, net.ErrClosed). 668 var ErrClosed error = errClosed 669 670 // noReadFrom can be embedded alongside another type to 671 // hide the ReadFrom method of that other type. 672 type noReadFrom struct{} 673 674 // ReadFrom hides another ReadFrom method. 675 // It should never be called. 676 func (noReadFrom) ReadFrom(io.Reader) (int64, error) { 677 panic("can't happen") 678 } 679 680 // tcpConnWithoutReadFrom implements all the methods of *TCPConn other 681 // than ReadFrom. This is used to permit ReadFrom to call io.Copy 682 // without leading to a recursive call to ReadFrom. 683 type tcpConnWithoutReadFrom struct { 684 noReadFrom 685 *TCPConn 686 } 687 688 // Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't 689 // applicable. 690 func genericReadFrom(c *TCPConn, r io.Reader) (n int64, err error) { 691 // Use wrapper to hide existing r.ReadFrom from io.Copy. 692 return io.Copy(tcpConnWithoutReadFrom{TCPConn: c}, r) 693 } 694 695 // noWriteTo can be embedded alongside another type to 696 // hide the WriteTo method of that other type. 697 type noWriteTo struct{} 698 699 // WriteTo hides another WriteTo method. 700 // It should never be called. 701 func (noWriteTo) WriteTo(io.Writer) (int64, error) { 702 panic("can't happen") 703 } 704 705 // tcpConnWithoutWriteTo implements all the methods of *TCPConn other 706 // than WriteTo. This is used to permit WriteTo to call io.Copy 707 // without leading to a recursive call to WriteTo. 708 type tcpConnWithoutWriteTo struct { 709 noWriteTo 710 *TCPConn 711 } 712 713 // Fallback implementation of io.WriterTo's WriteTo, when zero-copy isn't applicable. 714 func genericWriteTo(c *TCPConn, w io.Writer) (n int64, err error) { 715 // Use wrapper to hide existing w.WriteTo from io.Copy. 716 return io.Copy(w, tcpConnWithoutWriteTo{TCPConn: c}) 717 } 718 719 // Limit the number of concurrent cgo-using goroutines, because 720 // each will block an entire operating system thread. The usual culprit 721 // is resolving many DNS names in separate goroutines but the DNS 722 // server is not responding. Then the many lookups each use a different 723 // thread, and the system or the program runs out of threads. 724 725 var threadLimit chan struct{} 726 727 var threadOnce sync.Once 728 729 func acquireThread(ctx context.Context) error { 730 threadOnce.Do(func() { 731 threadLimit = make(chan struct{}, concurrentThreadsLimit()) 732 }) 733 select { 734 case threadLimit <- struct{}{}: 735 return nil 736 case <-ctx.Done(): 737 return ctx.Err() 738 } 739 } 740 741 func releaseThread() { 742 <-threadLimit 743 } 744 745 // buffersWriter is the interface implemented by Conns that support a 746 // "writev"-like batch write optimization. 747 // writeBuffers should fully consume and write all chunks from the 748 // provided Buffers, else it should report a non-nil error. 749 type buffersWriter interface { 750 writeBuffers(*Buffers) (int64, error) 751 } 752 753 // Buffers contains zero or more runs of bytes to write. 754 // 755 // On certain machines, for certain types of connections, this is 756 // optimized into an OS-specific batch write operation (such as 757 // "writev"). 758 type Buffers [][]byte 759 760 var ( 761 _ io.WriterTo = (*Buffers)(nil) 762 _ io.Reader = (*Buffers)(nil) 763 ) 764 765 // WriteTo writes contents of the buffers to w. 766 // 767 // WriteTo implements [io.WriterTo] for [Buffers]. 768 // 769 // WriteTo modifies the slice v as well as v[i] for 0 <= i < len(v), 770 // but does not modify v[i][j] for any i, j. 771 func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) { 772 if wv, ok := w.(buffersWriter); ok { 773 return wv.writeBuffers(v) 774 } 775 for _, b := range *v { 776 nb, err := w.Write(b) 777 n += int64(nb) 778 if err != nil { 779 v.consume(n) 780 return n, err 781 } 782 } 783 v.consume(n) 784 return n, nil 785 } 786 787 // Read from the buffers. 788 // 789 // Read implements [io.Reader] for [Buffers]. 790 // 791 // Read modifies the slice v as well as v[i] for 0 <= i < len(v), 792 // but does not modify v[i][j] for any i, j. 793 func (v *Buffers) Read(p []byte) (n int, err error) { 794 for len(p) > 0 && len(*v) > 0 { 795 n0 := copy(p, (*v)[0]) 796 v.consume(int64(n0)) 797 p = p[n0:] 798 n += n0 799 } 800 if len(*v) == 0 { 801 err = io.EOF 802 } 803 return 804 } 805 806 func (v *Buffers) consume(n int64) { 807 for len(*v) > 0 { 808 ln0 := int64(len((*v)[0])) 809 if ln0 > n { 810 (*v)[0] = (*v)[0][n:] 811 return 812 } 813 n -= ln0 814 (*v)[0] = nil 815 *v = (*v)[1:] 816 } 817 } 818