Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / libgo / go / net / iprawsock.go
blob241be150956bf45e05b200a7196fc182b786912e
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 // (Raw) IP sockets
7 package net
9 import (
10 "os"
11 "sync"
12 "syscall"
15 var onceReadProtocols sync.Once
17 func sockaddrToIP(sa syscall.Sockaddr) Addr {
18 switch sa := sa.(type) {
19 case *syscall.SockaddrInet4:
20 return &IPAddr{sa.Addr[0:]}
21 case *syscall.SockaddrInet6:
22 return &IPAddr{sa.Addr[0:]}
24 return nil
27 // IPAddr represents the address of a IP end point.
28 type IPAddr struct {
29 IP IP
32 // Network returns the address's network name, "ip".
33 func (a *IPAddr) Network() string { return "ip" }
35 func (a *IPAddr) String() string {
36 if a == nil {
37 return "<nil>"
39 return a.IP.String()
42 func (a *IPAddr) family() int {
43 if a == nil || len(a.IP) <= 4 {
44 return syscall.AF_INET
46 if ip := a.IP.To4(); ip != nil {
47 return syscall.AF_INET
49 return syscall.AF_INET6
52 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
53 return ipToSockaddr(family, a.IP, 0)
56 func (a *IPAddr) toAddr() sockaddr {
57 if a == nil { // nil *IPAddr
58 return nil // nil interface
60 return a
63 // ResolveIPAddr parses addr as a IP address and resolves domain
64 // names to numeric addresses. A literal IPv6 host address must be
65 // enclosed in square brackets, as in "[::]".
66 func ResolveIPAddr(addr string) (*IPAddr, os.Error) {
67 ip, err := hostToIP(addr)
68 if err != nil {
69 return nil, err
71 return &IPAddr{ip}, nil
74 // IPConn is the implementation of the Conn and PacketConn
75 // interfaces for IP network connections.
76 type IPConn struct {
77 fd *netFD
80 func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} }
82 func (c *IPConn) ok() bool { return c != nil && c.fd != nil }
84 // Implementation of the Conn interface - see Conn for documentation.
86 // Read implements the net.Conn Read method.
87 func (c *IPConn) Read(b []byte) (n int, err os.Error) {
88 n, _, err = c.ReadFrom(b)
89 return
92 // Write implements the net.Conn Write method.
93 func (c *IPConn) Write(b []byte) (n int, err os.Error) {
94 if !c.ok() {
95 return 0, os.EINVAL
97 return c.fd.Write(b)
100 // Close closes the IP connection.
101 func (c *IPConn) Close() os.Error {
102 if !c.ok() {
103 return os.EINVAL
105 err := c.fd.Close()
106 c.fd = nil
107 return err
110 // LocalAddr returns the local network address.
111 func (c *IPConn) LocalAddr() Addr {
112 if !c.ok() {
113 return nil
115 return c.fd.laddr
118 // RemoteAddr returns the remote network address, a *IPAddr.
119 func (c *IPConn) RemoteAddr() Addr {
120 if !c.ok() {
121 return nil
123 return c.fd.raddr
126 // SetTimeout implements the net.Conn SetTimeout method.
127 func (c *IPConn) SetTimeout(nsec int64) os.Error {
128 if !c.ok() {
129 return os.EINVAL
131 return setTimeout(c.fd, nsec)
134 // SetReadTimeout implements the net.Conn SetReadTimeout method.
135 func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
136 if !c.ok() {
137 return os.EINVAL
139 return setReadTimeout(c.fd, nsec)
142 // SetWriteTimeout implements the net.Conn SetWriteTimeout method.
143 func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
144 if !c.ok() {
145 return os.EINVAL
147 return setWriteTimeout(c.fd, nsec)
150 // SetReadBuffer sets the size of the operating system's
151 // receive buffer associated with the connection.
152 func (c *IPConn) SetReadBuffer(bytes int) os.Error {
153 if !c.ok() {
154 return os.EINVAL
156 return setReadBuffer(c.fd, bytes)
159 // SetWriteBuffer sets the size of the operating system's
160 // transmit buffer associated with the connection.
161 func (c *IPConn) SetWriteBuffer(bytes int) os.Error {
162 if !c.ok() {
163 return os.EINVAL
165 return setWriteBuffer(c.fd, bytes)
168 // IP-specific methods.
170 // ReadFromIP reads a IP packet from c, copying the payload into b.
171 // It returns the number of bytes copied into b and the return address
172 // that was on the packet.
174 // ReadFromIP can be made to time out and return an error with
175 // Timeout() == true after a fixed time limit; see SetTimeout and
176 // SetReadTimeout.
177 func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err os.Error) {
178 if !c.ok() {
179 return 0, nil, os.EINVAL
181 // TODO(cw,rsc): consider using readv if we know the family
182 // type to avoid the header trim/copy
183 n, sa, err := c.fd.ReadFrom(b)
184 switch sa := sa.(type) {
185 case *syscall.SockaddrInet4:
186 addr = &IPAddr{sa.Addr[0:]}
187 if len(b) >= 4 { // discard ipv4 header
188 hsize := (int(b[0]) & 0xf) * 4
189 copy(b, b[hsize:])
190 n -= hsize
192 case *syscall.SockaddrInet6:
193 addr = &IPAddr{sa.Addr[0:]}
195 return
198 // ReadFrom implements the net.PacketConn ReadFrom method.
199 func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
200 if !c.ok() {
201 return 0, nil, os.EINVAL
203 n, uaddr, err := c.ReadFromIP(b)
204 return n, uaddr.toAddr(), err
207 // WriteToIP writes a IP packet to addr via c, copying the payload from b.
209 // WriteToIP can be made to time out and return
210 // an error with Timeout() == true after a fixed time limit;
211 // see SetTimeout and SetWriteTimeout.
212 // On packet-oriented connections, write timeouts are rare.
213 func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
214 if !c.ok() {
215 return 0, os.EINVAL
217 sa, err1 := addr.sockaddr(c.fd.family)
218 if err1 != nil {
219 return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Error: err1}
221 return c.fd.WriteTo(b, sa)
224 // WriteTo implements the net.PacketConn WriteTo method.
225 func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
226 if !c.ok() {
227 return 0, os.EINVAL
229 a, ok := addr.(*IPAddr)
230 if !ok {
231 return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
233 return c.WriteToIP(b, a)
236 // Convert "host" into IP address.
237 func hostToIP(host string) (ip IP, err os.Error) {
238 var addr IP
239 // Try as an IP address.
240 addr = ParseIP(host)
241 if addr == nil {
242 // Not an IP address. Try as a DNS name.
243 _, addrs, err1 := LookupHost(host)
244 if err1 != nil {
245 err = err1
246 goto Error
248 addr = ParseIP(addrs[0])
249 if addr == nil {
250 // should not happen
251 err = &AddrError{"LookupHost returned invalid address", addrs[0]}
252 goto Error
256 return addr, nil
258 Error:
259 return nil, err
263 var protocols map[string]int
265 func readProtocols() {
266 protocols = make(map[string]int)
267 if file, err := open("/etc/protocols"); err == nil {
268 for line, ok := file.readLine(); ok; line, ok = file.readLine() {
269 // tcp 6 TCP # transmission control protocol
270 if i := byteIndex(line, '#'); i >= 0 {
271 line = line[0:i]
273 f := getFields(line)
274 if len(f) < 2 {
275 continue
277 if proto, _, ok := dtoi(f[1], 0); ok {
278 protocols[f[0]] = proto
279 for _, alias := range f[2:] {
280 protocols[alias] = proto
284 file.close()
288 func netProtoSplit(netProto string) (net string, proto int, err os.Error) {
289 onceReadProtocols.Do(readProtocols)
290 i := last(netProto, ':')
291 if i < 0 { // no colon
292 return "", 0, os.ErrorString("no IP protocol specified")
294 net = netProto[0:i]
295 protostr := netProto[i+1:]
296 proto, i, ok := dtoi(protostr, 0)
297 if !ok || i != len(protostr) {
298 // lookup by name
299 proto, ok = protocols[protostr]
300 if ok {
301 return
304 return
307 // DialIP connects to the remote address raddr on the network net,
308 // which must be "ip", "ip4", or "ip6".
309 func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
310 net, proto, err := netProtoSplit(netProto)
311 if err != nil {
312 return
314 switch prefixBefore(net, ':') {
315 case "ip", "ip4", "ip6":
316 default:
317 return nil, UnknownNetworkError(net)
319 if raddr == nil {
320 return nil, &OpError{"dial", "ip", nil, errMissingAddress}
322 fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
323 if e != nil {
324 return nil, e
326 return newIPConn(fd), nil
329 // ListenIP listens for incoming IP packets addressed to the
330 // local address laddr. The returned connection c's ReadFrom
331 // and WriteTo methods can be used to receive and send IP
332 // packets with per-packet addressing.
333 func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
334 net, proto, err := netProtoSplit(netProto)
335 if err != nil {
336 return
338 switch prefixBefore(net, ':') {
339 case "ip", "ip4", "ip6":
340 default:
341 return nil, UnknownNetworkError(net)
343 fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
344 if e != nil {
345 return nil, e
347 return newIPConn(fd), nil
350 // BindToDevice binds an IPConn to a network interface.
351 func (c *IPConn) BindToDevice(device string) os.Error {
352 if !c.ok() {
353 return os.EINVAL
355 c.fd.incref()
356 defer c.fd.decref()
357 return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))