@@ -900,54 +900,100 @@ os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled)
900900int
901901os_socket_set_ip_multicast_loop (bh_socket_t socket , bool ipv6 , bool is_enabled )
902902{
903- errno = ENOSYS ;
903+ int opt = is_enabled ? 1 : 0 ;
904+ int ret ;
904905
905- return BHT_ERROR ;
906+ #ifdef IPPROTO_IPV6
907+ if (ipv6 ) {
908+ ret = zsock_setsockopt (socket -> fd , IPPROTO_IPV6 ,
909+ IPV6_MULTICAST_LOOP , & opt , sizeof (opt ));
910+ } else
911+ #endif
912+ {
913+ ret = zsock_setsockopt (socket -> fd , IPPROTO_IP ,
914+ IP_MULTICAST_LOOP , & opt , sizeof (opt ));
915+ }
916+
917+ if (ret != 0 ) {
918+ /* Best-effort: some stacks don’t support this; don’t hard-fail */
919+ if (errno == ENOPROTOOPT || errno == ENOSYS ) {
920+ return BHT_OK ;
921+ }
922+ return BHT_ERROR ;
923+ }
924+ return BHT_OK ;
906925}
907926
908927int
909928os_socket_get_ip_multicast_loop (bh_socket_t socket , bool ipv6 , bool * is_enabled )
910929{
911- errno = ENOSYS ;
930+ int opt = 0 ;
931+ socklen_t len = sizeof (opt );
932+ int ret ;
912933
913- return BHT_ERROR ;
934+ #ifdef IPPROTO_IPV6
935+ if (ipv6 ) {
936+ ret = zsock_getsockopt (socket -> fd , IPPROTO_IPV6 ,
937+ IPV6_MULTICAST_LOOP , & opt , & len );
938+ } else
939+ #endif
940+ {
941+ ret = zsock_getsockopt (socket -> fd , IPPROTO_IP ,
942+ IP_MULTICAST_LOOP , & opt , & len );
943+ }
944+
945+ if (ret != 0 ) {
946+ if (errno == ENOPROTOOPT || errno == ENOSYS ) {
947+ /* Report “disabled” if the stack doesn’t expose the knob */
948+ * is_enabled = false;
949+ return BHT_OK ;
950+ }
951+ return BHT_ERROR ;
952+ }
953+
954+ * is_enabled = (opt != 0 );
955+ return BHT_OK ;
914956}
915957
958+
916959int
917960os_socket_set_ip_add_membership (bh_socket_t socket ,
918961 bh_ip_addr_buffer_t * imr_multiaddr ,
919962 uint32_t imr_interface , bool is_ipv6 )
920963{
921964 assert (imr_multiaddr );
922965
923- if (is_ipv6 ) {
924- #if defined(IPPROTO_IPV6 ) && !defined(BH_PLATFORM_COSMOPOLITAN )
925- struct ipv6_mreq mreq ;
966+ int ret = -1 ;
926967
927- for (int i = 0 ; i < 8 ; i ++ ) {
928- ((uint16_t * )mreq .ipv6mr_multiaddr .s6_addr )[i ] =
929- imr_multiaddr -> ipv6 [i ];
930- }
931- mreq .ipv6mr_interface = imr_interface ;
968+ #ifdef IPPROTO_IPV6
969+ if (is_ipv6 ) {
970+ struct ipv6_mreq mreq6 = {0 };
971+ memcpy (& mreq6 .ipv6mr_multiaddr ,
972+ & imr_multiaddr -> ipv6 [0 ], sizeof (mreq6 .ipv6mr_multiaddr ));
973+ mreq6 .ipv6mr_interface = imr_interface ; /* 0 ⇒ first suitable iface */
932974
933- if (zsock_setsockopt (socket -> fd , IPPROTO_IPV6 , IPV6_ADD_MEMBERSHIP , & mreq ,
934- sizeof (mreq ))
935- != 0 ) {
936- return BHT_ERROR ;
937- }
938- #else
939- errno = EAFNOSUPPORT ;
940- return BHT_ERROR ;
975+ ret = zsock_setsockopt (socket -> fd , IPPROTO_IPV6 ,
976+ IPV6_ADD_MEMBERSHIP , & mreq6 , sizeof (mreq6 ));
977+ } else
941978#endif
942- }
943- else {
944- struct ip_mreqn mreq ;
979+ {
980+ struct ip_mreqn mreq = {0 };
945981 mreq .imr_multiaddr .s_addr = imr_multiaddr -> ipv4 ;
946- mreq .imr_address .s_addr = imr_interface ;
982+ mreq .imr_address .s_addr = imr_interface ; /* 0 ⇒ first suitable iface */
983+ /* mreq.imr_ifindex is optional; leave 0 unless you have an index */
984+
985+ ret = zsock_setsockopt (socket -> fd , IPPROTO_IP ,
986+ IP_ADD_MEMBERSHIP , & mreq , sizeof (mreq ));
987+ }
947988
948- if (zsock_setsockopt (socket -> fd , IPPROTO_IP , IP_ADD_MEMBERSHIP , & mreq ,
949- sizeof (mreq ))
950- != 0 ) {
989+ if (ret != 0 ) {
990+ switch (errno ) {
991+ case EALREADY : /* already joined: OK */
992+ case EADDRINUSE : /* duplicate membership: OK */
993+ case ENOPROTOOPT : /* option not supported: treat as soft-OK */
994+ case ENOSYS : /* not implemented: soft-OK */
995+ return BHT_OK ;
996+ default :
951997 return BHT_ERROR ;
952998 }
953999 }
@@ -961,34 +1007,36 @@ os_socket_set_ip_drop_membership(bh_socket_t socket,
9611007{
9621008 assert (imr_multiaddr );
9631009
964- if (is_ipv6 ) {
965- #if defined(IPPROTO_IPV6 ) && !defined(BH_PLATFORM_COSMOPOLITAN )
966- struct ipv6_mreq mreq ;
1010+ int ret = -1 ;
9671011
968- for (int i = 0 ; i < 8 ; i ++ ) {
969- ((uint16_t * )mreq .ipv6mr_multiaddr .s6_addr )[i ] =
970- imr_multiaddr -> ipv6 [i ];
971- }
972- mreq .ipv6mr_interface = imr_interface ;
1012+ #ifdef IPPROTO_IPV6
1013+ if (is_ipv6 ) {
1014+ struct ipv6_mreq mreq6 = {0 };
1015+ memcpy (& mreq6 .ipv6mr_multiaddr ,
1016+ & imr_multiaddr -> ipv6 [0 ], sizeof (mreq6 .ipv6mr_multiaddr ));
1017+ mreq6 .ipv6mr_interface = imr_interface ;
9731018
974- if (zsock_setsockopt (socket -> fd , IPPROTO_IPV6 , IPV6_DROP_MEMBERSHIP ,
975- & mreq , sizeof (mreq ))
976- != 0 ) {
977- return BHT_ERROR ;
978- }
979- #else
980- errno = EAFNOSUPPORT ;
981- return BHT_ERROR ;
1019+ ret = zsock_setsockopt (socket -> fd , IPPROTO_IPV6 ,
1020+ IPV6_DROP_MEMBERSHIP , & mreq6 , sizeof (mreq6 ));
1021+ } else
9821022#endif
983- }
984- else {
985- struct ip_mreqn mreq ;
1023+ {
1024+ struct ip_mreqn mreq = {0 };
9861025 mreq .imr_multiaddr .s_addr = imr_multiaddr -> ipv4 ;
987- mreq .imr_address .s_addr = imr_interface ;
1026+ mreq .imr_address .s_addr = imr_interface ;
9881027
989- if (zsock_setsockopt (socket -> fd , IPPROTO_IP , IP_DROP_MEMBERSHIP , & mreq ,
990- sizeof (mreq ))
991- != 0 ) {
1028+ ret = zsock_setsockopt (socket -> fd , IPPROTO_IP ,
1029+ IP_DROP_MEMBERSHIP , & mreq , sizeof (mreq ));
1030+ }
1031+
1032+ if (ret != 0 ) {
1033+ switch (errno ) {
1034+ case ENOENT : /* not a member: OK */
1035+ case EINVAL : /* some stacks use this for “not joined” */
1036+ case ENOPROTOOPT :
1037+ case ENOSYS :
1038+ return BHT_OK ;
1039+ default :
9921040 return BHT_ERROR ;
9931041 }
9941042 }
0 commit comments