]> git.meshlink.io Git - catta/blobdiff - avahi-core/socket.c
fix fedora init script exit code (closes #115) patch from mbacovsk@redhat.com
[catta] / avahi-core / socket.c
index 444be6e5f81e91449b6219b3c57916faf17fa31c..61b5eb4c868021e920be7c8b7039a5e0274fcb75 100644 (file)
@@ -31,6 +31,9 @@
 #include <fcntl.h>
 #include <sys/time.h>
 #include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
 #include <assert.h>
 
 #include <sys/types.h>
@@ -125,8 +128,11 @@ int avahi_mdns_mcast_join_ipv4(int fd, const AvahiIPv4Address *a, int idx, int j
     mdns_mcast_group_ipv4(&sa);
     mreq.imr_multiaddr = sa.sin_addr;
 
+    /* Some network drivers have issues with dropping membership of
+     * mcast groups when the iface is down, but don't allow rejoining
+     * when it comes back up. This is an ugly workaround */
     if (join)
-      setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
+        setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
 
     if (setsockopt(fd, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
         avahi_log_warn("%s failed: %s", join ? "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP", strerror(errno));
@@ -149,6 +155,9 @@ int avahi_mdns_mcast_join_ipv6(int fd, const AvahiIPv6Address *a, int idx, int j
     mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
     mreq6.ipv6mr_interface = idx;
 
+    if (join)
+        setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
+    
     if (setsockopt(fd, IPPROTO_IPV6, join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
         avahi_log_warn("%s failed: %s", join ? "IPV6_ADD_MEMBERSHIP" : "IPV6_DROP_MEMBERSHIP", strerror(errno));
         return -1;
@@ -453,7 +462,14 @@ static int sendmsg_loop(int fd, struct msghdr *msg, int flags) {
     return 0;
 }
 
-int avahi_send_dns_packet_ipv4(int fd, AvahiIfIndex interface, AvahiDnsPacket *p, const AvahiIPv4Address *src_address, const AvahiIPv4Address *dst_address, uint16_t dst_port) {
+int avahi_send_dns_packet_ipv4(
+        int fd,
+        AvahiIfIndex interface,
+        AvahiDnsPacket *p,
+        const AvahiIPv4Address *src_address,
+        const AvahiIPv4Address *dst_address,
+        uint16_t dst_port) {
+    
     struct sockaddr_in sa;
     struct msghdr msg;
     struct iovec io;
@@ -493,7 +509,10 @@ int avahi_send_dns_packet_ipv4(int fd, AvahiIfIndex interface, AvahiDnsPacket *p
         struct in_pktinfo *pkti;
         
         memset(cmsg_data, 0, sizeof(cmsg_data));
-        cmsg = (struct cmsghdr*) cmsg_data;
+        msg.msg_control = cmsg_data;
+        msg.msg_controllen = sizeof(cmsg_data);
+       
+        cmsg = CMSG_FIRSTHDR(&msg);
         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
         cmsg->cmsg_level = IPPROTO_IP;
         cmsg->cmsg_type = IP_PKTINFO;
@@ -506,25 +525,26 @@ int avahi_send_dns_packet_ipv4(int fd, AvahiIfIndex interface, AvahiDnsPacket *p
         if (src_address)
             pkti->ipi_spec_dst.s_addr = src_address->address;
 
-        msg.msg_control = cmsg_data;
-        msg.msg_controllen = sizeof(cmsg_data);
+        msg.msg_controllen = cmsg->cmsg_len;
     }
 #elif defined(IP_SENDSRCADDR)
     if (src_address) {
         struct in_addr *addr;
-      
-       memset(cmsg_data, 0, sizeof(cmsg_data));
-       cmsg = (struct cmsghdr*) cmsg_data;
-       cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+
+        memset(cmsg_data, 0, sizeof(cmsg_data));
+       msg.msg_control = cmsg_data;
+       msg.msg_controllen = sizeof(cmsg_data);
+        
+       cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
        cmsg->cmsg_level = IPPROTO_IP;
        cmsg->cmsg_type = IP_SENDSRCADDR;
        
        addr = (struct in_addr *)CMSG_DATA(cmsg);
        addr->s_addr =  src_address->address;
-       
-       msg.msg_control = cmsg_data;
-       msg.msg_controllen = sizeof(cmsg_data);
-    }
+
+        msg.msg_controllen = cmsg->cmsg_len;
+}
 #elif defined(IP_MULTICAST_IF)
     {
         struct in_addr any = { INADDR_ANY };
@@ -540,7 +560,14 @@ int avahi_send_dns_packet_ipv4(int fd, AvahiIfIndex interface, AvahiDnsPacket *p
     return sendmsg_loop(fd, &msg, 0);
 }
 
-int avahi_send_dns_packet_ipv6(int fd, AvahiIfIndex interface, AvahiDnsPacket *p, const AvahiIPv6Address *src_address, const AvahiIPv6Address *dst_address, uint16_t dst_port) {
+int avahi_send_dns_packet_ipv6(
+        int fd,
+        AvahiIfIndex interface,
+        AvahiDnsPacket *p,
+        const AvahiIPv6Address *src_address,
+        const AvahiIPv6Address *dst_address,
+        uint16_t dst_port) {
+    
     struct sockaddr_in6 sa;
     struct msghdr msg;
     struct iovec io;
@@ -570,9 +597,12 @@ int avahi_send_dns_packet_ipv6(int fd, AvahiIfIndex interface, AvahiDnsPacket *p
 
     if (interface > 0 || src_address) {
         struct in6_pktinfo *pkti;
-    
+
         memset(cmsg_data, 0, sizeof(cmsg_data));
-        cmsg = (struct cmsghdr*) cmsg_data;
+        msg.msg_control = cmsg_data;
+        msg.msg_controllen = sizeof(cmsg_data);
+       
+        cmsg = CMSG_FIRSTHDR(&msg);
         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
         cmsg->cmsg_level = IPPROTO_IPV6;
         cmsg->cmsg_type = IPV6_PKTINFO;
@@ -585,8 +615,7 @@ int avahi_send_dns_packet_ipv6(int fd, AvahiIfIndex interface, AvahiDnsPacket *p
         if (src_address)
             memcpy(&pkti->ipi6_addr, src_address->address, sizeof(src_address->address));
         
-        msg.msg_control = cmsg_data;
-        msg.msg_controllen = sizeof(cmsg_data);
+        msg.msg_controllen = cmsg->cmsg_len;
     } else {
         msg.msg_control = NULL;
         msg.msg_controllen = 0;
@@ -595,7 +624,14 @@ int avahi_send_dns_packet_ipv6(int fd, AvahiIfIndex interface, AvahiDnsPacket *p
     return sendmsg_loop(fd, &msg, 0);
 }
 
-AvahiDnsPacket *avahi_recv_dns_packet_ipv4(int fd, AvahiIPv4Address *ret_src_address, uint16_t *ret_src_port, AvahiIPv4Address *ret_dst_address, AvahiIfIndex *ret_iface, uint8_t *ret_ttl) {
+AvahiDnsPacket *avahi_recv_dns_packet_ipv4(
+        int fd,
+        AvahiIPv4Address *ret_src_address,
+        uint16_t *ret_src_port,
+        AvahiIPv4Address *ret_dst_address,
+        AvahiIfIndex *ret_iface,
+        uint8_t *ret_ttl) {
+    
     AvahiDnsPacket *p= NULL;
     struct msghdr msg;
     struct iovec io;
@@ -613,6 +649,11 @@ AvahiDnsPacket *avahi_recv_dns_packet_ipv4(int fd, AvahiIPv4Address *ret_src_add
         goto fail;
     }
 
+    if (ms < 0) {
+        avahi_log_warn("FIONREAD returned negative value.");
+        goto fail;
+    }
+
     p = avahi_dns_packet_new(ms + AVAHI_DNS_PACKET_EXTRA_SIZE);
 
     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
@@ -628,7 +669,14 @@ AvahiDnsPacket *avahi_recv_dns_packet_ipv4(int fd, AvahiIPv4Address *ret_src_add
     msg.msg_flags = 0;
     
     if ((l = recvmsg(fd, &msg, 0)) < 0) {
-        avahi_log_warn("recvmsg(): %s", strerror(errno));
+        /* Linux returns EAGAIN when an invalid IP packet has been
+        recieved. We suppress warnings in this case because this might
+        create quite a bit of log traffic on machines with unstable
+        links. (See #60) */
+
+        if (errno != EAGAIN)
+            avahi_log_warn("recvmsg(): %s", strerror(errno));
+
         goto fail;
     }
 
@@ -692,7 +740,11 @@ AvahiDnsPacket *avahi_recv_dns_packet_ipv4(int fd, AvahiIPv4Address *ret_src_add
                     struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA (cmsg);
                     
                     if (ret_iface)
+#ifdef __sun
+                        *ret_iface = *(uint_t*) sdl;
+#else
                         *ret_iface = (int) sdl->sdl_index;
+#endif
 
                     break;
                 }
@@ -725,7 +777,14 @@ fail:
     return NULL;
 }
 
-AvahiDnsPacket *avahi_recv_dns_packet_ipv6(int fd, AvahiIPv6Address *ret_src_address, uint16_t *ret_src_port, AvahiIPv6Address *ret_dst_address, AvahiIfIndex *ret_iface, uint8_t *ret_ttl) {
+AvahiDnsPacket *avahi_recv_dns_packet_ipv6(
+        int fd,
+        AvahiIPv6Address *ret_src_address,
+        uint16_t *ret_src_port,
+        AvahiIPv6Address *ret_dst_address,
+        AvahiIfIndex *ret_iface,
+        uint8_t *ret_ttl) {
+    
     AvahiDnsPacket *p = NULL;
     struct msghdr msg;
     struct iovec io;
@@ -742,6 +801,11 @@ AvahiDnsPacket *avahi_recv_dns_packet_ipv6(int fd, AvahiIPv6Address *ret_src_add
         avahi_log_warn("ioctl(): %s", strerror(errno));
         goto fail;
     }
+
+    if (ms < 0) {
+        avahi_log_warn("FIONREAD returned negative value.");
+        goto fail;
+    }
     
     p = avahi_dns_packet_new(ms + AVAHI_DNS_PACKET_EXTRA_SIZE);
 
@@ -759,7 +823,14 @@ AvahiDnsPacket *avahi_recv_dns_packet_ipv6(int fd, AvahiIPv6Address *ret_src_add
     msg.msg_flags = 0;
     
     if ((l = recvmsg(fd, &msg, 0)) < 0) {
-        avahi_log_warn("recvmsg(): %s", strerror(errno));
+        /* Linux returns EAGAIN when an invalid IP packet has been
+        recieved. We suppress warnings in this case because this might
+        create quite a bit of log traffic on machines with unstable
+        links. (See #60) */
+
+        if (errno != EAGAIN)
+            avahi_log_warn("recvmsg(): %s", strerror(errno));
+        
         goto fail;
     }
 
@@ -814,7 +885,7 @@ AvahiDnsPacket *avahi_recv_dns_packet_ipv6(int fd, AvahiIPv6Address *ret_src_add
 
     assert(found_iface);
     assert(found_ttl);
-
+    
     return p;
 
 fail:
@@ -866,13 +937,19 @@ fail:
 
 int avahi_open_unicast_socket_ipv6(void) {
     struct sockaddr_in6 local;
-    int fd = -1;
+    int fd = -1, yes;
         
     if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
         avahi_log_warn("socket() failed: %s", strerror(errno));
         goto fail;
     }
     
+    yes = 1;
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
+        avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
+        goto fail;
+    }
+
     memset(&local, 0, sizeof(local));
     local.sin6_family = AF_INET6;