unix, win: extend uv_udp_set_membership for IPv6 multicast. #692
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
|
@@ -35,6 +35,10 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); | ||
static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); | static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); | ||
static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); | static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); | ||
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain); | static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain); | ||
static int uv__udp_set_membership6(uv_udp_t* handle, | |||
const char* multicast_addr, | |||
const char* interface_addr, | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
|||
uv_membership membership); | |||
|
|
||
|
|
||
void uv__udp_close(uv_udp_t* handle) { | void uv__udp_close(uv_udp_t* handle) { | ||
|
@@ -455,6 +459,11 @@ int uv_udp_set_membership(uv_udp_t* handle, | ||
uv_membership membership) { | uv_membership membership) { | ||
struct ip_mreq mreq; | struct ip_mreq mreq; | ||
int optname; | int optname; | ||
struct sockaddr_in6 addr6; | |||
|
|||
if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) { | |||
return uv__udp_set_membership6(handle, multicast_addr, interface_addr, membership); | |||
} | |||
|
|
||
memset(&mreq, 0, sizeof mreq); | memset(&mreq, 0, sizeof mreq); | ||
|
|
||
|
@@ -488,6 +497,73 @@ int uv_udp_set_membership(uv_udp_t* handle, | ||
return 0; | return 0; | ||
} | } | ||
|
|
||
static int uv__udp_set_membership6(uv_udp_t* handle, | |||
const char* multicast_addr, | |||
const char* interface_addr, | |||
uv_membership membership) { | |||
|
|||
int optname; | |||
int interfaces_count; | |||
int i; | |||
struct ipv6_mreq mreq; | |||
struct in6_addr multicast_addr_n; | |||
struct in6_addr interface_addr_n; | |||
uv_interface_address_t* interfaces; | |||
|
|||
memset(&mreq, 0, sizeof mreq); | |||
memset(&multicast_addr_n, 0, sizeof multicast_addr_n); | |||
memset(&interface_addr_n, 0, sizeof interface_addr_n); | |||
|
|||
if (interface_addr != NULL) { | |||
uv_inet_pton(AF_INET6, interface_addr, &interface_addr_n); | |||
if (uv_interface_addresses(&interfaces, &interfaces_count) != 0) | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Style: fold into a single-line statement ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just return |
|||
/*return uv__set_sys_error(handle->loop, UV_EINVAL);*/ | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bad idea :) |
|||
|
|||
for (i = 0; i < interfaces_count; i++) { | |||
if (interfaces[i].address.address6.sin6_family == AF_INET6) { | |||
if (memcmp(&interfaces[i].address.address6.sin6_addr, | |||
&interface_addr_n, | |||
sizeof interface_addr_n) == 0) { | |||
mreq.ipv6mr_interface = interfaces[i].if_index; | |||
break; | |||
} | |||
} | |||
} | |||
|
|||
if (mreq.ipv6mr_interface == 0) { | |||
/*uv__set_artificial_error(handle->loop, UV_EINVAL);*/ | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
|||
} | |||
} | |||
|
|||
if (uv_inet_pton(AF_INET6, multicast_addr, &multicast_addr_n) != 0) { | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And no need in braces if there will be one line There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also in all other places in diff. |
|||
/*uv__set_artificial_error(handle->loop, UV_EINVAL);*/ | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
|||
} | |||
|
|||
mreq.ipv6mr_multiaddr = multicast_addr_n; | |||
|
|||
switch (membership) { | |||
case UV_JOIN_GROUP: | |||
optname = IPV6_ADD_MEMBERSHIP; | |||
break; | |||
case UV_LEAVE_GROUP: | |||
optname = IPV6_DROP_MEMBERSHIP; | |||
break; | |||
default: | |||
/*uv__set_artificial_error(handle->loop, UV_EINVAL);*/ | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably should be an assertion, or UV_ENOTSUP |
|||
} | |||
|
|||
if (setsockopt(handle->io_watcher.fd, IPPROTO_IPV6, optname, &mreq, sizeof mreq) != 0) { | |||
/*uv__set_artificial_error(handle->loop, UV_EINVAL);*/ | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dito |
|||
} | |||
|
|||
return 0; | |||
} | |||
|
|||
|
|
||
static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { | static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { | ||
#if defined(__sun) | #if defined(__sun) | ||
|
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
|
@@ -539,7 +539,7 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, | ||
struct ip_mreq mreq; | struct ip_mreq mreq; | ||
|
|
||
/* If the socket is unbound, bind to inaddr_any. */ | /* If the socket is unbound, bind to inaddr_any. */ | ||
if (!(handle->flags & UV_HANDLE_BOUND)) { | if (!(handle->flags & UV_HANDLE_IPV6) && !(handle->flags & UV_HANDLE_BOUND)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
|||
err = uv_udp_try_bind(handle, | err = uv_udp_try_bind(handle, | ||
(const struct sockaddr*) &uv_addr_ip4_any_, | (const struct sockaddr*) &uv_addr_ip4_any_, | ||
sizeof(uv_addr_ip4_any_), | sizeof(uv_addr_ip4_any_), | ||
|
@@ -549,7 +549,7 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, | ||
} | } | ||
|
|
||
if (handle->flags & UV_HANDLE_IPV6) { | if (handle->flags & UV_HANDLE_IPV6) { | ||
return UV_ENOSYS; | return uv_udp_set_membership6(handle, multicast_addr, interface_addr, membership); | ||
} | } | ||
|
|
||
memset(&mreq, 0, sizeof mreq); | memset(&mreq, 0, sizeof mreq); | ||
|
@@ -570,7 +570,7 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, | ||
optname = IP_DROP_MEMBERSHIP; | optname = IP_DROP_MEMBERSHIP; | ||
break; | break; | ||
default: | default: | ||
return UV_EINVAL; | return UV__EINVAL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? |
|||
} | } | ||
|
|
||
if (setsockopt(handle->socket, | if (setsockopt(handle->socket, | ||
|
@@ -585,6 +585,87 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, | ||
} | } | ||
|
|
||
|
|
||
int uv_udp_set_membership6(uv_udp_t* handle, | |||
const char* multicast_addr, | |||
const char* interface_addr, | |||
uv_membership membership) { | |||
int optname; | |||
int interfaces_count; | |||
int i; | |||
int err; | |||
struct ipv6_mreq mreq; | |||
struct in6_addr multicast_addr_n; | |||
struct in6_addr interface_addr_n; | |||
uv_interface_address_t* interfaces; | |||
|
|||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
|||
if (!(handle->flags & UV_HANDLE_IPV6)) { | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
|||
} | |||
|
|||
if (!(handle->flags & UV_HANDLE_BOUND)) { | |||
err = uv_udp_try_bind(handle, | |||
(const struct sockaddr*) &uv_addr_ip6_any_, | |||
sizeof(uv_addr_ip6_any_), | |||
0); | |||
|
|||
if (err) { | |||
return uv_translate_sys_error(err); | |||
} | |||
} | |||
|
|||
memset(&mreq, 0, sizeof(mreq)); | |||
memset(&multicast_addr_n, 0, sizeof multicast_addr_n); | |||
memset(&interface_addr_n, 0, sizeof interface_addr_n); | |||
|
|||
if (interface_addr != NULL) { | |||
uv_inet_pton(AF_INET6, interface_addr, &interface_addr_n); | |||
if (uv_interface_addresses(&interfaces, &interfaces_count) != 0) { | |||
return uv_translate_sys_error(WSAGetLastError()); | |||
} | |||
|
|||
for (i = 0; i < interfaces_count; i++) { | |||
if (interfaces[i].address.address6.sin6_family == AF_INET6) { | |||
if (memcmp(&interfaces[i].address.address6.sin6_addr, | |||
&interface_addr_n, | |||
sizeof interface_addr_n) == 0) { | |||
mreq.ipv6mr_interface = interfaces[i].if_index; | |||
break; | |||
} | |||
} | |||
} | |||
|
|||
if (mreq.ipv6mr_interface == 0) { | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should return some meaningful error here |
|||
} | |||
} | |||
if (uv_inet_pton(AF_INET6, multicast_addr, &multicast_addr_n) != 0) { | |||
return uv_translate_sys_error(WSAGetLastError()); | |||
} | |||
|
|||
mreq.ipv6mr_multiaddr = multicast_addr_n; | |||
|
|||
switch (membership) { | |||
case UV_JOIN_GROUP: | |||
optname = IPV6_ADD_MEMBERSHIP; | |||
break; | |||
case UV_LEAVE_GROUP: | |||
optname = IPV6_DROP_MEMBERSHIP; | |||
break; | |||
default: | |||
return -1; | |||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And there |
|||
} | |||
|
|||
if (setsockopt(handle->socket, | |||
IPPROTO_IPV6, | |||
optname, | |||
(char*) &mreq, | |||
sizeof mreq) == SOCKET_ERROR) { | |||
return uv_translate_sys_error(WSAGetLastError()); | |||
} | |||
|
|||
return 0; | |||
} | |||
|
|||
int uv_udp_set_broadcast(uv_udp_t* handle, int value) { | int uv_udp_set_broadcast(uv_udp_t* handle, int value) { | ||
BOOL optval = (BOOL) value; | BOOL optval = (BOOL) value; | ||
int err; | int err; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whitespace at the end of the line