]> git.meshlink.io Git - catta/commitdiff
rework and cleanup socket handling to improve support for OS that don't support a...
authorLennart Poettering <lennart@poettering.net>
Thu, 3 Nov 2005 00:28:24 +0000 (00:28 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 3 Nov 2005 00:28:24 +0000 (00:28 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@923 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

avahi-core/iface.c
avahi-core/iface.h
avahi-core/server.c
avahi-core/socket.c
avahi-core/socket.h
avahi-core/wide-area.c

index 6fc66d315584df307dee7b19a7ca8bdb106e55d3..d117b9bd79fe1e2b65722c3628d2bb1efa271ba9 100644 (file)
@@ -27,7 +27,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-
+#include <netinet/in.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 
@@ -571,9 +571,9 @@ void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, c
 /*         avahi_log_debug("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */
     
     if (i->protocol == AVAHI_PROTO_INET && i->monitor->server->fd_ipv4 >= 0)
-        avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port);
+        avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, i->mcast_joined ? &i->local_mcast_address.data.ipv4 : NULL, a ? &a->data.ipv4 : NULL, port);
     else if (i->protocol == AVAHI_PROTO_INET6 && i->monitor->server->fd_ipv6 >= 0)
-        avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, a ? &a->data.ipv6 : NULL, port);
+        avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, i->mcast_joined ? &i->local_mcast_address.data.ipv6 : NULL, a ? &a->data.ipv6 : NULL, port);
 }
 
 void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
@@ -793,3 +793,27 @@ int avahi_interface_has_address(AvahiInterfaceMonitor *m, AvahiIfIndex iface, co
 
     return 0;
 }
+
+AvahiIfIndex avahi_find_interface_for_address(AvahiInterfaceMonitor *m, const AvahiAddress *a) {
+    AvahiInterface *i;
+    assert(m);
+
+    /* Some stupid OS don't support passing the interface index when a
+     * packet is recieved. We have to work around that limitation by
+     * looking for an interface that has the incoming address
+     * attached. This is sometimes ambiguous, but we have to live with
+     * it. */
+
+    for (i = m->interfaces; i; i = i->interface_next) {
+        AvahiInterfaceAddress *ai;
+
+        if (i->protocol != a->proto)
+            continue;
+        
+        for (ai = i->addresses; ai; ai = ai->address_next)
+            if (avahi_address_cmp(a, &ai->address) == 0)
+                return i->hardware->index;
+    }
+
+    return AVAHI_IF_UNSPEC;
+}
index e7c2298aca8576870065e1b805f0c4c0f5d04ebb..30d3d229d122d70bc82a7cc1322d8ab88076beb4 100644 (file)
@@ -186,4 +186,6 @@ int avahi_interface_address_is_relevant(AvahiInterfaceAddress *a);
 
 AvahiInterfaceAddress* avahi_interface_monitor_get_address(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *raddr);
 
+AvahiIfIndex avahi_find_interface_for_address(AvahiInterfaceMonitor *m, const AvahiAddress *a);
+
 #endif
index 3ec14a8f8a06b170c8d910ae88c26c1142566287..be246f9a72b4d4a8165e68d29d8b8185525d1694 100644 (file)
@@ -798,7 +798,7 @@ static void reflect_legacy_unicast_query_packet(AvahiServer *s, AvahiDnsPacket *
     avahi_elapse_time(&slot->elapse_time, 2000, 0);
     slot->time_event = avahi_time_event_new(s->time_event_queue, &slot->elapse_time, legacy_unicast_reflect_slot_timeout, slot);
 
-    /* Patch the packet with our new locally generatedt id */
+    /* Patch the packet with our new locally generatet id */
     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ID, slot->id);
     
     for (j = s->monitor->interfaces; j; j = j->interface_next)
@@ -807,47 +807,45 @@ static void reflect_legacy_unicast_query_packet(AvahiServer *s, AvahiDnsPacket *
             (s->config.reflect_ipv || j->protocol == i->protocol)) {
 
             if (j->protocol == AVAHI_PROTO_INET && s->fd_legacy_unicast_ipv4 >= 0) {
-                avahi_send_dns_packet_ipv4(s->fd_legacy_unicast_ipv4, j->hardware->index, p, NULL, 0);
-                } else if (j->protocol == AVAHI_PROTO_INET6 && s->fd_legacy_unicast_ipv6 >= 0)
-                avahi_send_dns_packet_ipv6(s->fd_legacy_unicast_ipv6, j->hardware->index, p, NULL, 0);
+                avahi_send_dns_packet_ipv4(s->fd_legacy_unicast_ipv4, j->hardware->index, p, NULL, NULL, 0);
+            } else if (j->protocol == AVAHI_PROTO_INET6 && s->fd_legacy_unicast_ipv6 >= 0)
+                avahi_send_dns_packet_ipv6(s->fd_legacy_unicast_ipv6, j->hardware->index, p, NULL, NULL, 0);
         }
 
     /* Reset the id */
     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ID, slot->original_id);
 }
 
-static int originates_from_local_legacy_unicast_socket(AvahiServer *s, const struct sockaddr *sa) {
-    AvahiAddress a;
+static int originates_from_local_legacy_unicast_socket(AvahiServer *s, const AvahiAddress *address, uint16_t port) {
     assert(s);
-    assert(sa);
+    assert(address);
+    assert(port > 0);
 
     if (!s->config.enable_reflector)
         return 0;
     
-    avahi_address_from_sockaddr(sa, &a);
-
-    if (!avahi_address_is_local(s->monitor, &a))
+    if (!avahi_address_is_local(s->monitor, address))
         return 0;
     
-    if (sa->sa_family == AF_INET && s->fd_legacy_unicast_ipv4 >= 0) {
+    if (address->proto == AVAHI_PROTO_INET && s->fd_legacy_unicast_ipv4 >= 0) {
         struct sockaddr_in lsa;
         socklen_t l = sizeof(lsa);
         
         if (getsockname(s->fd_legacy_unicast_ipv4, (struct sockaddr*) &lsa, &l) != 0)
             avahi_log_warn("getsockname(): %s", strerror(errno));
         else
-            return lsa.sin_port == ((const struct sockaddr_in*) sa)->sin_port;
+            return lsa.sin_port == port;
 
     }
 
-    if (sa->sa_family == AF_INET6 && s->fd_legacy_unicast_ipv6 >= 0) {
+    if (address->proto == AVAHI_PROTO_INET6 && s->fd_legacy_unicast_ipv6 >= 0) {
         struct sockaddr_in6 lsa;
         socklen_t l = sizeof(lsa);
 
         if (getsockname(s->fd_legacy_unicast_ipv6, (struct sockaddr*) &lsa, &l) != 0)
             avahi_log_warn("getsockname(): %s", strerror(errno));
         else
-            return lsa.sin6_port == ((const struct sockaddr_in6*) sa)->sin6_port;
+            return lsa.sin6_port == port;
     }
 
     return 0;
@@ -873,19 +871,18 @@ static int originates_from_local_iface(AvahiServer *s, AvahiIfIndex iface, const
     return avahi_interface_has_address(s->monitor, iface, a);
 }
 
-static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sockaddr *sa, AvahiAddress *dest, AvahiIfIndex iface, int ttl) {
+static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const AvahiAddress *src_address, uint16_t port, const AvahiAddress *dst_address, AvahiIfIndex iface, int ttl) {
     AvahiInterface *i;
-    AvahiAddress a;
-    uint16_t port;
     int from_local_iface = 0;
     
     assert(s);
     assert(p);
-    assert(sa);
-    assert(dest);
+    assert(src_address);
+    assert(dst_address);
     assert(iface > 0);
+    assert(src_address->proto == dst_address->proto);
 
-    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, avahi_af_to_proto(sa->sa_family))) ||
+    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, src_address->proto)) ||
         !avahi_interface_is_relevant(i)) {
         avahi_log_warn("Recieved packet from invalid interface.");
         return;
@@ -893,20 +890,17 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sock
 
 /*     avahi_log_debug("new packet received on interface '%s.%i'.", i->hardware->name, i->protocol); */
 
-    port = avahi_port_from_sockaddr(sa);
-    avahi_address_from_sockaddr(sa, &a);
-    
-    if (avahi_address_is_ipv4_in_ipv6(&a))
+    if (avahi_address_is_ipv4_in_ipv6(src_address))
         /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
         return;
 
-    if (originates_from_local_legacy_unicast_socket(s, sa))
+    if (originates_from_local_legacy_unicast_socket(s, src_address, port))
         /* This originates from our local reflector, so let's ignore it */
         return;
 
     /* We don't want to reflect local traffic, so we check if this packet is generated locally. */
     if (s->config.enable_reflector)
-        from_local_iface = originates_from_local_iface(s, iface, &a, port);
+        from_local_iface = originates_from_local_iface(s, iface, src_address, port);
 
     if (avahi_dns_packet_check_valid_multicast(p) < 0) {
         avahi_log_warn("Recieved invalid packet.");
@@ -934,9 +928,9 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sock
         }
 
         if (legacy_unicast)
-            reflect_legacy_unicast_query_packet(s, p, i, &a, port);
+            reflect_legacy_unicast_query_packet(s, p, i, src_address, port);
         
-        handle_query_packet(s, p, i, &a, port, legacy_unicast, from_local_iface);
+        handle_query_packet(s, p, i, src_address, port, legacy_unicast, from_local_iface);
         
 /*         avahi_log_debug("Handled query"); */
     } else {
@@ -950,8 +944,8 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sock
             return;
         }
 
-        if (!is_mdns_mcast_address(dest) &&
-            !avahi_interface_address_on_link(i, &a)) {
+        if (!is_mdns_mcast_address(dst_address) &&
+            !avahi_interface_address_on_link(i, src_address)) {
             avahi_log_warn("Received non-local response on interface '%s.%i'.", i->hardware->name, i->protocol);
             return;
         }
@@ -963,34 +957,17 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sock
             return;
         }
 
-        handle_response_packet(s, p, i, &a, from_local_iface);
+        handle_response_packet(s, p, i, src_address, from_local_iface);
 /*         avahi_log_debug("Handled response"); */
     }
 }
 
-static void dispatch_legacy_unicast_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sockaddr *sa, AvahiIfIndex iface) {
-    AvahiInterface *i, *j;
-    AvahiAddress a;
+static void dispatch_legacy_unicast_packet(AvahiServer *s, AvahiDnsPacket *p) {
+    AvahiInterface *j;
     AvahiLegacyUnicastReflectSlot *slot;
     
     assert(s);
     assert(p);
-    assert(sa);
-    assert(iface > 0);
-
-    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, avahi_af_to_proto(sa->sa_family))) ||
-        !avahi_interface_is_relevant(i)) {
-        avahi_log_warn("Recieved packet from invalid interface.");
-        return;
-    }
-
-/*     avahi_log_debug("new legacy unicast packet received on interface '%s.%i'.", i->hardware->name, i->protocol); */
-
-    avahi_address_from_sockaddr(sa, &a);
-    
-    if (avahi_address_is_ipv4_in_ipv6(&a))
-        /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
-        return;
 
     if (avahi_dns_packet_check_valid(p) < 0 || avahi_dns_packet_is_query(p)) {
         avahi_log_warn("Recieved invalid packet.");
@@ -1023,52 +1000,63 @@ static void cleanup_dead(AvahiServer *s) {
     avahi_browser_cleanup(s);
 }
 
-static void socket_event(AvahiWatch *w, int fd, AvahiWatchEvent events, void *userdata) {
+static void mcast_socket_event(AvahiWatch *w, int fd, AvahiWatchEvent events, void *userdata) {
     AvahiServer *s = userdata;
-    AvahiAddress dest;
-    AvahiDnsPacket *p;
+    AvahiAddress dest, src;
+    AvahiDnsPacket *p = NULL;
     AvahiIfIndex iface;
+    uint16_t port;
     uint8_t ttl;
-    struct sockaddr_in sa;
-    struct sockaddr_in6 sa6;
 
     assert(w);
     assert(fd >= 0);
+    assert(events & AVAHI_WATCH_IN);
+    
+    if (fd == s->fd_ipv4) {
+        dest.proto = src.proto = AVAHI_PROTO_INET;
+        p = avahi_recv_dns_packet_ipv4(s->fd_ipv4, &src.data.ipv4, &port, &dest.data.ipv4, &iface, &ttl);
+    } else {
+        assert(fd == s->fd_ipv6);
+        dest.proto = src.proto = AVAHI_PROTO_INET6;
+        p = avahi_recv_dns_packet_ipv6(s->fd_ipv6, &src.data.ipv6, &port, &dest.data.ipv6, &iface, &ttl);
+    }
+        
+    if (p) {
+        if (iface == AVAHI_IF_UNSPEC) 
+            iface = avahi_find_interface_for_address(s->monitor, &dest);
+        
+        if (iface != AVAHI_IF_UNSPEC)
+            dispatch_packet(s, p, &src, port, &dest, iface, ttl);
+        else
+            avahi_log_error("Incoming packet recieved on address that isn't local.");
 
-    if (events & AVAHI_WATCH_IN) {
+        avahi_dns_packet_free(p);
+
+        cleanup_dead(s);
+    }
+}
+
+static void legacy_unicast_socket_event(AvahiWatch *w, int fd, AvahiWatchEvent events, void *userdata) {
+    AvahiServer *s = userdata;
+    AvahiDnsPacket *p = NULL;
+
+    assert(w);
+    assert(fd >= 0);
+    assert(events & AVAHI_WATCH_IN);
     
-        if (fd == s->fd_ipv4) {
-            dest.proto = AVAHI_PROTO_INET;
-            if ((p = avahi_recv_dns_packet_ipv4(s->fd_ipv4, &sa, &dest.data.ipv4, &iface, &ttl))) {
-                dispatch_packet(s, p, (struct sockaddr*) &sa, &dest, iface, ttl);
-                avahi_dns_packet_free(p);
-            }
-        } else if (fd == s->fd_ipv6) {
-            dest.proto = AVAHI_PROTO_INET6;
+    if (fd == s->fd_legacy_unicast_ipv4)
+        p = avahi_recv_dns_packet_ipv4(s->fd_legacy_unicast_ipv4, NULL, NULL, NULL, NULL, NULL);
+    else {
+        assert(fd == s->fd_legacy_unicast_ipv6);
+        p = avahi_recv_dns_packet_ipv6(s->fd_legacy_unicast_ipv6, NULL, NULL, NULL, NULL, NULL);
+    }
 
-            if ((p = avahi_recv_dns_packet_ipv6(s->fd_ipv6, &sa6, &dest.data.ipv6, &iface, &ttl))) {
-                dispatch_packet(s, p, (struct sockaddr*) &sa6, &dest, iface, ttl);
-                avahi_dns_packet_free(p);
-            }
-        } else if (fd == s->fd_legacy_unicast_ipv4) {
-            dest.proto = AVAHI_PROTO_INET;
-            
-            if ((p = avahi_recv_dns_packet_ipv4(s->fd_legacy_unicast_ipv4, &sa, &dest.data.ipv4, &iface, &ttl))) {
-                dispatch_legacy_unicast_packet(s, p, (struct sockaddr*) &sa, iface);
-                avahi_dns_packet_free(p);
-            }
-        } else if (fd == s->fd_legacy_unicast_ipv6) {
-            dest.proto = AVAHI_PROTO_INET6;
-            
-            if ((p = avahi_recv_dns_packet_ipv6(s->fd_legacy_unicast_ipv6, &sa6, &dest.data.ipv6, &iface, &ttl))) {
-                dispatch_legacy_unicast_packet(s, p, (struct sockaddr*) &sa6, iface);
-                avahi_dns_packet_free(p);
-            }
-        }
+    if (p) {
+        dispatch_legacy_unicast_packet(s, p);
+        avahi_dns_packet_free(p);
 
         cleanup_dead(s);
-    } else
-        abort();
+    }
 }
 
 static void server_set_state(AvahiServer *s, AvahiServerState state) {
@@ -1297,14 +1285,14 @@ static int setup_sockets(AvahiServer *s) {
         s->watch_legacy_unicast_ipv6 = NULL;
     
     if (s->fd_ipv4 >= 0)
-        s->watch_ipv4 = s->poll_api->watch_new(s->poll_api, s->fd_ipv4, AVAHI_WATCH_IN, socket_event, s);
+        s->watch_ipv4 = s->poll_api->watch_new(s->poll_api, s->fd_ipv4, AVAHI_WATCH_IN, mcast_socket_event, s);
     if (s->fd_ipv6 >= 0)
-        s->watch_ipv6 = s->poll_api->watch_new(s->poll_api, s->fd_ipv6, AVAHI_WATCH_IN, socket_event, s);
+        s->watch_ipv6 = s->poll_api->watch_new(s->poll_api, s->fd_ipv6, AVAHI_WATCH_IN, mcast_socket_event, s);
     
     if (s->fd_legacy_unicast_ipv4 >= 0)
-        s->watch_legacy_unicast_ipv4 = s->poll_api->watch_new(s->poll_api, s->fd_legacy_unicast_ipv4, AVAHI_WATCH_IN, socket_event, s);
+        s->watch_legacy_unicast_ipv4 = s->poll_api->watch_new(s->poll_api, s->fd_legacy_unicast_ipv4, AVAHI_WATCH_IN, legacy_unicast_socket_event, s);
     if (s->fd_legacy_unicast_ipv6 >= 0)
-        s->watch_legacy_unicast_ipv6 = s->poll_api->watch_new(s->poll_api, s->fd_legacy_unicast_ipv6, AVAHI_WATCH_IN, socket_event, s);
+        s->watch_legacy_unicast_ipv6 = s->poll_api->watch_new(s->poll_api, s->fd_legacy_unicast_ipv6, AVAHI_WATCH_IN, legacy_unicast_socket_event, s);
             
     return 0;
 }
index 728bea5252268cf1e60238b57932470042273c38..8ec3a312c9ab50bb6395da118dfae06252bf931a 100644 (file)
@@ -48,6 +48,7 @@
 #include "fdutil.h"
 #include "socket.h"
 #include "log.h"
+#include "addr-util.h"
 
 /* this is a portability hack */
 #ifndef IPV6_ADD_MEMBERSHIP
@@ -449,24 +450,24 @@ static int sendmsg_loop(int fd, struct msghdr *msg, int flags) {
     return 0;
 }
 
-int avahi_send_dns_packet_ipv4(int fd, int interface, AvahiDnsPacket *p, const AvahiIPv4Address *a, uint16_t 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;
 #ifdef IP_PKTINFO
     struct cmsghdr *cmsg;
-    uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
+    uint8_t cmsg_data[CMSG_SPACE(sizeof(struct in_pktinfo))];
 #endif
 
     assert(fd >= 0);
     assert(p);
     assert(avahi_dns_packet_check_valid(p) >= 0);
-    assert(!a || port > 0);
+    assert(!dst_address || dst_port > 0);
 
-    if (!a)
+    if (!dst_address)
         mdns_mcast_group_ipv4(&sa);
     else
-        ipv4_address_to_sockaddr(&sa, a, port);
+        ipv4_address_to_sockaddr(&sa, dst_address, dst_port);
 
     memset(&io, 0, sizeof(io));
     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
@@ -482,51 +483,56 @@ int avahi_send_dns_packet_ipv4(int fd, int interface, AvahiDnsPacket *p, const A
     msg.msg_controllen = 0;
 
 #ifdef IP_PKTINFO
-    if (interface >= 0) {
+    if (interface > 0 || src_address) {
         struct in_pktinfo *pkti;
         
         memset(cmsg_data, 0, sizeof(cmsg_data));
         cmsg = (struct cmsghdr*) cmsg_data;
-        cmsg->cmsg_len = sizeof(cmsg_data);
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
         cmsg->cmsg_level = IPPROTO_IP;
         cmsg->cmsg_type = IP_PKTINFO;
 
-        pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
-        pkti->ipi_ifindex = interface;
+        pkti = (struct in_pktinfo*) CMSG_DATA(cmsg);
+
+        if (interface > 0) 
+            pkti->ipi_ifindex = interface;
+
+        if (src_address)
+            pkti->ipi_spec_dst.s_addr = src_address->address;
 
         msg.msg_control = cmsg_data;
         msg.msg_controllen = sizeof(cmsg_data);
     }
 #else
 #ifdef __GNUC__
-#warning "FIXME: We need some code to set the outgoing interface here if IP_PKTINFO is not available"
+#warning "FIXME: We need some code to set the outgoing interface/local address here if IP_PKTINFO is not available"
 #endif
 #endif
     
     return sendmsg_loop(fd, &msg, 0);
 }
 
-int avahi_send_dns_packet_ipv6(int fd, int interface, AvahiDnsPacket *p, const AvahiIPv6Address *a, uint16_t 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;
     struct cmsghdr *cmsg;
-    uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
+    uint8_t cmsg_data[CMSG_SPACE(sizeof(struct in6_pktinfo))];
 
     assert(fd >= 0);
     assert(p);
     assert(avahi_dns_packet_check_valid(p) >= 0);
+    assert(!dst_address || dst_port > 0);
 
-    if (!a)
+    if (!dst_address)
         mdns_mcast_group_ipv6(&sa);
     else
-        ipv6_address_to_sockaddr(&sa, a, port);
+        ipv6_address_to_sockaddr(&sa, dst_address, dst_port);
 
     memset(&io, 0, sizeof(io));
     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
     io.iov_len = p->size;
 
-    
     memset(&msg, 0, sizeof(msg));
     msg.msg_name = &sa;
     msg.msg_namelen = sizeof(sa);
@@ -534,17 +540,22 @@ int avahi_send_dns_packet_ipv6(int fd, int interface, AvahiDnsPacket *p, const A
     msg.msg_iovlen = 1;
     msg.msg_flags = 0;
 
-    if (interface >= 0) {
+    if (interface > 0 || src_address) {
         struct in6_pktinfo *pkti;
     
         memset(cmsg_data, 0, sizeof(cmsg_data));
         cmsg = (struct cmsghdr*) cmsg_data;
-        cmsg->cmsg_len = sizeof(cmsg_data);
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
         cmsg->cmsg_level = IPPROTO_IPV6;
         cmsg->cmsg_type = IPV6_PKTINFO;
         
-        pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
-        pkti->ipi6_ifindex = interface;
+        pkti = (struct in6_pktinfo*) CMSG_DATA(cmsg);
+
+        if (interface > 0)
+            pkti->ipi6_ifindex = interface;
+
+        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);
@@ -556,15 +567,16 @@ int avahi_send_dns_packet_ipv6(int fd, int interface, AvahiDnsPacket *p, const A
     return sendmsg_loop(fd, &msg, 0);
 }
 
-AvahiDnsPacket* avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in *ret_sa, AvahiIPv4Address *ret_dest_address, int *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;
     uint8_t aux[1024];
     ssize_t l;
     struct cmsghdr *cmsg;
-    int found_iface = 0, found_addr = 0;
+    int found_addr = 0;
     int ms;
+    struct sockaddr_in sa;
 
     assert(fd >= 0);
 
@@ -579,13 +591,8 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in *ret_sa, A
     io.iov_len = p->max_size;
     
     memset(&msg, 0, sizeof(msg));
-    if (ret_sa) {
-        msg.msg_name = ret_sa;
-        msg.msg_namelen = sizeof(struct sockaddr_in);
-    } else {
-        msg.msg_name = NULL;
-        msg.msg_namelen = 0;
-    }
+    msg.msg_name = &sa;
+    msg.msg_namelen = sizeof(sa);
     msg.msg_iov = &io;
     msg.msg_iovlen = 1;
     msg.msg_control = aux;
@@ -597,23 +604,35 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in *ret_sa, A
         goto fail;
     }
 
-    if (ret_sa && ret_sa->sin_addr.s_addr == INADDR_ANY) {
+    if (sa.sin_addr.s_addr == INADDR_ANY) {
         /* Linux 2.4 behaves very strangely sometimes! */
-
-        /*avahi_hexdump(AVAHI_DNS_PACKET_DATA(p), l); */
         goto fail;
     }
-    
+
     assert(!(msg.msg_flags & MSG_CTRUNC));
     assert(!(msg.msg_flags & MSG_TRUNC));
+
     p->size = (size_t) l;
 
+    if (ret_src_port)
+        *ret_src_port = avahi_port_from_sockaddr((struct sockaddr*) &sa);
+
+    if (ret_src_address) {
+        AvahiAddress a;
+        avahi_address_from_sockaddr((struct sockaddr*) &sa, &a);
+        *ret_src_address = a.data.ipv4;
+    }
+
     if (ret_ttl)
         *ret_ttl = 255;
+
+    if (ret_iface)
+        *ret_iface = AVAHI_IF_UNSPEC;
     
     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
         
         if (cmsg->cmsg_level == IPPROTO_IP) {
+            
             switch (cmsg->cmsg_type) {
 #ifdef IP_RECVTTL
                 case IP_RECVTTL:
@@ -631,21 +650,22 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in *ret_sa, A
                     if (ret_iface)
                         *ret_iface = (int) i->ipi_ifindex;
                     
-                    if (ret_dest_address)
-                        ret_dest_address->address = i->ipi_addr.s_addr;
+                    if (ret_dst_address)
+                        ret_dst_address->address = i->ipi_addr.s_addr;
                     
-                    found_addr = found_iface = 1;
+                    found_addr = 1;
 
                     break;
                 }
-#elif defined(IP_RECVIF)
+#endif
+                    
+#ifdef IP_RECVIF
                 case IP_RECVIF: {
                     struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA (cmsg);
                     
                     if (ret_iface)
                         *ret_iface = (int) sdl->sdl_index;
-                    
-                    found_iface = 1;
+
                     break;
                 }
 #endif
@@ -654,9 +674,9 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in *ret_sa, A
                 case IP_RECVDSTADDR:
                     if (ret_dest_address)
                         memcpy(&ret_dest_address->address, CMSG_DATA (cmsg), 4);
+                    
                     found_addr = 1;
                     break;
-                    
 #endif
                     
                 default:
@@ -666,7 +686,6 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in *ret_sa, A
         }
     }
 
-    assert(found_iface);
     assert(found_addr);
 
     return p;
@@ -678,7 +697,7 @@ fail:
     return NULL;
 }
 
-AvahiDnsPacket* avahi_recv_dns_packet_ipv6(int fd, struct sockaddr_in6 *ret_sa, AvahiIPv6Address *ret_dest_address, int *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;
@@ -687,6 +706,7 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv6(int fd, struct sockaddr_in6 *ret_sa,
     int ms;
     struct cmsghdr *cmsg;
     int found_ttl = 0, found_iface = 0;
+    struct sockaddr_in6 sa;
 
     assert(fd >= 0);
 
@@ -701,13 +721,8 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv6(int fd, struct sockaddr_in6 *ret_sa,
     io.iov_len = p->max_size;
     
     memset(&msg, 0, sizeof(msg));
-    if (ret_sa) {
-        msg.msg_name = ret_sa;
-        msg.msg_namelen = sizeof(struct sockaddr_in6);
-    } else {
-        msg.msg_name = NULL;
-        msg.msg_namelen = 0;
-    }
+    msg.msg_name = (struct sockaddr*) &sa;
+    msg.msg_namelen = sizeof(sa);
     
     msg.msg_iov = &io;
     msg.msg_iovlen = 1;
@@ -720,30 +735,52 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv6(int fd, struct sockaddr_in6 *ret_sa,
         goto fail;
     }
 
+    assert(!(msg.msg_flags & MSG_CTRUNC));
+    assert(!(msg.msg_flags & MSG_TRUNC));
     p->size = (size_t) l;
 
-    if (ret_ttl)
-        *ret_ttl = 0;
+    if (ret_src_port)
+        *ret_src_port = avahi_port_from_sockaddr((struct sockaddr*) &sa);
+
+    if (ret_src_address) {
+        AvahiAddress a;
+        avahi_address_from_sockaddr((struct sockaddr*) &sa, &a);
+        *ret_src_address = a.data.ipv6;
+    }
 
     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-        if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
 
-            if (ret_ttl)
-                *ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));
-            
-            found_ttl = 1;
-        }
-            
-        if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
-            struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
+        if (cmsg->cmsg_level == IPPROTO_IPV6) {
+
+            switch (cmsg->cmsg_type) {
 
-            if (ret_iface)
-                *ret_iface = i->ipi6_ifindex;
+                case IPV6_HOPLIMIT:
 
-            if (ret_dest_address)
-                memcpy(ret_dest_address->address, i->ipi6_addr.s6_addr, 16);
-            
-            found_iface = 1;
+                    if (ret_ttl)
+                        *ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));
+
+                    found_ttl = 1;
+                    
+                    break;
+
+                case IPV6_PKTINFO: {
+                    struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
+                    
+                    if (ret_iface)
+                        *ret_iface = i->ipi6_ifindex;
+                    
+                    if (ret_dst_address)
+                        memcpy(ret_dst_address->address, i->ipi6_addr.s6_addr, 16);
+
+                    found_iface = 1;
+                    break;
+                }
+                    
+                default:
+                    avahi_log_warn("Unhandled cmsg_type : %d", cmsg->cmsg_type);
+                    break;
+            }
         }
     }
 
index 57f9153f465c062542c132e3f79d17597e44e471..237b5346972d22608c6ff7190953319aba42069c 100644 (file)
@@ -22,7 +22,6 @@
   USA.
 ***/
 
-#include <netinet/in.h>
 #include <inttypes.h>
 
 #include "dns.h"
@@ -38,13 +37,13 @@ int avahi_open_socket_ipv6(int no_reuse);
 int avahi_open_unicast_socket_ipv4(void);
 int avahi_open_unicast_socket_ipv6(void);
 
-int avahi_send_dns_packet_ipv4(int fd, int iface, AvahiDnsPacket *p, const AvahiIPv4Address *a, uint16_t port);
-int avahi_send_dns_packet_ipv6(int fd, int iface, AvahiDnsPacket *p, const AvahiIPv6Address *a, uint16_t port);
+int avahi_send_dns_packet_ipv4(int fd, AvahiIfIndex iface, AvahiDnsPacket *p, const AvahiIPv4Address *src_address, const AvahiIPv4Address *dst_address, uint16_t dst_port);
+int avahi_send_dns_packet_ipv6(int fd, AvahiIfIndex iface, AvahiDnsPacket *p, const AvahiIPv6Address *src_address, const AvahiIPv6Address *dst_address, uint16_t dst_port);
 
-AvahiDnsPacket *avahi_recv_dns_packet_ipv4(int fd, struct sockaddr_in*ret_sa, AvahiIPv4Address *ret_dest_address, int *ret_iface, uint8_t *ret_ttl);
-AvahiDnsPacket *avahi_recv_dns_packet_ipv6(int fd, struct sockaddr_in6*ret_sa, AvahiIPv6Address *ret_dest_address, int *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 *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);
 
-int avahi_mdns_mcast_join_ipv4(int fd, const AvahiIPv4Address *a, int iface, int join);
-int avahi_mdns_mcast_join_ipv6(int fd, const AvahiIPv6Address *a, int iface, int join);
+int avahi_mdns_mcast_join_ipv4(int fd, const AvahiIPv4Address *local_address, int iface, int join);
+int avahi_mdns_mcast_join_ipv6(int fd, const AvahiIPv6Address *local_address, int iface, int join);
 
 #endif
index fdd35c063468225be35bb254a96dc20a0c81950c..abb00318b233d435817e883370e9e90ff640aeae 100644 (file)
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <netinet/in.h>
 
 #include <avahi-common/malloc.h>
 #include <avahi-common/error.h>
@@ -140,7 +141,7 @@ static int send_to_dns_server(AvahiWideAreaLookup *l, AvahiDnsPacket *p) {
         if (l->engine->fd_ipv4 < 0)
             return -1;
         
-        return avahi_send_dns_packet_ipv4(l->engine->fd_ipv4, AVAHI_IF_UNSPEC, p, &a->data.ipv4, AVAHI_DNS_PORT);
+        return avahi_send_dns_packet_ipv4(l->engine->fd_ipv4, AVAHI_IF_UNSPEC, p, NULL, &a->data.ipv4, AVAHI_DNS_PORT);
         
     } else {
         assert(a->proto == AVAHI_PROTO_INET6);
@@ -148,7 +149,7 @@ static int send_to_dns_server(AvahiWideAreaLookup *l, AvahiDnsPacket *p) {
         if (l->engine->fd_ipv6 < 0)
             return -1;
         
-        return avahi_send_dns_packet_ipv6(l->engine->fd_ipv6, AVAHI_IF_UNSPEC, p, &a->data.ipv6, AVAHI_DNS_PORT);
+        return avahi_send_dns_packet_ipv6(l->engine->fd_ipv6, AVAHI_IF_UNSPEC, p, NULL, &a->data.ipv6, AVAHI_DNS_PORT);
     }
 }
 
@@ -553,21 +554,13 @@ finish:
 
 static void socket_event(AVAHI_GCC_UNUSED AvahiWatch *w, int fd, AVAHI_GCC_UNUSED AvahiWatchEvent events, void *userdata) {
     AvahiWideAreaLookupEngine *e = userdata;
-    AvahiAddress a;
     AvahiDnsPacket *p = NULL;
     
-    if (fd == e->fd_ipv4) {
-        struct sockaddr_in sa;
-            
-        if ((p = avahi_recv_dns_packet_ipv4(e->fd_ipv4, &sa, NULL, NULL, NULL)))
-            avahi_address_from_sockaddr((struct sockaddr*) &sa, &a);
-            
-    } else if (fd == e->fd_ipv6) {
-        struct sockaddr_in6 sa6;
-        
-        if ((p = avahi_recv_dns_packet_ipv6(e->fd_ipv6, &sa6, NULL, NULL, NULL)))
-            avahi_address_from_sockaddr((struct sockaddr*) &sa6, &a);
-
+    if (fd == e->fd_ipv4)
+        p = avahi_recv_dns_packet_ipv4(e->fd_ipv4, NULL, NULL, NULL, NULL, NULL);
+    else {
+        assert(fd == e->fd_ipv6);
+        p = avahi_recv_dns_packet_ipv6(e->fd_ipv6, NULL, NULL, NULL, NULL, NULL);
     }
 
     if (p) {