dial.go 8.72 KB
Newer Older
1 2 3 4 5 6
// 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

7
import (
8
	"errors"
9 10 11
	"time"
)

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
// 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.
	//
	// 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
40 41 42 43 44 45 46

	// DualStack allows a single dial to attempt to establish
	// multiple IPv4 and IPv6 connections and to return the first
	// established connection when the network is "tcp" and the
	// destination is a host name that has multiple address family
	// DNS records.
	DualStack bool
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
}

// Return either now+Timeout or Deadline, whichever comes first.
// Or zero, if neither is set.
func (d *Dialer) deadline() time.Time {
	if d.Timeout == 0 {
		return d.Deadline
	}
	timeoutDeadline := time.Now().Add(d.Timeout)
	if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
		return timeoutDeadline
	} else {
		return d.Deadline
	}
}

func parseNetwork(net string) (afnet string, proto int, err error) {
64 65 66 67 68
	i := last(net, ':')
	if i < 0 { // no colon
		switch net {
		case "tcp", "tcp4", "tcp6":
		case "udp", "udp4", "udp6":
69
		case "ip", "ip4", "ip6":
70 71 72 73 74
		case "unix", "unixgram", "unixpacket":
		default:
			return "", 0, UnknownNetworkError(net)
		}
		return net, 0, nil
75
	}
76 77
	afnet = net[:i]
	switch afnet {
78
	case "ip", "ip4", "ip6":
79 80 81 82 83 84 85 86 87
		protostr := net[i+1:]
		proto, i, ok := dtoi(protostr, 0)
		if !ok || i != len(protostr) {
			proto, err = lookupProtocol(protostr)
			if err != nil {
				return "", 0, err
			}
		}
		return afnet, proto, nil
88
	}
89 90 91
	return "", 0, UnknownNetworkError(net)
}

92
func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
93
	afnet, _, err := parseNetwork(net)
94
	if err != nil {
95
		return nil, err
96 97
	}
	if op == "dial" && addr == "" {
98
		return nil, errMissingAddress
99
	}
100 101
	switch afnet {
	case "unix", "unixgram", "unixpacket":
102
		return ResolveUnixAddr(afnet, addr)
103
	}
104
	return resolveInternetAddr(afnet, addr, deadline)
105 106
}

107
// Dial connects to the address on the named network.
108 109 110
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
111 112
// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and
// "unixpacket".
113
//
114
// For TCP and UDP networks, addresses have the form host:port.
115 116 117 118 119
// If host is a literal IPv6 address or host name, it must be enclosed
// in square brackets as in "[::1]:80", "[ipv6-host]:http" or
// "[ipv6-host%zone]:80".
// The functions JoinHostPort and SplitHostPort manipulate addresses
// in this form.
120 121
//
// Examples:
122
//	Dial("tcp", "12.34.56.78:80")
123 124 125
//	Dial("tcp", "google.com:http")
//	Dial("tcp", "[2001:db8::1]:http")
//	Dial("tcp", "[fe80::1%lo0]:80")
126
//
127 128 129
// 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.
130 131 132 133 134
//
// Examples:
//	Dial("ip4:1", "127.0.0.1")
//	Dial("ip6:ospf", "::1")
//
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
// 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)
}

// 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) {
153 154 155 156 157 158 159 160 161 162 163 164 165
	ra, err := resolveAddr("dial", network, address, d.deadline())
	if err != nil {
		return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
	}
	dialer := func(deadline time.Time) (Conn, error) {
		return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
	}
	if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
		dialer = func(deadline time.Time) (Conn, error) {
			return dialMulti(network, address, d.LocalAddr, ras, deadline)
		}
	}
	return dial(network, ra.toAddr(), dialer, d.deadline())
166 167
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
// dialMulti attempts to establish connections to each destination of
// the list of addresses. It will return the first established
// connection and close the other connections. Otherwise it returns
// error on the last attempt.
func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
	type racer struct {
		Conn
		Addr
		error
	}
	// Sig controls the flow of dial results on lane. It passes a
	// token to the next racer and also indicates the end of flow
	// by using closed channel.
	sig := make(chan bool, 1)
	lane := make(chan racer, 1)
	for _, ra := range ras {
		go func(ra Addr) {
			c, err := dialSingle(net, addr, la, ra, deadline)
			if _, ok := <-sig; ok {
				lane <- racer{c, ra, err}
			} else if err == nil {
				// We have to return the resources
				// that belong to the other
				// connections here for avoiding
				// unnecessary resource starvation.
				c.Close()
			}
		}(ra.toAddr())
	}
	defer close(sig)
	var failAddr Addr
	lastErr := errTimeout
	nracers := len(ras)
	for nracers > 0 {
		sig <- true
		select {
		case racer := <-lane:
			if racer.error == nil {
				return racer.Conn, nil
			}
			failAddr = racer.Addr
			lastErr = racer.error
			nracers--
		}
	}
	return nil, &OpError{Op: "dial", Net: net, Addr: failAddr, Err: lastErr}
}

// dialSingle attempts to establish and returns a single connection to
// the destination address.
func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
219
	if la != nil && la.Network() != ra.Network() {
220
		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
221 222
	}
	switch ra := ra.(type) {
223
	case *TCPAddr:
224 225
		la, _ := la.(*TCPAddr)
		c, err = dialTCP(net, la, ra, deadline)
226
	case *UDPAddr:
227 228
		la, _ := la.(*UDPAddr)
		c, err = dialUDP(net, la, ra, deadline)
229
	case *IPAddr:
230 231
		la, _ := la.(*IPAddr)
		c, err = dialIP(net, la, ra, deadline)
232
	case *UnixAddr:
233 234
		la, _ := la.(*UnixAddr)
		c, err = dialUnix(net, la, ra, deadline)
235
	default:
236
		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
237 238
	}
	if err != nil {
239
		return nil, err // c is non-nil interface containing nil pointer
240
	}
241
	return c, nil
242 243
}

244
// Listen announces on the local network address laddr.
245 246 247
// The network net must be a stream-oriented network: "tcp", "tcp4",
// "tcp6", "unix" or "unixpacket".
// See Dial for the syntax of laddr.
248
func Listen(net, laddr string) (Listener, error) {
249
	la, err := resolveAddr("listen", net, laddr, noDeadline)
250
	if err != nil {
251
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
252
	}
253 254
	var l Listener
	switch la := la.toAddr().(type) {
255
	case *TCPAddr:
256
		l, err = ListenTCP(net, la)
257
	case *UnixAddr:
258 259 260
		l, err = ListenUnix(net, la)
	default:
		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
261
	}
262 263 264 265
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
	}
	return l, nil
266 267 268
}

// ListenPacket announces on the local network address laddr.
269 270 271
// The network net must be a packet-oriented network: "udp", "udp4",
// "udp6", "ip", "ip4", "ip6" or "unixgram".
// See Dial for the syntax of laddr.
272
func ListenPacket(net, laddr string) (PacketConn, error) {
273
	la, err := resolveAddr("listen", net, laddr, noDeadline)
274
	if err != nil {
275
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
276
	}
277 278
	var l PacketConn
	switch la := la.toAddr().(type) {
279
	case *UDPAddr:
280
		l, err = ListenUDP(net, la)
281
	case *IPAddr:
282
		l, err = ListenIP(net, la)
283
	case *UnixAddr:
284 285 286 287 288 289
		l, err = ListenUnixgram(net, la)
	default:
		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
	}
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
290
	}
291
	return l, nil
292
}