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