github.com/hongwozai/go-src-1.4.3@v0.0.0-20191127132709-dc3fce3dbccb/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 }