PageRenderTime 68ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/deps/libuv/src/win/udp.c

https://bitbucket.org/sourcey/libsourcey
C | 748 lines | 542 code | 125 blank | 81 comment | 136 complexity | 8997c658b774cb49e1d72d3eff711bf6 MD5 | raw file
Possible License(s): MIT, GPL-3.0, ISC
  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. #include <assert.h>
  22. #include "uv.h"
  23. #include "internal.h"
  24. #include "handle-inl.h"
  25. #include "stream-inl.h"
  26. #include "req-inl.h"
  27. /*
  28. * Threshold of active udp streams for which to preallocate udp read buffers.
  29. */
  30. const unsigned int uv_active_udp_streams_threshold = 0;
  31. /* A zero-size buffer for use by uv_udp_read */
  32. static char uv_zero_[] = "";
  33. int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name,
  34. int* namelen) {
  35. int result;
  36. if (!(handle->flags & UV_HANDLE_BOUND)) {
  37. return UV_EINVAL;
  38. }
  39. result = getsockname(handle->socket, name, namelen);
  40. if (result != 0) {
  41. return uv_translate_sys_error(WSAGetLastError());
  42. }
  43. return 0;
  44. }
  45. static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
  46. int family) {
  47. DWORD yes = 1;
  48. WSAPROTOCOL_INFOW info;
  49. int opt_len;
  50. assert(handle->socket == INVALID_SOCKET);
  51. /* Set SO_REUSEADDR on the socket. */
  52. if (setsockopt(socket,
  53. SOL_SOCKET,
  54. SO_REUSEADDR,
  55. (char*) &yes,
  56. sizeof yes) == SOCKET_ERROR) {
  57. return WSAGetLastError();
  58. }
  59. /* Set the socket to nonblocking mode */
  60. if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
  61. return WSAGetLastError();
  62. }
  63. /* Make the socket non-inheritable */
  64. if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
  65. return GetLastError();
  66. }
  67. /* Associate it with the I/O completion port. */
  68. /* Use uv_handle_t pointer as completion key. */
  69. if (CreateIoCompletionPort((HANDLE)socket,
  70. loop->iocp,
  71. (ULONG_PTR)socket,
  72. 0) == NULL) {
  73. return GetLastError();
  74. }
  75. if (pSetFileCompletionNotificationModes) {
  76. /* All know windowses that support SetFileCompletionNotificationModes */
  77. /* have a bug that makes it impossible to use this function in */
  78. /* conjunction with datagram sockets. We can work around that but only */
  79. /* if the user is using the default UDP driver (AFD) and has no other */
  80. /* LSPs stacked on top. Here we check whether that is the case. */
  81. opt_len = (int) sizeof info;
  82. if (getsockopt(socket,
  83. SOL_SOCKET,
  84. SO_PROTOCOL_INFOW,
  85. (char*) &info,
  86. &opt_len) == SOCKET_ERROR) {
  87. return GetLastError();
  88. }
  89. if (info.ProtocolChain.ChainLen == 1) {
  90. if (pSetFileCompletionNotificationModes((HANDLE)socket,
  91. FILE_SKIP_SET_EVENT_ON_HANDLE |
  92. FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
  93. handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
  94. handle->func_wsarecv = uv_wsarecv_workaround;
  95. handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
  96. } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
  97. return GetLastError();
  98. }
  99. }
  100. }
  101. handle->socket = socket;
  102. if (family == AF_INET6) {
  103. handle->flags |= UV_HANDLE_IPV6;
  104. } else {
  105. assert(!(handle->flags & UV_HANDLE_IPV6));
  106. }
  107. return 0;
  108. }
  109. int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
  110. uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
  111. handle->socket = INVALID_SOCKET;
  112. handle->reqs_pending = 0;
  113. handle->activecnt = 0;
  114. handle->func_wsarecv = WSARecv;
  115. handle->func_wsarecvfrom = WSARecvFrom;
  116. uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
  117. handle->recv_req.type = UV_UDP_RECV;
  118. handle->recv_req.data = handle;
  119. return 0;
  120. }
  121. void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
  122. uv_udp_recv_stop(handle);
  123. closesocket(handle->socket);
  124. uv__handle_closing(handle);
  125. if (handle->reqs_pending == 0) {
  126. uv_want_endgame(loop, (uv_handle_t*) handle);
  127. }
  128. }
  129. void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
  130. if (handle->flags & UV__HANDLE_CLOSING &&
  131. handle->reqs_pending == 0) {
  132. assert(!(handle->flags & UV_HANDLE_CLOSED));
  133. uv__handle_close(handle);
  134. }
  135. }
  136. static int uv_udp_try_bind(uv_udp_t* handle,
  137. const struct sockaddr* addr,
  138. unsigned int addrlen,
  139. unsigned int flags) {
  140. int r;
  141. int err;
  142. DWORD no = 0;
  143. if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
  144. /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
  145. return ERROR_INVALID_PARAMETER;
  146. }
  147. if (handle->socket == INVALID_SOCKET) {
  148. SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
  149. if (sock == INVALID_SOCKET) {
  150. return WSAGetLastError();
  151. }
  152. err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
  153. if (err) {
  154. closesocket(sock);
  155. return err;
  156. }
  157. if (addr->sa_family == AF_INET6)
  158. handle->flags |= UV_HANDLE_IPV6;
  159. }
  160. if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
  161. /* On windows IPV6ONLY is on by default. */
  162. /* If the user doesn't specify it libuv turns it off. */
  163. /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
  164. /* available, or when run on XP/2003 which have no support for dualstack */
  165. /* sockets. For now we're silently ignoring the error. */
  166. setsockopt(handle->socket,
  167. IPPROTO_IPV6,
  168. IPV6_V6ONLY,
  169. (char*) &no,
  170. sizeof no);
  171. }
  172. r = bind(handle->socket, addr, addrlen);
  173. if (r == SOCKET_ERROR) {
  174. return WSAGetLastError();
  175. }
  176. handle->flags |= UV_HANDLE_BOUND;
  177. return 0;
  178. }
  179. static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
  180. uv_req_t* req;
  181. uv_buf_t buf;
  182. DWORD bytes, flags;
  183. int result;
  184. assert(handle->flags & UV_HANDLE_READING);
  185. assert(!(handle->flags & UV_HANDLE_READ_PENDING));
  186. req = &handle->recv_req;
  187. memset(&req->overlapped, 0, sizeof(req->overlapped));
  188. /*
  189. * Preallocate a read buffer if the number of active streams is below
  190. * the threshold.
  191. */
  192. if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
  193. handle->flags &= ~UV_HANDLE_ZERO_READ;
  194. handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
  195. if (handle->recv_buffer.len == 0) {
  196. handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
  197. return;
  198. }
  199. assert(handle->recv_buffer.base != NULL);
  200. buf = handle->recv_buffer;
  201. memset(&handle->recv_from, 0, sizeof handle->recv_from);
  202. handle->recv_from_len = sizeof handle->recv_from;
  203. flags = 0;
  204. result = handle->func_wsarecvfrom(handle->socket,
  205. (WSABUF*) &buf,
  206. 1,
  207. &bytes,
  208. &flags,
  209. (struct sockaddr*) &handle->recv_from,
  210. &handle->recv_from_len,
  211. &req->overlapped,
  212. NULL);
  213. if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
  214. /* Process the req without IOCP. */
  215. handle->flags |= UV_HANDLE_READ_PENDING;
  216. req->overlapped.InternalHigh = bytes;
  217. handle->reqs_pending++;
  218. uv_insert_pending_req(loop, req);
  219. } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
  220. /* The req will be processed with IOCP. */
  221. handle->flags |= UV_HANDLE_READ_PENDING;
  222. handle->reqs_pending++;
  223. } else {
  224. /* Make this req pending reporting an error. */
  225. SET_REQ_ERROR(req, WSAGetLastError());
  226. uv_insert_pending_req(loop, req);
  227. handle->reqs_pending++;
  228. }
  229. } else {
  230. handle->flags |= UV_HANDLE_ZERO_READ;
  231. buf.base = (char*) uv_zero_;
  232. buf.len = 0;
  233. flags = MSG_PEEK;
  234. result = handle->func_wsarecv(handle->socket,
  235. (WSABUF*) &buf,
  236. 1,
  237. &bytes,
  238. &flags,
  239. &req->overlapped,
  240. NULL);
  241. if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
  242. /* Process the req without IOCP. */
  243. handle->flags |= UV_HANDLE_READ_PENDING;
  244. req->overlapped.InternalHigh = bytes;
  245. handle->reqs_pending++;
  246. uv_insert_pending_req(loop, req);
  247. } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
  248. /* The req will be processed with IOCP. */
  249. handle->flags |= UV_HANDLE_READ_PENDING;
  250. handle->reqs_pending++;
  251. } else {
  252. /* Make this req pending reporting an error. */
  253. SET_REQ_ERROR(req, WSAGetLastError());
  254. uv_insert_pending_req(loop, req);
  255. handle->reqs_pending++;
  256. }
  257. }
  258. }
  259. int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
  260. uv_udp_recv_cb recv_cb) {
  261. uv_loop_t* loop = handle->loop;
  262. int err;
  263. if (handle->flags & UV_HANDLE_READING) {
  264. return WSAEALREADY;
  265. }
  266. if (!(handle->flags & UV_HANDLE_BOUND)) {
  267. err = uv_udp_try_bind(handle,
  268. (const struct sockaddr*) &uv_addr_ip4_any_,
  269. sizeof(uv_addr_ip4_any_),
  270. 0);
  271. if (err)
  272. return err;
  273. }
  274. handle->flags |= UV_HANDLE_READING;
  275. INCREASE_ACTIVE_COUNT(loop, handle);
  276. loop->active_udp_streams++;
  277. handle->recv_cb = recv_cb;
  278. handle->alloc_cb = alloc_cb;
  279. /* If reading was stopped and then started again, there could still be a */
  280. /* recv request pending. */
  281. if (!(handle->flags & UV_HANDLE_READ_PENDING))
  282. uv_udp_queue_recv(loop, handle);
  283. return 0;
  284. }
  285. int uv__udp_recv_stop(uv_udp_t* handle) {
  286. if (handle->flags & UV_HANDLE_READING) {
  287. handle->flags &= ~UV_HANDLE_READING;
  288. handle->loop->active_udp_streams--;
  289. DECREASE_ACTIVE_COUNT(loop, handle);
  290. }
  291. return 0;
  292. }
  293. static int uv__send(uv_udp_send_t* req,
  294. uv_udp_t* handle,
  295. const uv_buf_t bufs[],
  296. unsigned int nbufs,
  297. const struct sockaddr* addr,
  298. unsigned int addrlen,
  299. uv_udp_send_cb cb) {
  300. uv_loop_t* loop = handle->loop;
  301. DWORD result, bytes;
  302. uv_req_init(loop, (uv_req_t*) req);
  303. req->type = UV_UDP_SEND;
  304. req->handle = handle;
  305. req->cb = cb;
  306. memset(&req->overlapped, 0, sizeof(req->overlapped));
  307. result = WSASendTo(handle->socket,
  308. (WSABUF*)bufs,
  309. nbufs,
  310. &bytes,
  311. 0,
  312. addr,
  313. addrlen,
  314. &req->overlapped,
  315. NULL);
  316. if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
  317. /* Request completed immediately. */
  318. req->queued_bytes = 0;
  319. handle->reqs_pending++;
  320. REGISTER_HANDLE_REQ(loop, handle, req);
  321. uv_insert_pending_req(loop, (uv_req_t*)req);
  322. } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
  323. /* Request queued by the kernel. */
  324. req->queued_bytes = uv_count_bufs(bufs, nbufs);
  325. handle->reqs_pending++;
  326. REGISTER_HANDLE_REQ(loop, handle, req);
  327. } else {
  328. /* Send failed due to an error. */
  329. return WSAGetLastError();
  330. }
  331. return 0;
  332. }
  333. void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
  334. uv_req_t* req) {
  335. uv_buf_t buf;
  336. int partial;
  337. assert(handle->type == UV_UDP);
  338. handle->flags &= ~UV_HANDLE_READ_PENDING;
  339. if (!REQ_SUCCESS(req)) {
  340. DWORD err = GET_REQ_SOCK_ERROR(req);
  341. if (err == WSAEMSGSIZE) {
  342. /* Not a real error, it just indicates that the received packet */
  343. /* was bigger than the receive buffer. */
  344. } else if (err == WSAECONNRESET || err == WSAENETRESET) {
  345. /* A previous sendto operation failed; ignore this error. If */
  346. /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
  347. /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
  348. /* immediately queue a new receive. */
  349. if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
  350. goto done;
  351. }
  352. } else {
  353. /* A real error occurred. Report the error to the user only if we're */
  354. /* currently reading. */
  355. if (handle->flags & UV_HANDLE_READING) {
  356. uv_udp_recv_stop(handle);
  357. buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
  358. uv_buf_init(NULL, 0) : handle->recv_buffer;
  359. handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
  360. }
  361. goto done;
  362. }
  363. }
  364. if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
  365. /* Successful read */
  366. partial = !REQ_SUCCESS(req);
  367. handle->recv_cb(handle,
  368. req->overlapped.InternalHigh,
  369. &handle->recv_buffer,
  370. (const struct sockaddr*) &handle->recv_from,
  371. partial ? UV_UDP_PARTIAL : 0);
  372. } else if (handle->flags & UV_HANDLE_READING) {
  373. DWORD bytes, err, flags;
  374. struct sockaddr_storage from;
  375. int from_len;
  376. /* Do a nonblocking receive */
  377. /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
  378. handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
  379. if (buf.len == 0) {
  380. handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
  381. goto done;
  382. }
  383. assert(buf.base != NULL);
  384. memset(&from, 0, sizeof from);
  385. from_len = sizeof from;
  386. flags = 0;
  387. if (WSARecvFrom(handle->socket,
  388. (WSABUF*)&buf,
  389. 1,
  390. &bytes,
  391. &flags,
  392. (struct sockaddr*) &from,
  393. &from_len,
  394. NULL,
  395. NULL) != SOCKET_ERROR) {
  396. /* Message received */
  397. handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
  398. } else {
  399. err = WSAGetLastError();
  400. if (err == WSAEMSGSIZE) {
  401. /* Message truncated */
  402. handle->recv_cb(handle,
  403. bytes,
  404. &buf,
  405. (const struct sockaddr*) &from,
  406. UV_UDP_PARTIAL);
  407. } if (err == WSAEWOULDBLOCK) {
  408. /* Kernel buffer empty */
  409. handle->recv_cb(handle, 0, &buf, NULL, 0);
  410. } else if (err != WSAECONNRESET && err != WSAENETRESET) {
  411. /* Serious error. WSAECONNRESET/WSANETRESET is ignored because this */
  412. /* just indicates that a previous sendto operation failed. */
  413. uv_udp_recv_stop(handle);
  414. handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
  415. }
  416. }
  417. }
  418. done:
  419. /* Post another read if still reading and not closing. */
  420. if ((handle->flags & UV_HANDLE_READING) &&
  421. !(handle->flags & UV_HANDLE_READ_PENDING)) {
  422. uv_udp_queue_recv(loop, handle);
  423. }
  424. DECREASE_PENDING_REQ_COUNT(handle);
  425. }
  426. void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
  427. uv_udp_send_t* req) {
  428. int err;
  429. assert(handle->type == UV_UDP);
  430. UNREGISTER_HANDLE_REQ(loop, handle, req);
  431. if (req->cb) {
  432. err = 0;
  433. if (!REQ_SUCCESS(req)) {
  434. err = GET_REQ_SOCK_ERROR(req);
  435. }
  436. req->cb(req, uv_translate_sys_error(err));
  437. }
  438. DECREASE_PENDING_REQ_COUNT(handle);
  439. }
  440. int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr,
  441. const char* interface_addr, uv_membership membership) {
  442. int err;
  443. int optname;
  444. struct ip_mreq mreq;
  445. /* If the socket is unbound, bind to inaddr_any. */
  446. if (!(handle->flags & UV_HANDLE_BOUND)) {
  447. err = uv_udp_try_bind(handle,
  448. (const struct sockaddr*) &uv_addr_ip4_any_,
  449. sizeof(uv_addr_ip4_any_),
  450. 0);
  451. if (err)
  452. return uv_translate_sys_error(err);
  453. }
  454. if (handle->flags & UV_HANDLE_IPV6) {
  455. return UV_ENOSYS;
  456. }
  457. memset(&mreq, 0, sizeof mreq);
  458. if (interface_addr) {
  459. mreq.imr_interface.s_addr = inet_addr(interface_addr);
  460. } else {
  461. mreq.imr_interface.s_addr = htonl(INADDR_ANY);
  462. }
  463. mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr);
  464. switch (membership) {
  465. case UV_JOIN_GROUP:
  466. optname = IP_ADD_MEMBERSHIP;
  467. break;
  468. case UV_LEAVE_GROUP:
  469. optname = IP_DROP_MEMBERSHIP;
  470. break;
  471. default:
  472. return UV_EINVAL;
  473. }
  474. if (setsockopt(handle->socket,
  475. IPPROTO_IP,
  476. optname,
  477. (char*) &mreq,
  478. sizeof mreq) == SOCKET_ERROR) {
  479. return uv_translate_sys_error(WSAGetLastError());
  480. }
  481. return 0;
  482. }
  483. int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
  484. BOOL optval = (BOOL) value;
  485. int err;
  486. /* If the socket is unbound, bind to inaddr_any. */
  487. if (!(handle->flags & UV_HANDLE_BOUND)) {
  488. err = uv_udp_try_bind(handle,
  489. (const struct sockaddr*) &uv_addr_ip4_any_,
  490. sizeof(uv_addr_ip4_any_),
  491. 0);
  492. if (err)
  493. return uv_translate_sys_error(err);
  494. }
  495. if (setsockopt(handle->socket,
  496. SOL_SOCKET,
  497. SO_BROADCAST,
  498. (char*) &optval,
  499. sizeof optval)) {
  500. return uv_translate_sys_error(WSAGetLastError());
  501. }
  502. return 0;
  503. }
  504. int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
  505. WSAPROTOCOL_INFOW protocol_info;
  506. int opt_len;
  507. int err;
  508. /* Detect the address family of the socket. */
  509. opt_len = (int) sizeof protocol_info;
  510. if (getsockopt(sock,
  511. SOL_SOCKET,
  512. SO_PROTOCOL_INFOW,
  513. (char*) &protocol_info,
  514. &opt_len) == SOCKET_ERROR) {
  515. return uv_translate_sys_error(GetLastError());
  516. }
  517. err = uv_udp_set_socket(handle->loop,
  518. handle,
  519. sock,
  520. protocol_info.iAddressFamily);
  521. return uv_translate_sys_error(err);
  522. }
  523. #define SOCKOPT_SETTER(name, option4, option6, validate) \
  524. int uv_udp_set_##name(uv_udp_t* handle, int value) { \
  525. DWORD optval = (DWORD) value; \
  526. int err; \
  527. \
  528. if (!(validate(value))) { \
  529. return UV_EINVAL; \
  530. } \
  531. \
  532. /* If the socket is unbound, bind to inaddr_any. */ \
  533. if (!(handle->flags & UV_HANDLE_BOUND)) { \
  534. err = uv_udp_try_bind(handle, \
  535. (const struct sockaddr*) &uv_addr_ip4_any_, \
  536. sizeof(uv_addr_ip4_any_), \
  537. 0); \
  538. if (err) \
  539. return uv_translate_sys_error(err); \
  540. } \
  541. \
  542. if (!(handle->flags & UV_HANDLE_IPV6)) { \
  543. /* Set IPv4 socket option */ \
  544. if (setsockopt(handle->socket, \
  545. IPPROTO_IP, \
  546. option4, \
  547. (char*) &optval, \
  548. sizeof optval)) { \
  549. return uv_translate_sys_error(WSAGetLastError()); \
  550. } \
  551. } else { \
  552. /* Set IPv6 socket option */ \
  553. if (setsockopt(handle->socket, \
  554. IPPROTO_IPV6, \
  555. option6, \
  556. (char*) &optval, \
  557. sizeof optval)) { \
  558. return uv_translate_sys_error(WSAGetLastError()); \
  559. } \
  560. } \
  561. return 0; \
  562. }
  563. #define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
  564. #define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
  565. #define VALIDATE_MULTICAST_LOOP(value) (1)
  566. SOCKOPT_SETTER(ttl,
  567. IP_TTL,
  568. IPV6_HOPLIMIT,
  569. VALIDATE_TTL)
  570. SOCKOPT_SETTER(multicast_ttl,
  571. IP_MULTICAST_TTL,
  572. IPV6_MULTICAST_HOPS,
  573. VALIDATE_MULTICAST_TTL)
  574. SOCKOPT_SETTER(multicast_loop,
  575. IP_MULTICAST_LOOP,
  576. IPV6_MULTICAST_LOOP,
  577. VALIDATE_MULTICAST_LOOP)
  578. #undef SOCKOPT_SETTER
  579. #undef VALIDATE_TTL
  580. #undef VALIDATE_MULTICAST_TTL
  581. #undef VALIDATE_MULTICAST_LOOP
  582. /* This function is an egress point, i.e. it returns libuv errors rather than
  583. * system errors.
  584. */
  585. int uv__udp_bind(uv_udp_t* handle,
  586. const struct sockaddr* addr,
  587. unsigned int addrlen,
  588. unsigned int flags) {
  589. int err;
  590. err = uv_udp_try_bind(handle, addr, addrlen, flags);
  591. if (err)
  592. return uv_translate_sys_error(err);
  593. return 0;
  594. }
  595. /* This function is an egress point, i.e. it returns libuv errors rather than
  596. * system errors.
  597. */
  598. int uv__udp_send(uv_udp_send_t* req,
  599. uv_udp_t* handle,
  600. const uv_buf_t bufs[],
  601. unsigned int nbufs,
  602. const struct sockaddr* addr,
  603. unsigned int addrlen,
  604. uv_udp_send_cb send_cb) {
  605. const struct sockaddr* bind_addr;
  606. int err;
  607. if (!(handle->flags & UV_HANDLE_BOUND)) {
  608. if (addrlen == sizeof(uv_addr_ip4_any_)) {
  609. bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
  610. } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
  611. bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
  612. } else {
  613. abort();
  614. }
  615. err = uv_udp_try_bind(handle, bind_addr, addrlen, 0);
  616. if (err)
  617. return uv_translate_sys_error(err);
  618. }
  619. err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
  620. if (err)
  621. return uv_translate_sys_error(err);
  622. return 0;
  623. }