]> git.meshlink.io Git - catta/commitdiff
fix detection whether an interface has a routable address assigned on BSD. Patch...
authorLennart Poettering <lennart@poettering.net>
Sun, 16 Dec 2007 21:03:02 +0000 (21:03 +0000)
committerLennart Poettering <lennart@poettering.net>
Sun, 16 Dec 2007 21:03:02 +0000 (21:03 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@1591 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

avahi-autoipd/iface-bsd.c
avahi-core/socket.c

index 23c02ddf436b030721e713d3054b2483025f83db..6a1085c800b0848cd3d6c97b60ca024959ea8a20 100644 (file)
@@ -3,17 +3,17 @@
 
 /***
   This file is part of avahi.
+
   avahi is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation; either version 2.1 of the
   License, or (at your option) any later version.
+
   avahi is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
   Public License for more details.
+
   You should have received a copy of the GNU Lesser General Public
   License along with avahi; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 #include "iface.h"
 
 #ifndef IN_LINKLOCAL
-#define IN_LINKLOCAL(i)        (((u_int32_t)(i) & (0xffff0000)) == (0xa9fe0000))
+#define IN_LINKLOCAL(i) (((u_int32_t)(i) & (0xffff0000)) == (0xa9fe0000))
 #endif
 
 #ifndef elementsof
-#define elementsof(array)      (sizeof(array)/sizeof(array[0]))
+#define elementsof(array)       (sizeof(array)/sizeof(array[0]))
 #endif
 
 #ifndef so_set_nonblock
 #define so_set_nonblock(s, val) \
-       do {                                            \
-               int __flags;                            \
-               __flags = fcntl((s), F_GETFL);          \
-               if (__flags == -1)                      \
-                       break;                          \
-               if (val != 0)                           \
-                       __flags |= O_NONBLOCK;          \
-               else                                    \
-                       __flags &= ~O_NONBLOCK;         \
-               (void)fcntl((s), F_SETFL, __flags);     \
-       } while (0)
+        do {                                            \
+                int __flags;                            \
+                __flags = fcntl((s), F_GETFL);          \
+                if (__flags == -1)                      \
+                        break;                          \
+                if (val != 0)                           \
+                        __flags |= O_NONBLOCK;          \
+                else                                    \
+                        __flags &= ~O_NONBLOCK;         \
+                (void)fcntl((s), F_SETFL, __flags);     \
+        } while (0)
 #endif
 
 #define MAX_RTMSG_SIZE 2048
 
 struct rtm_dispinfo {
-       u_char          *di_buf;
-       ssize_t          di_buflen;
-       ssize_t          di_len;
+        u_char          *di_buf;
+        ssize_t          di_buflen;
+        ssize_t          di_len;
 };
 
 union rtmunion {
-       struct rt_msghdr                 rtm;
-       struct if_msghdr                 ifm;
-       struct ifa_msghdr                ifam;
-       struct ifma_msghdr               ifmam;
-       struct if_announcemsghdr         ifan;
+        struct rt_msghdr                 rtm;
+        struct if_msghdr                 ifm;
+        struct ifa_msghdr                ifam;
+        struct ifma_msghdr               ifmam;
+        struct if_announcemsghdr         ifan;
 };
 typedef union rtmunion rtmunion_t;
 
@@ -94,8 +94,8 @@ struct Address;
 typedef struct Address Address;
 
 struct Address {
-       in_addr_t       address;
-       AVAHI_LLIST_FIELDS(Address, addresses);
+        in_addr_t       address;
+        AVAHI_LLIST_FIELDS(Address, addresses);
 };
 
 static int rtm_dispatch(void);
@@ -111,115 +111,115 @@ int
 iface_init(int idx)
 {
 
-       fd = socket(PF_ROUTE, SOCK_RAW, 0);
-       if (fd == -1) {
-               daemon_log(LOG_ERR, "socket(PF_ROUTE): %s", strerror(errno));
-               return (-1);
-       }
+        fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
+        if (fd == -1) {
+                daemon_log(LOG_ERR, "socket(PF_ROUTE): %s", strerror(errno));
+                return (-1);
+        }
 
-       so_set_nonblock(fd, 1);
+        so_set_nonblock(fd, 1);
 
-       ifindex = idx;
+        ifindex = idx;
 
-       return (fd);
+        return (fd);
 }
 
 int
 iface_get_initial_state(State *state)
 {
-       int                      mib[6];
-       char                    *buf;
-       struct if_msghdr        *ifm;
-       struct ifa_msghdr       *ifam;
-       char                    *lim;
-       char                    *next;
-       struct sockaddr         *sa;
-       size_t                   len;
-       int                      naddrs;
-
-       assert(state != NULL);
-       assert(fd != -1);
-
-       naddrs = 0;
-
-       mib[0] = CTL_NET;
-       mib[1] = PF_ROUTE;
-       mib[2] = 0;
-       mib[3] = 0;
-       mib[4] = NET_RT_IFLIST;
-       mib[5] = ifindex;
-
-       if (sysctl(mib, elementsof(mib), NULL, &len, NULL, 0) != 0) {
-               daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s",
-                   strerror(errno));
-               return (-1);
-       }
-
-       buf = malloc(len);
-       if (buf == NULL) {
-               daemon_log(LOG_ERR, "malloc(%d): %s", len, strerror(errno));
-               return (-1);
-       }
-
-       if (sysctl(mib, elementsof(mib), buf, &len, NULL, 0) != 0) {
-               daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s",
-                   strerror(errno));
-               free(buf);
-               return (-1);
-       }
-
-       lim = buf + len;
-       for (next = buf; next < lim; next += ifm->ifm_msglen) {
-               ifm = (struct if_msghdr *)next;
-               if (ifm->ifm_type == RTM_NEWADDR) {
-                       ifam = (struct ifa_msghdr *)next;
-                       sa = (struct sockaddr *)(ifam + 1);
-                       if (sa->sa_family != AF_INET)
-                               continue;
-                       ++naddrs;
-               }
-       }
-       free(buf);
-
-       *state = (naddrs > 0) ? STATE_SLEEPING : STATE_START;
-
-       return (0);
+        int                      mib[6];
+        char                    *buf;
+        struct if_msghdr        *ifm;
+        struct ifa_msghdr       *ifam;
+        char                    *lim;
+        char                    *next;
+        struct sockaddr         *sa;
+        size_t                   len;
+        int                      naddrs;
+
+        assert(state != NULL);
+        assert(fd != -1);
+
+        naddrs = 0;
+
+        mib[0] = CTL_NET;
+        mib[1] = PF_ROUTE;
+        mib[2] = 0;
+        mib[3] = 0;
+        mib[4] = NET_RT_IFLIST;
+        mib[5] = ifindex;
+
+        if (sysctl(mib, elementsof(mib), NULL, &len, NULL, 0) != 0) {
+                daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s",
+                    strerror(errno));
+                return (-1);
+        }
+
+        buf = malloc(len);
+        if (buf == NULL) {
+                daemon_log(LOG_ERR, "malloc(%d): %s", len, strerror(errno));
+                return (-1);
+        }
+
+        if (sysctl(mib, elementsof(mib), buf, &len, NULL, 0) != 0) {
+                daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s",
+                    strerror(errno));
+                free(buf);
+                return (-1);
+        }
+
+        lim = buf + len;
+        for (next = buf; next < lim; next += ifm->ifm_msglen) {
+                ifm = (struct if_msghdr *)next;
+                if (ifm->ifm_type == RTM_NEWADDR) {
+                        ifam = (struct ifa_msghdr *)next;
+                        sa = (struct sockaddr *)(ifam + 1);
+                        if (sa->sa_family != AF_INET)
+                                continue;
+                        ++naddrs;
+                }
+        }
+        free(buf);
+
+        *state = (naddrs > 0) ? STATE_SLEEPING : STATE_START;
+
+        return (0);
 }
 
 int
 iface_process(Event *event)
 {
-       int b;
+        int routable;
 
-       assert(fd != -1);
+        assert(fd != -1);
 
-       b = !!addresses;
+        routable = !!addresses;
 
-       if (rtm_dispatch() == -1)
-               return (-1);
+        if (rtm_dispatch() == -1)
+                return (-1);
 
-       if (b && !addresses)
-               *event = EVENT_ROUTABLE_ADDR_UNCONFIGURED;
-       else if (!b && addresses)
-               *event = EVENT_ROUTABLE_ADDR_CONFIGURED;
+        if (routable && !addresses)
+                *event = EVENT_ROUTABLE_ADDR_UNCONFIGURED;
+        else if (!routable && addresses)
+                *event = EVENT_ROUTABLE_ADDR_CONFIGURED;
 
-       return (0);
+        return (0);
 }
 
 void
 iface_done(void)
 {
-       Address *a;
+        Address *a;
 
-       if (fd != -1) {
-               close(fd);
-               fd = -1;
-       }
+        if (fd != -1) {
+                close(fd);
+                fd = -1;
+        }
 
-       while ((a = addresses) != NULL) {
-               AVAHI_LLIST_REMOVE(Address, addresses, addresses, a);
-               avahi_free(a);
-       }
+        while ((a = addresses) != NULL) {
+                AVAHI_LLIST_REMOVE(Address, addresses, addresses, a);
+                avahi_free(a);
+        }
 }
 
 /*
@@ -228,189 +228,213 @@ iface_done(void)
 static int
 rtm_dispatch(void)
 {
-       struct msghdr mh;
-       struct iovec iov[1];
-       struct rt_msghdr *rtm;
-       struct rtm_dispinfo *di;
-       ssize_t len;
-       int retval;
-
-       di = malloc(sizeof(*di));
-       if (di == NULL) {
-               daemon_log(LOG_ERR, "malloc(%d): %s", sizeof(*di),
-                   strerror(errno));
-               return (-1);
-       }
-       di->di_buflen = MAX_RTMSG_SIZE;
-       di->di_buf = calloc(MAX_RTMSG_SIZE, 1);
-       if (di->di_buf == NULL) {
-               free(di);
-               daemon_log(LOG_ERR, "calloc(%d): %s", MAX_RTMSG_SIZE,
-                   strerror(errno));
-               return (-1);
-       }
-
-       memset(&mh, 0, sizeof(mh));
-       iov[0].iov_base = di->di_buf;
-       iov[0].iov_len = di->di_buflen;
-       mh.msg_iov = iov;
-       mh.msg_iovlen = 1;
-
-       retval = 0;
-       for (;;) {
-               len = recvmsg(fd, &mh, MSG_DONTWAIT);
-               if (len == -1) {
-                       if (errno == EWOULDBLOCK)
-                               break;
-                       else {
-                               daemon_log(LOG_ERR, "recvmsg(): %s",
-                                   strerror(errno));
-                               retval = -1;
-                               break;
-                       }
-               }
-
-               rtm = (void *)di->di_buf;
-               if (rtm->rtm_version != RTM_VERSION) {
-                       daemon_log(LOG_ERR,
-                           "unknown routing socket message (version %d)\n",
-                           rtm->rtm_version);
-                       /* this is non-fatal; just ignore it for now. */
-                       continue;
-               }
-
-               switch (rtm->rtm_type) {
-               case RTM_NEWADDR:
-               case RTM_DELADDR:
-                       retval = rtm_dispatch_newdeladdr(di);
-                       break;
-               case RTM_IFANNOUNCE:
-                       retval = rtm_dispatch_ifannounce(di);
-                       break;
-               default:
-                       break;
-               }
-
-               /*
-                * If we got an error; assume our position on the call
-                * stack is enclosed by a level-triggered event loop,
-                * and signal the error condition.
-                */
-               if (retval != 0)
-                       break;
-       }
-       free(di->di_buf);
-       free(di);
-
-       return (retval);
+        struct msghdr mh;
+        struct iovec iov[1];
+        struct rt_msghdr *rtm;
+        struct rtm_dispinfo *di;
+        ssize_t len;
+        int retval;
+
+        di = malloc(sizeof(*di));
+        if (di == NULL) {
+                daemon_log(LOG_ERR, "malloc(%d): %s", sizeof(*di),
+                    strerror(errno));
+                return (-1);
+        }
+        di->di_buflen = MAX_RTMSG_SIZE;
+        di->di_buf = calloc(MAX_RTMSG_SIZE, 1);
+        if (di->di_buf == NULL) {
+                free(di);
+                daemon_log(LOG_ERR, "calloc(%d): %s", MAX_RTMSG_SIZE,
+                    strerror(errno));
+                return (-1);
+        }
+
+        memset(&mh, 0, sizeof(mh));
+        iov[0].iov_base = di->di_buf;
+        iov[0].iov_len = di->di_buflen;
+        mh.msg_iov = iov;
+        mh.msg_iovlen = 1;
+
+        retval = 0;
+        for (;;) {
+                len = recvmsg(fd, &mh, MSG_DONTWAIT);
+                if (len == -1) {
+                        if (errno == EWOULDBLOCK)
+                                break;
+                        else {
+                                daemon_log(LOG_ERR, "recvmsg(): %s",
+                                    strerror(errno));
+                                retval = -1;
+                                break;
+                        }
+                }
+
+                rtm = (void *)di->di_buf;
+                if (rtm->rtm_version != RTM_VERSION) {
+                        daemon_log(LOG_ERR,
+                            "unknown routing socket message (version %d)\n",
+                            rtm->rtm_version);
+                        /* this is non-fatal; just ignore it for now. */
+                        continue;
+                }
+
+                switch (rtm->rtm_type) {
+                case RTM_NEWADDR:
+                case RTM_DELADDR:
+                        retval = rtm_dispatch_newdeladdr(di);
+                        break;
+                case RTM_IFANNOUNCE:
+                        retval = rtm_dispatch_ifannounce(di);
+                        break;
+                default:
+                        daemon_log(LOG_DEBUG, "%s: rtm_type %d ignored", __func__, rtm->rtm_type);
+                        break;
+                }
+
+                /*
+                 * If we got an error; assume our position on the call
+                 * stack is enclosed by a level-triggered event loop,
+                 * and signal the error condition.
+                 */
+                if (retval != 0)
+                        break;
+        }
+        free(di->di_buf);
+        free(di);
+
+        return (retval);
 }
 
 /* handle link coming or going away */
 static int
 rtm_dispatch_ifannounce(struct rtm_dispinfo *di)
 {
-       rtmunion_t *rtm = (void *)di->di_buf;
+        rtmunion_t *rtm = (void *)di->di_buf;
 
-       assert(rtm->rtm.rtm_type == RTM_IFANNOUNCE);
+        assert(rtm->rtm.rtm_type == RTM_IFANNOUNCE);
 
-       switch (rtm->ifan.ifan_what) {
-       case IFAN_ARRIVAL:
-               if (rtm->ifan.ifan_index == ifindex) {
-                       daemon_log(LOG_ERR,
+        daemon_log(LOG_DEBUG, "%s: IFANNOUNCE for ifindex %d",
+            __func__, rtm->ifan.ifan_index);
+
+        switch (rtm->ifan.ifan_what) {
+        case IFAN_ARRIVAL:
+                if (rtm->ifan.ifan_index == ifindex) {
+                        daemon_log(LOG_ERR,
 "RTM_IFANNOUNCE IFAN_ARRIVAL, for ifindex %d, which we already manage.",
-                           ifindex);
-                       return (-1);
-               }
-               break;
-       case IFAN_DEPARTURE:
-               if (rtm->ifan.ifan_index == ifindex) {
-                       daemon_log(LOG_ERR, "Interface vanished.");
-                       return (-1);
-               }
-               break;
-       default:
-               /* ignore */
-               break;
-       }
-
-       return (0);
+                            ifindex);
+                        return (-1);
+                }
+                break;
+        case IFAN_DEPARTURE:
+                if (rtm->ifan.ifan_index == ifindex) {
+                        daemon_log(LOG_ERR, "Interface vanished.");
+                        return (-1);
+                }
+                break;
+        default:
+                /* ignore */
+                break;
+        }
+
+        return (0);
 }
 
 static struct sockaddr *
 next_sa(struct sockaddr *sa)
 {
-       void            *p;
-       size_t           sa_size;
+        void            *p;
+        size_t           sa_size;
+
+#ifdef SA_SIZE
+        sa_size = SA_SIZE(sa);
+#else
+        /* This is not foolproof, kernel may round. */
+        sa_size = sa->sa_len;
+        if (sa_size < sizeof(u_long))
+                sa_size = sizeof(u_long);
+#endif
 
-       sa_size = sa->sa_len;
-       if (sa_size < sizeof(u_long))
-               sa_size = sizeof(u_long);
-       p = ((char *)sa) + sa_size;
+        p = ((char *)sa) + sa_size;
 
-       return (struct sockaddr *)p;
+        return (struct sockaddr *)p;
 }
 
 /* handle address coming or going away */
 static int
 rtm_dispatch_newdeladdr(struct rtm_dispinfo *di)
 {
-       Address                 *ap;
-       rtmunion_t              *rtm;
-       struct sockaddr         *sa;
-       struct sockaddr_in      *sin;
+        Address                 *ap;
+        struct ifa_msghdr       *ifam;
+        struct sockaddr         *sa;
+        struct sockaddr_in      *sin;
+        int                     link_local;
 
 /* macro to skip to next RTA; has side-effects */
-#define SKIPRTA(rtmsgp, rta, sa)                                       \
-       do {                                                            \
-               if ((rtmsgp)->rtm_addrs & (rta))                        \
-                       (sa) = next_sa((sa));                           \
-       } while (0)
-
-       rtm = (void *)di->di_buf;
-
-       assert(rtm->rtm.rtm_type == RTM_NEWADDR ||
-              rtm->rtm.rtm_type == RTM_DELADDR);
-
-       if (rtm->rtm.rtm_index != ifindex)
-               return (0);
-
-       if (!(rtm->rtm.rtm_addrs & RTA_IFA)) {
-               daemon_log(LOG_ERR, "ifa msg has no RTA_IFA.");
-               return (0);
-       }
-
-       /* skip over rtmsg padding correctly */
-       sa = (struct sockaddr *)((&rtm->ifam) + 1);
-       SKIPRTA(&rtm->rtm, RTA_DST, sa);
-       SKIPRTA(&rtm->rtm, RTA_GATEWAY, sa);
-       SKIPRTA(&rtm->rtm, RTA_NETMASK, sa);
-       SKIPRTA(&rtm->rtm, RTA_GENMASK, sa);
-       SKIPRTA(&rtm->rtm, RTA_IFP, sa);
-
-       /*
-        * sa now points to RTA_IFA sockaddr; we are only interested
-        * in updates for link-local addresses.
-        */
-       if (sa->sa_family != AF_INET)
-               return (0);
-       sin = (struct sockaddr_in *)sa;
-       if (!IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr)))
-               return (0);
-
-       for (ap = addresses; ap; ap = ap->addresses_next) {
-               if (ap->address == sin->sin_addr.s_addr)
-                       break;
-       }
-       if (rtm->rtm.rtm_type == RTM_DELADDR && ap != NULL) {
-               AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap);
-               avahi_free(ap);
-       }
-       if (rtm->rtm.rtm_type == RTM_NEWADDR && ap == NULL) {
-               ap = avahi_new(Address, 1);
-               ap->address = sin->sin_addr.s_addr;
-               AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap);
-       }
-
-       return (0);
+#define SKIPRTA(ifamsgp, rta, sa)                                       \
+        do {                                                            \
+                if ((ifamsgp)->ifam_addrs & (rta))                      \
+                        (sa) = next_sa((sa));                           \
+        } while (0)
+
+        ifam = &((rtmunion_t *)di->di_buf)->ifam;
+
+        assert(ifam->ifam_type == RTM_NEWADDR ||
+               ifam->ifam_type == RTM_DELADDR);
+
+        daemon_log(LOG_DEBUG, "%s: %s for iface %d (%s)", __func__,
+            ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR",
+            ifam->ifam_index, (ifam->ifam_index == ifindex) ? "ours" : "not ours");
+
+        if (ifam->ifam_index != ifindex)
+                return (0);
+
+        if (!(ifam->ifam_addrs & RTA_IFA)) {
+                daemon_log(LOG_ERR, "ifa msg has no RTA_IFA.");
+                return (0);
+        }
+
+        /* skip over rtmsg padding correctly */
+        sa = (struct sockaddr *)(ifam + 1);
+        SKIPRTA(ifam, RTA_DST, sa);
+        SKIPRTA(ifam, RTA_GATEWAY, sa);
+        SKIPRTA(ifam, RTA_NETMASK, sa);
+        SKIPRTA(ifam, RTA_GENMASK, sa);
+        SKIPRTA(ifam, RTA_IFP, sa);
+
+        /*
+         * sa now points to RTA_IFA sockaddr; we are only interested
+         * in updates for routable addresses.
+         */
+        if (sa->sa_family != AF_INET) {
+                daemon_log(LOG_DEBUG, "%s: RTA_IFA family not AF_INET (=%d)", __func__, sa->sa_family);
+                return (0);
+        }
+
+        sin = (struct sockaddr_in *)sa;
+        link_local = IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr));
+
+        daemon_log(LOG_DEBUG, "%s: %s for %s (%s)", __func__,
+            ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR",
+            inet_ntoa(sin->sin_addr), link_local ? "link local" : "routable");
+
+        if (link_local)
+                return (0);
+
+        for (ap = addresses; ap; ap = ap->addresses_next) {
+                if (ap->address == sin->sin_addr.s_addr)
+                        break;
+        }
+        if (ifam->ifam_type == RTM_DELADDR && ap != NULL) {
+                AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap);
+                avahi_free(ap);
+        }
+        if (ifam->ifam_type == RTM_NEWADDR && ap == NULL) {
+                ap = avahi_new(Address, 1);
+                ap->address = sin->sin_addr.s_addr;
+                AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap);
+        }
+
+        return (0);
 #undef SKIPRTA
 }
index 265536de1d5f28ec9b208a47b2692e2ac0b01ef1..4146d5ad593e5d3d05dc8265192a147c539f390f 100644 (file)
@@ -451,7 +451,11 @@ static int sendmsg_loop(int fd, struct msghdr *msg, int flags) {
             break;
 
         if (errno != EAGAIN) {
-            avahi_log_debug("sendmsg() failed: %s", strerror(errno));
+            char where[64];
+            struct sockaddr_in *sin = msg->msg_name;
+
+            inet_ntop(sin->sin_family, &sin->sin_addr, where, sizeof(where));
+            avahi_log_debug("sendmsg() to %s failed: %s", where, strerror(errno));
             return -1;
         }