Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / net / udpsock_posix.go
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
5 // +build darwin freebsd linux netbsd openbsd windows
6
7 // UDP sockets for POSIX
8
9 package net
10
11 import (
12         "syscall"
13         "time"
14 )
15
16 func sockaddrToUDP(sa syscall.Sockaddr) Addr {
17         switch sa := sa.(type) {
18         case *syscall.SockaddrInet4:
19                 return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
20         case *syscall.SockaddrInet6:
21                 return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
22         }
23         return nil
24 }
25
26 func (a *UDPAddr) family() int {
27         if a == nil || len(a.IP) <= IPv4len {
28                 return syscall.AF_INET
29         }
30         if a.IP.To4() != nil {
31                 return syscall.AF_INET
32         }
33         return syscall.AF_INET6
34 }
35
36 func (a *UDPAddr) isWildcard() bool {
37         if a == nil || a.IP == nil {
38                 return true
39         }
40         return a.IP.IsUnspecified()
41 }
42
43 func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
44         return ipToSockaddr(family, a.IP, a.Port, a.Zone)
45 }
46
47 func (a *UDPAddr) toAddr() sockaddr {
48         if a == nil { // nil *UDPAddr
49                 return nil // nil interface
50         }
51         return a
52 }
53
54 // UDPConn is the implementation of the Conn and PacketConn
55 // interfaces for UDP network connections.
56 type UDPConn struct {
57         conn
58 }
59
60 func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
61
62 // ReadFromUDP reads a UDP 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.
65 //
66 // ReadFromUDP can be made to time out and return an error with Timeout() == true
67 // after a fixed time limit; see SetDeadline and SetReadDeadline.
68 func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
69         if !c.ok() {
70                 return 0, nil, syscall.EINVAL
71         }
72         n, sa, err := c.fd.ReadFrom(b)
73         switch sa := sa.(type) {
74         case *syscall.SockaddrInet4:
75                 addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
76         case *syscall.SockaddrInet6:
77                 addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
78         }
79         return
80 }
81
82 // ReadFrom implements the PacketConn ReadFrom method.
83 func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
84         if !c.ok() {
85                 return 0, nil, syscall.EINVAL
86         }
87         n, addr, err := c.ReadFromUDP(b)
88         return n, addr.toAddr(), err
89 }
90
91 // ReadMsgUDP reads a packet from c, copying the payload into b and
92 // the associdated out-of-band data into oob.  It returns the number
93 // of bytes copied into b, the number of bytes copied into oob, the
94 // flags that were set on the packet and the source address of the
95 // packet.
96 func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
97         if !c.ok() {
98                 return 0, 0, 0, nil, syscall.EINVAL
99         }
100         var sa syscall.Sockaddr
101         n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
102         switch sa := sa.(type) {
103         case *syscall.SockaddrInet4:
104                 addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
105         case *syscall.SockaddrInet6:
106                 addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
107         }
108         return
109 }
110
111 // WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
112 //
113 // WriteToUDP can be made to time out and return
114 // an error with Timeout() == true after a fixed time limit;
115 // see SetDeadline and SetWriteDeadline.
116 // On packet-oriented connections, write timeouts are rare.
117 func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
118         if !c.ok() {
119                 return 0, syscall.EINVAL
120         }
121         if c.fd.isConnected {
122                 return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
123         }
124         sa, err := addr.sockaddr(c.fd.family)
125         if err != nil {
126                 return 0, &OpError{"write", c.fd.net, addr, err}
127         }
128         return c.fd.WriteTo(b, sa)
129 }
130
131 // WriteTo implements the PacketConn WriteTo method.
132 func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
133         if !c.ok() {
134                 return 0, syscall.EINVAL
135         }
136         a, ok := addr.(*UDPAddr)
137         if !ok {
138                 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
139         }
140         return c.WriteToUDP(b, a)
141 }
142
143 // WriteMsgUDP writes a packet to addr via c, copying the payload from
144 // b and the associated out-of-band data from oob.  It returns the
145 // number of payload and out-of-band bytes written.
146 func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
147         if !c.ok() {
148                 return 0, 0, syscall.EINVAL
149         }
150         if c.fd.isConnected {
151                 return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
152         }
153         sa, err := addr.sockaddr(c.fd.family)
154         if err != nil {
155                 return 0, 0, &OpError{"write", c.fd.net, addr, err}
156         }
157         return c.fd.WriteMsg(b, oob, sa)
158 }
159
160 // DialUDP connects to the remote address raddr on the network net,
161 // which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is used
162 // as the local address for the connection.
163 func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
164         return dialUDP(net, laddr, raddr, noDeadline)
165 }
166
167 func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
168         switch net {
169         case "udp", "udp4", "udp6":
170         default:
171                 return nil, UnknownNetworkError(net)
172         }
173         if raddr == nil {
174                 return nil, &OpError{"dial", net, nil, errMissingAddress}
175         }
176         fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
177         if err != nil {
178                 return nil, err
179         }
180         return newUDPConn(fd), nil
181 }
182
183 // ListenUDP listens for incoming UDP packets addressed to the
184 // local address laddr.  The returned connection c's ReadFrom
185 // and WriteTo methods can be used to receive and send UDP
186 // packets with per-packet addressing.
187 func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
188         switch net {
189         case "udp", "udp4", "udp6":
190         default:
191                 return nil, UnknownNetworkError(net)
192         }
193         if laddr == nil {
194                 laddr = &UDPAddr{}
195         }
196         fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
197         if err != nil {
198                 return nil, err
199         }
200         return newUDPConn(fd), nil
201 }
202
203 // ListenMulticastUDP listens for incoming multicast UDP packets
204 // addressed to the group address gaddr on ifi, which specifies
205 // the interface to join.  ListenMulticastUDP uses default
206 // multicast interface if ifi is nil.
207 func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
208         switch net {
209         case "udp", "udp4", "udp6":
210         default:
211                 return nil, UnknownNetworkError(net)
212         }
213         if gaddr == nil || gaddr.IP == nil {
214                 return nil, &OpError{"listen", net, nil, errMissingAddress}
215         }
216         fd, err := internetSocket(net, gaddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
217         if err != nil {
218                 return nil, err
219         }
220         c := newUDPConn(fd)
221         if ip4 := gaddr.IP.To4(); ip4 != nil {
222                 if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
223                         c.Close()
224                         return nil, &OpError{"listen", net, &IPAddr{IP: ip4}, err}
225                 }
226         } else {
227                 if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
228                         c.Close()
229                         return nil, &OpError{"listen", net, &IPAddr{IP: gaddr.IP}, err}
230                 }
231         }
232         return c, nil
233 }
234
235 func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
236         if ifi != nil {
237                 if err := setIPv4MulticastInterface(c.fd, ifi); err != nil {
238                         return err
239                 }
240         }
241         if err := setIPv4MulticastLoopback(c.fd, false); err != nil {
242                 return err
243         }
244         if err := joinIPv4Group(c.fd, ifi, ip); err != nil {
245                 return err
246         }
247         return nil
248 }
249
250 func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
251         if ifi != nil {
252                 if err := setIPv6MulticastInterface(c.fd, ifi); err != nil {
253                         return err
254                 }
255         }
256         if err := setIPv6MulticastLoopback(c.fd, false); err != nil {
257                 return err
258         }
259         if err := joinIPv6Group(c.fd, ifi, ip); err != nil {
260                 return err
261         }
262         return nil
263 }