+static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
+
+ g_assert(ret_sa);
+
+ memset(ret_sa, 0, sizeof(struct sockaddr_in6));
+
+ ret_sa->sin6_family = AF_INET6;
+ ret_sa->sin6_port = htons(AVAHI_MDNS_PORT);
+ inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
+}
+
+int avahi_mdns_mcast_join_ipv4 (int index, int fd)
+{
+ struct ip_mreqn mreq;
+ struct sockaddr_in sa;
+
+ mdns_mcast_group_ipv4 (&sa);
+
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr = sa.sin_addr;
+ mreq.imr_ifindex = index;
+
+ if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
+ g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int avahi_mdns_mcast_join_ipv6 (int index, int fd)
+{
+ struct ipv6_mreq mreq6;
+ struct sockaddr_in6 sa6;
+
+ mdns_mcast_group_ipv6 (&sa6);
+
+ memset(&mreq6, 0, sizeof(mreq6));
+ mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
+ mreq6.ipv6mr_interface = index;
+
+ if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
+ g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int avahi_mdns_mcast_leave_ipv4 (int index, int fd)
+{
+ struct ip_mreqn mreq;
+ struct sockaddr_in sa;
+
+ mdns_mcast_group_ipv4 (&sa);
+
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr = sa.sin_addr;
+ mreq.imr_ifindex = index;
+
+ if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
+ g_warning("IP_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int avahi_mdns_mcast_leave_ipv6 (int index, int fd)
+{
+ struct ipv6_mreq mreq6;
+ struct sockaddr_in6 sa6;
+
+ mdns_mcast_group_ipv6 (&sa6);
+
+ memset(&mreq6, 0, sizeof(mreq6));
+ mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
+ mreq6.ipv6mr_interface = index;
+
+ if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
+ g_warning("IPV6_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+gint avahi_open_socket_ipv4(void) {