Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 1 | // Copyright 2009 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 | |
Rob Pike | 40a7db3 | 2009-11-08 15:57:25 -0800 | [diff] [blame] | 5 | // The net package provides a portable interface to Unix |
| 6 | // networks sockets, including TCP/IP, UDP, domain name |
| 7 | // resolution, and Unix domain sockets. |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 8 | package net |
| 9 | |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 10 | // TODO(rsc): |
| 11 | // support for raw IP sockets |
| 12 | // support for raw ethernet sockets |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 13 | |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 14 | import "os" |
Russ Cox | 97bc222 | 2009-05-07 17:36:29 -0700 | [diff] [blame] | 15 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 16 | // Addr represents a network end point address. |
| 17 | type Addr interface { |
| 18 | Network() string; // name of the network |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 19 | String() string; // string form of address |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 20 | } |
| 21 | |
| 22 | // Conn is a generic stream-oriented network connection. |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 23 | type Conn interface { |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 24 | // Read reads data from the connection. |
| 25 | // Read can be made to time out and return err == os.EAGAIN |
| 26 | // after a fixed time limit; see SetTimeout and SetReadTimeout. |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 27 | Read(b []byte) (n int, err os.Error); |
| 28 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 29 | // Write writes data to the connection. |
| 30 | // Write can be made to time out and return err == os.EAGAIN |
| 31 | // after a fixed time limit; see SetTimeout and SetReadTimeout. |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 32 | Write(b []byte) (n int, err os.Error); |
| 33 | |
| 34 | // Close closes the connection. |
| 35 | Close() os.Error; |
| 36 | |
Rob Pike | efc4088 | 2009-06-19 16:03:59 -0700 | [diff] [blame] | 37 | // LocalAddr returns the local network address. |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 38 | LocalAddr() Addr; |
Rob Pike | efc4088 | 2009-06-19 16:03:59 -0700 | [diff] [blame] | 39 | |
| 40 | // RemoteAddr returns the remote network address. |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 41 | RemoteAddr() Addr; |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 42 | |
| 43 | // SetTimeout sets the read and write deadlines associated |
| 44 | // with the connection. |
| 45 | SetTimeout(nsec int64) os.Error; |
| 46 | |
| 47 | // SetReadTimeout sets the time (in nanoseconds) that |
| 48 | // Read will wait for data before returning os.EAGAIN. |
| 49 | // Setting nsec == 0 (the default) disables the deadline. |
| 50 | SetReadTimeout(nsec int64) os.Error; |
| 51 | |
| 52 | // SetWriteTimeout sets the time (in nanoseconds) that |
| 53 | // Write will wait to send its data before returning os.EAGAIN. |
| 54 | // Setting nsec == 0 (the default) disables the deadline. |
| 55 | // Even if write times out, it may return n > 0, indicating that |
| 56 | // some of the data was successfully written. |
| 57 | SetWriteTimeout(nsec int64) os.Error; |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 58 | } |
| 59 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 60 | // PacketConn is a generic packet-oriented network connection. |
| 61 | type PacketConn interface { |
| 62 | // ReadFrom reads a packet from the connection, |
| 63 | // copying the payload into b. It returns the number of |
| 64 | // bytes copied into b and the return address that |
| 65 | // was on the packet. |
| 66 | // ReadFrom can be made to time out and return err == os.EAGAIN |
| 67 | // after a fixed time limit; see SetTimeout and SetReadTimeout. |
| 68 | ReadFrom(b []byte) (n int, addr Addr, err os.Error); |
| 69 | |
| 70 | // WriteTo writes a packet with payload b to addr. |
| 71 | // WriteTo can be made to time out and return err == os.EAGAIN |
| 72 | // after a fixed time limit; see SetTimeout and SetWriteTimeout. |
| 73 | // On packet-oriented connections, write timeouts are rare. |
| 74 | WriteTo(b []byte, addr Addr) (n int, err os.Error); |
| 75 | |
| 76 | // Close closes the connection. |
| 77 | Close() os.Error; |
| 78 | |
| 79 | // LocalAddr returns the local network address. |
| 80 | LocalAddr() Addr; |
| 81 | |
| 82 | // SetTimeout sets the read and write deadlines associated |
| 83 | // with the connection. |
| 84 | SetTimeout(nsec int64) os.Error; |
| 85 | |
| 86 | // SetReadTimeout sets the time (in nanoseconds) that |
| 87 | // Read will wait for data before returning os.EAGAIN. |
| 88 | // Setting nsec == 0 (the default) disables the deadline. |
| 89 | SetReadTimeout(nsec int64) os.Error; |
| 90 | |
| 91 | // SetWriteTimeout sets the time (in nanoseconds) that |
| 92 | // Write will wait to send its data before returning os.EAGAIN. |
| 93 | // Setting nsec == 0 (the default) disables the deadline. |
| 94 | // Even if write times out, it may return n > 0, indicating that |
| 95 | // some of the data was successfully written. |
| 96 | SetWriteTimeout(nsec int64) os.Error; |
| 97 | } |
| 98 | |
| 99 | // A Listener is a generic network listener for stream-oriented protocols. |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 100 | // Accept waits for the next connection and Close closes the connection. |
| 101 | type Listener interface { |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 102 | Accept() (c Conn, err os.Error); |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 103 | Close() os.Error; |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 104 | Addr() Addr; // Listener's network address |
Russ Cox | 5d2ee9d | 2009-06-17 21:44:26 -0700 | [diff] [blame] | 105 | } |
| 106 | |
Russ Cox | c93da7c7 | 2009-03-05 15:48:12 -0800 | [diff] [blame] | 107 | // Dial connects to the remote address raddr on the network net. |
| 108 | // If the string laddr is not empty, it is used as the local address |
| 109 | // for the connection. |
| 110 | // |
| 111 | // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), |
| 112 | // "udp", "udp4" (IPv4-only), and "udp6" (IPv6-only). |
| 113 | // |
| 114 | // For IP networks, addresses have the form host:port. If host is |
| 115 | // a literal IPv6 address, it must be enclosed in square brackets. |
| 116 | // |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 117 | // Examples: |
| 118 | // Dial("tcp", "", "12.34.56.78:80") |
Russ Cox | c93da7c7 | 2009-03-05 15:48:12 -0800 | [diff] [blame] | 119 | // Dial("tcp", "", "google.com:80") |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 120 | // Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80") |
| 121 | // Dial("tcp", "127.0.0.1:123", "127.0.0.1:88") |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 122 | // |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 123 | func Dial(net, laddr, raddr string) (c Conn, err os.Error) { |
Russ Cox | a4f1564 | 2008-09-30 14:03:13 -0700 | [diff] [blame] | 124 | switch net { |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 125 | case "tcp", "tcp4", "tcp6": |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 126 | var la, ra *TCPAddr; |
| 127 | if laddr != "" { |
| 128 | if la, err = ResolveTCPAddr(laddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 129 | goto Error |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 130 | } |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 131 | } |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 132 | if raddr != "" { |
| 133 | if ra, err = ResolveTCPAddr(raddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 134 | goto Error |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 135 | } |
| 136 | } |
| 137 | return DialTCP(net, la, ra); |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 138 | case "udp", "udp4", "upd6": |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 139 | var la, ra *UDPAddr; |
| 140 | if laddr != "" { |
| 141 | if la, err = ResolveUDPAddr(laddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 142 | goto Error |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 143 | } |
| 144 | } |
| 145 | if raddr != "" { |
| 146 | if ra, err = ResolveUDPAddr(raddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 147 | goto Error |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 148 | } |
| 149 | } |
| 150 | return DialUDP(net, la, ra); |
| 151 | case "unix", "unixgram": |
| 152 | var la, ra *UnixAddr; |
| 153 | if raddr != "" { |
| 154 | if ra, err = ResolveUnixAddr(net, raddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 155 | goto Error |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 156 | } |
| 157 | } |
| 158 | if laddr != "" { |
| 159 | if la, err = ResolveUnixAddr(net, laddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 160 | goto Error |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 161 | } |
| 162 | } |
| 163 | return DialUnix(net, la, ra); |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 164 | } |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 165 | err = UnknownNetworkError(net); |
| 166 | Error: |
| 167 | return nil, &OpError{"dial", net+" "+raddr, nil, err}; |
Russ Cox | e8a0223 | 2008-09-16 13:42:47 -0700 | [diff] [blame] | 168 | } |
| 169 | |
Russ Cox | c93da7c7 | 2009-03-05 15:48:12 -0800 | [diff] [blame] | 170 | // Listen announces on the local network address laddr. |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 171 | // The network string net must be a stream-oriented |
| 172 | // network: "tcp", "tcp4", "tcp6", or "unix". |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 173 | func Listen(net, laddr string) (l Listener, err os.Error) { |
Russ Cox | a4f1564 | 2008-09-30 14:03:13 -0700 | [diff] [blame] | 174 | switch net { |
Russ Cox | 9350ef4 | 2008-09-17 13:49:23 -0700 | [diff] [blame] | 175 | case "tcp", "tcp4", "tcp6": |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 176 | var la *TCPAddr; |
| 177 | if laddr != "" { |
| 178 | if la, err = ResolveTCPAddr(laddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 179 | return nil, err |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 180 | } |
| 181 | } |
| 182 | l, err := ListenTCP(net, la); |
Russ Cox | 9350ef4 | 2008-09-17 13:49:23 -0700 | [diff] [blame] | 183 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 184 | return nil, err |
Russ Cox | 9350ef4 | 2008-09-17 13:49:23 -0700 | [diff] [blame] | 185 | } |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 186 | return l, nil; |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 187 | case "unix": |
| 188 | var la *UnixAddr; |
| 189 | if laddr != "" { |
| 190 | if la, err = ResolveUnixAddr(net, laddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 191 | return nil, err |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 192 | } |
| 193 | } |
| 194 | l, err := ListenUnix(net, la); |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 195 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 196 | return nil, err |
Russ Cox | cc1d4b7 | 2009-05-13 18:03:41 -0700 | [diff] [blame] | 197 | } |
| 198 | return l, nil; |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 199 | } |
| 200 | return nil, UnknownNetworkError(net); |
| 201 | } |
| 202 | |
| 203 | // ListenPacket announces on the local network address laddr. |
| 204 | // The network string net must be a packet-oriented network: |
| 205 | // "udp", "udp4", "udp6", or "unixgram". |
| 206 | func ListenPacket(net, laddr string) (c PacketConn, err os.Error) { |
| 207 | switch net { |
| 208 | case "udp", "udp4", "udp6": |
| 209 | var la *UDPAddr; |
| 210 | if laddr != "" { |
| 211 | if la, err = ResolveUDPAddr(laddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 212 | return nil, err |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 213 | } |
| 214 | } |
| 215 | c, err := ListenUDP(net, la); |
| 216 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 217 | return nil, err |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 218 | } |
| 219 | return c, nil; |
| 220 | case "unixgram": |
| 221 | var la *UnixAddr; |
| 222 | if laddr != "" { |
| 223 | if la, err = ResolveUnixAddr(net, laddr); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 224 | return nil, err |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 225 | } |
| 226 | } |
| 227 | c, err := DialUnix(net, la, nil); |
| 228 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 229 | return nil, err |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 230 | } |
| 231 | return c, nil; |
Russ Cox | 9350ef4 | 2008-09-17 13:49:23 -0700 | [diff] [blame] | 232 | } |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 233 | return nil, UnknownNetworkError(net); |
Russ Cox | 9350ef4 | 2008-09-17 13:49:23 -0700 | [diff] [blame] | 234 | } |
Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [diff] [blame] | 235 | |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 236 | var errMissingAddress = os.ErrorString("missing address") |
| 237 | |
| 238 | type OpError struct { |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 239 | Op string; |
| 240 | Net string; |
| 241 | Addr Addr; |
| 242 | Error os.Error; |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 243 | } |
| 244 | |
| 245 | func (e *OpError) String() string { |
| 246 | s := e.Op; |
| 247 | if e.Net != "" { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 248 | s += " " + e.Net |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 249 | } |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 250 | if e.Addr != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 251 | s += " " + e.Addr.String() |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 252 | } |
| 253 | s += ": " + e.Error.String(); |
| 254 | return s; |
| 255 | } |
| 256 | |
| 257 | type AddrError struct { |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 258 | Error string; |
| 259 | Addr string; |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | func (e *AddrError) String() string { |
| 263 | s := e.Error; |
| 264 | if e.Addr != "" { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame^] | 265 | s += " " + e.Addr |
Russ Cox | 35ace1d | 2009-11-01 11:15:34 -0800 | [diff] [blame] | 266 | } |
| 267 | return s; |
| 268 | } |
| 269 | |
| 270 | type UnknownNetworkError string |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 271 | |
Robert Griesemer | 368f8cb | 2009-11-06 14:24:38 -0800 | [diff] [blame] | 272 | func (e UnknownNetworkError) String() string { return "unknown network " + string(e) } |