2013-02-11 Sebastian Huber <sebastian.huber@embedded-brains.de>
[official-gcc.git] / libgo / go / net / dial.go
blob354028a157ab4154b61cc4a672359719d525bd2a
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.
5 package net
7 import (
8 "time"
11 func parseDialNetwork(net string) (afnet string, proto int, err error) {
12 i := last(net, ':')
13 if i < 0 { // no colon
14 switch net {
15 case "tcp", "tcp4", "tcp6":
16 case "udp", "udp4", "udp6":
17 case "ip", "ip4", "ip6":
18 case "unix", "unixgram", "unixpacket":
19 default:
20 return "", 0, UnknownNetworkError(net)
22 return net, 0, nil
24 afnet = net[:i]
25 switch afnet {
26 case "ip", "ip4", "ip6":
27 protostr := net[i+1:]
28 proto, i, ok := dtoi(protostr, 0)
29 if !ok || i != len(protostr) {
30 proto, err = lookupProtocol(protostr)
31 if err != nil {
32 return "", 0, err
35 return afnet, proto, nil
37 return "", 0, UnknownNetworkError(net)
40 func resolveNetAddr(op, net, addr string, deadline time.Time) (afnet string, a Addr, err error) {
41 afnet, _, err = parseDialNetwork(net)
42 if err != nil {
43 return "", nil, &OpError{op, net, nil, err}
45 if op == "dial" && addr == "" {
46 return "", nil, &OpError{op, net, nil, errMissingAddress}
48 a, err = resolveAfnetAddr(afnet, addr, deadline)
49 return
52 func resolveAfnetAddr(afnet, addr string, deadline time.Time) (Addr, error) {
53 if addr == "" {
54 return nil, nil
56 switch afnet {
57 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6":
58 return resolveInternetAddr(afnet, addr, deadline)
59 case "unix", "unixgram", "unixpacket":
60 return ResolveUnixAddr(afnet, addr)
62 return nil, nil
65 // Dial connects to the address addr on the network net.
67 // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
68 // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
69 // (IPv4-only), "ip6" (IPv6-only), "unix" and "unixpacket".
71 // For TCP and UDP networks, addresses have the form host:port.
72 // If host is a literal IPv6 address, it must be enclosed
73 // in square brackets. The functions JoinHostPort and SplitHostPort
74 // manipulate addresses in this form.
76 // Examples:
77 // Dial("tcp", "12.34.56.78:80")
78 // Dial("tcp", "google.com:80")
79 // Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
81 // For IP networks, net must be "ip", "ip4" or "ip6" followed
82 // by a colon and a protocol number or name.
84 // Examples:
85 // Dial("ip4:1", "127.0.0.1")
86 // Dial("ip6:ospf", "::1")
88 func Dial(net, addr string) (Conn, error) {
89 _, addri, err := resolveNetAddr("dial", net, addr, noDeadline)
90 if err != nil {
91 return nil, err
93 return dialAddr(net, addr, addri, noDeadline)
96 func dialAddr(net, addr string, addri Addr, deadline time.Time) (c Conn, err error) {
97 switch ra := addri.(type) {
98 case *TCPAddr:
99 c, err = dialTCP(net, nil, ra, deadline)
100 case *UDPAddr:
101 c, err = dialUDP(net, nil, ra, deadline)
102 case *IPAddr:
103 c, err = dialIP(net, nil, ra, deadline)
104 case *UnixAddr:
105 c, err = dialUnix(net, nil, ra, deadline)
106 default:
107 err = &OpError{"dial", net + " " + addr, nil, UnknownNetworkError(net)}
109 if err != nil {
110 return nil, err
112 return
115 // DialTimeout acts like Dial but takes a timeout.
116 // The timeout includes name resolution, if required.
117 func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
118 return dialTimeout(net, addr, timeout)
121 // dialTimeoutRace is the old implementation of DialTimeout, still used
122 // on operating systems where the deadline hasn't been pushed down
123 // into the pollserver.
124 // TODO: fix this on plan9.
125 func dialTimeoutRace(net, addr string, timeout time.Duration) (Conn, error) {
126 t := time.NewTimer(timeout)
127 defer t.Stop()
128 type pair struct {
129 Conn
130 error
132 ch := make(chan pair, 1)
133 resolvedAddr := make(chan Addr, 1)
134 go func() {
135 _, addri, err := resolveNetAddr("dial", net, addr, noDeadline)
136 if err != nil {
137 ch <- pair{nil, err}
138 return
140 resolvedAddr <- addri // in case we need it for OpError
141 c, err := dialAddr(net, addr, addri, noDeadline)
142 ch <- pair{c, err}
144 select {
145 case <-t.C:
146 // Try to use the real Addr in our OpError, if we resolved it
147 // before the timeout. Otherwise we just use stringAddr.
148 var addri Addr
149 select {
150 case a := <-resolvedAddr:
151 addri = a
152 default:
153 addri = &stringAddr{net, addr}
155 err := &OpError{
156 Op: "dial",
157 Net: net,
158 Addr: addri,
159 Err: &timeoutError{},
161 return nil, err
162 case p := <-ch:
163 return p.Conn, p.error
165 panic("unreachable")
168 type stringAddr struct {
169 net, addr string
172 func (a stringAddr) Network() string { return a.net }
173 func (a stringAddr) String() string { return a.addr }
175 // Listen announces on the local network address laddr.
176 // The network string net must be a stream-oriented network:
177 // "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
178 func Listen(net, laddr string) (Listener, error) {
179 afnet, a, err := resolveNetAddr("listen", net, laddr, noDeadline)
180 if err != nil {
181 return nil, err
183 switch afnet {
184 case "tcp", "tcp4", "tcp6":
185 var la *TCPAddr
186 if a != nil {
187 la = a.(*TCPAddr)
189 return ListenTCP(net, la)
190 case "unix", "unixpacket":
191 var la *UnixAddr
192 if a != nil {
193 la = a.(*UnixAddr)
195 return ListenUnix(net, la)
197 return nil, UnknownNetworkError(net)
200 // ListenPacket announces on the local network address laddr.
201 // The network string net must be a packet-oriented network:
202 // "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
203 func ListenPacket(net, laddr string) (PacketConn, error) {
204 afnet, a, err := resolveNetAddr("listen", net, laddr, noDeadline)
205 if err != nil {
206 return nil, err
208 switch afnet {
209 case "udp", "udp4", "udp6":
210 var la *UDPAddr
211 if a != nil {
212 la = a.(*UDPAddr)
214 return ListenUDP(net, la)
215 case "ip", "ip4", "ip6":
216 var la *IPAddr
217 if a != nil {
218 la = a.(*IPAddr)
220 return ListenIP(net, la)
221 case "unixgram":
222 var la *UnixAddr
223 if a != nil {
224 la = a.(*UnixAddr)
226 return ListenUnixgram(net, la)
228 return nil, UnknownNetworkError(net)