コード例 #1
0
AvahiAddress *avahi_address_from_sockaddr(const struct sockaddr* sa, AvahiAddress *ret_addr) {
    assert(sa);
    assert(ret_addr);

    assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);

    ret_addr->proto = avahi_af_to_proto(sa->sa_family);

    if (sa->sa_family == AF_INET)
        memcpy(&ret_addr->data.ipv4, &((const struct sockaddr_in*) sa)->sin_addr, sizeof(ret_addr->data.ipv4));
    else
        memcpy(&ret_addr->data.ipv6, &((const struct sockaddr_in6*) sa)->sin6_addr, sizeof(ret_addr->data.ipv6));

    return ret_addr;
}
コード例 #2
0
ファイル: mdns_avahi.c プロジェクト: couteau/forked-daapd
int
mdns_browse(char *type, int family, mdns_browse_cb cb)
{
  struct mdns_browser *mb;
  AvahiServiceBrowser *b;

  DPRINTF(E_DBG, L_MDNS, "Adding service browser for type %s\n", type);

  mb = calloc(1, sizeof(struct mdns_browser));
  if (!mb)
    {
      DPRINTF(E_LOG, L_MDNS, "Out of memory for new mdns browser\n");
      return -1;
    }

  mb->protocol = avahi_af_to_proto(family);
  mb->type = strdup(type);
  mb->cb = cb;

  mb->next = browser_list;
  browser_list = mb;

  b = avahi_service_browser_new(mdns_client, AVAHI_IF_UNSPEC, mb->protocol, mb->type, NULL, 0, browse_callback, mb);
  if (!b)
    {
      DPRINTF(E_LOG, L_MDNS, "Failed to create service browser: %s\n", MDNSERR);

      browser_list = mb->next;
      free(mb->type);
      free(mb);

      return -1;
    }

  return 0;
}
コード例 #3
0
static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdata) {
    AvahiInterfaceMonitor *m = userdata;

    /* This routine is called for every RTNETLINK response packet */

    assert(m);
    assert(n);
    assert(m->osdep.netlink == nl);

    if (n->nlmsg_type == RTM_NEWLINK) {

        /* A new interface appeared or an existing one has been modified */

        struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
        AvahiHwInterface *hw;
        struct rtattr *a = NULL;
        size_t l;

        /* A (superfluous?) sanity check */
        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 */

        /* Check whether the flags of this interface are OK for us */
        hw->flags_ok =
            (ifinfomsg->ifi_flags & IFF_UP) &&
            (!m->server->config.use_iff_running || (ifinfomsg->ifi_flags & IFF_RUNNING)) &&
            !(ifinfomsg->ifi_flags & IFF_LOOPBACK) &&
            (ifinfomsg->ifi_flags & IFF_MULTICAST) &&
            (m->server->config.allow_point_to_point || !(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:

                    /* Fill in hardware (MAC) address */
                    hw->mac_address_size = RTA_PAYLOAD(a);
                    if (hw->mac_address_size > AVAHI_MAC_ADDRESS_MAX)
                        hw->mac_address_size = AVAHI_MAC_ADDRESS_MAX;

                    memcpy(hw->mac_address, RTA_DATA(a), hw->mac_address_size);
                    break;

                default:
                    ;
            }

            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, AVAHI_MDNS);
        avahi_hw_interface_check_relevant(hw, AVAHI_LLMNR);

        /* 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) {

        /* An interface has been removed */

        struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
        AvahiHwInterface *hw;

        /* A (superfluous?) sanity check */
        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) {

        /* An address has been added, modified or removed */

        struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
        AvahiInterface *i;
        struct rtattr *a = NULL;
        size_t l;
        AvahiAddress raddr, rlocal, *r;
        int raddr_valid = 0, rlocal_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 */
        rlocal.proto = raddr.proto = avahi_af_to_proto(ifaddrmsg->ifa_family);

        l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg));
        a = IFA_RTA(ifaddrmsg);

        while (RTA_OK(a, l)) {

            switch(a->rta_type) {

                case IFA_ADDRESS:

                    if ((rlocal.proto == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) ||
                        (rlocal.proto == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4))
                        return;

                    memcpy(rlocal.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
                    rlocal_valid = 1;

                    break;

                case IFA_LOCAL:

                    /* Fill in local address data. Usually this is
                     * preferable over IFA_ADDRESS if both are set,
                     * since this refers to the local address of a PPP
                     * link while IFA_ADDRESS refers to the other
                     * end. */

                    if ((raddr.proto == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) ||
                        (raddr.proto == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4))
                        return;

                    memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
                    raddr_valid = 1;

                    break;

                default:
                    ;
            }

            a = RTA_NEXT(a, l);
        }

        /* If there was no adress attached to this message, let's quit. */
        if (rlocal_valid)
            r = &rlocal;
        else if (raddr_valid)
            r = &raddr;
        else
            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, r)))

                /* Mmm, no object existing yet, so let's create a new one */
                if (!(addr = avahi_interface_address_new(m, i, r, 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;
            addr->deprecated = !!(ifaddrmsg->ifa_flags & IFA_F_DEPRECATED);
        } 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, r)))
                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, AVAHI_MDNS);
        avahi_interface_check_relevant(i, AVAHI_LLMNR);

        /* 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 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, AVAHI_MDNS);
            avahi_interface_monitor_check_relevant(m, AVAHI_LLMNR);

            /* 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));
    }
}