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 /*
33 * Threshold of active udp streams for which to preallocate udp read buffers.
34 */
35 const unsigned int uv_active_udp_streams_threshold = 0;
36
37 /* A zero-size buffer for use by uv_udp_read */
38 static char uv_zero_[] = "";
39
uv_udp_getsockname(const uv_udp_t * handle,struct sockaddr * name,int * namelen)40 int uv_udp_getsockname(const uv_udp_t* handle,
41 struct sockaddr* name,
42 int* namelen) {
43 int result;
44
45 if (handle->socket == INVALID_SOCKET) {
46 return UV_EINVAL;
47 }
48
49 result = getsockname(handle->socket, name, namelen);
50 if (result != 0) {
51 return uv_translate_sys_error(WSAGetLastError());
52 }
53
54 return 0;
55 }
56
57
uv_udp_set_socket(uv_loop_t * loop,uv_udp_t * handle,SOCKET socket,int family)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. */
78 /* Use uv_handle_t pointer as completion key. */
79 if (CreateIoCompletionPort((HANDLE)socket,
80 loop->iocp,
81 (ULONG_PTR)socket,
82 0) == NULL) {
83 return GetLastError();
84 }
85
86 if (pSetFileCompletionNotificationModes) {
87 /* All known Windows that support SetFileCompletionNotificationModes */
88 /* have a bug that makes it impossible to use this function in */
89 /* conjunction with datagram sockets. We can work around that but only */
90 /* if the user is using the default UDP driver (AFD) and has no other */
91 /* LSPs stacked on top. Here we check whether that is the case. */
92 opt_len = (int) sizeof info;
93 if (getsockopt(socket,
94 SOL_SOCKET,
95 SO_PROTOCOL_INFOW,
96 (char*) &info,
97 &opt_len) == SOCKET_ERROR) {
98 return GetLastError();
99 }
100
101 if (info.ProtocolChain.ChainLen == 1) {
102 if (pSetFileCompletionNotificationModes((HANDLE)socket,
103 FILE_SKIP_SET_EVENT_ON_HANDLE |
104 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
105 handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
106 handle->func_wsarecv = uv_wsarecv_workaround;
107 handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
108 } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
109 return GetLastError();
110 }
111 }
112 }
113
114 handle->socket = socket;
115
116 if (family == AF_INET6) {
117 handle->flags |= UV_HANDLE_IPV6;
118 } else {
119 assert(!(handle->flags & UV_HANDLE_IPV6));
120 }
121
122 return 0;
123 }
124
125
uv_udp_init_ex(uv_loop_t * loop,uv_udp_t * handle,unsigned int flags)126 int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
127 int domain;
128
129 /* Use the lower 8 bits for the domain */
130 domain = flags & 0xFF;
131 if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
132 return UV_EINVAL;
133
134 if (flags & ~0xFF)
135 return UV_EINVAL;
136
137 uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
138 handle->socket = INVALID_SOCKET;
139 handle->reqs_pending = 0;
140 handle->activecnt = 0;
141 handle->func_wsarecv = WSARecv;
142 handle->func_wsarecvfrom = WSARecvFrom;
143 handle->send_queue_size = 0;
144 handle->send_queue_count = 0;
145 UV_REQ_INIT(&handle->recv_req, UV_UDP_RECV);
146 handle->recv_req.data = handle;
147
148 /* If anything fails beyond this point we need to remove the handle from
149 * the handle queue, since it was added by uv__handle_init.
150 */
151
152 if (domain != AF_UNSPEC) {
153 SOCKET sock;
154 DWORD err;
155
156 sock = socket(domain, SOCK_DGRAM, 0);
157 if (sock == INVALID_SOCKET) {
158 err = WSAGetLastError();
159 QUEUE_REMOVE(&handle->handle_queue);
160 return uv_translate_sys_error(err);
161 }
162
163 err = uv_udp_set_socket(handle->loop, handle, sock, domain);
164 if (err) {
165 closesocket(sock);
166 QUEUE_REMOVE(&handle->handle_queue);
167 return uv_translate_sys_error(err);
168 }
169 }
170
171 return 0;
172 }
173
174
uv_udp_init(uv_loop_t * loop,uv_udp_t * handle)175 int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
176 return uv_udp_init_ex(loop, handle, AF_UNSPEC);
177 }
178
179
uv_udp_close(uv_loop_t * loop,uv_udp_t * handle)180 void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
181 uv_udp_recv_stop(handle);
182 closesocket(handle->socket);
183 handle->socket = INVALID_SOCKET;
184
185 uv__handle_closing(handle);
186
187 if (handle->reqs_pending == 0) {
188 uv_want_endgame(loop, (uv_handle_t*) handle);
189 }
190 }
191
192
uv_udp_endgame(uv_loop_t * loop,uv_udp_t * handle)193 void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
194 if (handle->flags & UV__HANDLE_CLOSING &&
195 handle->reqs_pending == 0) {
196 assert(!(handle->flags & UV_HANDLE_CLOSED));
197 uv__handle_close(handle);
198 }
199 }
200
201
uv_udp_maybe_bind(uv_udp_t * handle,const struct sockaddr * addr,unsigned int addrlen,unsigned int flags)202 static int uv_udp_maybe_bind(uv_udp_t* handle,
203 const struct sockaddr* addr,
204 unsigned int addrlen,
205 unsigned int flags) {
206 int r;
207 int err;
208 DWORD no = 0;
209
210 if (handle->flags & UV_HANDLE_BOUND)
211 return 0;
212
213 if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
214 /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
215 return ERROR_INVALID_PARAMETER;
216 }
217
218 if (handle->socket == INVALID_SOCKET) {
219 SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
220 if (sock == INVALID_SOCKET) {
221 return WSAGetLastError();
222 }
223
224 err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
225 if (err) {
226 closesocket(sock);
227 return err;
228 }
229 }
230
231 if (flags & UV_UDP_REUSEADDR) {
232 DWORD yes = 1;
233 /* Set SO_REUSEADDR on the socket. */
234 if (setsockopt(handle->socket,
235 SOL_SOCKET,
236 SO_REUSEADDR,
237 (char*) &yes,
238 sizeof yes) == SOCKET_ERROR) {
239 err = WSAGetLastError();
240 return err;
241 }
242 }
243
244 if (addr->sa_family == AF_INET6)
245 handle->flags |= UV_HANDLE_IPV6;
246
247 if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
248 /* On windows IPV6ONLY is on by default. */
249 /* If the user doesn't specify it libuv turns it off. */
250
251 /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
252 /* available, or when run on XP/2003 which have no support for dualstack */
253 /* sockets. For now we're silently ignoring the error. */
254 setsockopt(handle->socket,
255 IPPROTO_IPV6,
256 IPV6_V6ONLY,
257 (char*) &no,
258 sizeof no);
259 }
260
261 r = bind(handle->socket, addr, addrlen);
262 if (r == SOCKET_ERROR) {
263 return WSAGetLastError();
264 }
265
266 handle->flags |= UV_HANDLE_BOUND;
267
268 return 0;
269 }
270
271
uv_udp_queue_recv(uv_loop_t * loop,uv_udp_t * handle)272 static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
273 uv_req_t* req;
274 uv_buf_t buf;
275 DWORD bytes, flags;
276 int result;
277
278 assert(handle->flags & UV_HANDLE_READING);
279 assert(!(handle->flags & UV_HANDLE_READ_PENDING));
280
281 req = &handle->recv_req;
282 memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
283
284 /*
285 * Preallocate a read buffer if the number of active streams is below
286 * the threshold.
287 */
288 if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
289 handle->flags &= ~UV_HANDLE_ZERO_READ;
290
291 handle->recv_buffer = uv_buf_init(NULL, 0);
292 handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
293 if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
294 handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
295 return;
296 }
297 assert(handle->recv_buffer.base != NULL);
298
299 buf = handle->recv_buffer;
300 memset(&handle->recv_from, 0, sizeof handle->recv_from);
301 handle->recv_from_len = sizeof handle->recv_from;
302 flags = 0;
303
304 result = handle->func_wsarecvfrom(handle->socket,
305 (WSABUF*) &buf,
306 1,
307 &bytes,
308 &flags,
309 (struct sockaddr*) &handle->recv_from,
310 &handle->recv_from_len,
311 &req->u.io.overlapped,
312 NULL);
313
314 if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
315 /* Process the req without IOCP. */
316 handle->flags |= UV_HANDLE_READ_PENDING;
317 req->u.io.overlapped.InternalHigh = bytes;
318 handle->reqs_pending++;
319 uv_insert_pending_req(loop, req);
320 } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
321 /* The req will be processed with IOCP. */
322 handle->flags |= UV_HANDLE_READ_PENDING;
323 handle->reqs_pending++;
324 } else {
325 /* Make this req pending reporting an error. */
326 SET_REQ_ERROR(req, WSAGetLastError());
327 uv_insert_pending_req(loop, req);
328 handle->reqs_pending++;
329 }
330
331 } else {
332 handle->flags |= UV_HANDLE_ZERO_READ;
333
334 buf.base = (char*) uv_zero_;
335 buf.len = 0;
336 flags = MSG_PEEK;
337
338 result = handle->func_wsarecv(handle->socket,
339 (WSABUF*) &buf,
340 1,
341 &bytes,
342 &flags,
343 &req->u.io.overlapped,
344 NULL);
345
346 if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
347 /* Process the req without IOCP. */
348 handle->flags |= UV_HANDLE_READ_PENDING;
349 req->u.io.overlapped.InternalHigh = bytes;
350 handle->reqs_pending++;
351 uv_insert_pending_req(loop, req);
352 } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
353 /* The req will be processed with IOCP. */
354 handle->flags |= UV_HANDLE_READ_PENDING;
355 handle->reqs_pending++;
356 } else {
357 /* Make this req pending reporting an error. */
358 SET_REQ_ERROR(req, WSAGetLastError());
359 uv_insert_pending_req(loop, req);
360 handle->reqs_pending++;
361 }
362 }
363 }
364
365
uv__udp_recv_start(uv_udp_t * handle,uv_alloc_cb alloc_cb,uv_udp_recv_cb recv_cb)366 int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
367 uv_udp_recv_cb recv_cb) {
368 uv_loop_t* loop = handle->loop;
369 int err;
370
371 if (handle->flags & UV_HANDLE_READING) {
372 return WSAEALREADY;
373 }
374
375 err = uv_udp_maybe_bind(handle,
376 (const struct sockaddr*) &uv_addr_ip4_any_,
377 sizeof(uv_addr_ip4_any_),
378 0);
379 if (err)
380 return err;
381
382 handle->flags |= UV_HANDLE_READING;
383 INCREASE_ACTIVE_COUNT(loop, handle);
384 loop->active_udp_streams++;
385
386 handle->recv_cb = recv_cb;
387 handle->alloc_cb = alloc_cb;
388
389 /* If reading was stopped and then started again, there could still be a */
390 /* recv request pending. */
391 if (!(handle->flags & UV_HANDLE_READ_PENDING))
392 uv_udp_queue_recv(loop, handle);
393
394 return 0;
395 }
396
397
uv__udp_recv_stop(uv_udp_t * handle)398 int uv__udp_recv_stop(uv_udp_t* handle) {
399 if (handle->flags & UV_HANDLE_READING) {
400 handle->flags &= ~UV_HANDLE_READING;
401 handle->loop->active_udp_streams--;
402 DECREASE_ACTIVE_COUNT(loop, handle);
403 }
404
405 return 0;
406 }
407
408
uv__send(uv_udp_send_t * req,uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,unsigned int addrlen,uv_udp_send_cb cb)409 static int uv__send(uv_udp_send_t* req,
410 uv_udp_t* handle,
411 const uv_buf_t bufs[],
412 unsigned int nbufs,
413 const struct sockaddr* addr,
414 unsigned int addrlen,
415 uv_udp_send_cb cb) {
416 uv_loop_t* loop = handle->loop;
417 DWORD result, bytes;
418
419 UV_REQ_INIT(req, UV_UDP_SEND);
420 req->handle = handle;
421 req->cb = cb;
422 memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
423
424 result = WSASendTo(handle->socket,
425 (WSABUF*)bufs,
426 nbufs,
427 &bytes,
428 0,
429 addr,
430 addrlen,
431 &req->u.io.overlapped,
432 NULL);
433
434 if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
435 /* Request completed immediately. */
436 req->u.io.queued_bytes = 0;
437 handle->reqs_pending++;
438 handle->send_queue_size += req->u.io.queued_bytes;
439 handle->send_queue_count++;
440 REGISTER_HANDLE_REQ(loop, handle, req);
441 uv_insert_pending_req(loop, (uv_req_t*)req);
442 } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
443 /* Request queued by the kernel. */
444 req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
445 handle->reqs_pending++;
446 handle->send_queue_size += req->u.io.queued_bytes;
447 handle->send_queue_count++;
448 REGISTER_HANDLE_REQ(loop, handle, req);
449 } else {
450 /* Send failed due to an error. */
451 return WSAGetLastError();
452 }
453
454 return 0;
455 }
456
457
uv_process_udp_recv_req(uv_loop_t * loop,uv_udp_t * handle,uv_req_t * req)458 void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
459 uv_req_t* req) {
460 uv_buf_t buf;
461 int partial;
462
463 assert(handle->type == UV_UDP);
464
465 handle->flags &= ~UV_HANDLE_READ_PENDING;
466
467 if (!REQ_SUCCESS(req)) {
468 DWORD err = GET_REQ_SOCK_ERROR(req);
469 if (err == WSAEMSGSIZE) {
470 /* Not a real error, it just indicates that the received packet */
471 /* was bigger than the receive buffer. */
472 } else if (err == WSAECONNRESET || err == WSAENETRESET) {
473 /* A previous sendto operation failed; ignore this error. If */
474 /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
475 /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
476 /* immediately queue a new receive. */
477 if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
478 goto done;
479 }
480 } else {
481 /* A real error occurred. Report the error to the user only if we're */
482 /* currently reading. */
483 if (handle->flags & UV_HANDLE_READING) {
484 uv_udp_recv_stop(handle);
485 buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
486 uv_buf_init(NULL, 0) : handle->recv_buffer;
487 handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
488 }
489 goto done;
490 }
491 }
492
493 if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
494 /* Successful read */
495 partial = !REQ_SUCCESS(req);
496 handle->recv_cb(handle,
497 req->u.io.overlapped.InternalHigh,
498 &handle->recv_buffer,
499 (const struct sockaddr*) &handle->recv_from,
500 partial ? UV_UDP_PARTIAL : 0);
501 } else if (handle->flags & UV_HANDLE_READING) {
502 DWORD bytes, err, flags;
503 struct sockaddr_storage from;
504 int from_len;
505
506 /* Do a nonblocking receive */
507 /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
508 buf = uv_buf_init(NULL, 0);
509 handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
510 if (buf.base == NULL || buf.len == 0) {
511 handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
512 goto done;
513 }
514 assert(buf.base != NULL);
515
516 memset(&from, 0, sizeof from);
517 from_len = sizeof from;
518
519 flags = 0;
520
521 if (WSARecvFrom(handle->socket,
522 (WSABUF*)&buf,
523 1,
524 &bytes,
525 &flags,
526 (struct sockaddr*) &from,
527 &from_len,
528 NULL,
529 NULL) != SOCKET_ERROR) {
530
531 /* Message received */
532 handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
533 } else {
534 err = WSAGetLastError();
535 if (err == WSAEMSGSIZE) {
536 /* Message truncated */
537 handle->recv_cb(handle,
538 bytes,
539 &buf,
540 (const struct sockaddr*) &from,
541 UV_UDP_PARTIAL);
542 } else if (err == WSAEWOULDBLOCK) {
543 /* Kernel buffer empty */
544 handle->recv_cb(handle, 0, &buf, NULL, 0);
545 } else if (err == WSAECONNRESET || err == WSAENETRESET) {
546 /* WSAECONNRESET/WSANETRESET is ignored because this just indicates
547 * that a previous sendto operation failed.
548 */
549 handle->recv_cb(handle, 0, &buf, NULL, 0);
550 } else {
551 /* Any other error that we want to report back to the user. */
552 uv_udp_recv_stop(handle);
553 handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
554 }
555 }
556 }
557
558 done:
559 /* Post another read if still reading and not closing. */
560 if ((handle->flags & UV_HANDLE_READING) &&
561 !(handle->flags & UV_HANDLE_READ_PENDING)) {
562 uv_udp_queue_recv(loop, handle);
563 }
564
565 DECREASE_PENDING_REQ_COUNT(handle);
566 }
567
568
uv_process_udp_send_req(uv_loop_t * loop,uv_udp_t * handle,uv_udp_send_t * req)569 void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
570 uv_udp_send_t* req) {
571 int err;
572
573 assert(handle->type == UV_UDP);
574
575 assert(handle->send_queue_size >= req->u.io.queued_bytes);
576 assert(handle->send_queue_count >= 1);
577 handle->send_queue_size -= req->u.io.queued_bytes;
578 handle->send_queue_count--;
579
580 UNREGISTER_HANDLE_REQ(loop, handle, req);
581
582 if (req->cb) {
583 err = 0;
584 if (!REQ_SUCCESS(req)) {
585 err = GET_REQ_SOCK_ERROR(req);
586 }
587 req->cb(req, uv_translate_sys_error(err));
588 }
589
590 DECREASE_PENDING_REQ_COUNT(handle);
591 }
592
593
uv__udp_set_membership4(uv_udp_t * handle,const struct sockaddr_in * multicast_addr,const char * interface_addr,uv_membership membership)594 static int uv__udp_set_membership4(uv_udp_t* handle,
595 const struct sockaddr_in* multicast_addr,
596 const char* interface_addr,
597 uv_membership membership) {
598 int err;
599 int optname;
600 struct ip_mreq mreq;
601
602 if (handle->flags & UV_HANDLE_IPV6)
603 return UV_EINVAL;
604
605 /* If the socket is unbound, bind to inaddr_any. */
606 err = uv_udp_maybe_bind(handle,
607 (const struct sockaddr*) &uv_addr_ip4_any_,
608 sizeof(uv_addr_ip4_any_),
609 UV_UDP_REUSEADDR);
610 if (err)
611 return uv_translate_sys_error(err);
612
613 memset(&mreq, 0, sizeof mreq);
614
615 if (interface_addr) {
616 err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
617 if (err)
618 return err;
619 } else {
620 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
621 }
622
623 mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
624
625 switch (membership) {
626 case UV_JOIN_GROUP:
627 optname = IP_ADD_MEMBERSHIP;
628 break;
629 case UV_LEAVE_GROUP:
630 optname = IP_DROP_MEMBERSHIP;
631 break;
632 default:
633 return UV_EINVAL;
634 }
635
636 if (setsockopt(handle->socket,
637 IPPROTO_IP,
638 optname,
639 (char*) &mreq,
640 sizeof mreq) == SOCKET_ERROR) {
641 return uv_translate_sys_error(WSAGetLastError());
642 }
643
644 return 0;
645 }
646
647
uv__udp_set_membership6(uv_udp_t * handle,const struct sockaddr_in6 * multicast_addr,const char * interface_addr,uv_membership membership)648 int uv__udp_set_membership6(uv_udp_t* handle,
649 const struct sockaddr_in6* multicast_addr,
650 const char* interface_addr,
651 uv_membership membership) {
652 int optname;
653 int err;
654 struct ipv6_mreq mreq;
655 struct sockaddr_in6 addr6;
656
657 if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
658 return UV_EINVAL;
659
660 err = uv_udp_maybe_bind(handle,
661 (const struct sockaddr*) &uv_addr_ip6_any_,
662 sizeof(uv_addr_ip6_any_),
663 UV_UDP_REUSEADDR);
664
665 if (err)
666 return uv_translate_sys_error(err);
667
668 memset(&mreq, 0, sizeof(mreq));
669
670 if (interface_addr) {
671 if (uv_ip6_addr(interface_addr, 0, &addr6))
672 return UV_EINVAL;
673 mreq.ipv6mr_interface = addr6.sin6_scope_id;
674 } else {
675 mreq.ipv6mr_interface = 0;
676 }
677
678 mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
679
680 switch (membership) {
681 case UV_JOIN_GROUP:
682 optname = IPV6_ADD_MEMBERSHIP;
683 break;
684 case UV_LEAVE_GROUP:
685 optname = IPV6_DROP_MEMBERSHIP;
686 break;
687 default:
688 return UV_EINVAL;
689 }
690
691 if (setsockopt(handle->socket,
692 IPPROTO_IPV6,
693 optname,
694 (char*) &mreq,
695 sizeof mreq) == SOCKET_ERROR) {
696 return uv_translate_sys_error(WSAGetLastError());
697 }
698
699 return 0;
700 }
701
702
uv_udp_set_membership(uv_udp_t * handle,const char * multicast_addr,const char * interface_addr,uv_membership membership)703 int uv_udp_set_membership(uv_udp_t* handle,
704 const char* multicast_addr,
705 const char* interface_addr,
706 uv_membership membership) {
707 struct sockaddr_in addr4;
708 struct sockaddr_in6 addr6;
709
710 if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0)
711 return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
712 else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0)
713 return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
714 else
715 return UV_EINVAL;
716 }
717
718
uv_udp_set_multicast_interface(uv_udp_t * handle,const char * interface_addr)719 int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
720 struct sockaddr_storage addr_st;
721 struct sockaddr_in* addr4;
722 struct sockaddr_in6* addr6;
723
724 addr4 = (struct sockaddr_in*) &addr_st;
725 addr6 = (struct sockaddr_in6*) &addr_st;
726
727 if (!interface_addr) {
728 memset(&addr_st, 0, sizeof addr_st);
729 if (handle->flags & UV_HANDLE_IPV6) {
730 addr_st.ss_family = AF_INET6;
731 addr6->sin6_scope_id = 0;
732 } else {
733 addr_st.ss_family = AF_INET;
734 addr4->sin_addr.s_addr = htonl(INADDR_ANY);
735 }
736 } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
737 /* nothing, address was parsed */
738 } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
739 /* nothing, address was parsed */
740 } else {
741 return UV_EINVAL;
742 }
743
744 if (!(handle->flags & UV_HANDLE_BOUND))
745 return UV_EBADF;
746
747 if (addr_st.ss_family == AF_INET) {
748 if (setsockopt(handle->socket,
749 IPPROTO_IP,
750 IP_MULTICAST_IF,
751 (char*) &addr4->sin_addr,
752 sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
753 return uv_translate_sys_error(WSAGetLastError());
754 }
755 } else if (addr_st.ss_family == AF_INET6) {
756 if (setsockopt(handle->socket,
757 IPPROTO_IPV6,
758 IPV6_MULTICAST_IF,
759 (char*) &addr6->sin6_scope_id,
760 sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
761 return uv_translate_sys_error(WSAGetLastError());
762 }
763 } else {
764 assert(0 && "unexpected address family");
765 abort();
766 }
767
768 return 0;
769 }
770
771
uv_udp_set_broadcast(uv_udp_t * handle,int value)772 int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
773 BOOL optval = (BOOL) value;
774
775 if (!(handle->flags & UV_HANDLE_BOUND))
776 return UV_EBADF;
777
778 if (setsockopt(handle->socket,
779 SOL_SOCKET,
780 SO_BROADCAST,
781 (char*) &optval,
782 sizeof optval)) {
783 return uv_translate_sys_error(WSAGetLastError());
784 }
785
786 return 0;
787 }
788
789
uv_udp_open(uv_udp_t * handle,uv_os_sock_t sock)790 int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
791 WSAPROTOCOL_INFOW protocol_info;
792 int opt_len;
793 int err;
794
795 /* Detect the address family of the socket. */
796 opt_len = (int) sizeof protocol_info;
797 if (getsockopt(sock,
798 SOL_SOCKET,
799 SO_PROTOCOL_INFOW,
800 (char*) &protocol_info,
801 &opt_len) == SOCKET_ERROR) {
802 return uv_translate_sys_error(GetLastError());
803 }
804
805 err = uv_udp_set_socket(handle->loop,
806 handle,
807 sock,
808 protocol_info.iAddressFamily);
809 return uv_translate_sys_error(err);
810 }
811
812
813 #define SOCKOPT_SETTER(name, option4, option6, validate) \
814 int uv_udp_set_##name(uv_udp_t* handle, int value) { \
815 DWORD optval = (DWORD) value; \
816 \
817 if (!(validate(value))) { \
818 return UV_EINVAL; \
819 } \
820 \
821 if (!(handle->flags & UV_HANDLE_BOUND)) \
822 return UV_EBADF; \
823 \
824 if (!(handle->flags & UV_HANDLE_IPV6)) { \
825 /* Set IPv4 socket option */ \
826 if (setsockopt(handle->socket, \
827 IPPROTO_IP, \
828 option4, \
829 (char*) &optval, \
830 sizeof optval)) { \
831 return uv_translate_sys_error(WSAGetLastError()); \
832 } \
833 } else { \
834 /* Set IPv6 socket option */ \
835 if (setsockopt(handle->socket, \
836 IPPROTO_IPV6, \
837 option6, \
838 (char*) &optval, \
839 sizeof optval)) { \
840 return uv_translate_sys_error(WSAGetLastError()); \
841 } \
842 } \
843 return 0; \
844 }
845
846 #define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
847 #define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
848 #define VALIDATE_MULTICAST_LOOP(value) (1)
849
SOCKOPT_SETTER(ttl,IP_TTL,IPV6_HOPLIMIT,VALIDATE_TTL)850 SOCKOPT_SETTER(ttl,
851 IP_TTL,
852 IPV6_HOPLIMIT,
853 VALIDATE_TTL)
854 SOCKOPT_SETTER(multicast_ttl,
855 IP_MULTICAST_TTL,
856 IPV6_MULTICAST_HOPS,
857 VALIDATE_MULTICAST_TTL)
858 SOCKOPT_SETTER(multicast_loop,
859 IP_MULTICAST_LOOP,
860 IPV6_MULTICAST_LOOP,
861 VALIDATE_MULTICAST_LOOP)
862
863 #undef SOCKOPT_SETTER
864 #undef VALIDATE_TTL
865 #undef VALIDATE_MULTICAST_TTL
866 #undef VALIDATE_MULTICAST_LOOP
867
868
869 /* This function is an egress point, i.e. it returns libuv errors rather than
870 * system errors.
871 */
872 int uv__udp_bind(uv_udp_t* handle,
873 const struct sockaddr* addr,
874 unsigned int addrlen,
875 unsigned int flags) {
876 int err;
877
878 err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
879 if (err)
880 return uv_translate_sys_error(err);
881
882 return 0;
883 }
884
885
886 /* This function is an egress point, i.e. it returns libuv errors rather than
887 * system errors.
888 */
uv__udp_send(uv_udp_send_t * req,uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,unsigned int addrlen,uv_udp_send_cb send_cb)889 int uv__udp_send(uv_udp_send_t* req,
890 uv_udp_t* handle,
891 const uv_buf_t bufs[],
892 unsigned int nbufs,
893 const struct sockaddr* addr,
894 unsigned int addrlen,
895 uv_udp_send_cb send_cb) {
896 const struct sockaddr* bind_addr;
897 int err;
898
899 if (!(handle->flags & UV_HANDLE_BOUND)) {
900 if (addrlen == sizeof(uv_addr_ip4_any_))
901 bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
902 else if (addrlen == sizeof(uv_addr_ip6_any_))
903 bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
904 else
905 return UV_EINVAL;
906 err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
907 if (err)
908 return uv_translate_sys_error(err);
909 }
910
911 err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
912 if (err)
913 return uv_translate_sys_error(err);
914
915 return 0;
916 }
917
918
uv__udp_try_send(uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,unsigned int addrlen)919 int uv__udp_try_send(uv_udp_t* handle,
920 const uv_buf_t bufs[],
921 unsigned int nbufs,
922 const struct sockaddr* addr,
923 unsigned int addrlen) {
924 DWORD bytes;
925 const struct sockaddr* bind_addr;
926 struct sockaddr_storage converted;
927 int err;
928
929 assert(nbufs > 0);
930
931 err = uv__convert_to_localhost_if_unspecified(addr, &converted);
932 if (err)
933 return err;
934
935 /* Already sending a message.*/
936 if (handle->send_queue_count != 0)
937 return UV_EAGAIN;
938
939 if (!(handle->flags & UV_HANDLE_BOUND)) {
940 if (addrlen == sizeof(uv_addr_ip4_any_))
941 bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
942 else if (addrlen == sizeof(uv_addr_ip6_any_))
943 bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
944 else
945 return UV_EINVAL;
946 err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
947 if (err)
948 return uv_translate_sys_error(err);
949 }
950
951 err = WSASendTo(handle->socket,
952 (WSABUF*)bufs,
953 nbufs,
954 &bytes,
955 0,
956 (const struct sockaddr*) &converted,
957 addrlen,
958 NULL,
959 NULL);
960
961 if (err)
962 return uv_translate_sys_error(WSAGetLastError());
963
964 return bytes;
965 }
966