LEFT | RIGHT |
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 | 1 |
5 // +build darwin freebsd linux netbsd openbsd windows | 2 // +build darwin freebsd linux netbsd openbsd windows |
6 | 3 |
7 // UDP sockets for POSIX | 4 // UDP sockets |
8 | 5 |
9 package net | 6 package net |
10 | 7 |
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, ZoneId: zoneIdTo
String(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.ZoneId) | |
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() == tru
e | |
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, ZoneId: zoneIdTo
String(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, ZoneId: zoneIdTo
String(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 er
ror) { | |
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, ErrWriteToConnect
ed} | |
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, e
rror) { | |
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, e
rror) { | |
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{"listenmulticast", net, nil, errMissingAddr
ess} | |
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 ip4 := gaddr.IP.To4() | |
222 if ip4 != nil { | |
223 err := listenIPv4MulticastUDP(c, ifi, ip4) | |
224 if err != nil { | |
225 c.Close() | |
226 return nil, err | |
227 } | |
228 } else { | |
229 err := listenIPv6MulticastUDP(c, ifi, gaddr.IP) | |
230 if err != nil { | |
231 c.Close() | |
232 return nil, err | |
233 } | |
234 } | |
235 return c, nil | |
236 } | |
237 | |
238 func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error { | |
239 if ifi != nil { | |
240 err := setIPv4MulticastInterface(c.fd, ifi) | |
241 if err != nil { | |
242 return err | |
243 } | |
244 } | |
245 err := setIPv4MulticastLoopback(c.fd, false) | |
246 if err != nil { | |
247 return err | |
248 } | |
249 err = joinIPv4GroupUDP(c, ifi, ip) | |
250 if err != nil { | |
251 return err | |
252 } | |
253 return nil | |
254 } | |
255 | |
256 func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error { | |
257 if ifi != nil { | |
258 err := setIPv6MulticastInterface(c.fd, ifi) | |
259 if err != nil { | |
260 return err | |
261 } | |
262 } | |
263 err := setIPv6MulticastLoopback(c.fd, false) | |
264 if err != nil { | |
265 return err | |
266 } | |
267 err = joinIPv6GroupUDP(c, ifi, ip) | |
268 if err != nil { | |
269 return err | |
270 } | |
271 return nil | |
272 } | |
273 | |
274 func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { | |
275 err := joinIPv4Group(c.fd, ifi, ip) | |
276 if err != nil { | |
277 return &OpError{"joinipv4group", c.fd.net, &IPAddr{IP: ip}, err} | |
278 } | |
279 return nil | |
280 } | |
281 | |
282 func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { | |
283 err := joinIPv6Group(c.fd, ifi, ip) | |
284 if err != nil { | |
285 return &OpError{"joinipv6group", c.fd.net, &IPAddr{IP: ip}, err} | |
286 } | |
287 return nil | |
288 } | |
LEFT | RIGHT |