1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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:
10
* The above copyright notice and this permission notice shall be included in
11
* all copies or substantial portions of the Software.
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
27
#include "handle-inl.h"
28
#include "stream-inl.h"
33
* Threshold of active udp streams for which to preallocate udp read buffers.
35
const unsigned int uv_active_udp_streams_threshold = 0;
37
/* A zero-size buffer for use by uv_udp_read */
38
static char uv_zero_[] = "";
40
int uv_udp_getsockname(const uv_udp_t* handle,
41
struct sockaddr* name,
45
if (handle->socket == INVALID_SOCKET) {
49
result = getsockname(handle->socket, name, namelen);
51
return uv_translate_sys_error(WSAGetLastError());
58
static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
61
WSAPROTOCOL_INFOW info;
64
if (handle->socket != INVALID_SOCKET)
67
/* Set the socket to nonblocking mode */
68
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
69
return WSAGetLastError();
72
/* Make the socket non-inheritable */
73
if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
74
return GetLastError();
77
/* Associate it with the I/O completion port. */
78
/* Use uv_handle_t pointer as completion key. */
79
if (CreateIoCompletionPort((HANDLE)socket,
83
return GetLastError();
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,
97
&opt_len) == SOCKET_ERROR) {
98
return GetLastError();
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();
114
handle->socket = socket;
116
if (family == AF_INET6) {
117
handle->flags |= UV_HANDLE_IPV6;
119
assert(!(handle->flags & UV_HANDLE_IPV6));
126
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
129
/* Use the lower 8 bits for the domain */
130
domain = flags & 0xFF;
131
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
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(loop, (uv_req_t*) &(handle->recv_req));
146
handle->recv_req.type = UV_UDP_RECV;
147
handle->recv_req.data = handle;
149
/* If anything fails beyond this point we need to remove the handle from
150
* the handle queue, since it was added by uv__handle_init.
153
if (domain != AF_UNSPEC) {
157
sock = socket(domain, SOCK_DGRAM, 0);
158
if (sock == INVALID_SOCKET) {
159
err = WSAGetLastError();
160
QUEUE_REMOVE(&handle->handle_queue);
161
return uv_translate_sys_error(err);
164
err = uv_udp_set_socket(handle->loop, handle, sock, domain);
167
QUEUE_REMOVE(&handle->handle_queue);
168
return uv_translate_sys_error(err);
176
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
177
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
181
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
182
uv_udp_recv_stop(handle);
183
closesocket(handle->socket);
184
handle->socket = INVALID_SOCKET;
186
uv__handle_closing(handle);
188
if (handle->reqs_pending == 0) {
189
uv_want_endgame(loop, (uv_handle_t*) handle);
194
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
195
if (handle->flags & UV__HANDLE_CLOSING &&
196
handle->reqs_pending == 0) {
197
assert(!(handle->flags & UV_HANDLE_CLOSED));
198
uv__handle_close(handle);
203
static int uv_udp_maybe_bind(uv_udp_t* handle,
204
const struct sockaddr* addr,
205
unsigned int addrlen,
206
unsigned int flags) {
211
if (handle->flags & UV_HANDLE_BOUND)
214
if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
215
/* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
216
return ERROR_INVALID_PARAMETER;
219
if (handle->socket == INVALID_SOCKET) {
220
SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
221
if (sock == INVALID_SOCKET) {
222
return WSAGetLastError();
225
err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
232
if (flags & UV_UDP_REUSEADDR) {
234
/* Set SO_REUSEADDR on the socket. */
235
if (setsockopt(handle->socket,
239
sizeof yes) == SOCKET_ERROR) {
240
err = WSAGetLastError();
245
if (addr->sa_family == AF_INET6)
246
handle->flags |= UV_HANDLE_IPV6;
248
if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
249
/* On windows IPV6ONLY is on by default. */
250
/* If the user doesn't specify it libuv turns it off. */
252
/* TODO: how to handle errors? This may fail if there is no ipv4 stack */
253
/* available, or when run on XP/2003 which have no support for dualstack */
254
/* sockets. For now we're silently ignoring the error. */
255
setsockopt(handle->socket,
262
r = bind(handle->socket, addr, addrlen);
263
if (r == SOCKET_ERROR) {
264
return WSAGetLastError();
267
handle->flags |= UV_HANDLE_BOUND;
273
static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
279
assert(handle->flags & UV_HANDLE_READING);
280
assert(!(handle->flags & UV_HANDLE_READ_PENDING));
282
req = &handle->recv_req;
283
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
286
* Preallocate a read buffer if the number of active streams is below
289
if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
290
handle->flags &= ~UV_HANDLE_ZERO_READ;
292
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
293
if (handle->recv_buffer.len == 0) {
294
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
297
assert(handle->recv_buffer.base != NULL);
299
buf = handle->recv_buffer;
300
memset(&handle->recv_from, 0, sizeof handle->recv_from);
301
handle->recv_from_len = sizeof handle->recv_from;
304
result = handle->func_wsarecvfrom(handle->socket,
309
(struct sockaddr*) &handle->recv_from,
310
&handle->recv_from_len,
311
&req->u.io.overlapped,
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++;
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++;
332
handle->flags |= UV_HANDLE_ZERO_READ;
334
buf.base = (char*) uv_zero_;
338
result = handle->func_wsarecv(handle->socket,
343
&req->u.io.overlapped,
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++;
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++;
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;
371
if (handle->flags & UV_HANDLE_READING) {
375
err = uv_udp_maybe_bind(handle,
376
(const struct sockaddr*) &uv_addr_ip4_any_,
377
sizeof(uv_addr_ip4_any_),
382
handle->flags |= UV_HANDLE_READING;
383
INCREASE_ACTIVE_COUNT(loop, handle);
384
loop->active_udp_streams++;
386
handle->recv_cb = recv_cb;
387
handle->alloc_cb = alloc_cb;
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);
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);
409
static int uv__send(uv_udp_send_t* req,
411
const uv_buf_t bufs[],
413
const struct sockaddr* addr,
414
unsigned int addrlen,
416
uv_loop_t* loop = handle->loop;
419
uv_req_init(loop, (uv_req_t*) req);
420
req->type = UV_UDP_SEND;
421
req->handle = handle;
423
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
425
result = WSASendTo(handle->socket,
432
&req->u.io.overlapped,
435
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
436
/* Request completed immediately. */
437
req->u.io.queued_bytes = 0;
438
handle->reqs_pending++;
439
handle->send_queue_size += req->u.io.queued_bytes;
440
handle->send_queue_count++;
441
REGISTER_HANDLE_REQ(loop, handle, req);
442
uv_insert_pending_req(loop, (uv_req_t*)req);
443
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
444
/* Request queued by the kernel. */
445
req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
446
handle->reqs_pending++;
447
handle->send_queue_size += req->u.io.queued_bytes;
448
handle->send_queue_count++;
449
REGISTER_HANDLE_REQ(loop, handle, req);
451
/* Send failed due to an error. */
452
return WSAGetLastError();
459
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
464
assert(handle->type == UV_UDP);
466
handle->flags &= ~UV_HANDLE_READ_PENDING;
468
if (!REQ_SUCCESS(req)) {
469
DWORD err = GET_REQ_SOCK_ERROR(req);
470
if (err == WSAEMSGSIZE) {
471
/* Not a real error, it just indicates that the received packet */
472
/* was bigger than the receive buffer. */
473
} else if (err == WSAECONNRESET || err == WSAENETRESET) {
474
/* A previous sendto operation failed; ignore this error. If */
475
/* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
476
/* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
477
/* immediately queue a new receive. */
478
if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
482
/* A real error occurred. Report the error to the user only if we're */
483
/* currently reading. */
484
if (handle->flags & UV_HANDLE_READING) {
485
uv_udp_recv_stop(handle);
486
buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
487
uv_buf_init(NULL, 0) : handle->recv_buffer;
488
handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
494
if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
495
/* Successful read */
496
partial = !REQ_SUCCESS(req);
497
handle->recv_cb(handle,
498
req->u.io.overlapped.InternalHigh,
499
&handle->recv_buffer,
500
(const struct sockaddr*) &handle->recv_from,
501
partial ? UV_UDP_PARTIAL : 0);
502
} else if (handle->flags & UV_HANDLE_READING) {
503
DWORD bytes, err, flags;
504
struct sockaddr_storage from;
507
/* Do a nonblocking receive */
508
/* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
509
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
511
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
514
assert(buf.base != NULL);
516
memset(&from, 0, sizeof from);
517
from_len = sizeof from;
521
if (WSARecvFrom(handle->socket,
526
(struct sockaddr*) &from,
529
NULL) != SOCKET_ERROR) {
531
/* Message received */
532
handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
534
err = WSAGetLastError();
535
if (err == WSAEMSGSIZE) {
536
/* Message truncated */
537
handle->recv_cb(handle,
540
(const struct sockaddr*) &from,
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.
549
handle->recv_cb(handle, 0, &buf, NULL, 0);
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);
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);
565
DECREASE_PENDING_REQ_COUNT(handle);
569
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
570
uv_udp_send_t* req) {
573
assert(handle->type == UV_UDP);
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--;
580
UNREGISTER_HANDLE_REQ(loop, handle, req);
584
if (!REQ_SUCCESS(req)) {
585
err = GET_REQ_SOCK_ERROR(req);
587
req->cb(req, uv_translate_sys_error(err));
590
DECREASE_PENDING_REQ_COUNT(handle);
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) {
602
if (handle->flags & UV_HANDLE_IPV6)
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_),
611
return uv_translate_sys_error(err);
613
memset(&mreq, 0, sizeof mreq);
615
if (interface_addr) {
616
err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
620
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
623
mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
625
switch (membership) {
627
optname = IP_ADD_MEMBERSHIP;
630
optname = IP_DROP_MEMBERSHIP;
636
if (setsockopt(handle->socket,
640
sizeof mreq) == SOCKET_ERROR) {
641
return uv_translate_sys_error(WSAGetLastError());
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) {
654
struct ipv6_mreq mreq;
655
struct sockaddr_in6 addr6;
657
if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
660
err = uv_udp_maybe_bind(handle,
661
(const struct sockaddr*) &uv_addr_ip6_any_,
662
sizeof(uv_addr_ip6_any_),
666
return uv_translate_sys_error(err);
668
memset(&mreq, 0, sizeof(mreq));
670
if (interface_addr) {
671
if (uv_ip6_addr(interface_addr, 0, &addr6))
673
mreq.ipv6mr_interface = addr6.sin6_scope_id;
675
mreq.ipv6mr_interface = 0;
678
mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
680
switch (membership) {
682
optname = IPV6_ADD_MEMBERSHIP;
685
optname = IPV6_DROP_MEMBERSHIP;
691
if (setsockopt(handle->socket,
695
sizeof mreq) == SOCKET_ERROR) {
696
return uv_translate_sys_error(WSAGetLastError());
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;
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);
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;
724
addr4 = (struct sockaddr_in*) &addr_st;
725
addr6 = (struct sockaddr_in6*) &addr_st;
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;
733
addr_st.ss_family = AF_INET;
734
addr4->sin_addr.s_addr = htonl(INADDR_ANY);
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 */
744
if (!(handle->flags & UV_HANDLE_BOUND))
747
if (addr_st.ss_family == AF_INET) {
748
if (setsockopt(handle->socket,
751
(char*) &addr4->sin_addr,
752
sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
753
return uv_translate_sys_error(WSAGetLastError());
755
} else if (addr_st.ss_family == AF_INET6) {
756
if (setsockopt(handle->socket,
759
(char*) &addr6->sin6_scope_id,
760
sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
761
return uv_translate_sys_error(WSAGetLastError());
764
assert(0 && "unexpected address family");
772
int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
773
BOOL optval = (BOOL) value;
775
if (!(handle->flags & UV_HANDLE_BOUND))
778
if (setsockopt(handle->socket,
783
return uv_translate_sys_error(WSAGetLastError());
790
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
791
WSAPROTOCOL_INFOW protocol_info;
795
/* Detect the address family of the socket. */
796
opt_len = (int) sizeof protocol_info;
800
(char*) &protocol_info,
801
&opt_len) == SOCKET_ERROR) {
802
return uv_translate_sys_error(GetLastError());
805
err = uv_udp_set_socket(handle->loop,
808
protocol_info.iAddressFamily);
809
return uv_translate_sys_error(err);
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; \
817
if (!(validate(value))) { \
821
if (!(handle->flags & UV_HANDLE_BOUND)) \
824
if (!(handle->flags & UV_HANDLE_IPV6)) { \
825
/* Set IPv4 socket option */ \
826
if (setsockopt(handle->socket, \
831
return uv_translate_sys_error(WSAGetLastError()); \
834
/* Set IPv6 socket option */ \
835
if (setsockopt(handle->socket, \
840
return uv_translate_sys_error(WSAGetLastError()); \
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)
854
SOCKOPT_SETTER(multicast_ttl,
857
VALIDATE_MULTICAST_TTL)
858
SOCKOPT_SETTER(multicast_loop,
861
VALIDATE_MULTICAST_LOOP)
863
#undef SOCKOPT_SETTER
865
#undef VALIDATE_MULTICAST_TTL
866
#undef VALIDATE_MULTICAST_LOOP
869
/* This function is an egress point, i.e. it returns libuv errors rather than
872
int uv__udp_bind(uv_udp_t* handle,
873
const struct sockaddr* addr,
874
unsigned int addrlen,
875
unsigned int flags) {
878
err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
880
return uv_translate_sys_error(err);
886
/* This function is an egress point, i.e. it returns libuv errors rather than
889
int uv__udp_send(uv_udp_send_t* req,
891
const uv_buf_t bufs[],
893
const struct sockaddr* addr,
894
unsigned int addrlen,
895
uv_udp_send_cb send_cb) {
896
const struct sockaddr* bind_addr;
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_;
907
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
909
return uv_translate_sys_error(err);
912
err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
914
return uv_translate_sys_error(err);
920
int uv__udp_try_send(uv_udp_t* handle,
921
const uv_buf_t bufs[],
923
const struct sockaddr* addr,
924
unsigned int addrlen) {