Mercurial
comparison third_party/libuv/src/win/udp.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 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 } |