2013-02-11 Sebastian Huber <sebastian.huber@embedded-brains.de>
[official-gcc.git] / libgo / go / net / iprawsock_posix.go
blob7a8cd4470d613cfba743a3db534e1bdab095990d
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 // +build darwin freebsd linux netbsd openbsd windows
7 // Raw IP sockets for POSIX
9 package net
11 import (
12 "syscall"
13 "time"
16 func sockaddrToIP(sa syscall.Sockaddr) Addr {
17 switch sa := sa.(type) {
18 case *syscall.SockaddrInet4:
19 return &IPAddr{IP: sa.Addr[0:]}
20 case *syscall.SockaddrInet6:
21 return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
23 return nil
26 func (a *IPAddr) family() int {
27 if a == nil || len(a.IP) <= IPv4len {
28 return syscall.AF_INET
30 if a.IP.To4() != nil {
31 return syscall.AF_INET
33 return syscall.AF_INET6
36 func (a *IPAddr) isWildcard() bool {
37 if a == nil || a.IP == nil {
38 return true
40 return a.IP.IsUnspecified()
43 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
44 return ipToSockaddr(family, a.IP, 0, a.Zone)
47 func (a *IPAddr) toAddr() sockaddr {
48 if a == nil { // nil *IPAddr
49 return nil // nil interface
51 return a
54 // IPConn is the implementation of the Conn and PacketConn
55 // interfaces for IP network connections.
56 type IPConn struct {
57 conn
60 func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
62 // ReadFromIP reads an IP packet from c, copying the payload into b.
63 // It returns the number of bytes copied into b and the return address
64 // that was on the packet.
66 // ReadFromIP can be made to time out and return an error with
67 // Timeout() == true after a fixed time limit; see SetDeadline and
68 // SetReadDeadline.
69 func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
70 if !c.ok() {
71 return 0, nil, syscall.EINVAL
73 // TODO(cw,rsc): consider using readv if we know the family
74 // type to avoid the header trim/copy
75 var addr *IPAddr
76 n, sa, err := c.fd.ReadFrom(b)
77 switch sa := sa.(type) {
78 case *syscall.SockaddrInet4:
79 addr = &IPAddr{IP: sa.Addr[0:]}
80 if len(b) >= IPv4len { // discard ipv4 header
81 hsize := (int(b[0]) & 0xf) * 4
82 copy(b, b[hsize:])
83 n -= hsize
85 case *syscall.SockaddrInet6:
86 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
88 return n, addr, err
91 // ReadFrom implements the PacketConn ReadFrom method.
92 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
93 if !c.ok() {
94 return 0, nil, syscall.EINVAL
96 n, addr, err := c.ReadFromIP(b)
97 return n, addr.toAddr(), err
100 // ReadMsgIP reads a packet from c, copying the payload into b and the
101 // associdated out-of-band data into oob. It returns the number of
102 // bytes copied into b, the number of bytes copied into oob, the flags
103 // that were set on the packet and the source address of the packet.
104 func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
105 if !c.ok() {
106 return 0, 0, 0, nil, syscall.EINVAL
108 var sa syscall.Sockaddr
109 n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
110 switch sa := sa.(type) {
111 case *syscall.SockaddrInet4:
112 addr = &IPAddr{IP: sa.Addr[0:]}
113 case *syscall.SockaddrInet6:
114 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
116 return
119 // WriteToIP writes an IP packet to addr via c, copying the payload from b.
121 // WriteToIP can be made to time out and return
122 // an error with Timeout() == true after a fixed time limit;
123 // see SetDeadline and SetWriteDeadline.
124 // On packet-oriented connections, write timeouts are rare.
125 func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
126 if !c.ok() {
127 return 0, syscall.EINVAL
129 sa, err := addr.sockaddr(c.fd.family)
130 if err != nil {
131 return 0, &OpError{"write", c.fd.net, addr, err}
133 return c.fd.WriteTo(b, sa)
136 // WriteTo implements the PacketConn WriteTo method.
137 func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
138 if !c.ok() {
139 return 0, syscall.EINVAL
141 a, ok := addr.(*IPAddr)
142 if !ok {
143 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
145 return c.WriteToIP(b, a)
148 // WriteMsgIP writes a packet to addr via c, copying the payload from
149 // b and the associated out-of-band data from oob. It returns the
150 // number of payload and out-of-band bytes written.
151 func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
152 if !c.ok() {
153 return 0, 0, syscall.EINVAL
155 sa, err := addr.sockaddr(c.fd.family)
156 if err != nil {
157 return 0, 0, &OpError{"write", c.fd.net, addr, err}
159 return c.fd.WriteMsg(b, oob, sa)
162 // DialIP connects to the remote address raddr on the network protocol netProto,
163 // which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
164 func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
165 return dialIP(netProto, laddr, raddr, noDeadline)
168 func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
169 net, proto, err := parseDialNetwork(netProto)
170 if err != nil {
171 return nil, err
173 switch net {
174 case "ip", "ip4", "ip6":
175 default:
176 return nil, UnknownNetworkError(netProto)
178 if raddr == nil {
179 return nil, &OpError{"dial", netProto, nil, errMissingAddress}
181 fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
182 if err != nil {
183 return nil, err
185 return newIPConn(fd), nil
188 // ListenIP listens for incoming IP packets addressed to the
189 // local address laddr. The returned connection c's ReadFrom
190 // and WriteTo methods can be used to receive and send IP
191 // packets with per-packet addressing.
192 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
193 net, proto, err := parseDialNetwork(netProto)
194 if err != nil {
195 return nil, err
197 switch net {
198 case "ip", "ip4", "ip6":
199 default:
200 return nil, UnknownNetworkError(netProto)
202 fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
203 if err != nil {
204 return nil, err
206 return newIPConn(fd), nil