// Copyright 2010 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package netimport ()const (// defaultTCPKeepAliveIdle is a default constant value for TCP_KEEPIDLE. // See go.dev/issue/31510 for details. defaultTCPKeepAliveIdle = 15 * time.Second// defaultTCPKeepAliveInterval is a default constant value for TCP_KEEPINTVL. // It is the same as defaultTCPKeepAliveIdle, see go.dev/issue/31510 for details. defaultTCPKeepAliveInterval = 15 * time.Second// defaultTCPKeepAliveCount is a default constant value for TCP_KEEPCNT. defaultTCPKeepAliveCount = 9// For the moment, MultiPath TCP is not used by default // See go.dev/issue/56539 defaultMPTCPEnabled = false)var multipathtcp = godebug.New("multipathtcp")// mptcpStatus is a tristate for Multipath TCP, see go.dev/issue/56539type mptcpStatus uint8const (// The value 0 is the system default, linked to defaultMPTCPEnabled mptcpUseDefault mptcpStatus = iota mptcpEnabled mptcpDisabled)func ( *mptcpStatus) () bool {switch * {casemptcpEnabled:returntruecasemptcpDisabled:returnfalse }// If MPTCP is forced via GODEBUG=multipathtcp=1ifmultipathtcp.Value() == "1" {multipathtcp.IncNonDefault()returntrue }returndefaultMPTCPEnabled}func ( *mptcpStatus) ( bool) {if { * = mptcpEnabled } else { * = mptcpDisabled }}// A Dialer contains options for connecting to an address.//// The zero value for each field is equivalent to dialing// without that option. Dialing with the zero value of Dialer// is therefore equivalent to just calling the [Dial] function.//// It is safe to call Dialer's methods concurrently.typeDialerstruct {// Timeout is the maximum amount of time a dial will wait for // a connect to complete. If Deadline is also set, it may fail // earlier. // // The default is no timeout. // // When using TCP and dialing a host name with multiple IP // addresses, the timeout may be divided between them. // // With or without a timeout, the operating system may impose // its own earlier timeout. For instance, TCP timeouts are // often around 3 minutes. Timeout time.Duration// Deadline is the absolute point in time after which dials // will fail. If Timeout is set, it may fail earlier. // Zero means no deadline, or dependent on the operating system // as with the Timeout option. Deadline time.Time// LocalAddr is the local address to use when dialing an // address. The address must be of a compatible type for the // network being dialed. // If nil, a local address is automatically chosen. LocalAddr Addr// DualStack previously enabled RFC 6555 Fast Fallback // support, also known as "Happy Eyeballs", in which IPv4 is // tried soon if IPv6 appears to be misconfigured and // hanging. // // Deprecated: Fast Fallback is enabled by default. To // disable, set FallbackDelay to a negative value. DualStack bool// FallbackDelay specifies the length of time to wait before // spawning a RFC 6555 Fast Fallback connection. That is, this // is the amount of time to wait for IPv6 to succeed before // assuming that IPv6 is misconfigured and falling back to // IPv4. // // If zero, a default delay of 300ms is used. // A negative value disables Fast Fallback support. FallbackDelay time.Duration// KeepAlive specifies the interval between keep-alive // probes for an active network connection. // // KeepAlive is ignored if KeepAliveConfig.Enable is true. // // If zero, keep-alive probes are sent with a default value // (currently 15 seconds), if supported by the protocol and operating // system. Network protocols or operating systems that do // not support keep-alive ignore this field. // If negative, keep-alive probes are disabled. KeepAlive time.Duration// KeepAliveConfig specifies the keep-alive probe configuration // for an active network connection, when supported by the // protocol and operating system. // // If KeepAliveConfig.Enable is true, keep-alive probes are enabled. // If KeepAliveConfig.Enable is false and KeepAlive is negative, // keep-alive probes are disabled. KeepAliveConfig KeepAliveConfig// Resolver optionally specifies an alternate resolver to use. Resolver *Resolver// Cancel is an optional channel whose closure indicates that // the dial should be canceled. Not all types of dials support // cancellation. // // Deprecated: Use DialContext instead. Cancel <-chanstruct{}// If Control is not nil, it is called after creating the network // connection but before actually dialing. // // Network and address parameters passed to Control function are not // necessarily the ones passed to Dial. For example, passing "tcp" to Dial // will cause the Control function to be called with "tcp4" or "tcp6". // // Control is ignored if ControlContext is not nil. Control func(network, address string, c syscall.RawConn) error// If ControlContext is not nil, it is called after creating the network // connection but before actually dialing. // // Network and address parameters passed to ControlContext function are not // necessarily the ones passed to Dial. For example, passing "tcp" to Dial // will cause the ControlContext function to be called with "tcp4" or "tcp6". // // If ControlContext is not nil, Control is ignored. ControlContext func(ctx context.Context, network, address string, c syscall.RawConn) error// If mptcpStatus is set to a value allowing Multipath TCP (MPTCP) to be // used, any call to Dial with "tcp(4|6)" as network will use MPTCP if // supported by the operating system. mptcpStatus mptcpStatus}func ( *Dialer) () bool { return .FallbackDelay >= 0 }func minNonzeroTime(, time.Time) time.Time {if .IsZero() {return }if .IsZero() || .Before() {return }return}// deadline returns the earliest of:// - now+Timeout// - d.Deadline// - the context's deadline//// Or zero, if none of Timeout, Deadline, or context's deadline is set.func ( *Dialer) ( context.Context, time.Time) ( time.Time) {if .Timeout != 0 { // including negative, for historical reasons = .Add(.Timeout) }if , := .Deadline(); { = minNonzeroTime(, ) }returnminNonzeroTime(, .Deadline)}func ( *Dialer) () *Resolver {if .Resolver != nil {return .Resolver }returnDefaultResolver}// partialDeadline returns the deadline to use for a single address,// when multiple addresses are pending.func partialDeadline(, time.Time, int) (time.Time, error) {if .IsZero() {return , nil } := .Sub()if <= 0 {returntime.Time{}, errTimeout }// Tentatively allocate equal time to each remaining address. := / time.Duration()// If the time per address is too short, steal from the end of the list.const = 2 * time.Secondif < {if < { = } else { = } }return .Add(), nil}func ( *Dialer) () time.Duration {if .FallbackDelay > 0 {return .FallbackDelay } else {return300 * time.Millisecond }}func parseNetwork( context.Context, string, bool) ( string, int, error) { := bytealg.LastIndexByteString(, ':')if < 0 { // no colonswitch {case"tcp", "tcp4", "tcp6":case"udp", "udp4", "udp6":case"ip", "ip4", "ip6":if {return"", 0, UnknownNetworkError() }case"unix", "unixgram", "unixpacket":default:return"", 0, UnknownNetworkError() }return , 0, nil } = [:]switch {case"ip", "ip4", "ip6": := [+1:] , , := dtoi()if ! || != len() { , = lookupProtocol(, )if != nil {return"", 0, } }return , , nil }return"", 0, UnknownNetworkError()}// resolveAddrList resolves addr using hint and returns a list of// addresses. The result contains at least one address when error is// nil.func ( *Resolver) ( context.Context, , , string, Addr) (addrList, error) { , , := parseNetwork(, , true)if != nil {returnnil, }if == "dial" && == "" {returnnil, errMissingAddress }switch {case"unix", "unixgram", "unixpacket": , := ResolveUnixAddr(, )if != nil {returnnil, }if == "dial" && != nil && .Network() != .Network() {returnnil, &AddrError{Err: "mismatched local address type", Addr: .String()} }returnaddrList{}, nil } , := .internetAddrList(, , )if != nil || != "dial" || == nil {return , }var ( *TCPAddr *UDPAddr *IPAddrbool )switch hint := .(type) {case *TCPAddr: = = .isWildcard()case *UDPAddr: = = .isWildcard()case *IPAddr: = = .isWildcard() } := [:0]for , := range {if .Network() != .Network() {returnnil, &AddrError{Err: "mismatched local address type", Addr: .String()} }switch addr := .(type) {case *TCPAddr:if ! && !.isWildcard() && !.IP.matchAddrFamily(.IP) {continue } = append(, )case *UDPAddr:if ! && !.isWildcard() && !.IP.matchAddrFamily(.IP) {continue } = append(, )case *IPAddr:if ! && !.isWildcard() && !.IP.matchAddrFamily(.IP) {continue } = append(, ) } }iflen() == 0 {returnnil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: .String()} }return , nil}// MultipathTCP reports whether MPTCP will be used.//// This method doesn't check if MPTCP is supported by the operating// system or not.func ( *Dialer) () bool {return .mptcpStatus.get()}// SetMultipathTCP directs the [Dial] methods to use, or not use, MPTCP,// if supported by the operating system. This method overrides the// system default and the GODEBUG=multipathtcp=... setting if any.//// If MPTCP is not available on the host or not supported by the server,// the Dial methods will fall back to TCP.func ( *Dialer) ( bool) { .mptcpStatus.set()}// Dial connects to the address on the named network.//// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and// "unixpacket".//// For TCP and UDP networks, the address has the form "host:port".// The host must be a literal IP address, or a host name that can be// resolved to IP addresses.// The port must be a literal port number or a service name.// If the host is a literal IPv6 address it must be enclosed in square// brackets, as in "[2001:db8::1]:80" or "[fe80::1%zone]:80".// The zone specifies the scope of the literal IPv6 address as defined// in RFC 4007.// The functions [JoinHostPort] and [SplitHostPort] manipulate a pair of// host and port in this form.// When using TCP, and the host resolves to multiple IP addresses,// Dial will try each IP address in order until one succeeds.//// Examples://// Dial("tcp", "golang.org:http")// Dial("tcp", "192.0.2.1:http")// Dial("tcp", "198.51.100.1:80")// Dial("udp", "[2001:db8::1]:domain")// Dial("udp", "[fe80::1%lo0]:53")// Dial("tcp", ":80")//// For IP networks, the network must be "ip", "ip4" or "ip6" followed// by a colon and a literal protocol number or a protocol name, and// the address has the form "host". The host must be a literal IP// address or a literal IPv6 address with zone.// It depends on each operating system how the operating system// behaves with a non-well known protocol number such as "0" or "255".//// Examples://// Dial("ip4:1", "192.0.2.1")// Dial("ip6:ipv6-icmp", "2001:db8::1")// Dial("ip6:58", "fe80::1%lo0")//// For TCP, UDP and IP networks, if the host is empty or a literal// unspecified IP address, as in ":80", "0.0.0.0:80" or "[::]:80" for// TCP and UDP, "", "0.0.0.0" or "::" for IP, the local system is// assumed.//// For Unix networks, the address must be a file system path.func (, string) (Conn, error) {varDialerreturn .Dial(, )}// DialTimeout acts like [Dial] but takes a timeout.//// The timeout includes name resolution, if required.// When using TCP, and the host in the address parameter resolves to// multiple IP addresses, the timeout is spread over each consecutive// dial, such that each is given an appropriate fraction of the time// to connect.//// See func Dial for a description of the network and address// parameters.func (, string, time.Duration) (Conn, error) { := Dialer{Timeout: }return .Dial(, )}// sysDialer contains a Dial's parameters and configuration.type sysDialer struct {Dialer network, address string testHookDialTCP func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error)}// Dial connects to the address on the named network.//// See func Dial for a description of the network and address// parameters.//// Dial uses [context.Background] internally; to specify the context, use// [Dialer.DialContext].func ( *Dialer) (, string) (Conn, error) {return .DialContext(context.Background(), , )}// DialContext connects to the address on the named network using// the provided context.//// The provided Context must be non-nil. If the context expires before// the connection is complete, an error is returned. Once successfully// connected, any expiration of the context will not affect the// connection.//// When using TCP, and the host in the address parameter resolves to multiple// network addresses, any dial timeout (from d.Timeout or ctx) is spread// over each consecutive dial, such that each is given an appropriate// fraction of the time to connect.// For example, if a host has 4 IP addresses and the timeout is 1 minute,// the connect to each single address will be given 15 seconds to complete// before trying the next one.//// See func [Dial] for a description of the network and address// parameters.func ( *Dialer) ( context.Context, , string) (Conn, error) {if == nil {panic("nil context") } := .deadline(, time.Now())if !.IsZero() {testHookStepTime()if , := .Deadline(); ! || .Before() { , := context.WithDeadline(, )defer () = } }if := .Cancel; != nil { , := context.WithCancel()defer ()gofunc() {select {case<-: ()case<-.Done(): } }() = }// Shadow the nettrace (if any) during resolve so Connect events don't fire for DNS lookups. := if , := .Value(nettrace.TraceKey{}).(*nettrace.Trace); != nil { := * .ConnectStart = nil .ConnectDone = nil = context.WithValue(, nettrace.TraceKey{}, &) } , := .resolver().resolveAddrList(, "dial", , , .LocalAddr)if != nil {returnnil, &OpError{Op: "dial", Net: , Source: nil, Addr: nil, Err: } } := &sysDialer{Dialer: *,network: ,address: , }var , addrListif .dualStack() && == "tcp" { , = .partition(isIPv4) } else { = }return .dialParallel(, , )}// dialParallel races two copies of dialSerial, giving the first a// head start. It returns the first established connection and// closes the others. Otherwise it returns an error from the first// primary address.func ( *sysDialer) ( context.Context, , addrList) (Conn, error) {iflen() == 0 {return .dialSerial(, ) } := make(chanstruct{})deferclose()typestruct {Connerrorboolbool } := make(chan ) // unbuffered := func( context.Context, bool) { := if ! { = } , := .dialSerial(, )select {case<- {: , : , : , : true}:case<-:if != nil { .Close() } } }var , // Start the main racer. , := context.WithCancel()defer ()go (, true)// Start the timer for the fallback racer. := time.NewTimer(.fallbackDelay())defer .Stop()for {select {case<-.C: , := context.WithCancel()defer ()go (, false)case := <-:if . == nil {return ., nil }if . { = } else { = }if . && . {returnnil, . }if . && .Stop() {// If we were able to stop the timer, that means it // was running (hadn't yet started the fallback), but // we just got an error on the primary path, so start // the fallback immediately (in 0 nanoseconds). .Reset(0) } } }}// dialSerial connects to a list of addresses in sequence, returning// either the first successful connection, or the first error.func ( *sysDialer) ( context.Context, addrList) (Conn, error) {varerror// The error from the first address is most relevant.for , := range {select {case<-.Done():returnnil, &OpError{Op: "dial", Net: .network, Source: .LocalAddr, Addr: , Err: mapErr(.Err())}default: } := if , := .Deadline(); { , := partialDeadline(time.Now(), , len()-)if != nil {// Ran out of time.if == nil { = &OpError{Op: "dial", Net: .network, Source: .LocalAddr, Addr: , Err: } }break }if .Before() {varcontext.CancelFunc , = context.WithDeadline(, )defer () } } , := .dialSingle(, )if == nil {return , nil }if == nil { = } }if == nil { = &OpError{Op: "dial", Net: .network, Source: nil, Addr: nil, Err: errMissingAddress} }returnnil, }// dialSingle attempts to establish and returns a single connection to// the destination address.func ( *sysDialer) ( context.Context, Addr) ( Conn, error) { , := .Value(nettrace.TraceKey{}).(*nettrace.Trace)if != nil { := .String()if .ConnectStart != nil { .ConnectStart(.network, ) }if .ConnectDone != nil {deferfunc() { .ConnectDone(.network, , ) }() } } := .LocalAddrswitch ra := .(type) {case *TCPAddr: , := .(*TCPAddr)if .MultipathTCP() { , = .dialMPTCP(, , ) } else { , = .dialTCP(, , ) }case *UDPAddr: , := .(*UDPAddr) , = .dialUDP(, , )case *IPAddr: , := .(*IPAddr) , = .dialIP(, , )case *UnixAddr: , := .(*UnixAddr) , = .dialUnix(, , )default:returnnil, &OpError{Op: "dial", Net: .network, Source: , Addr: , Err: &AddrError{Err: "unexpected address type", Addr: .address}} }if != nil {returnnil, &OpError{Op: "dial", Net: .network, Source: , Addr: , Err: } // c is non-nil interface containing nil pointer }return , nil}// ListenConfig contains options for listening to an address.typeListenConfigstruct {// If Control is not nil, it is called after creating the network // connection but before binding it to the operating system. // // Network and address parameters passed to Control method are not // necessarily the ones passed to Listen. For example, passing "tcp" to // Listen will cause the Control function to be called with "tcp4" or "tcp6". Control func(network, address string, c syscall.RawConn) error// KeepAlive specifies the keep-alive period for network // connections accepted by this listener. // // KeepAlive is ignored if KeepAliveConfig.Enable is true. // // If zero, keep-alive are enabled if supported by the protocol // and operating system. Network protocols or operating systems // that do not support keep-alive ignore this field. // If negative, keep-alive are disabled. KeepAlive time.Duration// KeepAliveConfig specifies the keep-alive probe configuration // for an active network connection, when supported by the // protocol and operating system. // // If KeepAliveConfig.Enable is true, keep-alive probes are enabled. // If KeepAliveConfig.Enable is false and KeepAlive is negative, // keep-alive probes are disabled. KeepAliveConfig KeepAliveConfig// If mptcpStatus is set to a value allowing Multipath TCP (MPTCP) to be // used, any call to Listen with "tcp(4|6)" as network will use MPTCP if // supported by the operating system. mptcpStatus mptcpStatus}// MultipathTCP reports whether MPTCP will be used.//// This method doesn't check if MPTCP is supported by the operating// system or not.func ( *ListenConfig) () bool {return .mptcpStatus.get()}// SetMultipathTCP directs the [Listen] method to use, or not use, MPTCP,// if supported by the operating system. This method overrides the// system default and the GODEBUG=multipathtcp=... setting if any.//// If MPTCP is not available on the host or not supported by the client,// the Listen method will fall back to TCP.func ( *ListenConfig) ( bool) { .mptcpStatus.set()}// Listen announces on the local network address.//// See func Listen for a description of the network and address// parameters.func ( *ListenConfig) ( context.Context, , string) (Listener, error) { , := DefaultResolver.resolveAddrList(, "listen", , , nil)if != nil {returnnil, &OpError{Op: "listen", Net: , Source: nil, Addr: nil, Err: } } := &sysListener{ListenConfig: *,network: ,address: , }varListener := .first(isIPv4)switch la := .(type) {case *TCPAddr:if .MultipathTCP() { , = .listenMPTCP(, ) } else { , = .listenTCP(, ) }case *UnixAddr: , = .listenUnix(, )default:returnnil, &OpError{Op: "listen", Net: .network, Source: nil, Addr: , Err: &AddrError{Err: "unexpected address type", Addr: }} }if != nil {returnnil, &OpError{Op: "listen", Net: .network, Source: nil, Addr: , Err: } // l is non-nil interface containing nil pointer }return , nil}// ListenPacket announces on the local network address.//// See func ListenPacket for a description of the network and address// parameters.func ( *ListenConfig) ( context.Context, , string) (PacketConn, error) { , := DefaultResolver.resolveAddrList(, "listen", , , nil)if != nil {returnnil, &OpError{Op: "listen", Net: , Source: nil, Addr: nil, Err: } } := &sysListener{ListenConfig: *,network: ,address: , }varPacketConn := .first(isIPv4)switch la := .(type) {case *UDPAddr: , = .listenUDP(, )case *IPAddr: , = .listenIP(, )case *UnixAddr: , = .listenUnixgram(, )default:returnnil, &OpError{Op: "listen", Net: .network, Source: nil, Addr: , Err: &AddrError{Err: "unexpected address type", Addr: }} }if != nil {returnnil, &OpError{Op: "listen", Net: .network, Source: nil, Addr: , Err: } // c is non-nil interface containing nil pointer }return , nil}// sysListener contains a Listen's parameters and configuration.type sysListener struct {ListenConfig network, address string}// Listen announces on the local network address.//// The network must be "tcp", "tcp4", "tcp6", "unix" or "unixpacket".//// For TCP networks, if the host in the address parameter is empty or// a literal unspecified IP address, Listen listens on all available// unicast and anycast IP addresses of the local system.// To only use IPv4, use network "tcp4".// The address can use a host name, but this is not recommended,// because it will create a listener for at most one of the host's IP// addresses.// If the port in the address parameter is empty or "0", as in// "127.0.0.1:" or "[::1]:0", a port number is automatically chosen.// The [Addr] method of [Listener] can be used to discover the chosen// port.//// See func [Dial] for a description of the network and address// parameters.//// Listen uses context.Background internally; to specify the context, use// [ListenConfig.Listen].func (, string) (Listener, error) {varListenConfigreturn .Listen(context.Background(), , )}// ListenPacket announces on the local network address.//// The network must be "udp", "udp4", "udp6", "unixgram", or an IP// transport. The IP transports are "ip", "ip4", or "ip6" followed by// a colon and a literal protocol number or a protocol name, as in// "ip:1" or "ip:icmp".//// For UDP and IP networks, if the host in the address parameter is// empty or a literal unspecified IP address, ListenPacket listens on// all available IP addresses of the local system except multicast IP// addresses.// To only use IPv4, use network "udp4" or "ip4:proto".// The address can use a host name, but this is not recommended,// because it will create a listener for at most one of the host's IP// addresses.// If the port in the address parameter is empty or "0", as in// "127.0.0.1:" or "[::1]:0", a port number is automatically chosen.// The LocalAddr method of [PacketConn] can be used to discover the// chosen port.//// See func [Dial] for a description of the network and address// parameters.//// ListenPacket uses context.Background internally; to specify the context, use// [ListenConfig.ListenPacket].func (, string) (PacketConn, error) {varListenConfigreturn .ListenPacket(context.Background(), , )}
The pages are generated with Goldsv0.6.9-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.