From d322a943be5387a539f8f3ea3a19a7e2ed5a55a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Oct 2005 01:30:46 +0000 Subject: * Some minor cleanups in netlink code * add some comments to iface-linux.c, to ease porting for sebest git-svn-id: file:///home/lennart/svn/public/avahi/trunk@762 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-core/iface-linux.c | 108 +++++++++++++++++++++++++++++++++++++++++------ avahi-core/netlink.c | 6 +-- 2 files changed, 98 insertions(+), 16 deletions(-) (limited to 'avahi-core') diff --git a/avahi-core/iface-linux.c b/avahi-core/iface-linux.c index 5e16d6a..64bb0ae 100644 --- a/avahi-core/iface-linux.c +++ b/avahi-core/iface-linux.c @@ -69,7 +69,18 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat if (ifinfomsg->ifi_family != AF_UNSPEC) return; + /* Check whether there already is an AvahiHwInterface object + * for this link, so that we can update its data. Note that + * Netlink sends us an RTM_NEWLINK not only when a new + * interface appears, but when it changes, too */ + if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index))) + + /* No object found, so let's create a new + * one. avahi_hw_interface_new() will call + * avahi_interface_new() internally twice for IPv4 and + * IPv6, so there is no need for us to do that + * ourselves */ if (!(hw = avahi_hw_interface_new(m, (AvahiIfIndex) ifinfomsg->ifi_index))) return; /* OOM */ @@ -80,31 +91,36 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat !(ifinfomsg->ifi_flags & IFF_LOOPBACK) && (ifinfomsg->ifi_flags & IFF_MULTICAST) && !(ifinfomsg->ifi_flags & IFF_POINTOPOINT); - + /* Handle interface attributes */ l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg)); a = IFLA_RTA(ifinfomsg); while (RTA_OK(a, l)) { switch(a->rta_type) { case IFLA_IFNAME: + + /* Fill in interface name */ avahi_free(hw->name); hw->name = avahi_strndup(RTA_DATA(a), RTA_PAYLOAD(a)); break; case IFLA_MTU: + + /* Fill in MTU */ assert(RTA_PAYLOAD(a) == sizeof(unsigned int)); hw->mtu = *((unsigned int*) RTA_DATA(a)); break; - case IFLA_ADDRESS: { + case IFLA_ADDRESS: + + /* Fill in hardware (MAC) address */ hw->mac_address_size = RTA_PAYLOAD(a); if (hw->mac_address_size > AVAHI_MAX_MAC_ADDRESS) hw->mac_address_size = AVAHI_MAX_MAC_ADDRESS; memcpy(hw->mac_address, RTA_DATA(a), hw->mac_address_size); break; - } default: ; @@ -113,7 +129,14 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat a = RTA_NEXT(a, l); } + /* Check whether this interface is now "relevant" for us. If + * it is Avahi will start to announce its records on this + * interface and send out queries for subscribed records on + * it */ avahi_hw_interface_check_relevant(hw); + + /* Update any associated RRs of this interface. (i.e. the + * _workstation._tcp record containing the MAC address) */ avahi_hw_interface_update_rrs(hw, 0); } else if (n->nlmsg_type == RTM_DELLINK) { @@ -122,10 +145,12 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat if (ifinfomsg->ifi_family != AF_UNSPEC) return; - + + /* Get a reference to our AvahiHwInterface object of this interface */ if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifinfomsg->ifi_index))) return; + /* Free our object */ avahi_hw_interface_free(hw, 0); } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { @@ -137,12 +162,17 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat AvahiAddress raddr; int raddr_valid = 0; + /* We are only interested in IPv4 and IPv6 */ if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6) return; + /* Try to get a reference to our AvahiInterface object for the + * interface this address is assigned to. If ther is no object + * for this interface, we ignore this address. */ if (!(i = avahi_interface_monitor_get_interface(m, (AvahiIfIndex) ifaddrmsg->ifa_index, avahi_af_to_proto(ifaddrmsg->ifa_family)))) return; + /* Fill in address family for our new address */ raddr.proto = avahi_af_to_proto(ifaddrmsg->ifa_family); l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg)); @@ -152,6 +182,8 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat switch(a->rta_type) { case IFA_ADDRESS: + /* Fill in address data */ + if ((raddr.proto == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) || (raddr.proto == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4)) return; @@ -167,55 +199,91 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat a = RTA_NEXT(a, l); } - + + /* If there was no adress attached to this message, let's quit. */ if (!raddr_valid) return; if (n->nlmsg_type == RTM_NEWADDR) { AvahiInterfaceAddress *addr; - + + /* This address is new or has been modified, so let's get an object for it */ if (!(addr = avahi_interface_monitor_get_address(m, i, &raddr))) + + /* Mmm, no object existing yet, so let's create a new one */ if (!(addr = avahi_interface_address_new(m, i, &raddr, ifaddrmsg->ifa_prefixlen))) return; /* OOM */ - + + /* Update the scope field for the address */ addr->global_scope = ifaddrmsg->ifa_scope == RT_SCOPE_UNIVERSE || ifaddrmsg->ifa_scope == RT_SCOPE_SITE; } else { AvahiInterfaceAddress *addr; - + assert(n->nlmsg_type == RTM_DELADDR); + + /* Try to get a reference to our AvahiInterfaceAddress object for this address */ if (!(addr = avahi_interface_monitor_get_address(m, i, &raddr))) return; + /* And free it */ avahi_interface_address_free(addr); } + /* Avahi only considers interfaces with at least one address + * attached relevant. Since we migh have added or removed an + * address, let's have it check again whether the interface is + * now relevant */ avahi_interface_check_relevant(i); + + /* Update any associated RRs, like A or AAAA for our new/removed address */ avahi_interface_update_rrs(i, 0); } else if (n->nlmsg_type == NLMSG_DONE) { + + /* This wild dump request ended, so let's see what we do next */ if (m->osdep.list == LIST_IFACE) { + + /* Mmmm, interfaces have been wild dumped already, so + * let's go on with wild dumping the addresses */ if (netlink_list_items(m->osdep.netlink, RTM_GETADDR, &m->osdep.query_addr_seq) < 0) { avahi_log_warn("NETLINK: Failed to list addrs: %s", strerror(errno)); m->osdep.list = LIST_DONE; } else + + /* Update state information */ m->osdep.list = LIST_ADDR; } else - /* We're through */ + /* We're done. Tell avahi_interface_monitor_sync() to finish. */ m->osdep.list = LIST_DONE; if (m->osdep.list == LIST_DONE) { + + /* Only after this boolean variable has been set, Avahi + * will start to announce or browse on all interfaces. It + * is originaly set to 0, which means that relevancy + * checks and RR updates are disabled during the wild + * dumps. */ m->list_complete = 1; + + /* So let's check if any interfaces are relevant now */ avahi_interface_monitor_check_relevant(m); + + /* And update all RRs attached to any interface */ avahi_interface_monitor_update_rrs(m, 0); + + /* Tell the user that the wild dump is complete */ avahi_log_info("Network interface enumeration completed."); } } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->osdep.query_link_seq || n->nlmsg_seq == m->osdep.query_addr_seq)) { struct nlmsgerr *e = NLMSG_DATA (n); - + + /* Some kind of error happened. Let's just tell the user and + * ignore it otherwise */ + if (e->error) avahi_log_warn("NETLINK: Failed to browse: %s", strerror(-e->error)); } @@ -224,15 +292,23 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat int avahi_interface_monitor_init_osdep(AvahiInterfaceMonitor *m) { assert(m); + /* Initialize our own data */ + m->osdep.netlink = NULL; m->osdep.query_addr_seq = m->osdep.query_link_seq = 0; - + + /* Create a netlink object for us. It abstracts some things and + * makes netlink easier to use. It will attach to the main loop + * for us and call netlink_callback() whenever an event + * happens. */ if (!(m->osdep.netlink = avahi_netlink_new(m->server->poll_api, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, netlink_callback, m))) goto fail; + /* Start the wild dump for the interfaces */ if (netlink_list_items(m->osdep.netlink, RTM_GETLINK, &m->osdep.query_link_seq) < 0) goto fail; + /* Set the initial state. */ m->osdep.list = LIST_IFACE; return 0; @@ -258,9 +334,15 @@ void avahi_interface_monitor_free_osdep(AvahiInterfaceMonitor *m) { void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) { assert(m); + + /* Let's handle netlink events until we are done with wild + * dumping */ while (m->osdep.list != LIST_DONE) { - if (!avahi_netlink_work(m->osdep.netlink, 1)) + if (!avahi_netlink_work(m->osdep.netlink, 1) == 0) break; - } + } + + /* At this point Avahi knows about all local interfaces and + * addresses in existance. */ } diff --git a/avahi-core/netlink.c b/avahi-core/netlink.c index ccb4d83..d5d2295 100644 --- a/avahi-core/netlink.c +++ b/avahi-core/netlink.c @@ -56,10 +56,10 @@ int avahi_netlink_work(AvahiNetlink *nl, int block) { if ((bytes = recv(nl->fd, nl->buffer, nl->buffer_length, block ? 0 : MSG_DONTWAIT)) < 0) { if (errno == EAGAIN || errno == EINTR) - return 1; + return 0; avahi_log_error(__FILE__": recv() failed: %s", strerror(errno)); - return 0; + return -1; } break; @@ -71,7 +71,7 @@ int avahi_netlink_work(AvahiNetlink *nl, int block) { for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) { if (!NLMSG_OK(p, (size_t) bytes)) { avahi_log_warn(__FILE__": packet truncated"); - return 0; + return -1; } nl->callback(nl, p, nl->userdata); -- cgit