|
160
|
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
|
2 *
|
|
|
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
4 * of this software and associated documentation files (the "Software"), to
|
|
|
5 * deal in the Software without restriction, including without limitation the
|
|
|
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
7 * sell copies of the Software, and to permit persons to whom the Software is
|
|
|
8 * furnished to do so, subject to the following conditions:
|
|
|
9 *
|
|
|
10 * The above copyright notice and this permission notice shall be included in
|
|
|
11 * all copies or substantial portions of the Software.
|
|
|
12 *
|
|
|
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
19 * IN THE SOFTWARE.
|
|
|
20 */
|
|
|
21
|
|
|
22 #include <assert.h>
|
|
|
23 #include <stdlib.h>
|
|
|
24
|
|
|
25 #include "uv.h"
|
|
|
26 #include "internal.h"
|
|
|
27 #include "handle-inl.h"
|
|
|
28 #include "stream-inl.h"
|
|
|
29 #include "req-inl.h"
|
|
|
30
|
|
|
31
|
|
|
32 /* A zero-size buffer for use by uv_udp_read */
|
|
|
33 static char uv_zero_[] = "";
|
|
|
34 int uv_udp_getpeername(const uv_udp_t* handle,
|
|
|
35 struct sockaddr* name,
|
|
|
36 int* namelen) {
|
|
|
37
|
|
|
38 return uv__getsockpeername((const uv_handle_t*) handle,
|
|
|
39 getpeername,
|
|
|
40 name,
|
|
|
41 namelen,
|
|
|
42 0);
|
|
|
43 }
|
|
|
44
|
|
|
45
|
|
|
46 int uv_udp_getsockname(const uv_udp_t* handle,
|
|
|
47 struct sockaddr* name,
|
|
|
48 int* namelen) {
|
|
|
49
|
|
|
50 return uv__getsockpeername((const uv_handle_t*) handle,
|
|
|
51 getsockname,
|
|
|
52 name,
|
|
|
53 namelen,
|
|
|
54 0);
|
|
|
55 }
|
|
|
56
|
|
|
57
|
|
|
58 static int uv__udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
|
|
59 int family) {
|
|
|
60 DWORD yes = 1;
|
|
|
61 WSAPROTOCOL_INFOW info;
|
|
|
62 int opt_len;
|
|
|
63
|
|
|
64 if (handle->socket != INVALID_SOCKET)
|
|
|
65 return UV_EBUSY;
|
|
|
66
|
|
|
67 /* Set the socket to nonblocking mode */
|
|
|
68 if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
|
|
|
69 return WSAGetLastError();
|
|
|
70 }
|
|
|
71
|
|
|
72 /* Make the socket non-inheritable */
|
|
|
73 if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
|
|
|
74 return GetLastError();
|
|
|
75 }
|
|
|
76
|
|
|
77 /* Associate it with the I/O completion port. Use uv_handle_t pointer as
|
|
|
78 * completion key. */
|
|
|
79 if (CreateIoCompletionPort((HANDLE)socket,
|
|
|
80 loop->iocp,
|
|
|
81 (ULONG_PTR)socket,
|
|
|
82 0) == NULL) {
|
|
|
83 return GetLastError();
|
|
|
84 }
|
|
|
85
|
|
|
86 /* All known Windows that support SetFileCompletionNotificationModes have a
|
|
|
87 * bug that makes it impossible to use this function in conjunction with
|
|
|
88 * datagram sockets. We can work around that but only if the user is using
|
|
|
89 * the default UDP driver (AFD) and has no other. LSPs stacked on top. Here
|
|
|
90 * we check whether that is the case. */
|
|
|
91 opt_len = (int) sizeof info;
|
|
|
92 if (getsockopt(
|
|
|
93 socket, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &info, &opt_len) ==
|
|
|
94 SOCKET_ERROR) {
|
|
|
95 return GetLastError();
|
|
|
96 }
|
|
|
97
|
|
|
98 if (info.ProtocolChain.ChainLen == 1) {
|
|
|
99 if (SetFileCompletionNotificationModes(
|
|
|
100 (HANDLE) socket,
|
|
|
101 FILE_SKIP_SET_EVENT_ON_HANDLE |
|
|
|
102 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
|
|
|
103 handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
|
|
104 handle->func_wsarecv = uv__wsarecv_workaround;
|
|
|
105 handle->func_wsarecvfrom = uv__wsarecvfrom_workaround;
|
|
|
106 } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
|
|
|
107 return GetLastError();
|
|
|
108 }
|
|
|
109 }
|
|
|
110
|
|
|
111 handle->socket = socket;
|
|
|
112
|
|
|
113 if (family == AF_INET6) {
|
|
|
114 handle->flags |= UV_HANDLE_IPV6;
|
|
|
115 } else {
|
|
|
116 assert(!(handle->flags & UV_HANDLE_IPV6));
|
|
|
117 }
|
|
|
118
|
|
|
119 return 0;
|
|
|
120 }
|
|
|
121
|
|
|
122
|
|
|
123 int uv__udp_init_ex(uv_loop_t* loop,
|
|
|
124 uv_udp_t* handle,
|
|
|
125 unsigned flags,
|
|
|
126 int domain) {
|
|
|
127 uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
|
|
|
128 handle->socket = INVALID_SOCKET;
|
|
|
129 handle->reqs_pending = 0;
|
|
|
130 handle->activecnt = 0;
|
|
|
131 handle->func_wsarecv = WSARecv;
|
|
|
132 handle->func_wsarecvfrom = WSARecvFrom;
|
|
|
133 handle->send_queue_size = 0;
|
|
|
134 handle->send_queue_count = 0;
|
|
|
135 UV_REQ_INIT(&handle->recv_req, UV_UDP_RECV);
|
|
|
136 handle->recv_req.data = handle;
|
|
|
137
|
|
|
138 /* If anything fails beyond this point we need to remove the handle from
|
|
|
139 * the handle queue, since it was added by uv__handle_init.
|
|
|
140 */
|
|
|
141
|
|
|
142 if (domain != AF_UNSPEC) {
|
|
|
143 SOCKET sock;
|
|
|
144 DWORD err;
|
|
|
145
|
|
|
146 sock = socket(domain, SOCK_DGRAM, 0);
|
|
|
147 if (sock == INVALID_SOCKET) {
|
|
|
148 err = WSAGetLastError();
|
|
|
149 uv__queue_remove(&handle->handle_queue);
|
|
|
150 return uv_translate_sys_error(err);
|
|
|
151 }
|
|
|
152
|
|
|
153 err = uv__udp_set_socket(handle->loop, handle, sock, domain);
|
|
|
154 if (err) {
|
|
|
155 closesocket(sock);
|
|
|
156 uv__queue_remove(&handle->handle_queue);
|
|
|
157 return uv_translate_sys_error(err);
|
|
|
158 }
|
|
|
159 }
|
|
|
160
|
|
|
161 return 0;
|
|
|
162 }
|
|
|
163
|
|
|
164
|
|
|
165 void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle) {
|
|
|
166 uv_udp_recv_stop(handle);
|
|
|
167 closesocket(handle->socket);
|
|
|
168 handle->socket = INVALID_SOCKET;
|
|
|
169
|
|
|
170 uv__handle_closing(handle);
|
|
|
171
|
|
|
172 if (handle->reqs_pending == 0) {
|
|
|
173 uv__want_endgame(loop, (uv_handle_t*) handle);
|
|
|
174 }
|
|
|
175 }
|
|
|
176
|
|
|
177
|
|
|
178 void uv__udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
|
|
|
179 if (handle->flags & UV_HANDLE_CLOSING &&
|
|
|
180 handle->reqs_pending == 0) {
|
|
|
181 assert(!(handle->flags & UV_HANDLE_CLOSED));
|
|
|
182 uv__handle_close(handle);
|
|
|
183 }
|
|
|
184 }
|
|
|
185
|
|
|
186
|
|
|
187 int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
|
|
|
188 return 0;
|
|
|
189 }
|
|
|
190
|
|
|
191
|
|
|
192 static int uv__udp_maybe_bind(uv_udp_t* handle,
|
|
|
193 const struct sockaddr* addr,
|
|
|
194 unsigned int addrlen,
|
|
|
195 unsigned int flags) {
|
|
|
196 int r;
|
|
|
197 int err;
|
|
|
198 DWORD no = 0;
|
|
|
199
|
|
|
200 if (handle->flags & UV_HANDLE_BOUND)
|
|
|
201 return 0;
|
|
|
202
|
|
|
203 /* There is no SO_REUSEPORT on Windows, Windows only knows SO_REUSEADDR.
|
|
|
204 * so we just return an error directly when UV_UDP_REUSEPORT is requested
|
|
|
205 * for binding the socket. */
|
|
|
206 if (flags & UV_UDP_REUSEPORT)
|
|
|
207 return ERROR_NOT_SUPPORTED;
|
|
|
208
|
|
|
209 if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
|
|
|
210 /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
|
|
|
211 return ERROR_INVALID_PARAMETER;
|
|
|
212 }
|
|
|
213
|
|
|
214 if (handle->socket == INVALID_SOCKET) {
|
|
|
215 SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
|
|
|
216 if (sock == INVALID_SOCKET) {
|
|
|
217 return WSAGetLastError();
|
|
|
218 }
|
|
|
219
|
|
|
220 err = uv__udp_set_socket(handle->loop, handle, sock, addr->sa_family);
|
|
|
221 if (err) {
|
|
|
222 closesocket(sock);
|
|
|
223 return err;
|
|
|
224 }
|
|
|
225 }
|
|
|
226
|
|
|
227 if (flags & UV_UDP_REUSEADDR) {
|
|
|
228 DWORD yes = 1;
|
|
|
229 /* Set SO_REUSEADDR on the socket. */
|
|
|
230 if (setsockopt(handle->socket,
|
|
|
231 SOL_SOCKET,
|
|
|
232 SO_REUSEADDR,
|
|
|
233 (char*) &yes,
|
|
|
234 sizeof yes) == SOCKET_ERROR) {
|
|
|
235 err = WSAGetLastError();
|
|
|
236 return err;
|
|
|
237 }
|
|
|
238 }
|
|
|
239
|
|
|
240 if (addr->sa_family == AF_INET6)
|
|
|
241 handle->flags |= UV_HANDLE_IPV6;
|
|
|
242
|
|
|
243 if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
|
|
|
244 /* On windows IPV6ONLY is on by default. If the user doesn't specify it
|
|
|
245 * libuv turns it off. */
|
|
|
246
|
|
|
247 /* TODO: how to handle errors? This may fail if there is no ipv4 stack
|
|
|
248 * available, or when run on XP/2003 which have no support for dualstack
|
|
|
249 * sockets. For now we're silently ignoring the error. */
|
|
|
250 setsockopt(handle->socket,
|
|
|
251 IPPROTO_IPV6,
|
|
|
252 IPV6_V6ONLY,
|
|
|
253 (char*) &no,
|
|
|
254 sizeof no);
|
|
|
255 }
|
|
|
256
|
|
|
257 r = bind(handle->socket, addr, addrlen);
|
|
|
258 if (r == SOCKET_ERROR) {
|
|
|
259 return WSAGetLastError();
|
|
|
260 }
|
|
|
261
|
|
|
262 handle->flags |= UV_HANDLE_BOUND;
|
|
|
263
|
|
|
264 return 0;
|
|
|
265 }
|
|
|
266
|
|
|
267
|
|
|
268 static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
|
|
269 uv_req_t* req;
|
|
|
270 uv_buf_t buf;
|
|
|
271 DWORD bytes, flags;
|
|
|
272 int result;
|
|
|
273
|
|
|
274 assert(handle->flags & UV_HANDLE_READING);
|
|
|
275 assert(!(handle->flags & UV_HANDLE_READ_PENDING));
|
|
|
276
|
|
|
277 req = &handle->recv_req;
|
|
|
278 memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
|
|
279
|
|
|
280 handle->flags |= UV_HANDLE_ZERO_READ;
|
|
|
281
|
|
|
282 buf.base = (char*) uv_zero_;
|
|
|
283 buf.len = 0;
|
|
|
284 flags = MSG_PEEK;
|
|
|
285
|
|
|
286 result = handle->func_wsarecv(handle->socket,
|
|
|
287 (WSABUF*) &buf,
|
|
|
288 1,
|
|
|
289 &bytes,
|
|
|
290 &flags,
|
|
|
291 &req->u.io.overlapped,
|
|
|
292 NULL);
|
|
|
293
|
|
|
294 if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
|
|
|
295 /* Process the req without IOCP. */
|
|
|
296 handle->flags |= UV_HANDLE_READ_PENDING;
|
|
|
297 req->u.io.overlapped.InternalHigh = bytes;
|
|
|
298 handle->reqs_pending++;
|
|
|
299 uv__insert_pending_req(loop, req);
|
|
|
300 } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
|
|
301 /* The req will be processed with IOCP. */
|
|
|
302 handle->flags |= UV_HANDLE_READ_PENDING;
|
|
|
303 handle->reqs_pending++;
|
|
|
304 } else {
|
|
|
305 /* Make this req pending reporting an error. */
|
|
|
306 SET_REQ_ERROR(req, WSAGetLastError());
|
|
|
307 uv__insert_pending_req(loop, req);
|
|
|
308 handle->reqs_pending++;
|
|
|
309 }
|
|
|
310 }
|
|
|
311
|
|
|
312
|
|
|
313 int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
|
|
314 uv_udp_recv_cb recv_cb) {
|
|
|
315 uv_loop_t* loop = handle->loop;
|
|
|
316 int err;
|
|
|
317
|
|
|
318 if (handle->flags & UV_HANDLE_READING) {
|
|
|
319 return UV_EALREADY;
|
|
|
320 }
|
|
|
321
|
|
|
322 err = uv__udp_maybe_bind(handle,
|
|
|
323 (const struct sockaddr*) &uv_addr_ip4_any_,
|
|
|
324 sizeof(uv_addr_ip4_any_),
|
|
|
325 0);
|
|
|
326 if (err)
|
|
|
327 return uv_translate_sys_error(err);
|
|
|
328
|
|
|
329 handle->flags |= UV_HANDLE_READING;
|
|
|
330 INCREASE_ACTIVE_COUNT(loop, handle);
|
|
|
331
|
|
|
332 handle->recv_cb = recv_cb;
|
|
|
333 handle->alloc_cb = alloc_cb;
|
|
|
334
|
|
|
335 /* If reading was stopped and then started again, there could still be a recv
|
|
|
336 * request pending. */
|
|
|
337 if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
|
|
338 uv__udp_queue_recv(loop, handle);
|
|
|
339
|
|
|
340 return 0;
|
|
|
341 }
|
|
|
342
|
|
|
343
|
|
|
344 int uv__udp_recv_stop(uv_udp_t* handle) {
|
|
|
345 if (handle->flags & UV_HANDLE_READING) {
|
|
|
346 handle->flags &= ~UV_HANDLE_READING;
|
|
|
347 DECREASE_ACTIVE_COUNT(loop, handle);
|
|
|
348 }
|
|
|
349
|
|
|
350 return 0;
|
|
|
351 }
|
|
|
352
|
|
|
353
|
|
|
354 static int uv__send(uv_udp_send_t* req,
|
|
|
355 uv_udp_t* handle,
|
|
|
356 const uv_buf_t bufs[],
|
|
|
357 unsigned int nbufs,
|
|
|
358 const struct sockaddr* addr,
|
|
|
359 unsigned int addrlen,
|
|
|
360 uv_udp_send_cb cb) {
|
|
|
361 uv_loop_t* loop = handle->loop;
|
|
|
362 DWORD result, bytes;
|
|
|
363
|
|
|
364 UV_REQ_INIT(req, UV_UDP_SEND);
|
|
|
365 req->handle = handle;
|
|
|
366 req->cb = cb;
|
|
|
367 memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
|
|
368
|
|
|
369 result = WSASendTo(handle->socket,
|
|
|
370 (WSABUF*)bufs,
|
|
|
371 nbufs,
|
|
|
372 &bytes,
|
|
|
373 0,
|
|
|
374 addr,
|
|
|
375 addrlen,
|
|
|
376 &req->u.io.overlapped,
|
|
|
377 NULL);
|
|
|
378
|
|
|
379 if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
|
|
|
380 /* Request completed immediately. */
|
|
|
381 req->u.io.queued_bytes = 0;
|
|
|
382 handle->reqs_pending++;
|
|
|
383 handle->send_queue_size += req->u.io.queued_bytes;
|
|
|
384 handle->send_queue_count++;
|
|
|
385 REGISTER_HANDLE_REQ(loop, handle);
|
|
|
386 uv__insert_pending_req(loop, (uv_req_t*)req);
|
|
|
387 } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
|
|
388 /* Request queued by the kernel. */
|
|
|
389 req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
|
|
|
390 handle->reqs_pending++;
|
|
|
391 handle->send_queue_size += req->u.io.queued_bytes;
|
|
|
392 handle->send_queue_count++;
|
|
|
393 REGISTER_HANDLE_REQ(loop, handle);
|
|
|
394 } else {
|
|
|
395 /* Send failed due to an error. */
|
|
|
396 return WSAGetLastError();
|
|
|
397 }
|
|
|
398
|
|
|
399 return 0;
|
|
|
400 }
|
|
|
401
|
|
|
402
|
|
|
403 void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
|
|
404 uv_req_t* req) {
|
|
|
405 uv_buf_t buf;
|
|
|
406 int partial;
|
|
|
407
|
|
|
408 assert(handle->type == UV_UDP);
|
|
|
409
|
|
|
410 handle->flags &= ~UV_HANDLE_READ_PENDING;
|
|
|
411
|
|
|
412 if (!REQ_SUCCESS(req)) {
|
|
|
413 DWORD err = GET_REQ_SOCK_ERROR(req);
|
|
|
414 if (err == WSAEMSGSIZE) {
|
|
|
415 /* Not a real error, it just indicates that the received packet was
|
|
|
416 * bigger than the receive buffer. */
|
|
|
417 } else if (err == WSAECONNRESET || err == WSAENETRESET) {
|
|
|
418 /* A previous sendto operation failed; ignore this error. If zero-reading
|
|
|
419 * we need to call WSARecv/WSARecvFrom _without_ the. MSG_PEEK flag to
|
|
|
420 * clear out the error queue. For nonzero reads, immediately queue a new
|
|
|
421 * receive. */
|
|
|
422 if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
|
|
|
423 goto done;
|
|
|
424 }
|
|
|
425 } else {
|
|
|
426 /* A real error occurred. Report the error to the user only if we're
|
|
|
427 * currently reading. */
|
|
|
428 if (handle->flags & UV_HANDLE_READING) {
|
|
|
429 uv_udp_recv_stop(handle);
|
|
|
430 buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
|
|
|
431 uv_buf_init(NULL, 0) : handle->recv_buffer;
|
|
|
432 handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
|
|
|
433 }
|
|
|
434 goto done;
|
|
|
435 }
|
|
|
436 }
|
|
|
437
|
|
|
438 if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
|
|
|
439 /* Successful read */
|
|
|
440 partial = !REQ_SUCCESS(req);
|
|
|
441 handle->recv_cb(handle,
|
|
|
442 req->u.io.overlapped.InternalHigh,
|
|
|
443 &handle->recv_buffer,
|
|
|
444 (const struct sockaddr*) &handle->recv_from,
|
|
|
445 partial ? UV_UDP_PARTIAL : 0);
|
|
|
446 } else if (handle->flags & UV_HANDLE_READING) {
|
|
|
447 DWORD bytes, err, flags;
|
|
|
448 struct sockaddr_storage from;
|
|
|
449 int from_len;
|
|
|
450 int count;
|
|
|
451
|
|
|
452 /* Prevent loop starvation when the data comes in as fast as
|
|
|
453 * (or faster than) we can read it. */
|
|
|
454 count = 32;
|
|
|
455
|
|
|
456 do {
|
|
|
457 /* Do at most `count` nonblocking receive. */
|
|
|
458 buf = uv_buf_init(NULL, 0);
|
|
|
459 handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
|
|
|
460 if (buf.base == NULL || buf.len == 0) {
|
|
|
461 handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
|
|
462 goto done;
|
|
|
463 }
|
|
|
464
|
|
|
465 memset(&from, 0, sizeof from);
|
|
|
466 from_len = sizeof from;
|
|
|
467
|
|
|
468 flags = 0;
|
|
|
469
|
|
|
470 if (WSARecvFrom(handle->socket,
|
|
|
471 (WSABUF*)&buf,
|
|
|
472 1,
|
|
|
473 &bytes,
|
|
|
474 &flags,
|
|
|
475 (struct sockaddr*) &from,
|
|
|
476 &from_len,
|
|
|
477 NULL,
|
|
|
478 NULL) != SOCKET_ERROR) {
|
|
|
479
|
|
|
480 /* Message received */
|
|
|
481 err = ERROR_SUCCESS;
|
|
|
482 handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
|
|
|
483 } else {
|
|
|
484 err = WSAGetLastError();
|
|
|
485 if (err == WSAEMSGSIZE) {
|
|
|
486 /* Message truncated */
|
|
|
487 handle->recv_cb(handle,
|
|
|
488 bytes,
|
|
|
489 &buf,
|
|
|
490 (const struct sockaddr*) &from,
|
|
|
491 UV_UDP_PARTIAL);
|
|
|
492 } else if (err == WSAEWOULDBLOCK) {
|
|
|
493 /* Kernel buffer empty */
|
|
|
494 handle->recv_cb(handle, 0, &buf, NULL, 0);
|
|
|
495 } else if (err == WSAECONNRESET || err == WSAENETRESET) {
|
|
|
496 /* WSAECONNRESET/WSANETRESET is ignored because this just indicates
|
|
|
497 * that a previous sendto operation failed.
|
|
|
498 */
|
|
|
499 handle->recv_cb(handle, 0, &buf, NULL, 0);
|
|
|
500 } else {
|
|
|
501 /* Any other error that we want to report back to the user. */
|
|
|
502 uv_udp_recv_stop(handle);
|
|
|
503 handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
|
|
|
504 }
|
|
|
505 }
|
|
|
506 }
|
|
|
507 while (err == ERROR_SUCCESS &&
|
|
|
508 count-- > 0 &&
|
|
|
509 /* The recv_cb callback may decide to pause or close the handle. */
|
|
|
510 (handle->flags & UV_HANDLE_READING) &&
|
|
|
511 !(handle->flags & UV_HANDLE_READ_PENDING));
|
|
|
512 }
|
|
|
513
|
|
|
514 done:
|
|
|
515 /* Post another read if still reading and not closing. */
|
|
|
516 if ((handle->flags & UV_HANDLE_READING) &&
|
|
|
517 !(handle->flags & UV_HANDLE_READ_PENDING)) {
|
|
|
518 uv__udp_queue_recv(loop, handle);
|
|
|
519 }
|
|
|
520
|
|
|
521 DECREASE_PENDING_REQ_COUNT(handle);
|
|
|
522 }
|
|
|
523
|
|
|
524
|
|
|
525 void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
|
|
|
526 uv_udp_send_t* req) {
|
|
|
527 int err;
|
|
|
528
|
|
|
529 assert(handle->type == UV_UDP);
|
|
|
530
|
|
|
531 assert(handle->send_queue_size >= req->u.io.queued_bytes);
|
|
|
532 assert(handle->send_queue_count >= 1);
|
|
|
533 handle->send_queue_size -= req->u.io.queued_bytes;
|
|
|
534 handle->send_queue_count--;
|
|
|
535
|
|
|
536 UNREGISTER_HANDLE_REQ(loop, handle);
|
|
|
537
|
|
|
538 if (req->cb) {
|
|
|
539 err = 0;
|
|
|
540 if (!REQ_SUCCESS(req)) {
|
|
|
541 err = GET_REQ_SOCK_ERROR(req);
|
|
|
542 }
|
|
|
543 req->cb(req, uv_translate_sys_error(err));
|
|
|
544 }
|
|
|
545
|
|
|
546 DECREASE_PENDING_REQ_COUNT(handle);
|
|
|
547 }
|
|
|
548
|
|
|
549
|
|
|
550 static int uv__udp_set_membership4(uv_udp_t* handle,
|
|
|
551 const struct sockaddr_in* multicast_addr,
|
|
|
552 const char* interface_addr,
|
|
|
553 uv_membership membership) {
|
|
|
554 int err;
|
|
|
555 int optname;
|
|
|
556 struct ip_mreq mreq;
|
|
|
557
|
|
|
558 if (handle->flags & UV_HANDLE_IPV6)
|
|
|
559 return UV_EINVAL;
|
|
|
560
|
|
|
561 /* If the socket is unbound, bind to inaddr_any. */
|
|
|
562 err = uv__udp_maybe_bind(handle,
|
|
|
563 (const struct sockaddr*) &uv_addr_ip4_any_,
|
|
|
564 sizeof(uv_addr_ip4_any_),
|
|
|
565 UV_UDP_REUSEADDR);
|
|
|
566 if (err)
|
|
|
567 return uv_translate_sys_error(err);
|
|
|
568
|
|
|
569 memset(&mreq, 0, sizeof mreq);
|
|
|
570
|
|
|
571 if (interface_addr) {
|
|
|
572 err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
|
|
|
573 if (err)
|
|
|
574 return err;
|
|
|
575 } else {
|
|
|
576 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
|
577 }
|
|
|
578
|
|
|
579 mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
|
|
|
580
|
|
|
581 switch (membership) {
|
|
|
582 case UV_JOIN_GROUP:
|
|
|
583 optname = IP_ADD_MEMBERSHIP;
|
|
|
584 break;
|
|
|
585 case UV_LEAVE_GROUP:
|
|
|
586 optname = IP_DROP_MEMBERSHIP;
|
|
|
587 break;
|
|
|
588 default:
|
|
|
589 return UV_EINVAL;
|
|
|
590 }
|
|
|
591
|
|
|
592 if (setsockopt(handle->socket,
|
|
|
593 IPPROTO_IP,
|
|
|
594 optname,
|
|
|
595 (char*) &mreq,
|
|
|
596 sizeof mreq) == SOCKET_ERROR) {
|
|
|
597 return uv_translate_sys_error(WSAGetLastError());
|
|
|
598 }
|
|
|
599
|
|
|
600 return 0;
|
|
|
601 }
|
|
|
602
|
|
|
603
|
|
|
604 int uv__udp_set_membership6(uv_udp_t* handle,
|
|
|
605 const struct sockaddr_in6* multicast_addr,
|
|
|
606 const char* interface_addr,
|
|
|
607 uv_membership membership) {
|
|
|
608 int optname;
|
|
|
609 int err;
|
|
|
610 struct ipv6_mreq mreq;
|
|
|
611 struct sockaddr_in6 addr6;
|
|
|
612
|
|
|
613 if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
|
|
|
614 return UV_EINVAL;
|
|
|
615
|
|
|
616 err = uv__udp_maybe_bind(handle,
|
|
|
617 (const struct sockaddr*) &uv_addr_ip6_any_,
|
|
|
618 sizeof(uv_addr_ip6_any_),
|
|
|
619 UV_UDP_REUSEADDR);
|
|
|
620
|
|
|
621 if (err)
|
|
|
622 return uv_translate_sys_error(err);
|
|
|
623
|
|
|
624 memset(&mreq, 0, sizeof(mreq));
|
|
|
625
|
|
|
626 if (interface_addr) {
|
|
|
627 if (uv_ip6_addr(interface_addr, 0, &addr6))
|
|
|
628 return UV_EINVAL;
|
|
|
629 mreq.ipv6mr_interface = addr6.sin6_scope_id;
|
|
|
630 } else {
|
|
|
631 mreq.ipv6mr_interface = 0;
|
|
|
632 }
|
|
|
633
|
|
|
634 mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
|
|
|
635
|
|
|
636 switch (membership) {
|
|
|
637 case UV_JOIN_GROUP:
|
|
|
638 optname = IPV6_ADD_MEMBERSHIP;
|
|
|
639 break;
|
|
|
640 case UV_LEAVE_GROUP:
|
|
|
641 optname = IPV6_DROP_MEMBERSHIP;
|
|
|
642 break;
|
|
|
643 default:
|
|
|
644 return UV_EINVAL;
|
|
|
645 }
|
|
|
646
|
|
|
647 if (setsockopt(handle->socket,
|
|
|
648 IPPROTO_IPV6,
|
|
|
649 optname,
|
|
|
650 (char*) &mreq,
|
|
|
651 sizeof mreq) == SOCKET_ERROR) {
|
|
|
652 return uv_translate_sys_error(WSAGetLastError());
|
|
|
653 }
|
|
|
654
|
|
|
655 return 0;
|
|
|
656 }
|
|
|
657
|
|
|
658
|
|
|
659 static int uv__udp_set_source_membership4(uv_udp_t* handle,
|
|
|
660 const struct sockaddr_in* multicast_addr,
|
|
|
661 const char* interface_addr,
|
|
|
662 const struct sockaddr_in* source_addr,
|
|
|
663 uv_membership membership) {
|
|
|
664 struct ip_mreq_source mreq;
|
|
|
665 int optname;
|
|
|
666 int err;
|
|
|
667
|
|
|
668 if (handle->flags & UV_HANDLE_IPV6)
|
|
|
669 return UV_EINVAL;
|
|
|
670
|
|
|
671 /* If the socket is unbound, bind to inaddr_any. */
|
|
|
672 err = uv__udp_maybe_bind(handle,
|
|
|
673 (const struct sockaddr*) &uv_addr_ip4_any_,
|
|
|
674 sizeof(uv_addr_ip4_any_),
|
|
|
675 UV_UDP_REUSEADDR);
|
|
|
676 if (err)
|
|
|
677 return uv_translate_sys_error(err);
|
|
|
678
|
|
|
679 memset(&mreq, 0, sizeof(mreq));
|
|
|
680
|
|
|
681 if (interface_addr != NULL) {
|
|
|
682 err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
|
|
|
683 if (err)
|
|
|
684 return err;
|
|
|
685 } else {
|
|
|
686 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
|
687 }
|
|
|
688
|
|
|
689 mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
|
|
|
690 mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr;
|
|
|
691
|
|
|
692 if (membership == UV_JOIN_GROUP)
|
|
|
693 optname = IP_ADD_SOURCE_MEMBERSHIP;
|
|
|
694 else if (membership == UV_LEAVE_GROUP)
|
|
|
695 optname = IP_DROP_SOURCE_MEMBERSHIP;
|
|
|
696 else
|
|
|
697 return UV_EINVAL;
|
|
|
698
|
|
|
699 if (setsockopt(handle->socket,
|
|
|
700 IPPROTO_IP,
|
|
|
701 optname,
|
|
|
702 (char*) &mreq,
|
|
|
703 sizeof(mreq)) == SOCKET_ERROR) {
|
|
|
704 return uv_translate_sys_error(WSAGetLastError());
|
|
|
705 }
|
|
|
706
|
|
|
707 return 0;
|
|
|
708 }
|
|
|
709
|
|
|
710
|
|
|
711 int uv__udp_set_source_membership6(uv_udp_t* handle,
|
|
|
712 const struct sockaddr_in6* multicast_addr,
|
|
|
713 const char* interface_addr,
|
|
|
714 const struct sockaddr_in6* source_addr,
|
|
|
715 uv_membership membership) {
|
|
|
716 struct group_source_req mreq;
|
|
|
717 struct sockaddr_in6 addr6;
|
|
|
718 int optname;
|
|
|
719 int err;
|
|
|
720
|
|
|
721 STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
|
|
|
722 STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
|
|
|
723
|
|
|
724 if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
|
|
|
725 return UV_EINVAL;
|
|
|
726
|
|
|
727 err = uv__udp_maybe_bind(handle,
|
|
|
728 (const struct sockaddr*) &uv_addr_ip6_any_,
|
|
|
729 sizeof(uv_addr_ip6_any_),
|
|
|
730 UV_UDP_REUSEADDR);
|
|
|
731
|
|
|
732 if (err)
|
|
|
733 return uv_translate_sys_error(err);
|
|
|
734
|
|
|
735 memset(&mreq, 0, sizeof(mreq));
|
|
|
736
|
|
|
737 if (interface_addr != NULL) {
|
|
|
738 err = uv_ip6_addr(interface_addr, 0, &addr6);
|
|
|
739 if (err)
|
|
|
740 return err;
|
|
|
741 mreq.gsr_interface = addr6.sin6_scope_id;
|
|
|
742 } else {
|
|
|
743 mreq.gsr_interface = 0;
|
|
|
744 }
|
|
|
745
|
|
|
746 memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
|
|
|
747 memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
|
|
|
748
|
|
|
749 if (membership == UV_JOIN_GROUP)
|
|
|
750 optname = MCAST_JOIN_SOURCE_GROUP;
|
|
|
751 else if (membership == UV_LEAVE_GROUP)
|
|
|
752 optname = MCAST_LEAVE_SOURCE_GROUP;
|
|
|
753 else
|
|
|
754 return UV_EINVAL;
|
|
|
755
|
|
|
756 if (setsockopt(handle->socket,
|
|
|
757 IPPROTO_IPV6,
|
|
|
758 optname,
|
|
|
759 (char*) &mreq,
|
|
|
760 sizeof(mreq)) == SOCKET_ERROR) {
|
|
|
761 return uv_translate_sys_error(WSAGetLastError());
|
|
|
762 }
|
|
|
763
|
|
|
764 return 0;
|
|
|
765 }
|
|
|
766
|
|
|
767
|
|
|
768 int uv_udp_set_membership(uv_udp_t* handle,
|
|
|
769 const char* multicast_addr,
|
|
|
770 const char* interface_addr,
|
|
|
771 uv_membership membership) {
|
|
|
772 struct sockaddr_in addr4;
|
|
|
773 struct sockaddr_in6 addr6;
|
|
|
774
|
|
|
775 if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0)
|
|
|
776 return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
|
|
|
777 else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0)
|
|
|
778 return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
|
|
|
779 else
|
|
|
780 return UV_EINVAL;
|
|
|
781 }
|
|
|
782
|
|
|
783
|
|
|
784 int uv_udp_set_source_membership(uv_udp_t* handle,
|
|
|
785 const char* multicast_addr,
|
|
|
786 const char* interface_addr,
|
|
|
787 const char* source_addr,
|
|
|
788 uv_membership membership) {
|
|
|
789 int err;
|
|
|
790 struct sockaddr_storage mcast_addr;
|
|
|
791 struct sockaddr_in* mcast_addr4;
|
|
|
792 struct sockaddr_in6* mcast_addr6;
|
|
|
793 struct sockaddr_storage src_addr;
|
|
|
794 struct sockaddr_in* src_addr4;
|
|
|
795 struct sockaddr_in6* src_addr6;
|
|
|
796
|
|
|
797 mcast_addr4 = (struct sockaddr_in*)&mcast_addr;
|
|
|
798 mcast_addr6 = (struct sockaddr_in6*)&mcast_addr;
|
|
|
799 src_addr4 = (struct sockaddr_in*)&src_addr;
|
|
|
800 src_addr6 = (struct sockaddr_in6*)&src_addr;
|
|
|
801
|
|
|
802 err = uv_ip4_addr(multicast_addr, 0, mcast_addr4);
|
|
|
803 if (err) {
|
|
|
804 err = uv_ip6_addr(multicast_addr, 0, mcast_addr6);
|
|
|
805 if (err)
|
|
|
806 return err;
|
|
|
807 err = uv_ip6_addr(source_addr, 0, src_addr6);
|
|
|
808 if (err)
|
|
|
809 return err;
|
|
|
810 return uv__udp_set_source_membership6(handle,
|
|
|
811 mcast_addr6,
|
|
|
812 interface_addr,
|
|
|
813 src_addr6,
|
|
|
814 membership);
|
|
|
815 }
|
|
|
816
|
|
|
817 err = uv_ip4_addr(source_addr, 0, src_addr4);
|
|
|
818 if (err)
|
|
|
819 return err;
|
|
|
820 return uv__udp_set_source_membership4(handle,
|
|
|
821 mcast_addr4,
|
|
|
822 interface_addr,
|
|
|
823 src_addr4,
|
|
|
824 membership);
|
|
|
825 }
|
|
|
826
|
|
|
827
|
|
|
828 int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
|
|
|
829 struct sockaddr_storage addr_st;
|
|
|
830 struct sockaddr_in* addr4;
|
|
|
831 struct sockaddr_in6* addr6;
|
|
|
832
|
|
|
833 addr4 = (struct sockaddr_in*) &addr_st;
|
|
|
834 addr6 = (struct sockaddr_in6*) &addr_st;
|
|
|
835
|
|
|
836 if (!interface_addr) {
|
|
|
837 memset(&addr_st, 0, sizeof addr_st);
|
|
|
838 if (handle->flags & UV_HANDLE_IPV6) {
|
|
|
839 addr_st.ss_family = AF_INET6;
|
|
|
840 addr6->sin6_scope_id = 0;
|
|
|
841 } else {
|
|
|
842 addr_st.ss_family = AF_INET;
|
|
|
843 addr4->sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
844 }
|
|
|
845 } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
|
|
|
846 /* nothing, address was parsed */
|
|
|
847 } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
|
|
|
848 /* nothing, address was parsed */
|
|
|
849 } else {
|
|
|
850 return UV_EINVAL;
|
|
|
851 }
|
|
|
852
|
|
|
853 if (handle->socket == INVALID_SOCKET)
|
|
|
854 return UV_EBADF;
|
|
|
855
|
|
|
856 if (addr_st.ss_family == AF_INET) {
|
|
|
857 if (setsockopt(handle->socket,
|
|
|
858 IPPROTO_IP,
|
|
|
859 IP_MULTICAST_IF,
|
|
|
860 (char*) &addr4->sin_addr,
|
|
|
861 sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
|
|
|
862 return uv_translate_sys_error(WSAGetLastError());
|
|
|
863 }
|
|
|
864 } else if (addr_st.ss_family == AF_INET6) {
|
|
|
865 if (setsockopt(handle->socket,
|
|
|
866 IPPROTO_IPV6,
|
|
|
867 IPV6_MULTICAST_IF,
|
|
|
868 (char*) &addr6->sin6_scope_id,
|
|
|
869 sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
|
|
|
870 return uv_translate_sys_error(WSAGetLastError());
|
|
|
871 }
|
|
|
872 } else {
|
|
|
873 assert(0 && "unexpected address family");
|
|
|
874 abort();
|
|
|
875 }
|
|
|
876
|
|
|
877 return 0;
|
|
|
878 }
|
|
|
879
|
|
|
880
|
|
|
881 int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
|
|
|
882 BOOL optval = (BOOL) value;
|
|
|
883
|
|
|
884 if (handle->socket == INVALID_SOCKET)
|
|
|
885 return UV_EBADF;
|
|
|
886
|
|
|
887 if (setsockopt(handle->socket,
|
|
|
888 SOL_SOCKET,
|
|
|
889 SO_BROADCAST,
|
|
|
890 (char*) &optval,
|
|
|
891 sizeof optval)) {
|
|
|
892 return uv_translate_sys_error(WSAGetLastError());
|
|
|
893 }
|
|
|
894
|
|
|
895 return 0;
|
|
|
896 }
|
|
|
897
|
|
|
898
|
|
|
899 int uv__udp_is_bound(uv_udp_t* handle) {
|
|
|
900 struct sockaddr_storage addr;
|
|
|
901 int addrlen;
|
|
|
902
|
|
|
903 addrlen = sizeof(addr);
|
|
|
904 if (uv_udp_getsockname(handle, (struct sockaddr*) &addr, &addrlen) != 0)
|
|
|
905 return 0;
|
|
|
906
|
|
|
907 return addrlen > 0;
|
|
|
908 }
|
|
|
909
|
|
|
910
|
|
|
911 int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
|
|
912 WSAPROTOCOL_INFOW protocol_info;
|
|
|
913 int opt_len;
|
|
|
914 int err;
|
|
|
915
|
|
|
916 /* Detect the address family of the socket. */
|
|
|
917 opt_len = (int) sizeof protocol_info;
|
|
|
918 if (getsockopt(sock,
|
|
|
919 SOL_SOCKET,
|
|
|
920 SO_PROTOCOL_INFOW,
|
|
|
921 (char*) &protocol_info,
|
|
|
922 &opt_len) == SOCKET_ERROR) {
|
|
|
923 return uv_translate_sys_error(GetLastError());
|
|
|
924 }
|
|
|
925
|
|
|
926 err = uv__udp_set_socket(handle->loop,
|
|
|
927 handle,
|
|
|
928 sock,
|
|
|
929 protocol_info.iAddressFamily);
|
|
|
930 if (err)
|
|
|
931 return uv_translate_sys_error(err);
|
|
|
932
|
|
|
933 if (uv__udp_is_bound(handle))
|
|
|
934 handle->flags |= UV_HANDLE_BOUND;
|
|
|
935
|
|
|
936 if (uv__udp_is_connected(handle))
|
|
|
937 handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
|
|
938
|
|
|
939 return 0;
|
|
|
940 }
|
|
|
941
|
|
|
942
|
|
|
943 #define SOCKOPT_SETTER(name, option4, option6, validate) \
|
|
|
944 int uv_udp_set_##name(uv_udp_t* handle, int value) { \
|
|
|
945 DWORD optval = (DWORD) value; \
|
|
|
946 \
|
|
|
947 if (!(validate(value))) { \
|
|
|
948 return UV_EINVAL; \
|
|
|
949 } \
|
|
|
950 \
|
|
|
951 if (handle->socket == INVALID_SOCKET) \
|
|
|
952 return UV_EBADF; \
|
|
|
953 \
|
|
|
954 if (!(handle->flags & UV_HANDLE_IPV6)) { \
|
|
|
955 /* Set IPv4 socket option */ \
|
|
|
956 if (setsockopt(handle->socket, \
|
|
|
957 IPPROTO_IP, \
|
|
|
958 option4, \
|
|
|
959 (char*) &optval, \
|
|
|
960 sizeof optval)) { \
|
|
|
961 return uv_translate_sys_error(WSAGetLastError()); \
|
|
|
962 } \
|
|
|
963 } else { \
|
|
|
964 /* Set IPv6 socket option */ \
|
|
|
965 if (setsockopt(handle->socket, \
|
|
|
966 IPPROTO_IPV6, \
|
|
|
967 option6, \
|
|
|
968 (char*) &optval, \
|
|
|
969 sizeof optval)) { \
|
|
|
970 return uv_translate_sys_error(WSAGetLastError()); \
|
|
|
971 } \
|
|
|
972 } \
|
|
|
973 return 0; \
|
|
|
974 }
|
|
|
975
|
|
|
976 #define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
|
|
|
977 #define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
|
|
|
978 #define VALIDATE_MULTICAST_LOOP(value) (1)
|
|
|
979
|
|
|
980 SOCKOPT_SETTER(ttl,
|
|
|
981 IP_TTL,
|
|
|
982 IPV6_HOPLIMIT,
|
|
|
983 VALIDATE_TTL)
|
|
|
984 SOCKOPT_SETTER(multicast_ttl,
|
|
|
985 IP_MULTICAST_TTL,
|
|
|
986 IPV6_MULTICAST_HOPS,
|
|
|
987 VALIDATE_MULTICAST_TTL)
|
|
|
988 SOCKOPT_SETTER(multicast_loop,
|
|
|
989 IP_MULTICAST_LOOP,
|
|
|
990 IPV6_MULTICAST_LOOP,
|
|
|
991 VALIDATE_MULTICAST_LOOP)
|
|
|
992
|
|
|
993 #undef SOCKOPT_SETTER
|
|
|
994 #undef VALIDATE_TTL
|
|
|
995 #undef VALIDATE_MULTICAST_TTL
|
|
|
996 #undef VALIDATE_MULTICAST_LOOP
|
|
|
997
|
|
|
998
|
|
|
999 /* This function is an egress point, i.e. it returns libuv errors rather than
|
|
|
1000 * system errors.
|
|
|
1001 */
|
|
|
1002 int uv__udp_bind(uv_udp_t* handle,
|
|
|
1003 const struct sockaddr* addr,
|
|
|
1004 unsigned int addrlen,
|
|
|
1005 unsigned int flags) {
|
|
|
1006 int err;
|
|
|
1007
|
|
|
1008 err = uv__udp_maybe_bind(handle, addr, addrlen, flags);
|
|
|
1009 if (err)
|
|
|
1010 return uv_translate_sys_error(err);
|
|
|
1011
|
|
|
1012 return 0;
|
|
|
1013 }
|
|
|
1014
|
|
|
1015
|
|
|
1016 int uv__udp_connect(uv_udp_t* handle,
|
|
|
1017 const struct sockaddr* addr,
|
|
|
1018 unsigned int addrlen) {
|
|
|
1019 const struct sockaddr* bind_addr;
|
|
|
1020 int err;
|
|
|
1021
|
|
|
1022 if (!(handle->flags & UV_HANDLE_BOUND)) {
|
|
|
1023 if (addrlen == sizeof(uv_addr_ip4_any_))
|
|
|
1024 bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
|
|
|
1025 else if (addrlen == sizeof(uv_addr_ip6_any_))
|
|
|
1026 bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
|
|
1027 else
|
|
|
1028 return UV_EINVAL;
|
|
|
1029
|
|
|
1030 err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
|
|
1031 if (err)
|
|
|
1032 return uv_translate_sys_error(err);
|
|
|
1033 }
|
|
|
1034
|
|
|
1035 err = connect(handle->socket, addr, addrlen);
|
|
|
1036 if (err)
|
|
|
1037 return uv_translate_sys_error(WSAGetLastError());
|
|
|
1038
|
|
|
1039 handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
|
|
1040
|
|
|
1041 return 0;
|
|
|
1042 }
|
|
|
1043
|
|
|
1044
|
|
|
1045 int uv__udp_disconnect(uv_udp_t* handle) {
|
|
|
1046 int err;
|
|
|
1047 struct sockaddr_storage addr;
|
|
|
1048
|
|
|
1049 memset(&addr, 0, sizeof(addr));
|
|
|
1050
|
|
|
1051 err = connect(handle->socket, (struct sockaddr*) &addr, sizeof(addr));
|
|
|
1052 if (err)
|
|
|
1053 return uv_translate_sys_error(WSAGetLastError());
|
|
|
1054
|
|
|
1055 handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
|
|
|
1056 return 0;
|
|
|
1057 }
|
|
|
1058
|
|
|
1059
|
|
|
1060 /* This function is an egress point, i.e. it returns libuv errors rather than
|
|
|
1061 * system errors.
|
|
|
1062 */
|
|
|
1063 int uv__udp_send(uv_udp_send_t* req,
|
|
|
1064 uv_udp_t* handle,
|
|
|
1065 const uv_buf_t bufs[],
|
|
|
1066 unsigned int nbufs,
|
|
|
1067 const struct sockaddr* addr,
|
|
|
1068 unsigned int addrlen,
|
|
|
1069 uv_udp_send_cb send_cb) {
|
|
|
1070 const struct sockaddr* bind_addr;
|
|
|
1071 int err;
|
|
|
1072
|
|
|
1073 if (!(handle->flags & UV_HANDLE_BOUND)) {
|
|
|
1074 if (addrlen == sizeof(uv_addr_ip4_any_))
|
|
|
1075 bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
|
|
|
1076 else if (addrlen == sizeof(uv_addr_ip6_any_))
|
|
|
1077 bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
|
|
1078 else
|
|
|
1079 return UV_EINVAL;
|
|
|
1080
|
|
|
1081 err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
|
|
1082 if (err)
|
|
|
1083 return uv_translate_sys_error(err);
|
|
|
1084 }
|
|
|
1085
|
|
|
1086 err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
|
|
|
1087 if (err)
|
|
|
1088 return uv_translate_sys_error(err);
|
|
|
1089
|
|
|
1090 return 0;
|
|
|
1091 }
|
|
|
1092
|
|
|
1093
|
|
|
1094 int uv__udp_try_send(uv_udp_t* handle,
|
|
|
1095 const uv_buf_t bufs[],
|
|
|
1096 unsigned int nbufs,
|
|
|
1097 const struct sockaddr* addr,
|
|
|
1098 unsigned int addrlen) {
|
|
|
1099 DWORD bytes;
|
|
|
1100 const struct sockaddr* bind_addr;
|
|
|
1101 struct sockaddr_storage converted;
|
|
|
1102 int err;
|
|
|
1103
|
|
|
1104 if (nbufs < 1)
|
|
|
1105 return UV_EINVAL;
|
|
|
1106
|
|
|
1107 if (addr != NULL) {
|
|
|
1108 err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
|
|
1109 if (err)
|
|
|
1110 return err;
|
|
|
1111 addr = (const struct sockaddr*) &converted;
|
|
|
1112 }
|
|
|
1113
|
|
|
1114 /* Already sending a message.*/
|
|
|
1115 if (handle->send_queue_count != 0)
|
|
|
1116 return UV_EAGAIN;
|
|
|
1117
|
|
|
1118 if (!(handle->flags & UV_HANDLE_BOUND)) {
|
|
|
1119 if (addrlen == sizeof(uv_addr_ip4_any_))
|
|
|
1120 bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
|
|
|
1121 else if (addrlen == sizeof(uv_addr_ip6_any_))
|
|
|
1122 bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
|
|
1123 else
|
|
|
1124 return UV_EINVAL;
|
|
|
1125 err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
|
|
1126 if (err)
|
|
|
1127 return uv_translate_sys_error(err);
|
|
|
1128 }
|
|
|
1129
|
|
|
1130 err = WSASendTo(handle->socket,
|
|
|
1131 (WSABUF*)bufs,
|
|
|
1132 nbufs,
|
|
|
1133 &bytes,
|
|
|
1134 0,
|
|
|
1135 addr,
|
|
|
1136 addrlen,
|
|
|
1137 NULL,
|
|
|
1138 NULL);
|
|
|
1139
|
|
|
1140 if (err)
|
|
|
1141 return uv_translate_sys_error(WSAGetLastError());
|
|
|
1142
|
|
|
1143 return bytes;
|
|
|
1144 }
|
|
|
1145
|
|
|
1146
|
|
|
1147 int uv__udp_try_send2(uv_udp_t* handle,
|
|
|
1148 unsigned int count,
|
|
|
1149 uv_buf_t* bufs[/*count*/],
|
|
|
1150 unsigned int nbufs[/*count*/],
|
|
|
1151 struct sockaddr* addrs[/*count*/]) {
|
|
|
1152 unsigned int i;
|
|
|
1153 int r;
|
|
|
1154
|
|
|
1155 for (i = 0; i < count; i++) {
|
|
|
1156 r = uv_udp_try_send(handle, bufs[i], nbufs[i], addrs[i]);
|
|
|
1157 if (r < 0)
|
|
|
1158 return i > 0 ? i : r; /* Error if first packet, else send count. */
|
|
|
1159 }
|
|
|
1160
|
|
|
1161 return i;
|
|
|
1162 }
|