github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/net/dial.go (about)

     1  // Copyright 2010 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  package net
     6  
     7  import (
     8  	"errors"
     9  	"time"
    10  )
    11  
    12  // A Dialer contains options for connecting to an address.
    13  //
    14  // The zero value for each field is equivalent to dialing
    15  // without that option. Dialing with the zero value of Dialer
    16  // is therefore equivalent to just calling the Dial function.
    17  type Dialer struct {
    18  	// Timeout is the maximum amount of time a dial will wait for
    19  	// a connect to complete. If Deadline is also set, it may fail
    20  	// earlier.
    21  	//
    22  	// The default is no timeout.
    23  	//
    24  	// With or without a timeout, the operating system may impose
    25  	// its own earlier timeout. For instance, TCP timeouts are
    26  	// often around 3 minutes.
    27  	Timeout time.Duration
    28  
    29  	// Deadline is the absolute point in time after which dials
    30  	// will fail. If Timeout is set, it may fail earlier.
    31  	// Zero means no deadline, or dependent on the operating system
    32  	// as with the Timeout option.
    33  	Deadline time.Time
    34  
    35  	// LocalAddr is the local address to use when dialing an
    36  	// address. The address must be of a compatible type for the
    37  	// network being dialed.
    38  	// If nil, a local address is automatically chosen.
    39  	LocalAddr Addr
    40  
    41  	// DualStack allows a single dial to attempt to establish
    42  	// multiple IPv4 and IPv6 connections and to return the first
    43  	// established connection when the network is "tcp" and the
    44  	// destination is a host name that has multiple address family
    45  	// DNS records.
    46  	DualStack bool
    47  
    48  	// KeepAlive specifies the keep-alive period for an active
    49  	// network connection.
    50  	// If zero, keep-alives are not enabled. Network protocols
    51  	// that do not support keep-alives ignore this field.
    52  	KeepAlive time.Duration
    53  }
    54  
    55  // Return either now+Timeout or Deadline, whichever comes first.
    56  // Or zero, if neither is set.
    57  func (d *Dialer) deadline() time.Time {
    58  	if d.Timeout == 0 {
    59  		return d.Deadline
    60  	}
    61  	timeoutDeadline := time.Now().Add(d.Timeout)
    62  	if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
    63  		return timeoutDeadline
    64  	} else {
    65  		return d.Deadline
    66  	}
    67  }
    68  
    69  func parseNetwork(net string) (afnet string, proto int, err error) {
    70  	i := last(net, ':')
    71  	if i < 0 { // no colon
    72  		switch net {
    73  		case "tcp", "tcp4", "tcp6":
    74  		case "udp", "udp4", "udp6":
    75  		case "ip", "ip4", "ip6":
    76  		case "unix", "unixgram", "unixpacket":
    77  		default:
    78  			return "", 0, UnknownNetworkError(net)
    79  		}
    80  		return net, 0, nil
    81  	}
    82  	afnet = net[:i]
    83  	switch afnet {
    84  	case "ip", "ip4", "ip6":
    85  		protostr := net[i+1:]
    86  		proto, i, ok := dtoi(protostr, 0)
    87  		if !ok || i != len(protostr) {
    88  			proto, err = lookupProtocol(protostr)
    89  			if err != nil {
    90  				return "", 0, err
    91  			}
    92  		}
    93  		return afnet, proto, nil
    94  	}
    95  	return "", 0, UnknownNetworkError(net)
    96  }
    97  
    98  func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
    99  	afnet, _, err := parseNetwork(net)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	if op == "dial" && addr == "" {
   104  		return nil, errMissingAddress
   105  	}
   106  	switch afnet {
   107  	case "unix", "unixgram", "unixpacket":
   108  		return ResolveUnixAddr(afnet, addr)
   109  	}
   110  	return resolveInternetAddr(afnet, addr, deadline)
   111  }
   112  
   113  // Dial connects to the address on the named network.
   114  //
   115  // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
   116  // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
   117  // (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and
   118  // "unixpacket".
   119  //
   120  // For TCP and UDP networks, addresses have the form host:port.
   121  // If host is a literal IPv6 address it must be enclosed
   122  // in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80".
   123  // The functions JoinHostPort and SplitHostPort manipulate addresses
   124  // in this form.
   125  //
   126  // Examples:
   127  //	Dial("tcp", "12.34.56.78:80")
   128  //	Dial("tcp", "google.com:http")
   129  //	Dial("tcp", "[2001:db8::1]:http")
   130  //	Dial("tcp", "[fe80::1%lo0]:80")
   131  //
   132  // For IP networks, the network must be "ip", "ip4" or "ip6" followed
   133  // by a colon and a protocol number or name and the addr must be a
   134  // literal IP address.
   135  //
   136  // Examples:
   137  //	Dial("ip4:1", "127.0.0.1")
   138  //	Dial("ip6:ospf", "::1")
   139  //
   140  // For Unix networks, the address must be a file system path.
   141  func Dial(network, address string) (Conn, error) {
   142  	var d Dialer
   143  	return d.Dial(network, address)
   144  }
   145  
   146  // DialTimeout acts like Dial but takes a timeout.
   147  // The timeout includes name resolution, if required.
   148  func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
   149  	d := Dialer{Timeout: timeout}
   150  	return d.Dial(network, address)
   151  }
   152  
   153  // Dial connects to the address on the named network.
   154  //
   155  // See func Dial for a description of the network and address
   156  // parameters.
   157  func (d *Dialer) Dial(network, address string) (Conn, error) {
   158  	ra, err := resolveAddr("dial", network, address, d.deadline())
   159  	if err != nil {
   160  		return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
   161  	}
   162  	dialer := func(deadline time.Time) (Conn, error) {
   163  		return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
   164  	}
   165  	if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
   166  		dialer = func(deadline time.Time) (Conn, error) {
   167  			return dialMulti(network, address, d.LocalAddr, ras, deadline)
   168  		}
   169  	}
   170  	c, err := dial(network, ra.toAddr(), dialer, d.deadline())
   171  	if d.KeepAlive > 0 && err == nil {
   172  		if tc, ok := c.(*TCPConn); ok {
   173  			tc.SetKeepAlive(true)
   174  			tc.SetKeepAlivePeriod(d.KeepAlive)
   175  			testHookSetKeepAlive()
   176  		}
   177  	}
   178  	return c, err
   179  }
   180  
   181  var testHookSetKeepAlive = func() {} // changed by dial_test.go
   182  
   183  // dialMulti attempts to establish connections to each destination of
   184  // the list of addresses. It will return the first established
   185  // connection and close the other connections. Otherwise it returns
   186  // error on the last attempt.
   187  func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
   188  	type racer struct {
   189  		Conn
   190  		error
   191  	}
   192  	// Sig controls the flow of dial results on lane. It passes a
   193  	// token to the next racer and also indicates the end of flow
   194  	// by using closed channel.
   195  	sig := make(chan bool, 1)
   196  	lane := make(chan racer, 1)
   197  	for _, ra := range ras {
   198  		go func(ra Addr) {
   199  			c, err := dialSingle(net, addr, la, ra, deadline)
   200  			if _, ok := <-sig; ok {
   201  				lane <- racer{c, err}
   202  			} else if err == nil {
   203  				// We have to return the resources
   204  				// that belong to the other
   205  				// connections here for avoiding
   206  				// unnecessary resource starvation.
   207  				c.Close()
   208  			}
   209  		}(ra.toAddr())
   210  	}
   211  	defer close(sig)
   212  	lastErr := errTimeout
   213  	nracers := len(ras)
   214  	for nracers > 0 {
   215  		sig <- true
   216  		racer := <-lane
   217  		if racer.error == nil {
   218  			return racer.Conn, nil
   219  		}
   220  		lastErr = racer.error
   221  		nracers--
   222  	}
   223  	return nil, lastErr
   224  }
   225  
   226  // dialSingle attempts to establish and returns a single connection to
   227  // the destination address.
   228  func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
   229  	if la != nil && la.Network() != ra.Network() {
   230  		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
   231  	}
   232  	switch ra := ra.(type) {
   233  	case *TCPAddr:
   234  		la, _ := la.(*TCPAddr)
   235  		c, err = dialTCP(net, la, ra, deadline)
   236  	case *UDPAddr:
   237  		la, _ := la.(*UDPAddr)
   238  		c, err = dialUDP(net, la, ra, deadline)
   239  	case *IPAddr:
   240  		la, _ := la.(*IPAddr)
   241  		c, err = dialIP(net, la, ra, deadline)
   242  	case *UnixAddr:
   243  		la, _ := la.(*UnixAddr)
   244  		c, err = dialUnix(net, la, ra, deadline)
   245  	default:
   246  		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
   247  	}
   248  	if err != nil {
   249  		return nil, err // c is non-nil interface containing nil pointer
   250  	}
   251  	return c, nil
   252  }
   253  
   254  // Listen announces on the local network address laddr.
   255  // The network net must be a stream-oriented network: "tcp", "tcp4",
   256  // "tcp6", "unix" or "unixpacket".
   257  // See Dial for the syntax of laddr.
   258  func Listen(net, laddr string) (Listener, error) {
   259  	la, err := resolveAddr("listen", net, laddr, noDeadline)
   260  	if err != nil {
   261  		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
   262  	}
   263  	var l Listener
   264  	switch la := la.toAddr().(type) {
   265  	case *TCPAddr:
   266  		l, err = ListenTCP(net, la)
   267  	case *UnixAddr:
   268  		l, err = ListenUnix(net, la)
   269  	default:
   270  		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
   271  	}
   272  	if err != nil {
   273  		return nil, err // l is non-nil interface containing nil pointer
   274  	}
   275  	return l, nil
   276  }
   277  
   278  // ListenPacket announces on the local network address laddr.
   279  // The network net must be a packet-oriented network: "udp", "udp4",
   280  // "udp6", "ip", "ip4", "ip6" or "unixgram".
   281  // See Dial for the syntax of laddr.
   282  func ListenPacket(net, laddr string) (PacketConn, error) {
   283  	la, err := resolveAddr("listen", net, laddr, noDeadline)
   284  	if err != nil {
   285  		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
   286  	}
   287  	var l PacketConn
   288  	switch la := la.toAddr().(type) {
   289  	case *UDPAddr:
   290  		l, err = ListenUDP(net, la)
   291  	case *IPAddr:
   292  		l, err = ListenIP(net, la)
   293  	case *UnixAddr:
   294  		l, err = ListenUnixgram(net, la)
   295  	default:
   296  		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
   297  	}
   298  	if err != nil {
   299  		return nil, err // l is non-nil interface containing nil pointer
   300  	}
   301  	return l, nil
   302  }