OSDN Git Service

9e820e1c57acd716c7f016983f6c72e8d6334b6d
[pf3gnuchains/gcc-fork.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
8
9 package net
10
11 import (
12         "errors"
13         "os"
14         "syscall"
15         "time"
16 )
17
18 var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
19
20 func sockaddrToUDP(sa syscall.Sockaddr) Addr {
21         switch sa := sa.(type) {
22         case *syscall.SockaddrInet4:
23                 return &UDPAddr{sa.Addr[0:], sa.Port}
24         case *syscall.SockaddrInet6:
25                 return &UDPAddr{sa.Addr[0:], sa.Port}
26         }
27         return nil
28 }
29
30 func (a *UDPAddr) family() int {
31         if a == nil || len(a.IP) <= IPv4len {
32                 return syscall.AF_INET
33         }
34         if a.IP.To4() != nil {
35                 return syscall.AF_INET
36         }
37         return syscall.AF_INET6
38 }
39
40 func (a *UDPAddr) isWildcard() bool {
41         if a == nil || a.IP == nil {
42                 return true
43         }
44         return a.IP.IsUnspecified()
45 }
46
47 func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
48         return ipToSockaddr(family, a.IP, a.Port)
49 }
50
51 func (a *UDPAddr) toAddr() sockaddr {
52         if a == nil { // nil *UDPAddr
53                 return nil // nil interface
54         }
55         return a
56 }
57
58 // UDPConn is the implementation of the Conn and PacketConn
59 // interfaces for UDP network connections.
60 type UDPConn struct {
61         fd *netFD
62 }
63
64 func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{fd} }
65
66 func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
67
68 // Implementation of the Conn interface - see Conn for documentation.
69
70 // Read implements the Conn Read method.
71 func (c *UDPConn) Read(b []byte) (int, error) {
72         if !c.ok() {
73                 return 0, syscall.EINVAL
74         }
75         return c.fd.Read(b)
76 }
77
78 // Write implements the Conn Write method.
79 func (c *UDPConn) Write(b []byte) (int, error) {
80         if !c.ok() {
81                 return 0, syscall.EINVAL
82         }
83         return c.fd.Write(b)
84 }
85
86 // Close closes the UDP connection.
87 func (c *UDPConn) Close() error {
88         if !c.ok() {
89                 return syscall.EINVAL
90         }
91         err := c.fd.Close()
92         c.fd = nil
93         return err
94 }
95
96 // LocalAddr returns the local network address.
97 func (c *UDPConn) LocalAddr() Addr {
98         if !c.ok() {
99                 return nil
100         }
101         return c.fd.laddr
102 }
103
104 // RemoteAddr returns the remote network address, a *UDPAddr.
105 func (c *UDPConn) RemoteAddr() Addr {
106         if !c.ok() {
107                 return nil
108         }
109         return c.fd.raddr
110 }
111
112 // SetDeadline implements the Conn SetDeadline method.
113 func (c *UDPConn) SetDeadline(t time.Time) error {
114         if !c.ok() {
115                 return syscall.EINVAL
116         }
117         return setDeadline(c.fd, t)
118 }
119
120 // SetReadDeadline implements the Conn SetReadDeadline method.
121 func (c *UDPConn) SetReadDeadline(t time.Time) error {
122         if !c.ok() {
123                 return syscall.EINVAL
124         }
125         return setReadDeadline(c.fd, t)
126 }
127
128 // SetWriteDeadline implements the Conn SetWriteDeadline method.
129 func (c *UDPConn) SetWriteDeadline(t time.Time) error {
130         if !c.ok() {
131                 return syscall.EINVAL
132         }
133         return setWriteDeadline(c.fd, t)
134 }
135
136 // SetReadBuffer sets the size of the operating system's
137 // receive buffer associated with the connection.
138 func (c *UDPConn) SetReadBuffer(bytes int) error {
139         if !c.ok() {
140                 return syscall.EINVAL
141         }
142         return setReadBuffer(c.fd, bytes)
143 }
144
145 // SetWriteBuffer sets the size of the operating system's
146 // transmit buffer associated with the connection.
147 func (c *UDPConn) SetWriteBuffer(bytes int) error {
148         if !c.ok() {
149                 return syscall.EINVAL
150         }
151         return setWriteBuffer(c.fd, bytes)
152 }
153
154 // UDP-specific methods.
155
156 // ReadFromUDP reads a UDP packet from c, copying the payload into b.
157 // It returns the number of bytes copied into b and the return address
158 // that was on the packet.
159 //
160 // ReadFromUDP can be made to time out and return an error with Timeout() == true
161 // after a fixed time limit; see SetDeadline and SetReadDeadline.
162 func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
163         if !c.ok() {
164                 return 0, nil, syscall.EINVAL
165         }
166         n, sa, err := c.fd.ReadFrom(b)
167         switch sa := sa.(type) {
168         case *syscall.SockaddrInet4:
169                 addr = &UDPAddr{sa.Addr[0:], sa.Port}
170         case *syscall.SockaddrInet6:
171                 addr = &UDPAddr{sa.Addr[0:], sa.Port}
172         }
173         return
174 }
175
176 // ReadFrom implements the PacketConn ReadFrom method.
177 func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
178         if !c.ok() {
179                 return 0, nil, syscall.EINVAL
180         }
181         n, uaddr, err := c.ReadFromUDP(b)
182         return n, uaddr.toAddr(), err
183 }
184
185 // WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
186 //
187 // WriteToUDP can be made to time out and return
188 // an error with Timeout() == true after a fixed time limit;
189 // see SetDeadline and SetWriteDeadline.
190 // On packet-oriented connections, write timeouts are rare.
191 func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
192         if !c.ok() {
193                 return 0, syscall.EINVAL
194         }
195         if c.fd.isConnected {
196                 return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
197         }
198         sa, err := addr.sockaddr(c.fd.family)
199         if err != nil {
200                 return 0, &OpError{"write", c.fd.net, addr, err}
201         }
202         return c.fd.WriteTo(b, sa)
203 }
204
205 // WriteTo implements the PacketConn WriteTo method.
206 func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
207         if !c.ok() {
208                 return 0, syscall.EINVAL
209         }
210         a, ok := addr.(*UDPAddr)
211         if !ok {
212                 return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
213         }
214         return c.WriteToUDP(b, a)
215 }
216
217 // File returns a copy of the underlying os.File, set to blocking mode.
218 // It is the caller's responsibility to close f when finished.
219 // Closing c does not affect f, and closing f does not affect c.
220 func (c *UDPConn) File() (f *os.File, err error) { return c.fd.dup() }
221
222 // DialUDP connects to the remote address raddr on the network net,
223 // which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is used
224 // as the local address for the connection.
225 func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
226         switch net {
227         case "udp", "udp4", "udp6":
228         default:
229                 return nil, UnknownNetworkError(net)
230         }
231         if raddr == nil {
232                 return nil, &OpError{"dial", net, nil, errMissingAddress}
233         }
234         fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
235         if err != nil {
236                 return nil, err
237         }
238         return newUDPConn(fd), nil
239 }
240
241 // ListenUDP listens for incoming UDP packets addressed to the
242 // local address laddr.  The returned connection c's ReadFrom
243 // and WriteTo methods can be used to receive and send UDP
244 // packets with per-packet addressing.
245 func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
246         switch net {
247         case "udp", "udp4", "udp6":
248         default:
249                 return nil, UnknownNetworkError(net)
250         }
251         if laddr == nil {
252                 return nil, &OpError{"listen", net, nil, errMissingAddress}
253         }
254         fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
255         if err != nil {
256                 return nil, err
257         }
258         return newUDPConn(fd), nil
259 }
260
261 // ListenMulticastUDP listens for incoming multicast UDP packets
262 // addressed to the group address gaddr on ifi, which specifies
263 // the interface to join.  ListenMulticastUDP uses default
264 // multicast interface if ifi is nil.
265 func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
266         switch net {
267         case "udp", "udp4", "udp6":
268         default:
269                 return nil, UnknownNetworkError(net)
270         }
271         if gaddr == nil || gaddr.IP == nil {
272                 return nil, &OpError{"listenmulticast", net, nil, errMissingAddress}
273         }
274         fd, err := internetSocket(net, gaddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
275         if err != nil {
276                 return nil, err
277         }
278         c := newUDPConn(fd)
279         ip4 := gaddr.IP.To4()
280         if ip4 != nil {
281                 err := listenIPv4MulticastUDP(c, ifi, ip4)
282                 if err != nil {
283                         c.Close()
284                         return nil, err
285                 }
286         } else {
287                 err := listenIPv6MulticastUDP(c, ifi, gaddr.IP)
288                 if err != nil {
289                         c.Close()
290                         return nil, err
291                 }
292         }
293         return c, nil
294 }
295
296 func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
297         if ifi != nil {
298                 err := setIPv4MulticastInterface(c.fd, ifi)
299                 if err != nil {
300                         return err
301                 }
302         }
303         err := setIPv4MulticastLoopback(c.fd, false)
304         if err != nil {
305                 return err
306         }
307         err = joinIPv4GroupUDP(c, ifi, ip)
308         if err != nil {
309                 return err
310         }
311         return nil
312 }
313
314 func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
315         if ifi != nil {
316                 err := setIPv6MulticastInterface(c.fd, ifi)
317                 if err != nil {
318                         return err
319                 }
320         }
321         err := setIPv6MulticastLoopback(c.fd, false)
322         if err != nil {
323                 return err
324         }
325         err = joinIPv6GroupUDP(c, ifi, ip)
326         if err != nil {
327                 return err
328         }
329         return nil
330 }
331
332 func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
333         err := joinIPv4Group(c.fd, ifi, ip)
334         if err != nil {
335                 return &OpError{"joinipv4group", c.fd.net, &IPAddr{ip}, err}
336         }
337         return nil
338 }
339
340 func leaveIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
341         err := leaveIPv4Group(c.fd, ifi, ip)
342         if err != nil {
343                 return &OpError{"leaveipv4group", c.fd.net, &IPAddr{ip}, err}
344         }
345         return nil
346 }
347
348 func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
349         err := joinIPv6Group(c.fd, ifi, ip)
350         if err != nil {
351                 return &OpError{"joinipv6group", c.fd.net, &IPAddr{ip}, err}
352         }
353         return nil
354 }
355
356 func leaveIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
357         err := leaveIPv6Group(c.fd, ifi, ip)
358         if err != nil {
359                 return &OpError{"leaveipv6group", c.fd.net, &IPAddr{ip}, err}
360         }
361         return nil
362 }