mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			575 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			575 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
// 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 net
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"internal/nettrace"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// 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.
 | 
						|
type Dialer struct {
 | 
						|
	// 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 dialing a 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 enables RFC 6555-compliant "Happy Eyeballs" dialing
 | 
						|
	// when the network is "tcp" and the destination is a host name
 | 
						|
	// with both IPv4 and IPv6 addresses. This allows a client to
 | 
						|
	// tolerate networks where one address family is silently broken.
 | 
						|
	DualStack bool
 | 
						|
 | 
						|
	// FallbackDelay specifies the length of time to wait before
 | 
						|
	// spawning a fallback connection, when DualStack is enabled.
 | 
						|
	// If zero, a default delay of 300ms is used.
 | 
						|
	FallbackDelay time.Duration
 | 
						|
 | 
						|
	// KeepAlive specifies the keep-alive period for an active
 | 
						|
	// network connection.
 | 
						|
	// If zero, keep-alives are not enabled. Network protocols
 | 
						|
	// that do not support keep-alives ignore this field.
 | 
						|
	KeepAlive time.Duration
 | 
						|
 | 
						|
	// Cancel is an optional channel whose closure indicates that
 | 
						|
	// the dial should be canceled. Not all types of dials support
 | 
						|
	// cancelation.
 | 
						|
	//
 | 
						|
	// Deprecated: Use DialContext instead.
 | 
						|
	Cancel <-chan struct{}
 | 
						|
}
 | 
						|
 | 
						|
func minNonzeroTime(a, b time.Time) time.Time {
 | 
						|
	if a.IsZero() {
 | 
						|
		return b
 | 
						|
	}
 | 
						|
	if b.IsZero() || a.Before(b) {
 | 
						|
		return a
 | 
						|
	}
 | 
						|
	return b
 | 
						|
}
 | 
						|
 | 
						|
// 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 (d *Dialer) deadline(ctx context.Context, now time.Time) (earliest time.Time) {
 | 
						|
	if d.Timeout != 0 { // including negative, for historical reasons
 | 
						|
		earliest = now.Add(d.Timeout)
 | 
						|
	}
 | 
						|
	if d, ok := ctx.Deadline(); ok {
 | 
						|
		earliest = minNonzeroTime(earliest, d)
 | 
						|
	}
 | 
						|
	return minNonzeroTime(earliest, d.Deadline)
 | 
						|
}
 | 
						|
 | 
						|
// partialDeadline returns the deadline to use for a single address,
 | 
						|
// when multiple addresses are pending.
 | 
						|
func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) {
 | 
						|
	if deadline.IsZero() {
 | 
						|
		return deadline, nil
 | 
						|
	}
 | 
						|
	timeRemaining := deadline.Sub(now)
 | 
						|
	if timeRemaining <= 0 {
 | 
						|
		return time.Time{}, errTimeout
 | 
						|
	}
 | 
						|
	// Tentatively allocate equal time to each remaining address.
 | 
						|
	timeout := timeRemaining / time.Duration(addrsRemaining)
 | 
						|
	// If the time per address is too short, steal from the end of the list.
 | 
						|
	const saneMinimum = 2 * time.Second
 | 
						|
	if timeout < saneMinimum {
 | 
						|
		if timeRemaining < saneMinimum {
 | 
						|
			timeout = timeRemaining
 | 
						|
		} else {
 | 
						|
			timeout = saneMinimum
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return now.Add(timeout), nil
 | 
						|
}
 | 
						|
 | 
						|
func (d *Dialer) fallbackDelay() time.Duration {
 | 
						|
	if d.FallbackDelay > 0 {
 | 
						|
		return d.FallbackDelay
 | 
						|
	} else {
 | 
						|
		return 300 * time.Millisecond
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err error) {
 | 
						|
	i := last(net, ':')
 | 
						|
	if i < 0 { // no colon
 | 
						|
		switch net {
 | 
						|
		case "tcp", "tcp4", "tcp6":
 | 
						|
		case "udp", "udp4", "udp6":
 | 
						|
		case "ip", "ip4", "ip6":
 | 
						|
		case "unix", "unixgram", "unixpacket":
 | 
						|
		default:
 | 
						|
			return "", 0, UnknownNetworkError(net)
 | 
						|
		}
 | 
						|
		return net, 0, nil
 | 
						|
	}
 | 
						|
	afnet = net[:i]
 | 
						|
	switch afnet {
 | 
						|
	case "ip", "ip4", "ip6":
 | 
						|
		protostr := net[i+1:]
 | 
						|
		proto, i, ok := dtoi(protostr, 0)
 | 
						|
		if !ok || i != len(protostr) {
 | 
						|
			proto, err = lookupProtocol(ctx, protostr)
 | 
						|
			if err != nil {
 | 
						|
				return "", 0, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return afnet, proto, nil
 | 
						|
	}
 | 
						|
	return "", 0, UnknownNetworkError(net)
 | 
						|
}
 | 
						|
 | 
						|
// resolverAddrList resolves addr using hint and returns a list of
 | 
						|
// addresses. The result contains at least one address when error is
 | 
						|
// nil.
 | 
						|
func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
 | 
						|
	afnet, _, err := parseNetwork(ctx, network)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if op == "dial" && addr == "" {
 | 
						|
		return nil, errMissingAddress
 | 
						|
	}
 | 
						|
	switch afnet {
 | 
						|
	case "unix", "unixgram", "unixpacket":
 | 
						|
		// TODO(bradfitz): push down context
 | 
						|
		addr, err := ResolveUnixAddr(afnet, addr)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if op == "dial" && hint != nil && addr.Network() != hint.Network() {
 | 
						|
			return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
 | 
						|
		}
 | 
						|
		return addrList{addr}, nil
 | 
						|
	}
 | 
						|
	addrs, err := internetAddrList(ctx, afnet, addr)
 | 
						|
	if err != nil || op != "dial" || hint == nil {
 | 
						|
		return addrs, err
 | 
						|
	}
 | 
						|
	var (
 | 
						|
		tcp      *TCPAddr
 | 
						|
		udp      *UDPAddr
 | 
						|
		ip       *IPAddr
 | 
						|
		wildcard bool
 | 
						|
	)
 | 
						|
	switch hint := hint.(type) {
 | 
						|
	case *TCPAddr:
 | 
						|
		tcp = hint
 | 
						|
		wildcard = tcp.isWildcard()
 | 
						|
	case *UDPAddr:
 | 
						|
		udp = hint
 | 
						|
		wildcard = udp.isWildcard()
 | 
						|
	case *IPAddr:
 | 
						|
		ip = hint
 | 
						|
		wildcard = ip.isWildcard()
 | 
						|
	}
 | 
						|
	naddrs := addrs[:0]
 | 
						|
	for _, addr := range addrs {
 | 
						|
		if addr.Network() != hint.Network() {
 | 
						|
			return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
 | 
						|
		}
 | 
						|
		switch addr := addr.(type) {
 | 
						|
		case *TCPAddr:
 | 
						|
			if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(tcp.IP) {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			naddrs = append(naddrs, addr)
 | 
						|
		case *UDPAddr:
 | 
						|
			if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(udp.IP) {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			naddrs = append(naddrs, addr)
 | 
						|
		case *IPAddr:
 | 
						|
			if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(ip.IP) {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			naddrs = append(naddrs, addr)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if len(naddrs) == 0 {
 | 
						|
		return nil, errNoSuitableAddress
 | 
						|
	}
 | 
						|
	return naddrs, nil
 | 
						|
}
 | 
						|
 | 
						|
// 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, addresses have the form host:port.
 | 
						|
// If host is a literal IPv6 address it must be enclosed
 | 
						|
// in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80".
 | 
						|
// The functions JoinHostPort and SplitHostPort manipulate addresses
 | 
						|
// in this form.
 | 
						|
// If the host is empty, as in ":80", the local system is assumed.
 | 
						|
//
 | 
						|
// Examples:
 | 
						|
//	Dial("tcp", "192.0.2.1:80")
 | 
						|
//	Dial("tcp", "golang.org:http")
 | 
						|
//	Dial("tcp", "[2001:db8::1]:http")
 | 
						|
//	Dial("tcp", "[fe80::1%lo0]:80")
 | 
						|
//	Dial("tcp", ":80")
 | 
						|
//
 | 
						|
// For IP networks, the network must be "ip", "ip4" or "ip6" followed
 | 
						|
// by a colon and a protocol number or name and the addr must be a
 | 
						|
// literal IP address.
 | 
						|
//
 | 
						|
// Examples:
 | 
						|
//	Dial("ip4:1", "192.0.2.1")
 | 
						|
//	Dial("ip6:ipv6-icmp", "2001:db8::1")
 | 
						|
//
 | 
						|
// For Unix networks, the address must be a file system path.
 | 
						|
func Dial(network, address string) (Conn, error) {
 | 
						|
	var d Dialer
 | 
						|
	return d.Dial(network, address)
 | 
						|
}
 | 
						|
 | 
						|
// DialTimeout acts like Dial but takes a timeout.
 | 
						|
// The timeout includes name resolution, if required.
 | 
						|
func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
 | 
						|
	d := Dialer{Timeout: timeout}
 | 
						|
	return d.Dial(network, address)
 | 
						|
}
 | 
						|
 | 
						|
// dialParam contains a Dial's parameters and configuration.
 | 
						|
type dialParam struct {
 | 
						|
	Dialer
 | 
						|
	network, address string
 | 
						|
}
 | 
						|
 | 
						|
// Dial connects to the address on the named network.
 | 
						|
//
 | 
						|
// See func Dial for a description of the network and address
 | 
						|
// parameters.
 | 
						|
func (d *Dialer) Dial(network, address string) (Conn, error) {
 | 
						|
	return d.DialContext(context.Background(), network, address)
 | 
						|
}
 | 
						|
 | 
						|
// 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.
 | 
						|
//
 | 
						|
// See func Dial for a description of the network and address
 | 
						|
// parameters.
 | 
						|
func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {
 | 
						|
	if ctx == nil {
 | 
						|
		panic("nil context")
 | 
						|
	}
 | 
						|
	deadline := d.deadline(ctx, time.Now())
 | 
						|
	if !deadline.IsZero() {
 | 
						|
		if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
 | 
						|
			subCtx, cancel := context.WithDeadline(ctx, deadline)
 | 
						|
			defer cancel()
 | 
						|
			ctx = subCtx
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if oldCancel := d.Cancel; oldCancel != nil {
 | 
						|
		subCtx, cancel := context.WithCancel(ctx)
 | 
						|
		defer cancel()
 | 
						|
		go func() {
 | 
						|
			select {
 | 
						|
			case <-oldCancel:
 | 
						|
				cancel()
 | 
						|
			case <-subCtx.Done():
 | 
						|
			}
 | 
						|
		}()
 | 
						|
		ctx = subCtx
 | 
						|
	}
 | 
						|
 | 
						|
	// Shadow the nettrace (if any) during resolve so Connect events don't fire for DNS lookups.
 | 
						|
	resolveCtx := ctx
 | 
						|
	if trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace); trace != nil {
 | 
						|
		shadow := *trace
 | 
						|
		shadow.ConnectStart = nil
 | 
						|
		shadow.ConnectDone = nil
 | 
						|
		resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow)
 | 
						|
	}
 | 
						|
 | 
						|
	addrs, err := resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
 | 
						|
	if err != nil {
 | 
						|
		return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
 | 
						|
	}
 | 
						|
 | 
						|
	dp := &dialParam{
 | 
						|
		Dialer:  *d,
 | 
						|
		network: network,
 | 
						|
		address: address,
 | 
						|
	}
 | 
						|
 | 
						|
	var primaries, fallbacks addrList
 | 
						|
	if d.DualStack && network == "tcp" {
 | 
						|
		primaries, fallbacks = addrs.partition(isIPv4)
 | 
						|
	} else {
 | 
						|
		primaries = addrs
 | 
						|
	}
 | 
						|
 | 
						|
	var c Conn
 | 
						|
	if len(fallbacks) > 0 {
 | 
						|
		c, err = dialParallel(ctx, dp, primaries, fallbacks)
 | 
						|
	} else {
 | 
						|
		c, err = dialSerial(ctx, dp, primaries)
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	if tc, ok := c.(*TCPConn); ok && d.KeepAlive > 0 {
 | 
						|
		setKeepAlive(tc.fd, true)
 | 
						|
		setKeepAlivePeriod(tc.fd, d.KeepAlive)
 | 
						|
		testHookSetKeepAlive()
 | 
						|
	}
 | 
						|
	return c, nil
 | 
						|
}
 | 
						|
 | 
						|
// 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 dialParallel(ctx context.Context, dp *dialParam, primaries, fallbacks addrList) (Conn, error) {
 | 
						|
	if len(fallbacks) == 0 {
 | 
						|
		return dialSerial(ctx, dp, primaries)
 | 
						|
	}
 | 
						|
 | 
						|
	returned := make(chan struct{})
 | 
						|
	defer close(returned)
 | 
						|
 | 
						|
	type dialResult struct {
 | 
						|
		Conn
 | 
						|
		error
 | 
						|
		primary bool
 | 
						|
		done    bool
 | 
						|
	}
 | 
						|
	results := make(chan dialResult) // unbuffered
 | 
						|
 | 
						|
	startRacer := func(ctx context.Context, primary bool) {
 | 
						|
		ras := primaries
 | 
						|
		if !primary {
 | 
						|
			ras = fallbacks
 | 
						|
		}
 | 
						|
		c, err := dialSerial(ctx, dp, ras)
 | 
						|
		select {
 | 
						|
		case results <- dialResult{Conn: c, error: err, primary: primary, done: true}:
 | 
						|
		case <-returned:
 | 
						|
			if c != nil {
 | 
						|
				c.Close()
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	var primary, fallback dialResult
 | 
						|
 | 
						|
	// Start the main racer.
 | 
						|
	primaryCtx, primaryCancel := context.WithCancel(ctx)
 | 
						|
	defer primaryCancel()
 | 
						|
	go startRacer(primaryCtx, true)
 | 
						|
 | 
						|
	// Start the timer for the fallback racer.
 | 
						|
	fallbackTimer := time.NewTimer(dp.fallbackDelay())
 | 
						|
	defer fallbackTimer.Stop()
 | 
						|
 | 
						|
	for {
 | 
						|
		select {
 | 
						|
		case <-fallbackTimer.C:
 | 
						|
			fallbackCtx, fallbackCancel := context.WithCancel(ctx)
 | 
						|
			defer fallbackCancel()
 | 
						|
			go startRacer(fallbackCtx, false)
 | 
						|
 | 
						|
		case res := <-results:
 | 
						|
			if res.error == nil {
 | 
						|
				return res.Conn, nil
 | 
						|
			}
 | 
						|
			if res.primary {
 | 
						|
				primary = res
 | 
						|
			} else {
 | 
						|
				fallback = res
 | 
						|
			}
 | 
						|
			if primary.done && fallback.done {
 | 
						|
				return nil, primary.error
 | 
						|
			}
 | 
						|
			if res.primary && fallbackTimer.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).
 | 
						|
				fallbackTimer.Reset(0)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// dialSerial connects to a list of addresses in sequence, returning
 | 
						|
// either the first successful connection, or the first error.
 | 
						|
func dialSerial(ctx context.Context, dp *dialParam, ras addrList) (Conn, error) {
 | 
						|
	var firstErr error // The error from the first address is most relevant.
 | 
						|
 | 
						|
	for i, ra := range ras {
 | 
						|
		select {
 | 
						|
		case <-ctx.Done():
 | 
						|
			return nil, &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: mapErr(ctx.Err())}
 | 
						|
		default:
 | 
						|
		}
 | 
						|
 | 
						|
		deadline, _ := ctx.Deadline()
 | 
						|
		partialDeadline, err := partialDeadline(time.Now(), deadline, len(ras)-i)
 | 
						|
		if err != nil {
 | 
						|
			// Ran out of time.
 | 
						|
			if firstErr == nil {
 | 
						|
				firstErr = &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: err}
 | 
						|
			}
 | 
						|
			break
 | 
						|
		}
 | 
						|
		dialCtx := ctx
 | 
						|
		if partialDeadline.Before(deadline) {
 | 
						|
			var cancel context.CancelFunc
 | 
						|
			dialCtx, cancel = context.WithDeadline(ctx, partialDeadline)
 | 
						|
			defer cancel()
 | 
						|
		}
 | 
						|
 | 
						|
		c, err := dialSingle(dialCtx, dp, ra)
 | 
						|
		if err == nil {
 | 
						|
			return c, nil
 | 
						|
		}
 | 
						|
		if firstErr == nil {
 | 
						|
			firstErr = err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if firstErr == nil {
 | 
						|
		firstErr = &OpError{Op: "dial", Net: dp.network, Source: nil, Addr: nil, Err: errMissingAddress}
 | 
						|
	}
 | 
						|
	return nil, firstErr
 | 
						|
}
 | 
						|
 | 
						|
// dialSingle attempts to establish and returns a single connection to
 | 
						|
// the destination address.
 | 
						|
func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error) {
 | 
						|
	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
 | 
						|
	if trace != nil {
 | 
						|
		raStr := ra.String()
 | 
						|
		if trace.ConnectStart != nil {
 | 
						|
			trace.ConnectStart(dp.network, raStr)
 | 
						|
		}
 | 
						|
		if trace.ConnectDone != nil {
 | 
						|
			defer func() { trace.ConnectDone(dp.network, raStr, err) }()
 | 
						|
		}
 | 
						|
	}
 | 
						|
	la := dp.LocalAddr
 | 
						|
	switch ra := ra.(type) {
 | 
						|
	case *TCPAddr:
 | 
						|
		la, _ := la.(*TCPAddr)
 | 
						|
		c, err = dialTCP(ctx, dp.network, la, ra)
 | 
						|
	case *UDPAddr:
 | 
						|
		la, _ := la.(*UDPAddr)
 | 
						|
		c, err = dialUDP(ctx, dp.network, la, ra)
 | 
						|
	case *IPAddr:
 | 
						|
		la, _ := la.(*IPAddr)
 | 
						|
		c, err = dialIP(ctx, dp.network, la, ra)
 | 
						|
	case *UnixAddr:
 | 
						|
		la, _ := la.(*UnixAddr)
 | 
						|
		c, err = dialUnix(ctx, dp.network, la, ra)
 | 
						|
	default:
 | 
						|
		return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: dp.address}}
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: err} // c is non-nil interface containing nil pointer
 | 
						|
	}
 | 
						|
	return c, nil
 | 
						|
}
 | 
						|
 | 
						|
// Listen announces on the local network address laddr.
 | 
						|
// The network net must be a stream-oriented network: "tcp", "tcp4",
 | 
						|
// "tcp6", "unix" or "unixpacket".
 | 
						|
// For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
 | 
						|
// If host is omitted, as in ":8080", Listen listens on all available interfaces
 | 
						|
// instead of just the interface with the given host address.
 | 
						|
// See Dial for more details about address syntax.
 | 
						|
func Listen(net, laddr string) (Listener, error) {
 | 
						|
	addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil)
 | 
						|
	if err != nil {
 | 
						|
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 | 
						|
	}
 | 
						|
	var l Listener
 | 
						|
	switch la := addrs.first(isIPv4).(type) {
 | 
						|
	case *TCPAddr:
 | 
						|
		l, err = ListenTCP(net, la)
 | 
						|
	case *UnixAddr:
 | 
						|
		l, err = ListenUnix(net, la)
 | 
						|
	default:
 | 
						|
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, err // l is non-nil interface containing nil pointer
 | 
						|
	}
 | 
						|
	return l, nil
 | 
						|
}
 | 
						|
 | 
						|
// ListenPacket announces on the local network address laddr.
 | 
						|
// The network net must be a packet-oriented network: "udp", "udp4",
 | 
						|
// "udp6", "ip", "ip4", "ip6" or "unixgram".
 | 
						|
// For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
 | 
						|
// If host is omitted, as in ":8080", ListenPacket listens on all available interfaces
 | 
						|
// instead of just the interface with the given host address.
 | 
						|
// See Dial for the syntax of laddr.
 | 
						|
func ListenPacket(net, laddr string) (PacketConn, error) {
 | 
						|
	addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil)
 | 
						|
	if err != nil {
 | 
						|
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 | 
						|
	}
 | 
						|
	var l PacketConn
 | 
						|
	switch la := addrs.first(isIPv4).(type) {
 | 
						|
	case *UDPAddr:
 | 
						|
		l, err = ListenUDP(net, la)
 | 
						|
	case *IPAddr:
 | 
						|
		l, err = ListenIP(net, la)
 | 
						|
	case *UnixAddr:
 | 
						|
		l, err = ListenUnixgram(net, la)
 | 
						|
	default:
 | 
						|
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, err // l is non-nil interface containing nil pointer
 | 
						|
	}
 | 
						|
	return l, nil
 | 
						|
}
 |