* gcc.dg/guality/guality.exp: Skip on AIX.
[official-gcc.git] / libgo / go / net / iprawsock_posix.go
blobcaeeb465383d1794755fe1569cdeebc3e19ab9c4
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 package net
9 import (
10 "syscall"
11 "time"
14 func sockaddrToIP(sa syscall.Sockaddr) Addr {
15 switch sa := sa.(type) {
16 case *syscall.SockaddrInet4:
17 return &IPAddr{IP: sa.Addr[0:]}
18 case *syscall.SockaddrInet6:
19 return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
21 return nil
24 func (a *IPAddr) family() int {
25 if a == nil || len(a.IP) <= IPv4len {
26 return syscall.AF_INET
28 if a.IP.To4() != nil {
29 return syscall.AF_INET
31 return syscall.AF_INET6
34 func (a *IPAddr) isWildcard() bool {
35 if a == nil || a.IP == nil {
36 return true
38 return a.IP.IsUnspecified()
41 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
42 return ipToSockaddr(family, a.IP, 0, a.Zone)
45 func (a *IPAddr) toAddr() sockaddr {
46 if a == nil { // nil *IPAddr
47 return nil // nil interface
49 return a
52 // IPConn is the implementation of the Conn and PacketConn interfaces
53 // for IP network connections.
54 type IPConn struct {
55 conn
58 func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
60 // ReadFromIP reads an IP packet from c, copying the payload into b.
61 // It returns the number of bytes copied into b and the return address
62 // that was on the packet.
64 // ReadFromIP can be made to time out and return an error with
65 // Timeout() == true after a fixed time limit; see SetDeadline and
66 // SetReadDeadline.
67 func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
68 if !c.ok() {
69 return 0, nil, syscall.EINVAL
71 // TODO(cw,rsc): consider using readv if we know the family
72 // type to avoid the header trim/copy
73 var addr *IPAddr
74 n, sa, err := c.fd.ReadFrom(b)
75 switch sa := sa.(type) {
76 case *syscall.SockaddrInet4:
77 addr = &IPAddr{IP: sa.Addr[0:]}
78 if len(b) >= IPv4len { // discard ipv4 header
79 hsize := (int(b[0]) & 0xf) * 4
80 copy(b, b[hsize:])
81 n -= hsize
83 case *syscall.SockaddrInet6:
84 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
86 return n, addr, err
89 // ReadFrom implements the PacketConn ReadFrom method.
90 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
91 if !c.ok() {
92 return 0, nil, syscall.EINVAL
94 n, addr, err := c.ReadFromIP(b)
95 return n, addr.toAddr(), err
98 // ReadMsgIP reads a packet from c, copying the payload into b and the
99 // associated out-of-band data into oob. It returns the number of
100 // bytes copied into b, the number of bytes copied into oob, the flags
101 // that were set on the packet and the source address of the packet.
102 func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
103 if !c.ok() {
104 return 0, 0, 0, nil, syscall.EINVAL
106 var sa syscall.Sockaddr
107 n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
108 switch sa := sa.(type) {
109 case *syscall.SockaddrInet4:
110 addr = &IPAddr{IP: sa.Addr[0:]}
111 case *syscall.SockaddrInet6:
112 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
114 return
117 // WriteToIP writes an IP packet to addr via c, copying the payload
118 // from b.
120 // WriteToIP can be made to time out and return an error with
121 // Timeout() == true after a fixed time limit; see SetDeadline and
122 // SetWriteDeadline. On packet-oriented connections, write timeouts
123 // are rare.
124 func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
125 if !c.ok() {
126 return 0, syscall.EINVAL
128 sa, err := addr.sockaddr(c.fd.family)
129 if err != nil {
130 return 0, &OpError{"write", c.fd.net, addr, err}
132 return c.fd.WriteTo(b, sa)
135 // WriteTo implements the PacketConn WriteTo method.
136 func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
137 if !c.ok() {
138 return 0, syscall.EINVAL
140 a, ok := addr.(*IPAddr)
141 if !ok {
142 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
144 return c.WriteToIP(b, a)
147 // WriteMsgIP writes a packet to addr via c, copying the payload from
148 // b and the associated out-of-band data from oob. It returns the
149 // number of payload and out-of-band bytes written.
150 func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
151 if !c.ok() {
152 return 0, 0, syscall.EINVAL
154 sa, err := addr.sockaddr(c.fd.family)
155 if err != nil {
156 return 0, 0, &OpError{"write", c.fd.net, addr, err}
158 return c.fd.WriteMsg(b, oob, sa)
161 // DialIP connects to the remote address raddr on the network protocol
162 // netProto, which must be "ip", "ip4", or "ip6" followed by a colon
163 // 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 := parseNetwork(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 local
189 // address laddr. The returned connection's ReadFrom and WriteTo
190 // methods can be used to receive and send IP packets with per-packet
191 // addressing.
192 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
193 net, proto, err := parseNetwork(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