Skip to content

Commit b9441de

Browse files
committed
zbeacon: Fix setsockopt IP_MULTICAST_IF parameter type
zbeacon multicast always fails at `setsockopt` for IP_MULTICAST_IF on Linux, because Linux expects the parameter type to be either `ip_mreqn`, `ip_mreq`, or `in_addr` structure instead of interface index. On the other hand, Windows does not support those structures, but instead supports a DWORD of IPv4 address or an interface index. OSX seems to support `in_addr`. Modified the parameter type to be interface index for Windows and `in_addr` for others. Multicast beacons were also received from all multicast groups instead of just the one we join to. This is because the code bound the listening UDP socket to `INADDR_ANY` when using multicast. Modified to bind the listening UDP socket only to the specified multicast address.
1 parent 8329eca commit b9441de

File tree

2 files changed

+35
-35
lines changed

2 files changed

+35
-35
lines changed

src/zbeacon.c

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -273,16 +273,27 @@ s_self_prepare_udp (self_t *self)
273273
inaddr_storage_t bind_address;
274274

275275
// On Windows we bind to the host address
276-
// On *NIX we bind to INADDR_ANY or in6addr_any, otherwise multicast
277-
// packets will be filtered out despite joining the group
276+
// On *NIX we bind to INADDR_ANY or in6addr_any if using broadcast,
277+
// and to the specific multicast address when using IPv4 multicast.
278+
// Binding to INADDR_ANY would make us receive packets from all
279+
// IPv4 multicast groups despite joining only one.
278280
#if (defined (__WINDOWS__))
279281
memcpy (&bind_address, bind_to->ai_addr, bind_to->ai_addrlen);
280282
#else
281283
memcpy (&bind_address, send_to->ai_addr, send_to->ai_addrlen);
282-
if (zsys_ipv6 ())
284+
if (zsys_ipv6 ()) {
283285
bind_address.__inaddr_u.__addr6.sin6_addr = in6addr_any;
284-
else
285-
bind_address.__inaddr_u.__addr.sin_addr.s_addr = htonl (INADDR_ANY);
286+
}
287+
else {
288+
if (enable_multicast) {
289+
if (inet_pton (AF_INET, zsys_ipv4_mcast_address(),
290+
&bind_address.__inaddr_u.__addr.sin_addr) != 1)
291+
zsys_socket_error ("zbeacon: multicast inet_pton failed");
292+
}
293+
else {
294+
bind_address.__inaddr_u.__addr.sin_addr.s_addr = htonl (INADDR_ANY);
295+
}
296+
}
286297
#endif
287298
memcpy (&self->broadcast, send_to->ai_addr, send_to->ai_addrlen);
288299

@@ -323,20 +334,32 @@ s_self_prepare_udp (self_t *self)
323334
zsys_socket_error (
324335
"zbeacon: setsockopt IP_ADD_MEMBERSHIP failed");
325336

337+
if (setsockopt (self->udpsock_send, IPPROTO_IP, IP_ADD_MEMBERSHIP,
338+
(char *) &mreq, sizeof (mreq)))
339+
zsys_socket_error (
340+
"zbeacon: setsockopt IP_ADD_MEMBERSHIP failed");
341+
342+
#if (defined (__WINDOWS__))
326343
if (setsockopt (self->udpsock, IPPROTO_IP, IP_MULTICAST_IF,
327344
(char *) &if_index, sizeof (if_index)))
328345
zsys_socket_error (
329346
"zbeacon: setsockopt IP_MULTICAST_IF failed");
330347

331-
if (setsockopt (self->udpsock_send, IPPROTO_IP, IP_ADD_MEMBERSHIP,
332-
(char *) &mreq, sizeof (mreq)))
348+
if (setsockopt (self->udpsock_send, IPPROTO_IP, IP_MULTICAST_IF,
349+
(char *) &if_index, sizeof (if_index)))
333350
zsys_socket_error (
334-
"zbeacon: setsockopt IP_ADD_MEMBERSHIP failed");
351+
"zbeacon: setsockopt IP_MULTICAST_IF failed");
352+
#else
353+
if (setsockopt (self->udpsock, IPPROTO_IP, IP_MULTICAST_IF,
354+
(char *) &mreq.imr_interface, sizeof (mreq.imr_interface)))
355+
zsys_socket_error (
356+
"zbeacon: setsockopt IP_MULTICAST_IF failed");
335357

336358
if (setsockopt (self->udpsock_send, IPPROTO_IP, IP_MULTICAST_IF,
337-
(char *) &if_index, sizeof (if_index)))
359+
(char *) &mreq.imr_interface, sizeof (mreq.imr_interface)))
338360
zsys_socket_error (
339361
"zbeacon: setsockopt IP_MULTICAST_IF failed");
362+
#endif
340363
}
341364

342365
// If bind fails, we close the socket for opening again later (next poll interval)
@@ -597,29 +620,6 @@ static void zbeacon_ipv4_mcast_test (bool verbose)
597620
// Before starting test configure beacon for ipv4 multicast
598621
zsys_set_ipv4_mcast_address ("239.0.0.0");
599622

600-
// Check that udp multicast is enabled
601-
{
602-
SOCKET sock = zsys_udp_new (true);
603-
if (sock == INVALID_SOCKET) {
604-
// multicast may not be enabled during test so skip!
605-
printf ("SKIPPED - Is IPv4 UDP multicast allowed?\n");
606-
// Unset multicast
607-
zsys_set_ipv4_mcast_address (NULL);
608-
return;
609-
}
610-
unsigned int if_index = 1;
611-
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&if_index,
612-
sizeof(if_index)) != 0){
613-
// multicast may not be enabled during test so skip!
614-
printf ("SKIPPED - Is IPv4 UDP multicast allowed?\n");
615-
zsys_udp_close (sock);
616-
// Unset multicast
617-
zsys_set_ipv4_mcast_address (NULL);
618-
return;
619-
}
620-
zsys_udp_close (sock);
621-
}
622-
623623
// @selftest
624624
// Test 1 - two beacons, one speaking, one listening
625625
// Create speaker beacon to broadcast our service
@@ -631,7 +631,7 @@ static void zbeacon_ipv4_mcast_test (bool verbose)
631631
zsock_send (speaker, "si", "CONFIGURE", 9999);
632632
char *hostname = zstr_recv (speaker);
633633
if (!*hostname) {
634-
printf ("OK (skipping test, no UDP broadcasting)\n");
634+
printf ("SKIPPED - Is IPv4 multicast allowed?\n");
635635
zactor_destroy (&speaker);
636636
freen (hostname);
637637
return;

src/zsys.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,8 +1147,8 @@ zsys_vprintf (const char *format, va_list argptr)
11471147

11481148
// --------------------------------------------------------------------------
11491149
// Create a UDP beacon socket; if the routable option is true, uses
1150-
// multicast (not yet implemented), else uses broadcast. This method
1151-
// and related ones might _eventually_ be moved to a zudp class.
1150+
// multicast for IPv4 (IPv6 multicast not implemented yet), else uses broadcast.
1151+
// This method and related ones might _eventually_ be moved to a zudp class.
11521152

11531153
SOCKET
11541154
zsys_udp_new (bool routable)

0 commit comments

Comments
 (0)