Esempio n. 1
0
void PublishAvahi::create_services(AvahiClient *c)
{
	char *n, r[128];
	int ret;
	assert(c);

	/* If this is the first time we're called, let's create a new
		* entry group if necessary */

	if (!group)
	{
		if (!(group = avahi_entry_group_new(c, entry_group_callback, this)))
		{
			logE << "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)) << "\n";
			goto fail;
		}
	}
	/* If the group is empty (either because it was just created, or
		* because it was reset previously, add our entries.  */

	if (avahi_entry_group_is_empty(group))
	{
		logO << "Adding service '" << name << "'\n";

		/* Create some random TXT data */
		snprintf(r, sizeof(r), "random=%i", rand());

		/* We will now add two services and one subtype to the entry
			* group. The two services have the same name, but differ in
			* the service type (IPP vs. BSD LPR). Only services with the
			* same name should be put in the same entry group. */

		/* Add the service for IPP */
/*        if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_UNIQUE, name, "_ipp._tcp", NULL, NULL, 651, "test=blah", r, NULL)) < 0)
		{

			if (ret == AVAHI_ERR_COLLISION)
				goto collision;

			fprintf(stderr, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret));
			goto fail;
		}
*/
		/* Add the same service for BSD LPR */
		for (size_t n=0; n<services.size(); ++n)
		{
			if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, services[n].proto_, AvahiPublishFlags(0), name, services[n].name_.c_str(), NULL, NULL, services[n].port_, NULL)) < 0)
			{

				if (ret == AVAHI_ERR_COLLISION)
					goto collision;

				logE << "Failed to add " << services[n].name_ << " service: " << avahi_strerror(ret) << "\n";
				goto fail;
			}
		}

		/* Add an additional (hypothetic) subtype */
/*        if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0))
		{
			fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret));
			goto fail;
		}
*/
		/* Tell the server to register the service */
		if ((ret = avahi_entry_group_commit(group)) < 0)
		{
			logE << "Failed to commit entry group: " << avahi_strerror(ret) << "\n";
			goto fail;
		}
	}

	return;

collision:

	/* A service name collision with a local service happened. Let's
		* pick a new name */
	n = avahi_alternative_service_name(name);
	avahi_free(name);
	name = n;

	logO << "Service name collision, renaming service to '" << name << "'\n";

	avahi_entry_group_reset(group);

	create_services(c);
	return;

fail:
	avahi_simple_poll_quit(simple_poll);
}
Esempio n. 2
0
void QxtMDNSPrivate::avahiRecordBrowserCallback(AvahiRecordBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, uint16_t clazz, uint16_t type, const void *rdata, size_t size, AvahiLookupResultFlags flags, void *userdata)
{
	///@TODO Support IPv6
	Q_UNUSED(interface);
	Q_UNUSED(protocol);
	Q_UNUSED(name);
	Q_UNUSED(clazz);
	Q_UNUSED(type);
	Q_UNUSED(size);
	Q_UNUSED(flags);
	QxtMDNSPrivate* self = static_cast<QxtMDNSPrivate*>(userdata);
	self->recordbrowser = b;
// 	qDebug() << "Return thing" << md->name << name << size;
	switch (event)
	{
		case AVAHI_BROWSER_NEW:
		{
			//Found an entry!
			uint32_t ip = qFromBigEndian(*static_cast<const uint32_t*>(rdata));
			if (self->sent)
			{
				QHostInfo info(self->info.lookupId());
				info.setAddresses(QList<QHostAddress>() << QHostAddress(ip));
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, info));
			}
			else
			{
				self->addresses << QHostAddress(ip);
			}
			break;
		}
		case AVAHI_BROWSER_REMOVE:
		{
			uint32_t ip = qFromBigEndian(*static_cast<const uint32_t*>(rdata));
			self->addresses.removeAll(QHostAddress(ip));
			break;
		}
		case AVAHI_BROWSER_CACHE_EXHAUSTED:
			break;
		case AVAHI_BROWSER_ALL_FOR_NOW:
			if (self->addresses.count() == 0)
			{
				self->info.setError(QHostInfo::HostNotFound);
				self->info.setErrorString("The host was not found.");
			}
			else
			{
				self->info.setAddresses(self->addresses);
				self->addresses.clear();
			}
			QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
			self->sent = true;
			break;
		case AVAHI_BROWSER_FAILURE:

			if (self->sent)
			{
				QHostInfo info(self->info.lookupId());
				info.setError(QHostInfo::UnknownError);
				info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
				info.setAddresses(self->addresses);
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, info));
			}
			else
			{
				self->info.setError(QHostInfo::UnknownError);
				self->info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
				self->info.setAddresses(self->addresses);
				self->addresses.clear();
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
				self->sent = true;
			}
			break;
	}
}
static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) {
    struct userdata *u = userdata;

    pa_assert(c);
    pa_assert(u);

    u->client = c;

    switch (state) {
        case AVAHI_CLIENT_S_REGISTERING:
        case AVAHI_CLIENT_S_RUNNING:
        case AVAHI_CLIENT_S_COLLISION:

            if (!u->sink_browser) {

                if (!(u->sink_browser = avahi_service_browser_new(
                              c,
                              AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
                              SERVICE_TYPE_SINK,
                              NULL,
                              0,
                              browser_cb, u))) {

                    pa_log("avahi_service_browser_new() failed: %s", avahi_strerror(avahi_client_errno(c)));
                    pa_module_unload_request(u->module, TRUE);
                }
            }

            if (!u->source_browser) {

                if (!(u->source_browser = avahi_service_browser_new(
                              c,
                              AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
                              SERVICE_TYPE_SOURCE,
                              NULL,
                              0,
                              browser_cb, u))) {

                    pa_log("avahi_service_browser_new() failed: %s", avahi_strerror(avahi_client_errno(c)));
                    pa_module_unload_request(u->module, TRUE);
                }
            }

            break;

        case AVAHI_CLIENT_FAILURE:
            if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) {
                int error;

                pa_log_debug("Avahi daemon disconnected.");

                if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) {
                    pa_log("avahi_client_new() failed: %s", avahi_strerror(error));
                    pa_module_unload_request(u->module, TRUE);
                }
            }

            /* Fall through */

        case AVAHI_CLIENT_CONNECTING:

            if (u->sink_browser) {
                avahi_service_browser_free(u->sink_browser);
                u->sink_browser = NULL;
            }

            if (u->source_browser) {
                avahi_service_browser_free(u->source_browser);
                u->source_browser = NULL;
            }

            break;

        default: ;
    }
}
int
main (AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[])
{
    GMainLoop *loop = NULL;
    const AvahiPoll *poll_api;
    AvahiGLibPoll *glib_poll;
    AvahiClient *client;
    struct timeval tv;
    const char *version;
    int error;

    /* Optional: Tell avahi to use g_malloc and g_free */
    avahi_set_allocator (avahi_glib_allocator ());

    /* Create the GLIB main loop */
    loop = g_main_loop_new (NULL, FALSE);

    /* Create the GLIB Adaptor */
    glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
    poll_api = avahi_glib_poll_get (glib_poll);

    /* Example, schedule a timeout event with the Avahi API */
    avahi_elapse_time (&tv,                         /* timeval structure */
            1000,                                   /* 1 second */
            0);                                     /* "jitter" - Random additional delay from 0 to this value */

    poll_api->timeout_new (poll_api,                /* The AvahiPoll object */
                      &tv,                          /* struct timeval indicating when to go activate */
                      avahi_timeout_event,          /* Pointer to function to call */
                      NULL);                        /* User data to pass to function */

    /* Schedule a timeout event with the glib api */
    g_timeout_add (5000,                            /* 5 seconds */
            avahi_timeout_event_glib,               /* Pointer to function callback */
            loop);                                  /* User data to pass to function */

    /* Create a new AvahiClient instance */
    client = avahi_client_new (poll_api,            /* AvahiPoll object from above */
                               0,
            avahi_client_callback,                  /* Callback function for Client state changes */
            loop,                                   /* User data */
            &error);                                /* Error return */

    /* Check the error return code */
    if (client == NULL)
    {
        /* Print out the error string */
        g_warning ("Error initializing Avahi: %s", avahi_strerror (error));

        goto fail;
    }

    /* Make a call to get the version string from the daemon */
    version = avahi_client_get_version_string (client);

    /* Check if the call suceeded */
    if (version == NULL)
    {
        g_warning ("Error getting version string: %s", avahi_strerror (avahi_client_errno (client)));

        goto fail;
    }

    g_message ("Avahi Server Version: %s", version);

    /* Start the GLIB Main Loop */
    g_main_loop_run (loop);

fail:
    /* Clean up */
    g_main_loop_unref (loop);
    avahi_client_free (client);
    avahi_glib_poll_free (glib_poll);

    return 0;
}
Esempio n. 5
0
void CZeroconfAvahi::addService(tServiceMap::mapped_type fp_service_info, AvahiClient* fp_client)
{
  assert(fp_client);
  CLog::Log(LOGDEBUG, "CZeroconfAvahi::addService() named: %s type: %s port:%i", fp_service_info->m_name.c_str(), fp_service_info->m_type.c_str(), fp_service_info->m_port);
  //create the group if it doesn't exist
  if (!fp_service_info->mp_group)
  {
    if (!(fp_service_info->mp_group = avahi_entry_group_new(fp_client, &CZeroconfAvahi::groupCallback, this)))
    {
      CLog::Log(LOGDEBUG, "CZeroconfAvahi::addService() avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(fp_client)));
      fp_service_info->mp_group = 0;
      return;
    }
  }


  // add entries to the group if it's empty
  int ret;
  if (avahi_entry_group_is_empty(fp_service_info->mp_group))
  {
    if ((ret = avahi_entry_group_add_service_strlst(fp_service_info->mp_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0),
                                             fp_service_info->m_name.c_str(),
                                             fp_service_info->m_type.c_str(), NULL, NULL, fp_service_info->m_port, fp_service_info->mp_txt)) < 0)
    {
      if (ret == AVAHI_ERR_COLLISION)
      {
        char* alt_name = avahi_alternative_service_name(fp_service_info->m_name.c_str());
        fp_service_info->m_name = alt_name;
        avahi_free(alt_name);
        CLog::Log(LOGNOTICE, "CZeroconfAvahi::addService: Service name collision. Renamed to: %s", fp_service_info->m_name.c_str());
        addService(fp_service_info, fp_client);
        return;
      }
      CLog::Log(LOGERROR, "CZeroconfAvahi::addService(): failed to add service named:%s@$(HOSTNAME) type:%s port:%i. Error:%s :/ FIXME!",
                fp_service_info->m_name.c_str(), fp_service_info->m_type.c_str(), fp_service_info->m_port,  avahi_strerror(ret));
      return;
    }
  }

  // Tell the server to register the service
  if ((ret = avahi_entry_group_commit(fp_service_info->mp_group)) < 0)
  {
    CLog::Log(LOGERROR, "CZeroconfAvahi::addService(): Failed to commit entry group! Error:%s",  avahi_strerror(ret));
    //! @todo what now? reset the group? free it?
  }
}
static void resolver_cb(
        AvahiServiceResolver *r,
        AvahiIfIndex interface, AvahiProtocol protocol,
        AvahiResolverEvent event,
        const char *name, const char *type, const char *domain,
        const char *host_name, const AvahiAddress *a, uint16_t port,
        AvahiStringList *txt,
        AvahiLookupResultFlags flags,
        void *userdata) {
    struct userdata *u = userdata;
    struct tunnel *tnl;
    char *device = NULL, *nicename, *dname, *vname, *args;
    char *tp = NULL, *et = NULL, *cn = NULL;
    char *ch = NULL, *ss = NULL, *sr = NULL;
    char *t = NULL;
    char at[AVAHI_ADDRESS_STR_MAX];
    AvahiStringList *l;
    pa_module *m;

    pa_assert(u);

    tnl = tunnel_new(interface, protocol, name, type, domain);

    if (event != AVAHI_RESOLVER_FOUND) {
        pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client)));
        goto finish;
    }

    if ((nicename = strstr(name, "@"))) {
        ++nicename;
        if (strlen(nicename) > 0) {
            pa_log_debug("Found RAOP: %s", nicename);
            nicename = pa_escape(nicename, "\"'");
        } else
            nicename = NULL;
    }

    for (l = txt; l; l = l->next) {
        char *key, *value;
        pa_assert_se(avahi_string_list_get_pair(l, &key, &value, NULL) == 0);

        pa_log_debug("Found key: '%s' with value: '%s'", key, value);
        if (pa_streq(key, "device")) {
            device = value;
            value = NULL;
        } else if (pa_streq(key, "tp")) {
            /* Transport protocol:
             *  - TCP = only TCP,
             *  - UDP = only UDP,
             *  - TCP,UDP = both supported (UDP should be prefered) */
            pa_xfree(tp);
            if (pa_str_in_list(value, ",", "UDP"))
                tp = pa_xstrdup("UDP");
            else if (pa_str_in_list(value, ",", "TCP"))
                tp = pa_xstrdup("TCP");
            else
                tp = pa_xstrdup(value);
        } else if (pa_streq(key, "et")) {
            /* Supported encryption types:
             *  - 0 = none,
             *  - 1 = RSA,
             *  - 2 = FairPlay,
             *  - 3 = MFiSAP,
             *  - 4 = FairPlay SAPv2.5. */
            pa_xfree(et);
            if (pa_str_in_list(value, ",", "1"))
                et = pa_xstrdup("RSA");
            else
                et = pa_xstrdup("none");
        } else if (pa_streq(key, "cn")) {
            /* Suported audio codecs:
             *  - 0 = PCM,
             *  - 1 = ALAC,
             *  - 2 = AAC,
             *  - 3 = AAC ELD. */
            pa_xfree(cn);
            if (pa_str_in_list(value, ",", "1"))
                cn = pa_xstrdup("ALAC");
            else
                cn = pa_xstrdup("PCM");
        } else if (pa_streq(key, "md")) {
            /* Supported metadata types:
             *  - 0 = text,
             *  - 1 = artwork,
             *  - 2 = progress. */
        } else if (pa_streq(key, "pw")) {
            /* Requires password ? (true/false) */
        } else if (pa_streq(key, "ch")) {
            /* Number of channels */
            pa_xfree(ch);
            ch = pa_xstrdup(value);
        } else if (pa_streq(key, "ss")) {
            /* Sample size */
            pa_xfree(ss);
            ss = pa_xstrdup(value);
        } else if (pa_streq(key, "sr")) {
            /* Sample rate */
            pa_xfree(sr);
            sr = pa_xstrdup(value);
        }

        avahi_free(key);
        avahi_free(value);
    }

    if (device)
        dname = pa_sprintf_malloc("raop_output.%s.%s", host_name, device);
    else
        dname = pa_sprintf_malloc("raop_output.%s", host_name);

    if (!(vname = pa_namereg_make_valid_name(dname))) {
        pa_log("Cannot construct valid device name from '%s'.", dname);
        avahi_free(device);
        pa_xfree(dname);
        pa_xfree(tp);
        pa_xfree(et);
        pa_xfree(cn);
        pa_xfree(ch);
        pa_xfree(ss);
        pa_xfree(sr);
        goto finish;
    }

    avahi_free(device);
    pa_xfree(dname);

    avahi_address_snprint(at, sizeof(at), a);
    if (nicename) {
        args = pa_sprintf_malloc("server=[%s]:%u "
                                 "sink_name=%s "
                                 "sink_properties='device.description=\"%s (%s:%u)\"'",
                                 at, port,
                                 vname,
                                 nicename, at, port);
        pa_xfree(nicename);
    } else {
        args = pa_sprintf_malloc("server=[%s]:%u "
                                 "sink_name=%s"
                                 "sink_properties='device.description=\"%s:%u\"'",
                                 at, port,
                                 vname,
                                 at, port);
    }

    if (tp != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s protocol=%s", args, tp);
        pa_xfree(tp);
        pa_xfree(t);
    }
    if (et != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s encryption=%s", args, et);
        pa_xfree(et);
        pa_xfree(t);
    }
    if (cn != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s codec=%s", args, cn);
        pa_xfree(cn);
        pa_xfree(t);
    }
    if (ch != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s channels=%s", args, ch);
        pa_xfree(ch);
        pa_xfree(t);
    }
    if (ss != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s format=%s", args, ss);
        pa_xfree(ss);
        pa_xfree(t);
    }
    if (sr != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s rate=%s", args, sr);
        pa_xfree(sr);
        pa_xfree(t);
    }

    pa_log_debug("Loading module-raop-sink with arguments '%s'", args);

    if ((m = pa_module_load(u->core, "module-raop-sink", args))) {
        tnl->module_index = m->index;
        pa_hashmap_put(u->tunnels, tnl, tnl);
        tnl = NULL;
    }

    pa_xfree(vname);
    pa_xfree(args);

finish:
    avahi_service_resolver_free(r);

    if (tnl)
        tunnel_free(tnl);
}
Esempio n. 7
0
static void host_name_resolver_callback(
    AvahiHostNameResolver *r,
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
    AvahiResolverEvent event,
    const char *name,
    const AvahiAddress *a,
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    AVAHI_GCC_UNUSED void *userdata) {

    assert(r);

    switch (event) {
        case AVAHI_RESOLVER_FOUND: {
            char address[AVAHI_ADDRESS_STR_MAX];

            avahi_address_snprint(address, sizeof(address), a);

            printf("%s\t%s\n", name, address);

            break;
        }

        case AVAHI_RESOLVER_FAILURE:

            fprintf(stderr, _("Failed to resolve host name '%s': %s\n"), name, avahi_strerror(avahi_client_errno(client)));
            break;
    }


    avahi_host_name_resolver_free(r);

    assert(n_resolving > 0);
    n_resolving--;

    if (n_resolving <= 0)
        avahi_simple_poll_quit(simple_poll);
}
void NetworkServicesProviderAvahi::serviceBrowserCallback(
    AVAHI_GCC_UNUSED AvahiServiceBrowser* b,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiBrowserEvent event,
    const char* name,
    const char* type,
    const char* domain,
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    void* userdata) 
{
    NetworkServicesProviderAvahi* p = static_cast<NetworkServicesProviderAvahi*>(userdata);

    ASSERT(b);
    ASSERT(p);

    switch (event) {
    case AVAHI_BROWSER_NEW: 
        {
            ServiceInfo* info;

            printServiceLine('+', interface, protocol, name, type, domain);

            if ((info = p->findService(interface, protocol, name, type, domain))) {
                char* id;
                NetworkServiceDescription* desc;
                
                if (!(info->notify))
                    return;

                id = (char*) avahi_malloc(strlen(name) + strlen(type) + strlen(domain) + 4);
                sprintf(id, "%s.%s.%s.", name, type, domain);
                desc = p->getServiceDescriptionById(String::fromUTF8(id));
                if (desc) {
                    desc->setOnline(true);
                    p->notifyNetworkServiceChanged(desc);
                }
                avahi_free(id);
                info->notify = false;

                return;
            }

            p->addServiceInfo(interface, protocol, name, type, domain);

            break;

        }

    case AVAHI_BROWSER_REMOVE: 
        {
            ServiceInfo* info;

            if (!(info = p->findService(interface, protocol, name, type, domain)))
                return;

            if (info->notify) {
                p->removeServiceInfo(info);
                info->notify = false;
            }

            printServiceLine('-', interface, protocol, name, type, domain);
            break;
        }

    case AVAHI_BROWSER_FAILURE:
        LOG_ERROR("service_browser failed: %s\n", avahi_strerror(avahi_client_errno(p->m_avahiClient)));
        break;

    case AVAHI_BROWSER_CACHE_EXHAUSTED:
        break;

    case AVAHI_BROWSER_ALL_FOR_NOW:
        p->m_allForNow--;
        p->checkTerminate();
        break;
    }
}
Esempio n. 9
0
static void
browse_resolve_callback(AvahiServiceResolver *r, AvahiIfIndex intf, AvahiProtocol proto, AvahiResolverEvent event,
			const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *addr,
			uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata)
{
  char address[AVAHI_ADDRESS_STR_MAX + IF_NAMESIZE + 2];
  char ifname[IF_NAMESIZE];
  struct keyval txt_kv;
  struct mdns_browser *mb;
  char *key;
  char *value;
  size_t len;
  int family;
  int ll;
  int ret;

  mb = (struct mdns_browser *)userdata;

  switch (event)
    {
      case AVAHI_RESOLVER_FAILURE:
	DPRINTF(E_LOG, L_MDNS, "Avahi Resolver failure: service '%s' type '%s': %s\n", name, type,
		avahi_strerror(avahi_client_errno(mdns_client)));
	break;

      case AVAHI_RESOLVER_FOUND:
	DPRINTF(E_DBG, L_MDNS, "Avahi Resolver: resolved service '%s' type '%s' proto %d\n", name, type, proto);

	// KK - if I reject 192.168.* my AirTunes get rejected.
	// How does avahi passes multiple IP addresses?
	// ll = is_link_local(addr);
	ll = 0;

	switch (proto)
	  {
	    case AVAHI_PROTO_INET:
		    avahi_record_browser_new()
	      if (ll)
		{
		  family = AF_UNSPEC;

		  DPRINTF(E_DBG, L_MDNS, "Discarding IPv4 LL address\n");
		  break;
		}

	      family = AF_INET;
	      avahi_address_snprint(address, sizeof(address), addr);
	      break;

	    case AVAHI_PROTO_INET6:
	      avahi_address_snprint(address, sizeof(address), addr);

	      if (ll)
		{
		  DPRINTF(E_DBG, L_MDNS, "Appending interface name to IPv6 LL address\n");

		  if (!if_indextoname(intf, ifname))
		    {
		      DPRINTF(E_LOG, L_MDNS, "Could not map interface index %d to a name\n", intf);

		      family = AF_UNSPEC;
		      break;
		    }

		  len = strlen(address);
		  ret = snprintf(address + len, sizeof(address) - len, "%%%s", ifname);
		  if ((ret < 0) || (ret > sizeof(address) - len))
		    {
		      DPRINTF(E_LOG, L_MDNS, "Buffer too short for scoped IPv6 LL\n");

		      family = AF_UNSPEC;
		      break;
		    }

		  DPRINTF(E_DBG, L_MDNS, "Scoped IPv6 LL: %s\n", address);
		}

	      family = AF_INET6;
	      break;

	    default:
	      DPRINTF(E_INFO, L_MDNS, "Avahi Resolver: unknown protocol %d\n", proto);

	      family = AF_UNSPEC;
	      break;
	  }

	if (family == AF_UNSPEC)
	  break;

	memset(&txt_kv, 0, sizeof(struct keyval));

	while (txt)
	  {
	    len = avahi_string_list_get_size(txt);
	    key = (char *)avahi_string_list_get_text(txt);

	    value = memchr(key, '=', len);
	    if (!value)
	      {
		value = "";
		len = 0;
	      }
	    else
	      {
		*value = '\0';
		value++;

		len -= strlen(key) + 1;
	      }

	    ret = keyval_add_size(&txt_kv, key, value, len);
	    if (ret < 0)
	      {
		DPRINTF(E_LOG, L_MDNS, "Could not build TXT record keyval\n");

		goto out_clear_txt_kv;
	      }

	    txt = avahi_string_list_get_next(txt);
	  }

	/* Execute callback (mb->cb) with all the data */
	mb->cb(name, type, domain, hostname, family, address, port, &txt_kv);

    out_clear_txt_kv:
	keyval_clear(&txt_kv);
	break;
    }

  avahi_service_resolver_free(r);
}
Esempio n. 10
0
static void browse_callback(
    AvahiServiceBrowser *b,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiBrowserEvent event,
    const char *name,
    const char *type,
    const char *domain,
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    void* userdata) {
    
    AvahiClient *c = userdata;
    const AvahiPoll *api = avahi_simple_poll_get (simple_poll);
    struct timeval *tv;

    assert(b);

    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */

    switch (event) {
        case AVAHI_BROWSER_FAILURE:
            
            fprintf(stderr, "(Browser) %s\n", 
					avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
            avahi_simple_poll_quit(simple_poll);
            return;

        case AVAHI_BROWSER_NEW:
            /* Count the pending resolvers so we know when we can quit. */
            n_pending_resolvers++;

            /* We ignore the returned resolver object. In the callback
               function we free it. If the server is terminated before
               the callback function is called the server will free
               the resolver for us. */

            if (!(avahi_service_resolver_new(c, interface, 
											 protocol, name, 
											 type, domain, 
											 AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
                fprintf(stderr, "Failed to resolve service '%s': %s\n", 
						name, avahi_strerror(avahi_client_errno(c)));
            
            break;

        case AVAHI_BROWSER_REMOVE:
			break;
        case AVAHI_BROWSER_ALL_FOR_NOW:
            /* The all for now event is emitted when each published service was
               announced by the new event (handled above). But there still might
               be some pending resolvers, so we have to wait for the resolvers
               to be finished, before quitting the main loop. */

            tv = avahi_malloc0 (sizeof (struct timeval));
            avahi_elapse_time (tv, 200, 0);
            api->timeout_new (api, tv, timeout_callback, tv);
            break;
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
            break;
    }
}
void NetworkServicesProviderAvahi::serviceResolverCallback(
    AVAHI_GCC_UNUSED AvahiServiceResolver* r,
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
    AvahiResolverEvent event,
    const char* name,
    const char* type,
    const char* domain,
    const char* hostName,
    const AvahiAddress* a,
    AVAHI_GCC_UNUSED uint16_t port,
    AvahiStringList* txt,
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    void* userdata) 
{
    ServiceInfo* i = static_cast<ServiceInfo*>(userdata);
    NetworkServicesProviderAvahi* p = i->provider;

    ASSERT(r);
    ASSERT(i);

    switch (event) {
    case AVAHI_RESOLVER_FOUND: 
        {
            NetworkServiceDescription* desc;
            char address[AVAHI_ADDRESS_STR_MAX];
            char* id;
            char* ztype;
            char* url;
            char* config;

            avahi_address_snprint(address, sizeof(address), a);

            config = avahi_string_list_to_string(txt);

            printServiceLine('=', interface, protocol, name, type, domain);

            LOG(Network,
                "   hostname = [%s]\n"
                "   address = [%s]\n"
                "   port = [%u]\n"
                "   txt = [%s]\n",
                hostName,
                address,
                port,
                config);
    
            id = (char*) avahi_malloc(strlen(name) + strlen(type) + strlen(domain) + 4);
            sprintf(id, "%s.%s.%s.", name, type, domain);

            ztype = (char*) avahi_malloc(strlen(type) + strlen("zeroconf:") + 1);
            sprintf(ztype, "zeroconf:%s", type);

            url = (char*) avahi_malloc(strlen("http://") + strlen(hostName) + 1);
            sprintf(url, "http://%s", hostName);

            if (!(desc = p->getServiceDescriptionById(String::fromUTF8(id))))
                p->addServiceDescription(id, name, ztype, url, config);
            else {
                desc->setOnline(true);
                p->notifyNetworkServiceChanged(desc);
            }

            avahi_free(id);
            avahi_free(ztype);
            avahi_free(url);
            avahi_free(config);

            break;
        }

    case AVAHI_RESOLVER_FAILURE:

        LOG_ERROR("Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(p->m_avahiClient)));
        break;
    }

    avahi_service_resolver_free(i->resolver);
    i->resolver = 0;

    p->m_resolving--;
    p->checkTerminate();
}
Esempio n. 12
0
static void resolve_callback(
    AvahiServiceResolver *r,
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
    AvahiResolverEvent event,
    const char *name,
    const char *type,
    const char *domain,
    const char *host_name,
    const AvahiAddress *address,
    uint16_t port,
    AvahiStringList *txt,
    AvahiLookupResultFlags flags,
    AVAHI_GCC_UNUSED void* userdata) {

    assert(r);

    /* Called whenever a service has been resolved successfully or timed out */

    switch (event) {
        case AVAHI_RESOLVER_FAILURE:
            fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
            break;

        case AVAHI_RESOLVER_FOUND: {
            char a[AVAHI_ADDRESS_STR_MAX];
            
            fprintf(stderr, "XMMS2 running on '%s@%s'\n", name, domain);
            
            avahi_address_snprint(a, sizeof(a), address);
			fprintf(stderr, "tcp://%s:%u\n", a, port);
        }
    }

    n_pending_resolvers--;
    avahi_service_resolver_free(r);
}
Esempio n. 13
0
int main( AVAHI_GCC_UNUSED int argc, char *argv[] )
{
    AvahiClient *client = NULL;
    AvahiServiceBrowser *serviceBrowser = NULL;
    char       *myName;
    int         error;
    int         result = 1;
    TiVoUnit   *tivo;

    myName = strrchr(argv[0], '/') + 1;
    if (myName == (NULL+1))
        myName = argv[0];

    openlog( myName, LOG_PID, LOG_DAEMON );
    loginfo("started");

    /* must be done before any threads start */
    curl_global_init( CURL_GLOBAL_ALL );

    /* Allocate main loop object */
    bonjourThread = avahi_threaded_poll_new();
    if ( !bonjourThread )
    {
        logerror( "Failed to create threaded poll object." );
    }
    else
    {
        /* Allocate a new client */
        client = avahi_client_new( avahi_threaded_poll_get( bonjourThread ), 0, client_callback, NULL, &error );

        /* Check wether creating the client object succeeded */
        if ( !client )
        {
            logerror( "Unable to create client: %s", avahi_strerror( error ) );
        }
        else
        {
            /* Create the service browser */
            serviceBrowser = avahi_service_browser_new( client,
                                                        AVAHI_IF_UNSPEC,
                                                        AVAHI_PROTO_UNSPEC,
                                                        "_tivo-device._tcp",
                                                        NULL, 0,
                                                        browseCallback, client );
            if ( !serviceBrowser )
            {
                logerror( "Unable to create service browser: %s", avahi_strerror( avahi_client_errno( client ) ) );
            }
            else
            {
                /* start the background network scan for TiVos */
                avahi_threaded_poll_start( bonjourThread );

                /* hack: wait for some results to arrive */
                sleep(5);
                /* what did we find? */
                result = dumpTiVos();

                avahi_threaded_poll_stop( bonjourThread );
                avahi_service_browser_free( serviceBrowser );
            }
            avahi_client_free( client );
        }
        avahi_threaded_poll_free( bonjourThread );
    }

    /* docs say no other threads may be running */
    curl_global_cleanup();

    loginfo( "stopped" );
    closelog();

    return result;
}
Esempio n. 14
0
static void browseCallback( AvahiServiceBrowser *b,
                            AvahiIfIndex interface,
                            AvahiProtocol protocol,
                            AvahiBrowserEvent event,
                            const char *name,
                            const char *type,
                            const char *domain,
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
                            void* userdata )
{
    AvahiClient *c = userdata;
    TiVoUnit    *tivo, *prev, *next;

    /* Called whenever a new tivo becomes available on the LAN or is removed from the LAN */

    switch (event)
    {
    case AVAHI_BROWSER_NEW:  /* detected a new TiVo on the LAN */

        tivo = rememberTiVo( name );

        /* We don't save the resolver object returned by avahi_service_resolver_new().
           Instead, when the resolver calls the callback function with the results, the new
           TiVoUnit is added, then the resolver is freed. If the server terminates before
           the callback function is called, the server will free the resolver for us. */

        if ( !avahi_service_resolver_new( c, interface, protocol,
                                          name, type, domain,
                                          AVAHI_PROTO_UNSPEC, 0,
                                          resolveCallback, tivo) )
        {
            logerror( "Failed to resolve service '%s': %s", name, avahi_strerror(avahi_client_errno(c)) );
        }
        break;

    case AVAHI_BROWSER_REMOVE:  /* a TiVo disappeared from the LAN */

        loginfo( "TiVo '%s' disappeared from network", name );

        /*-- begin critical section --*/
        prev = NULL;
        tivo = tivoUnits;
        while ( tivo != NULL )
        {
            next = tivo->next;
            if ( !strcmp( tivo->name, name ) )
            {   /* found it, so unlink it */
                if ( prev == NULL )
                     tivoUnits  = next;
                else prev->next = next;
                /* prev itself stays put */
                forgetTiVo( tivo );
            }
            else prev = tivo;

            tivo = next;
        }
        /*-- end critical section --*/
        break;

    case AVAHI_BROWSER_CACHE_EXHAUSTED:
        loginfo( "(Browser) cache exhausted" );
        break;

    case AVAHI_BROWSER_ALL_FOR_NOW:
        loginfo( "(Browser) all for now" );
        break;

    case AVAHI_BROWSER_FAILURE:
        logerror( "(Browser) %s", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))) );
        avahi_threaded_poll_quit( bonjourThread );
        return;
    }
}
Esempio n. 15
0
static void
client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata)
{
  struct mdns_browser *mb;
  AvahiServiceBrowser *b;
  int error;

  switch (state)
    {
      case AVAHI_CLIENT_S_RUNNING:
        DPRINTF(E_LOG, L_MDNS, "Avahi state change: Client running\n");
        if (!mdns_group)
	  _create_services();

	for (mb = browser_list; mb; mb = mb->next)
	  {
	    b = avahi_service_browser_new(mdns_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, mb->type, NULL, 0, browse_callback, mb);
	    if (!b)
	      {
		DPRINTF(E_LOG, L_MDNS, "Failed to recreate service browser (service type %s): %s\n", mb->type,
			avahi_strerror(avahi_client_errno(mdns_client)));
	      }
	  }
        break;

      case AVAHI_CLIENT_S_COLLISION:
        DPRINTF(E_LOG, L_MDNS, "Avahi state change: Client collision\n");
        if(mdns_group)
	  avahi_entry_group_reset(mdns_group);
        break;

      case AVAHI_CLIENT_FAILURE:
        DPRINTF(E_LOG, L_MDNS, "Avahi state change: Client failure\n");

	error = avahi_client_errno(c);
	if (error == AVAHI_ERR_DISCONNECTED)
	  {
	    DPRINTF(E_LOG, L_MDNS, "Avahi Server disconnected, reconnecting\n");

	    avahi_client_free(mdns_client);
	    mdns_group = NULL;

	    mdns_client = avahi_client_new(&ev_poll_api, AVAHI_CLIENT_NO_FAIL,
					   client_callback, NULL, &error);
	    if (!mdns_client)
	      {
		DPRINTF(E_LOG, L_MDNS, "Failed to create new Avahi client: %s\n",
			avahi_strerror(error));
	      }
	  }
	else
	  {
	    DPRINTF(E_LOG, L_MDNS, "Avahi client failure: %s\n", avahi_strerror(error));
	  }
        break;

      case AVAHI_CLIENT_S_REGISTERING:
        DPRINTF(E_LOG, L_MDNS, "Avahi state change: Client registering\n");
        if (mdns_group)
	  avahi_entry_group_reset(mdns_group);
        break;

      case AVAHI_CLIENT_CONNECTING:
        DPRINTF(E_LOG, L_MDNS, "Avahi state change: Client connecting\n");
        break;
    }
}
Esempio n. 16
0
void CZeroconfBrowserAvahi::browseCallback (
  AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event,
  const char *name, const char *type, const char *domain,
  AvahiLookupResultFlags flags, void* fp_data )
{
  CZeroconfBrowserAvahi* p_instance = static_cast<CZeroconfBrowserAvahi*> ( fp_data );
  assert ( browser );
  bool update_gui = false;
  /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
  switch ( event )
  {
    case AVAHI_BROWSER_FAILURE:
      CLog::Log ( LOGERROR, "CZeroconfBrowserAvahi::browseCallback error: %s\n", avahi_strerror ( avahi_client_errno ( avahi_service_browser_get_client ( browser ) ) ) );
      //TODO
      return;
    case AVAHI_BROWSER_NEW:
      {
        CLog::Log ( LOGDEBUG, "CZeroconfBrowserAvahi::browseCallback NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain );
        //store the service
        ZeroconfService service(name, type, domain);
        AvahiSpecificInfos info;
        info.interface = interface;
        info.protocol = protocol;
        p_instance->m_discovered_services.insert ( std::make_pair ( service, info ) );
        //if this browser already sent the all for now message, we need to update the gui now
        if( p_instance->m_all_for_now_browsers.find(browser) != p_instance->m_all_for_now_browsers.end() )
          update_gui = true;
        break;
      }
    case AVAHI_BROWSER_REMOVE:
      {
        //remove the service
        ZeroconfService service(name, type, domain);
        p_instance->m_discovered_services.erase ( service );
        CLog::Log ( LOGDEBUG, "CZeroconfBrowserAvahi::browseCallback REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain );
        //if this browser already sent the all for now message, we need to update the gui now
        if( p_instance->m_all_for_now_browsers.find(browser) != p_instance->m_all_for_now_browsers.end() )
          update_gui = true;
        break;
      }
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
      //do we need that?
      break;
    case AVAHI_BROWSER_ALL_FOR_NOW:
      CLog::Log ( LOGDEBUG, "CZeroconfBrowserAvahi::browseCallback all for now (service = %s)", type);
      //if this browser already sent the all for now message, we need to update the gui now
      bool success = p_instance->m_all_for_now_browsers.insert(browser).second;
      if(!success)
        CLog::Log ( LOGDEBUG, "CZeroconfBrowserAvahi::browseCallback AVAHI_BROWSER_ALL_FOR_NOW sent twice?!");
      update_gui = true;
      break;
  }
  if ( update_gui )
  {
    CGUIMessage message ( GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH );
    message.SetStringParam ( "zeroconf://" );
    g_windowManager.SendThreadMessage ( message );
    CLog::Log ( LOGDEBUG, "CZeroconfBrowserAvahi::browseCallback sent gui update for path zeroconf://" );
  }
}
static void resolve_callback(
    AvahiServiceResolver *r,
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
    AvahiResolverEvent event,
    const char *name,
    const char *type,
    const char *domain,
    const char *host_name,
    const AvahiAddress *address,
    uint16_t port,
    AvahiStringList *txt,
    AvahiLookupResultFlags flags,
    AVAHI_GCC_UNUSED void* userdata) {

    assert(r);

    /* Called whenever a service has been resolved successfully or timed out */

    switch (event) {
        case AVAHI_RESOLVER_FAILURE:
            fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
            break;

        case AVAHI_RESOLVER_FOUND: {
            char a[AVAHI_ADDRESS_STR_MAX], *t;

            fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);

            avahi_address_snprint(a, sizeof(a), address);
            t = avahi_string_list_to_string(txt);
            fprintf(stderr,
                    "\t%s:%u (%s)\n"
                    "\tTXT=%s\n"
                    "\tcookie is %u\n"
                    "\tis_local: %i\n"
                    "\tour_own: %i\n"
                    "\twide_area: %i\n"
                    "\tmulticast: %i\n"
                    "\tcached: %i\n",
                    host_name, port, a,
                    t,
                    avahi_string_list_get_service_cookie(txt),
                    !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
                    !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
                    !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
                    !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
                    !!(flags & AVAHI_LOOKUP_RESULT_CACHED));

            avahi_free(t);
        }
    }

    avahi_service_resolver_free(r);
}
Esempio n. 18
0
void CZeroconfBrowserAvahi::resolveCallback(
  AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event,
  const char *name, const char *type, const char *domain, const char *host_name,
  const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata )
{
  assert ( r );
  assert ( userdata );
  CZeroconfBrowserAvahi* p_instance = static_cast<CZeroconfBrowserAvahi*> ( userdata );
  switch ( event )
  {
    case AVAHI_RESOLVER_FAILURE:
      CLog::Log ( LOGERROR, "CZeroconfBrowserAvahi::resolveCallback Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror ( avahi_client_errno ( avahi_service_resolver_get_client ( r ) ) ) );
      break;
    case AVAHI_RESOLVER_FOUND:
    {
      char a[AVAHI_ADDRESS_STR_MAX];
      CLog::Log ( LOGDEBUG, "CZeroconfBrowserAvahi::resolveCallback resolved service '%s' of type '%s' in domain '%s':\n", name, type, domain );

      avahi_address_snprint ( a, sizeof ( a ), address );
      p_instance->m_resolving_service.SetIP(a);
      p_instance->m_resolving_service.SetPort(port);
      //get txt-record list
      p_instance->m_resolving_service.SetTxtRecords(GetTxtRecords(txt));
      break;
    }
  }
  avahi_service_resolver_free ( r );
  p_instance->m_resolved_event.Set();
}
Esempio n. 19
0
int main(int argc, char *argv[]) {
    int ret = 1, error;
    Config config;
    const char *argv0;

    avahi_init_i18n();
    setlocale(LC_ALL, "");

    if ((argv0 = strrchr(argv[0], '/')))
        argv0++;
    else
        argv0 = argv[0];

    if (parse_command_line(&config, argv0, argc, argv) < 0)
        goto fail;

    switch (config.command) {
        case COMMAND_UNSPEC:
            ret = 1;
            fprintf(stderr, _("No command specified.\n"));
            break;

        case COMMAND_HELP:
            help(stdout, argv0);
            ret = 0;
            break;

        case COMMAND_VERSION:
            printf("%s "PACKAGE_VERSION"\n", argv0);
            ret = 0;
            break;

        case COMMAND_RESOLVE_HOST_NAME:
        case COMMAND_RESOLVE_ADDRESS: {
            int i;

            if (!(simple_poll = avahi_simple_poll_new())) {
                fprintf(stderr, _("Failed to create simple poll object.\n"));
                goto fail;
            }

            if (sigint_install(simple_poll) < 0)
                goto fail;

            if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error))) {
                fprintf(stderr, _("Failed to create client object: %s\n"), avahi_strerror(error));
                goto fail;
            }

            if (config.verbose) {
                const char *version, *hn;

                if (!(version = avahi_client_get_version_string(client))) {
                    fprintf(stderr, _("Failed to query version string: %s\n"), avahi_strerror(avahi_client_errno(client)));
                    goto fail;
                }

                if (!(hn = avahi_client_get_host_name_fqdn(client))) {
                    fprintf(stderr, _("Failed to query host name: %s\n"), avahi_strerror(avahi_client_errno(client)));
                    goto fail;
                }

                fprintf(stderr, _("Server version: %s; Host name: %s\n"), version, hn);
            }

            n_resolving = 0;

            for (i = optind; i < argc; i++) {

                if (config.command == COMMAND_RESOLVE_HOST_NAME) {

                    if (!(avahi_host_name_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, argv[i], config.proto, 0, host_name_resolver_callback, NULL))) {
                        fprintf(stderr, _("Failed to create host name resolver: %s\n"), avahi_strerror(avahi_client_errno(client)));
                        goto fail;
                    }

                } else {
                    AvahiAddress a;

                    assert(config.command == COMMAND_RESOLVE_ADDRESS);

                    if (!avahi_address_parse(argv[i], AVAHI_PROTO_UNSPEC, &a)) {
                        fprintf(stderr, _("Failed to parse address '%s'\n"), argv[i]);
                        goto fail;
                    }

                    if (!(avahi_address_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, &a, 0, address_resolver_callback, NULL))) {
                        fprintf(stderr, _("Failed to create address resolver: %s\n"), avahi_strerror(avahi_client_errno(client)));
                        goto fail;
                    }
                }

                n_resolving++;
            }

            avahi_simple_poll_loop(simple_poll);
            ret = 0;
            break;
        }
    }

fail:

    if (client)
        avahi_client_free(client);

    sigint_uninstall();

    if (simple_poll)
        avahi_simple_poll_free(simple_poll);

    return ret;
}
int main(int argc, char *argv[]) {
    int ret = 1, error;
    Config config;
    const char *argv0;

    if ((argv0 = strrchr(argv[0], '/')))
        argv0++;
    else
        argv0 = argv[0];

    if (parse_command_line(&config, argv0, argc, argv) < 0)
        goto fail;

    switch (config.command) {
        case COMMAND_UNSPEC:
            ret = 1;
            fprintf(stderr, "No command specified.\n");
            break;
            
        case COMMAND_HELP:
            help(stdout, argv0);
            ret = 0;
            break;
            
        case COMMAND_VERSION:
            printf("%s "PACKAGE_VERSION"\n", argv0);
            ret = 0;
            break;

        case COMMAND_PUBLISH_SERVICE:
        case COMMAND_PUBLISH_ADDRESS:
            
            if (!(simple_poll = avahi_simple_poll_new())) {
                fprintf(stderr, "Failed to create simple poll object.\n");
                goto fail;
            }
            
            if (sigint_install(simple_poll) < 0)
                goto fail;
            
            if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), config.no_fail ? AVAHI_CLIENT_NO_FAIL : 0, client_callback, &config, &error))) {
                fprintf(stderr, "Failed to create client object: %s\n", avahi_strerror(error));
                goto fail;
            }

            if (avahi_client_get_state(client) != AVAHI_CLIENT_CONNECTING && config.verbose) {
                const char *version, *hn;

                if (!(version = avahi_client_get_version_string(client))) {
                    fprintf(stderr, "Failed to query version string: %s\n", avahi_strerror(avahi_client_errno(client)));
                    goto fail;
                }

                if (!(hn = avahi_client_get_host_name_fqdn(client))) {
                    fprintf(stderr, "Failed to query host name: %s\n", avahi_strerror(avahi_client_errno(client)));
                    goto fail;
                }
                
                fprintf(stderr, "Server version: %s; Host name: %s\n", version, hn);
            }

            avahi_simple_poll_loop(simple_poll);
            ret = 0;
            break;
    }
    
fail:

    if (client)
        avahi_client_free(client);

    sigint_uninstall();
    
    if (simple_poll)
        avahi_simple_poll_free(simple_poll);

    avahi_free(config.host);
    avahi_free(config.name);
    avahi_free(config.stype);
    avahi_free(config.domain);
    avahi_string_list_free(config.subtypes);
    avahi_string_list_free(config.txt);

    return ret;
}
Esempio n. 21
0
static void
create_service (AurAvahi * avahi)
{
  AurAvahiPrivate *priv = avahi->priv;
  int ret;

  do {
    if (priv->group == NULL) {
      priv->group =
          avahi_entry_group_new (priv->client, entry_group_callback, avahi);
      if (priv->group == NULL) {
        g_critical ("avahi_entry_group_new() failed: %s\n",
            avahi_strerror (avahi_client_errno (priv->client)));
        goto fail;
      }
    }

    /* If the group is empty (either because it was just created, or
     * because it was reset previously, add our entries.  */
    if (avahi_entry_group_is_empty (priv->group)) {
      g_message ("Adding service '%s' on port %d", priv->service_name, priv->port);

      ret =
          avahi_entry_group_add_service (priv->group, AVAHI_IF_UNSPEC,
          AVAHI_PROTO_UNSPEC, 0, priv->service_name, "_aurena._tcp", NULL,
          NULL, priv->port, NULL);
      if (ret < 0) {
        if (ret == AVAHI_ERR_COLLISION) {
          /* A service name collision with a local service happened. Let's
           * pick a new name */
          char *n = avahi_alternative_service_name (priv->service_name);
          g_free (priv->service_name);
          priv->service_name = n;
          g_message ("Service name collision, renaming service to '%s'\n",
              priv->service_name);
          avahi_entry_group_reset (priv->group);
          continue;
        } else {
          g_critical ("Failed to add _aurena._tcp service: %s",
              avahi_strerror (ret));
          goto fail;
        }
      }
#if 0
      /* Add an additional (hypothetic) subtype */
      if ((ret =
              avahi_entry_group_add_service_subtype (group, AVAHI_IF_UNSPEC,
                  AVAHI_PROTO_UNSPEC, 0, name, "_printer._tcp", NULL,
                  "_magic._sub._printer._tcp") < 0)) {
        fprintf (stderr,
            "Failed to add subtype _magic._sub._printer._tcp: %s\n",
            avahi_strerror (ret));
        goto fail;
      }
#endif

      if ((ret = avahi_entry_group_commit (priv->group)) < 0) {
        g_critical ("Failed to commit entry group: %s\n", avahi_strerror (ret));
      }
    }
    return;
  } while (TRUE);

fail:
  return;
}
Esempio n. 22
0
static void
browse_record_callback_v4(AvahiRecordBrowser *b, AvahiIfIndex intf, AvahiProtocol proto,
			  AvahiBrowserEvent event, const char *hostname, uint16_t clazz, uint16_t type,
			  const void *rdata, size_t size, AvahiLookupResultFlags flags, void *userdata)
{
  char address[INET_ADDRSTRLEN];
  struct in_addr addr;
  struct mdns_record_browser *rb_data;
  int ll;

  rb_data = (struct mdns_record_browser *)userdata;

  switch (event)
    {
      case AVAHI_BROWSER_NEW:
	if (size != sizeof(addr.s_addr))
	  {
	    DPRINTF(E_WARN, L_MDNS, "Got RR type A size %ld (should be %ld)\n", (long)size, (long)sizeof(addr.s_addr));

	    return;
	  }

	memcpy(&addr.s_addr, rdata, sizeof(addr.s_addr));

	ll = is_v4ll(&addr);
	if (ll && !(rb_data->mb->flags & MDNS_WANT_V4LL))
	  {
	    DPRINTF(E_DBG, L_MDNS, "Discarding IPv4 LL, not interested (service %s)\n", rb_data->name);
	    return;
	  }
	else if (!ll && !(rb_data->mb->flags & MDNS_WANT_V4))
	  {
	    DPRINTF(E_DBG, L_MDNS, "Discarding IPv4, not interested (service %s)\n", rb_data->name);
	    return;
	  }

	if (!inet_ntop(AF_INET, &addr.s_addr, address, sizeof(address)))
	  {
	    DPRINTF(E_LOG, L_MDNS, "Could not print IPv4 address: %s\n", strerror(errno));

	    return;
	  }

	DPRINTF(E_DBG, L_MDNS, "Service %s, hostname %s resolved to %s\n", rb_data->name, hostname, address);

	/* Execute callback (mb->cb) with all the data */
	rb_data->mb->cb(rb_data->name, rb_data->mb->type, rb_data->domain, hostname, AF_INET, address, rb_data->port, &rb_data->txt_kv);
	/* Got a suitable address, stop record browser */
	break;

      case AVAHI_BROWSER_REMOVE:
	/* Not handled - record browser lifetime too short for this to happen */
	return;

      case AVAHI_BROWSER_CACHE_EXHAUSTED:
      case AVAHI_BROWSER_ALL_FOR_NOW:
	DPRINTF(E_DBG, L_MDNS, "Avahi Record Browser (%s v4): no more results (%s)\n", hostname,
		(event == AVAHI_BROWSER_CACHE_EXHAUSTED) ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");	

	break;

      case AVAHI_BROWSER_FAILURE:
	DPRINTF(E_LOG, L_MDNS, "Avahi Record Browser (%s v4) failure: %s\n", hostname,
		avahi_strerror(avahi_client_errno(avahi_record_browser_get_client(b))));

	break;
    }

  keyval_clear(&rb_data->txt_kv);      
  free(rb_data->name);
  free(rb_data->domain);
  free(rb_data);

  avahi_record_browser_free(b);
}
Esempio n. 23
0
void CZeroconfAvahi::groupCallback(AvahiEntryGroup *fp_group, AvahiEntryGroupState f_state, void * fp_data)
{
  CZeroconfAvahi* p_instance = static_cast<CZeroconfAvahi*>(fp_data);
  //store our thread ID and check for shutdown -> check details in destructor
  p_instance->m_thread_id = pthread_self();
  if (p_instance->m_shutdown)
  {
    avahi_threaded_poll_quit(p_instance->mp_poll);
    return;
  }

  switch (f_state)
  {
  case AVAHI_ENTRY_GROUP_ESTABLISHED :
    // The entry group has been established successfully
    CLog::Log(LOGDEBUG, "CZeroconfAvahi::groupCallback: Service successfully established");
    break;

  case AVAHI_ENTRY_GROUP_COLLISION :
  {
    //need to find the ServiceInfo struct for this group
    tServiceMap::iterator it = p_instance->m_services.begin();
    for(; it != p_instance->m_services.end(); ++it)
    {
      if (it->second->mp_group == fp_group)
        break;
    }
    if( it != p_instance->m_services.end() ) {
      char* alt_name = avahi_alternative_service_name( it->second->m_name.c_str() );
      it->second->m_name = alt_name;
      avahi_free(alt_name);
      CLog::Log(LOGNOTICE, "CZeroconfAvahi::groupCallback: Service name collision. Renamed to: %s", it->second->m_name.c_str());
      p_instance->addService(it->second, p_instance->mp_client);
    }
    break;
  }

  case AVAHI_ENTRY_GROUP_FAILURE:
    CLog::Log(LOGERROR, "CZeroconfAvahi::groupCallback: Entry group failure: %s ",
              (fp_group) ?
              avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(fp_group)))
              : "Unknown");
    //free the group and set to 0 so it may be added later
    if (fp_group)
    {
      //need to find the ServiceInfo struct for this group
      tServiceMap::iterator it = p_instance->m_services.begin();
      for (; it != p_instance->m_services.end(); ++it)
      {
        if (it->second->mp_group == fp_group)
        {
          avahi_entry_group_free(it->second->mp_group);
          it->second->mp_group = 0;
          if (it->second->mp_txt)
          {
            avahi_string_list_free(it->second->mp_txt);
            it->second->mp_txt = NULL;
          }
          break;
        }
      }
    }
    break;

  case AVAHI_ENTRY_GROUP_UNCOMMITED:
  case AVAHI_ENTRY_GROUP_REGISTERING:
  default:
    break;
  }
}
Esempio n. 24
0
static void
browse_record_callback_v6(AvahiRecordBrowser *b, AvahiIfIndex intf, AvahiProtocol proto,
			  AvahiBrowserEvent event, const char *hostname, uint16_t clazz, uint16_t type,
			  const void *rdata, size_t size, AvahiLookupResultFlags flags, void *userdata)
{
  char address[INET6_ADDRSTRLEN + IF_NAMESIZE + 1];
  char ifname[IF_NAMESIZE];
  struct in6_addr addr;
  struct mdns_record_browser *rb_data;
  int ll;
  int len;
  int ret;

  rb_data = (struct mdns_record_browser *)userdata;

  switch (event)
    {
      case AVAHI_BROWSER_NEW:
	if (size != sizeof(addr.s6_addr))
	  {
	    DPRINTF(E_WARN, L_MDNS, "Got RR type AAAA size %ld (should be %ld)\n", (long)size, (long)sizeof(addr.s6_addr));

	    return;
	  }

	memcpy(&addr.s6_addr, rdata, sizeof(addr.s6_addr));

	ll = is_v6ll(&addr);
	if (ll && !(rb_data->mb->flags & MDNS_WANT_V6LL))
	  {
	    DPRINTF(E_DBG, L_MDNS, "Discarding IPv6 LL, not interested (service %s)\n", rb_data->name);
	    return;
	  }
	else if (!ll && !(rb_data->mb->flags & MDNS_WANT_V6))
	  {
	    DPRINTF(E_DBG, L_MDNS, "Discarding IPv6, not interested (service %s)\n", rb_data->name);
	    return;
	  }

	if (!inet_ntop(AF_INET6, &addr.s6_addr, address, sizeof(address)))
	  {
	    DPRINTF(E_LOG, L_MDNS, "Could not print IPv6 address: %s\n", strerror(errno));

	    return;
	  }

	if (ll)
	  {
	    if (!if_indextoname(intf, ifname))
	      {
		DPRINTF(E_LOG, L_MDNS, "Could not map interface index %d to a name\n", intf);

		return;
	      }

	    len = strlen(address);
	    ret = snprintf(address + len, sizeof(address) - len, "%%%s", ifname);
	    if ((ret < 0) || (ret > sizeof(address) - len))
	      {
		DPRINTF(E_LOG, L_MDNS, "Buffer too short for scoped IPv6 LL\n");

		return;
	      }
	  }

	DPRINTF(E_DBG, L_MDNS, "Service %s, hostname %s resolved to %s\n", rb_data->name, hostname, address);

	/* Execute callback (mb->cb) with all the data */
	rb_data->mb->cb(rb_data->name, rb_data->mb->type, rb_data->domain, hostname, AF_INET6, address, rb_data->port, &rb_data->txt_kv);
	/* Got a suitable address, stop record browser */
	break;

      case AVAHI_BROWSER_REMOVE:
	/* Not handled - record browser lifetime too short for this to happen */
	return;

      case AVAHI_BROWSER_CACHE_EXHAUSTED:
      case AVAHI_BROWSER_ALL_FOR_NOW:
	DPRINTF(E_DBG, L_MDNS, "Avahi Record Browser (%s v6): no more results (%s)\n", hostname,
		(event == AVAHI_BROWSER_CACHE_EXHAUSTED) ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");	

	break;

      case AVAHI_BROWSER_FAILURE:
	DPRINTF(E_LOG, L_MDNS, "Avahi Record Browser (%s v6) failure: %s\n", hostname,
		avahi_strerror(avahi_client_errno(avahi_record_browser_get_client(b))));

	break;
    }

  /* Cleanup when done/error */
  keyval_clear(&rb_data->txt_kv);      
  free(rb_data->name);
  free(rb_data->domain);
  free(rb_data);

  avahi_record_browser_free(b);
}
Esempio n. 25
0
void PublishAvahi::create_services(AvahiClient *c)
{
	assert(c);
	char *n;
	
	/// If this is the first time we're called, let's create a new entry group if necessary
	if (!group)
	{
		if (!(group = avahi_entry_group_new(c, entry_group_callback, this)))
		{
			logE << "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)) << "\n";
			goto fail;
		}
	}

	/// If the group is empty (either because it was just created, or because it was reset previously, add our entries. 
	int ret;
	if (avahi_entry_group_is_empty(group))
	{
		logO << "Adding service '" << name << "'\n";

		/// We will now add two services and one subtype to the entry group
		for (const auto& service: services_)
		{
			if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, service.name_.c_str(), NULL, NULL, service.port_, NULL)) < 0)
			{
				if (ret == AVAHI_ERR_COLLISION)
					goto collision;

				logE << "Failed to add " << service.name_ << " service: " << avahi_strerror(ret) << "\n";
				goto fail;
			}
		}

		/// Add an additional (hypothetic) subtype
/*		if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0))
		{
			fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret));
			goto fail;
		}
*/
		/// Tell the server to register the service
		if ((ret = avahi_entry_group_commit(group)) < 0)
		{
			logE << "Failed to commit entry group: " << avahi_strerror(ret) << "\n";
			goto fail;
		}
	}

	return;

collision:

	/// A service name collision with a local service happened. Let's pick a new name
	n = avahi_alternative_service_name(name);
	avahi_free(name);
	name = n;

	logO << "Service name collision, renaming service to '" << name << "'\n";

	avahi_entry_group_reset(group);

	create_services(c);
	return;

fail:
	avahi_simple_poll_quit(simple_poll);
}
Esempio n. 26
0
static int
spawn_record_browser(AvahiClient *c, AvahiIfIndex intf, AvahiProtocol proto, const char *hostname, const char *domain,
		     uint16_t type, struct mdns_browser *mb, const char *name, uint16_t port, AvahiStringList *txt)
{
  AvahiRecordBrowser *rb;
  struct mdns_record_browser *rb_data;
  char *key;
  char *value;
  char *ptr;
  size_t len;
  int ret;

  rb_data = (struct mdns_record_browser *)malloc(sizeof(struct mdns_record_browser));
  if (!rb_data)
    {
      DPRINTF(E_LOG, L_MDNS, "Out of memory for record browser data\n");

      return -1;
    }

  memset(rb_data, 0, sizeof(struct mdns_record_browser));

  rb_data->mb = mb;
  rb_data->port = port;

  rb_data->name = strdup(name);
  if (!rb_data->name)
    {
      DPRINTF(E_LOG, L_MDNS, "Out of memory for service name\n");

      goto out_free_rb;
    }

  rb_data->domain = strdup(domain);
  if (!rb_data->domain)
    {
      DPRINTF(E_LOG, L_MDNS, "Out of memory for service domain\n");

      goto out_free_name;
    }

  while (txt)
    {
      len = avahi_string_list_get_size(txt);
      key = (char *)avahi_string_list_get_text(txt);

      ptr = memchr(key, '=', len);
      if (!ptr)
	{
	  value = "";
	  len = 0;
	}
      else
	{
	  *ptr = '\0';
	  value = ptr + 1;

	  len -= strlen(key) + 1;
	}

      ret = keyval_add_size(&rb_data->txt_kv, key, value, len);

      if (ptr)
	*ptr = '=';

      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_MDNS, "Could not build TXT record keyval\n");

	  goto out_free_keyval;
	}

      txt = avahi_string_list_get_next(txt);
    }

  rb = NULL;
  switch (type)
    {
      case AVAHI_DNS_TYPE_A:
	rb = avahi_record_browser_new(c, intf, proto, hostname,
				      AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, 0,
				      browse_record_callback_v4, rb_data);
	if (!rb)
	  DPRINTF(E_LOG, L_MDNS, "Could not create v4 record browser for host %s: %s\n",
		  hostname, avahi_strerror(avahi_client_errno(c)));
	break;

      case AVAHI_DNS_TYPE_AAAA:
	rb = avahi_record_browser_new(c, intf, proto, hostname,
				      AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, 0,
				      browse_record_callback_v6, rb_data);
	if (!rb)
	  DPRINTF(E_LOG, L_MDNS, "Could not create v4 record browser for host %s: %s\n",
		  hostname, avahi_strerror(avahi_client_errno(c)));
	break;
    }

  if (!rb)
    goto out_free_keyval;

  return 0;

 out_free_keyval:
  keyval_clear(&rb_data->txt_kv);
  free(rb_data->domain);
 out_free_name:
  free(rb_data->name);
 out_free_rb:
  free(rb_data);

  return -1;
}
Esempio n. 27
0
static void resolver_cb(
        AvahiServiceResolver *r,
        AvahiIfIndex interface, AvahiProtocol protocol,
        AvahiResolverEvent event,
        const char *name, const char *type, const char *domain,
        const char *host_name, const AvahiAddress *a, uint16_t port,
        AvahiStringList *txt,
        AvahiLookupResultFlags flags,
        void *userdata) {

    struct userdata *u = userdata;
    struct tunnel *tnl;

    pa_assert(u);

    tnl = tunnel_new(interface, protocol, name, type, domain);

    if (event != AVAHI_RESOLVER_FOUND)
        pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client)));
    else {
        char *device = NULL, *dname, *module_name, *args;
        const char *t;
        char at[AVAHI_ADDRESS_STR_MAX], cmt[PA_CHANNEL_MAP_SNPRINT_MAX];
        pa_sample_spec ss;
        pa_channel_map cm;
        AvahiStringList *l;
        pa_bool_t channel_map_set = FALSE;
        pa_module *m;

        ss = u->core->default_sample_spec;
        cm = u->core->default_channel_map;

        for (l = txt; l; l = l->next) {
            char *key, *value;
            pa_assert_se(avahi_string_list_get_pair(l, &key, &value, NULL) == 0);

            if (pa_streq(key, "device")) {
                pa_xfree(device);
                device = value;
                value = NULL;
            } else if (pa_streq(key, "rate"))
                ss.rate = (uint32_t) atoi(value);
            else if (pa_streq(key, "channels"))
                ss.channels = (uint8_t) atoi(value);
            else if (pa_streq(key, "format"))
                ss.format = pa_parse_sample_format(value);
            else if (pa_streq(key, "channel_map")) {
                pa_channel_map_parse(&cm, value);
                channel_map_set = TRUE;
            }

            avahi_free(key);
            avahi_free(value);
        }

        if (!channel_map_set && cm.channels != ss.channels)
            pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);

        if (!pa_sample_spec_valid(&ss)) {
            pa_log("Service '%s' contains an invalid sample specification.", name);
            avahi_free(device);
            goto finish;
        }

        if (!pa_channel_map_valid(&cm) || cm.channels != ss.channels) {
            pa_log("Service '%s' contains an invalid channel map.", name);
            avahi_free(device);
            goto finish;
        }

        if (device)
            dname = pa_sprintf_malloc("tunnel.%s.%s", host_name, device);
        else
            dname = pa_sprintf_malloc("tunnel.%s", host_name);

        if (!pa_namereg_is_valid_name(dname)) {
            pa_log("Cannot construct valid device name from credentials of service '%s'.", dname);
            avahi_free(device);
            pa_xfree(dname);
            goto finish;
        }

        t = strstr(type, "sink") ? "sink" : "source";

        module_name = pa_sprintf_malloc("module-tunnel-%s", t);
        args = pa_sprintf_malloc("server=[%s]:%u "
                                 "%s=%s "
                                 "format=%s "
                                 "channels=%u "
                                 "rate=%u "
                                 "%s_name=%s "
                                 "channel_map=%s",
                                 avahi_address_snprint(at, sizeof(at), a), port,
                                 t, device,
                                 pa_sample_format_to_string(ss.format),
                                 ss.channels,
                                 ss.rate,
                                 t, dname,
                                 pa_channel_map_snprint(cmt, sizeof(cmt), &cm));

        pa_log_debug("Loading %s with arguments '%s'", module_name, args);

        if ((m = pa_module_load(u->core, module_name, args))) {
            tnl->module_index = m->index;
            pa_hashmap_put(u->tunnels, tnl, tnl);
            tnl = NULL;
        }

        pa_xfree(module_name);
        pa_xfree(dname);
        pa_xfree(args);
        avahi_free(device);
    }

finish:

    avahi_service_resolver_free(r);

    if (tnl)
        tunnel_free(tnl);
}
Esempio n. 28
0
static void
browse_callback(AvahiServiceBrowser *b, AvahiIfIndex intf, AvahiProtocol proto, AvahiBrowserEvent event,
		const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata)
{
  struct mdns_browser *mb;
  AvahiServiceResolver *res;
  int family;

  mb = (struct mdns_browser *)userdata;

  switch (event)
    {
      case AVAHI_BROWSER_FAILURE:
	DPRINTF(E_LOG, L_MDNS, "Avahi Browser failure: %s\n",
		avahi_strerror(avahi_client_errno(mdns_client)));

	avahi_service_browser_free(b);

	b = avahi_service_browser_new(mdns_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, mb->type, NULL, 0, browse_callback, mb);
	if (!b)
	  {
	    DPRINTF(E_LOG, L_MDNS, "Failed to recreate service browser (service type %s): %s\n", mb->type,
		    avahi_strerror(avahi_client_errno(mdns_client)));
	  }
	return;

      case AVAHI_BROWSER_NEW:
	DPRINTF(E_DBG, L_MDNS, "Avahi Browser: NEW service '%s' type '%s' proto %d\n", name, type, proto);

	res = avahi_service_resolver_new(mdns_client, intf, proto, name, type, domain, proto, 0, browse_resolve_callback, mb);
	if (!res)
	  DPRINTF(E_LOG, L_MDNS, "Failed to create service resolver: %s\n",
		  avahi_strerror(avahi_client_errno(mdns_client)));
	break;

      case AVAHI_BROWSER_REMOVE:
	DPRINTF(E_DBG, L_MDNS, "Avahi Browser: REMOVE service '%s' type '%s' proto %d\n", name, type, proto);

	switch (proto)
	  {
	    case AVAHI_PROTO_INET:
	      family = AF_INET;
	      break;

	    case AVAHI_PROTO_INET6:
	      family = AF_INET6;
	      break;

	    default:
	      DPRINTF(E_INFO, L_MDNS, "Avahi Browser: unknown protocol %d\n", proto);

	      family = AF_UNSPEC;
	      break;
	  }

	if (family != AF_UNSPEC)
	  mb->cb(name, type, domain, NULL, family, NULL, -1, NULL);
	break;

      case AVAHI_BROWSER_ALL_FOR_NOW:
      case AVAHI_BROWSER_CACHE_EXHAUSTED:
	DPRINTF(E_DBG, L_MDNS, "Avahi Browser (%s): no more results (%s)\n", mb->type,
		(event == AVAHI_BROWSER_CACHE_EXHAUSTED) ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
	break;
    }
}
Esempio n. 29
0
static void 
resolve_callback(AvahiServiceResolver *r,
		 AvahiIfIndex interface,
		 AvahiProtocol protocol,
		 AvahiResolverEvent event,
		 const char *name,
		 const char *type,
		 const char *domain,
		 const char *host_name,
		 const AvahiAddress *address,
		 uint16_t port,
		 AvahiStringList *txt,
		 AvahiLookupResultFlags flags,
		 void *userdata)
{
  service_instance_t *si = userdata;
  service_aux_t *sa = si->si_opaque;
  char a[AVAHI_ADDRESS_STR_MAX];
  AvahiStringList *apath;
  char *path;
  AvahiStringList *acontents;
  char *contents;

  switch(event) {
  case AVAHI_RESOLVER_FAILURE:
    TRACE(TRACE_ERROR, "AVAHI",
	  "Failed to resolve service '%s' of type '%s' in domain '%s': %s\n",
	  name, type, domain, 
	  avahi_strerror(avahi_client_errno(sa->sa_c)));
    si_destroy(si);
    break;

  case AVAHI_RESOLVER_FOUND:

    avahi_address_snprint(a, sizeof(a), address);

    TRACE(TRACE_DEBUG, "AVAHI",
	  "Found service '%s' of type '%s' at %s:%d (%s)",
	  name, type, a, port, host_name);

    switch(sa->sa_class) {
    case SERVICE_HTSP:
      sd_add_service_htsp(si, name, a, port);
      break;

    case SERVICE_WEBDAV:
      apath = avahi_string_list_find(txt, "path");
      if(apath == NULL ||
	 avahi_string_list_get_pair(apath, NULL, &path, NULL))
        path = NULL;

      acontents = avahi_string_list_find(txt, "contents");
      if(acontents == NULL ||
	 avahi_string_list_get_pair(acontents, NULL, &contents, NULL))
        contents = NULL;
        
      sd_add_service_webdav(si, name, a, port, path, contents);
        
      if(path)
        avahi_free(path);
      break;
    }
  }
  avahi_service_resolver_free(r);
}
Esempio n. 30
0
static void register_stuff(struct context *ctx) {

    if (!ctx->group) {

        if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
            rs_log_crit("Failed to create entry group: %s", avahi_strerror(avahi_client_errno(ctx->client)));
            goto fail;
        }

    }

    if (avahi_entry_group_is_empty(ctx->group)) {
        char cpus[32] = "";
        char machine[64] = "cc_machine=", version[64] = "cc_version=";
        char *m = NULL, *v = NULL;

        if (ctx->advertise_capabilities) {
            snprintf(cpus, sizeof(cpus), "cpus=%i", ctx->n_cpus);
            v = dcc_get_gcc_version(version+11, sizeof(version)-11);
            m = dcc_get_gcc_machine(machine+11, sizeof(machine)-11);
        }

        /* Register our service */

        if (avahi_entry_group_add_service(
                    ctx->group,
                    AVAHI_IF_UNSPEC,
                    AVAHI_PROTO_UNSPEC,
                    0,
                    ctx->name,
                    ctx->service_type,
                    NULL,
                    NULL,
                    ctx->port,
                    !ctx->advertise_capabilities ? NULL : "txtvers=1",
                    cpus,
                    "distcc="PACKAGE_VERSION,
                    "gnuhost="GNU_HOST,
                    v ? version : NULL,
                    m ? machine : NULL,
                    NULL) < 0) {
            rs_log_crit("Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client)));
            goto fail;
        }

        if (ctx->advertise_capabilities) {
            if (v && m) {
                char stype[128];

                dcc_make_dnssd_subtype(stype, sizeof(stype), v, m);

                if (avahi_entry_group_add_service_subtype(
                            ctx->group,
                            AVAHI_IF_UNSPEC,
                            AVAHI_PROTO_UNSPEC,
                            0,
                            ctx->name,
                            ctx->service_type,
                            NULL,
                            stype) < 0) {
                    rs_log_crit("Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client)));
                    goto fail;
                }
            } else
                rs_log_warning("Failed to determine CC version, not registering DNS-SD service subtype!");
        }

        if (avahi_entry_group_commit(ctx->group) < 0) {
            rs_log_crit("Failed to commit entry group: %s", avahi_strerror(avahi_client_errno(ctx->client)));
            goto fail;
        }

    }

    return;

fail:
    avahi_threaded_poll_quit(ctx->threaded_poll);
}