@@ -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 ;
0 commit comments