int avahi_server_add_dns_server_address(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *domain,
    AvahiDNSServerType type,
    const AvahiAddress *address,
    uint16_t port /** should be 53 */) {

    AvahiRecord *r;
    char n[64], h[64];
    AvahiEntry *a_entry, *s_entry;

    assert(s);
    assert(address);

    AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(address->proto), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY(s, type == AVAHI_DNS_SERVER_UPDATE || type == AVAHI_DNS_SERVER_RESOLVE, AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY(s, port != 0, AVAHI_ERR_INVALID_PORT);
    AVAHI_CHECK_VALIDITY(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);

    if (!domain)
        domain = s->domain_name;

    transport_flags_from_domain(s, &flags, domain);
    AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);
    
    if (address->proto == AVAHI_PROTO_INET) {
        hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv4Address));
        snprintf(n, sizeof(n), "ip-%s.%s", h, domain);
        r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME);
        r->data.a.address = address->data.ipv4;
    } else {
        hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv6Address));
        snprintf(n, sizeof(n), "ip6-%s.%s", h, domain);
        r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME);
        r->data.aaaa.address = address->data.ipv6;
    }

    if (!r)
        return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
    
    a_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r);
    avahi_record_unref(r);

    if (!a_entry)
        return avahi_server_errno(s);
    
    if (!(s_entry = server_add_dns_server_name(s, g, interface, protocol, flags, domain, type, n, port))) {
        if (!(flags & AVAHI_PUBLISH_UPDATE))
            avahi_entry_free(s, a_entry);
        return avahi_server_errno(s);
    }

    return AVAHI_OK;
}
Beispiel #2
0
void Browser::browserCallback(AvahiSServiceBrowser *b,
                              AvahiIfIndex iface,
                              AvahiProtocol protocol,
                              AvahiBrowserEvent event,
                              const char *name,
                              const char *type,
                              const char *domain,
                              AvahiLookupResultFlags flags,
                              void *userdata)  noexcept {
    auto browser = static_cast<Browser*>(userdata);

    switch (event) {
    case AVAHI_BROWSER_NEW:
        printf("Found %s of type %s in domain %s\n", name, type, domain);
        browser->addService(iface, protocol, name, type, domain);
        break;
    case AVAHI_BROWSER_REMOVE:
        printf("Removing %s of type %s in domain %s\n", name, type, domain);
        browser->removeService(name);
        break;
    case AVAHI_BROWSER_FAILURE:
        printf("Error: %s\n", avahi_strerror(avahi_server_errno(browser->server_.get())));
        break;
    default:
        break;
    }
}
void avahi_dbus_entry_group_callback(AvahiServer *s, AvahiSEntryGroup *g, AvahiEntryGroupState state, void* userdata) {
    EntryGroupInfo *i = userdata;
    DBusMessage *m;
    int32_t t;
    const char *e;

    assert(s);
    assert(g);
    assert(i);

    m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged");

    if (!m) {
        avahi_log_error("Failed allocate message");
        return;
    }

    t = (int32_t) state;
    if (state == AVAHI_ENTRY_GROUP_FAILURE)
        e = avahi_error_number_to_dbus(avahi_server_errno(s));
    else if (state == AVAHI_ENTRY_GROUP_COLLISION)
        e = AVAHI_DBUS_ERR_COLLISION;
    else
        e = AVAHI_DBUS_ERR_OK;

    dbus_message_append_args(
        m,
        DBUS_TYPE_INT32, &t,
        DBUS_TYPE_STRING, &e,
        DBUS_TYPE_INVALID);
    dbus_message_set_destination(m, i->client->name);
    dbus_connection_send(server->bus, m, NULL);
    dbus_message_unref(m);
}
Beispiel #4
0
static void add_static_host_to_server(StaticHost *h)
{

    if (!h->group)
        if (!(h->group = avahi_s_entry_group_new (avahi_server, entry_group_callback, h))) {
            avahi_log_error("avahi_s_entry_group_new() failed: %s", avahi_strerror(avahi_server_errno(avahi_server)));
            return;
        }

    if (avahi_s_entry_group_is_empty(h->group)) {
        AvahiProtocol p;
        int err;
        const AvahiServerConfig *config;
        config = avahi_server_get_config(avahi_server);
        
        p = (h->address.proto == AVAHI_PROTO_INET && config->publish_a_on_ipv6) ||
            (h->address.proto == AVAHI_PROTO_INET6 && config->publish_aaaa_on_ipv4) ? AVAHI_PROTO_UNSPEC : h->address.proto;
        
        if ((err = avahi_server_add_address(avahi_server, h->group, AVAHI_IF_UNSPEC, p, 0, h->host, &h->address)) < 0) {
            avahi_log_error ("Static host name %s: avahi_server_add_address failure: %s", h->host, avahi_strerror(err));
            return;
        }

        avahi_s_entry_group_commit (h->group);
    }
}
static void server_callback(AvahiServer *s, AvahiServerState state, AVAHI_GCC_UNUSED void * userdata) {
    assert(s);

    /* Called whenever the server state changes */

    switch (state) {

        case AVAHI_SERVER_RUNNING:
            /* The serve has startup successfully and registered its host
             * name on the network, so it's time to create our services */

            if (!group)
                create_services(s);

            break;

        case AVAHI_SERVER_COLLISION: {
            char *n;
            int r;

            /* A host name collision happened. Let's pick a new name for the server */
            n = avahi_alternative_host_name(avahi_server_get_host_name(s));
            fprintf(stderr, "Host name collision, retrying with '%s'\n", n);
            r = avahi_server_set_host_name(s, n);
            avahi_free(n);

            if (r < 0) {
                fprintf(stderr, "Failed to set new host name: %s\n", avahi_strerror(r));

                avahi_simple_poll_quit(simple_poll);
                return;
            }

        }

            /* Fall through */

        case AVAHI_SERVER_REGISTERING:

	    /* Let's drop our registered services. When the server is back
             * in AVAHI_SERVER_RUNNING state we will register them
             * again with the new host name. */
            if (group)
                avahi_s_entry_group_reset(group);

            break;

        case AVAHI_SERVER_FAILURE:

            /* Terminate on failure */

            fprintf(stderr, "Server failure: %s\n", avahi_strerror(avahi_server_errno(s)));
            avahi_simple_poll_quit(simple_poll);
            break;

        case AVAHI_SERVER_INVALID:
            ;
    }
}
static int server_update_service_txt_strlst_nocopy(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *name,     
    const char *type,     
    const char *domain,   
    AvahiStringList *strlst) {

    char svc_name[AVAHI_DOMAIN_NAME_MAX];
    int ret = AVAHI_OK;
    AvahiEntry *e;
    
    assert(s);
    assert(type);
    assert(name);

    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags,
                                                                AVAHI_PUBLISH_NO_COOKIE|
                                                                AVAHI_PUBLISH_USE_WIDE_AREA|
                                                                AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);

    if (!domain)
        domain = s->domain_name;

    transport_flags_from_domain(s, &flags, domain);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);

    if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0) {
        avahi_server_set_errno(s, ret);
        goto fail;
    }

    /* Add TXT record */
    if (!(flags & AVAHI_PUBLISH_NO_COOKIE))
        strlst = add_magic_cookie(s, strlst);
    
    e = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_UPDATE, AVAHI_DEFAULT_TTL, svc_name, strlst);
    strlst = NULL;

    if (!e)
        ret = avahi_server_errno(s);
    
fail:
    
    avahi_string_list_free(strlst);
    
    return ret;
}
static void server_callback(AvahiServer *s, AvahiServerState state, void* userdata) {
  assert(s);
  
  switch (state) {
    case AVAHI_SERVER_RUNNING:
      DEBUG("Server created and running");
      /* Create the service browser */
      stb = avahi_s_service_type_browser_new(s, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "mesh.local", 0, browse_type_callback, s);
      if (!stb)
	ERROR("Failed to create service type browser: %s", avahi_strerror(avahi_server_errno(s)));
      break;
    case AVAHI_SERVER_COLLISION:
      WARN("AVAHI_SERVER_COLLISION");
    case AVAHI_SERVER_REGISTERING:
      WARN("AVAHI_SERVER_REGISTERING");
    case AVAHI_SERVER_INVALID:
      WARN("AVAHI_SERVER_INVALID");
    case AVAHI_SERVER_FAILURE:
      WARN("Server failure: %s", avahi_strerror(avahi_server_errno(s)));
  }
}
/**
 * Callback function that is called whenever an Entry Group state changes
 *
 * @param s An Avahi Server
 *
 * @param g An Avahi Entry Group
 *
 * @param state The state of the Entry Group
 *
 * @param userdata The Service that is involved in this state change
 *
 * @return void
 *
 */
static void 
entry_group_callback(	AvahiServer *s, 
						AvahiSEntryGroup *g, 
						AvahiEntryGroupState state, 
						AVAHI_GCC_UNUSED void *userdata) 
{    

	assert(s);

	//Service *_called_service = (Service*) avahi_s_entry_group_get_data(g);
	Service *called_service = (Service*) userdata;

	/* Called whenever the entry group state changes */

	switch (state) {

		case AVAHI_ENTRY_GROUP_ESTABLISHED:

			/* The entry group has been established successfully */
			fprintf(stderr, "Service '%s' successfully established.\n", called_service->zeroConfName);
			break;

			case AVAHI_ENTRY_GROUP_COLLISION: {
				char *n;

				/* A service name collision happened. Let's pick a new name */
				n = avahi_alternative_service_name(called_service->ID);
				avahi_free(called_service->ID);
				called_service->ID = n;

				fprintf(stderr, "Service name collision, renaming service to '%s'\n", name);

				/* And recreate the services */

				avahi_core_create_service(called_service);

				break;
			}

		case AVAHI_ENTRY_GROUP_FAILURE :

			fprintf(stderr, "Entry group failure: %s\n", avahi_strerror(avahi_server_errno(s)));

			/* Some kind of failure happened while we were registering our services */
			avahi_threaded_poll_quit(threaded_poll);
			break;

		case AVAHI_ENTRY_GROUP_UNCOMMITED:
		case AVAHI_ENTRY_GROUP_REGISTERING:
			;
	}
}
int avahi_server_add(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    AvahiRecord *r) {

    if (!server_add_internal(s, g, interface, protocol, flags, r))
        return avahi_server_errno(s);

    return AVAHI_OK;
}
void ofxAvahiCoreBrowser::browse_cb(
    AvahiSServiceBrowser *b,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiBrowserEvent event,
    const char *name,
    const char *type,
    const char *domain,
    AvahiLookupResultFlags flags,
    ofxAvahiCoreBrowser* browser) {

    AvahiServer *s = browser->server;
    assert(b);

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

    switch (event) {

        case AVAHI_BROWSER_FAILURE:
        	ofLogError(LOG_NAME) <<  "(Browser)" << avahi_strerror(avahi_server_errno(browser->server));
            browser->close();
            return;

        case AVAHI_BROWSER_NEW:
            ofLogNotice(LOG_NAME) << "(Browser) NEW: service '"<< name << "' of type '" << type<<"' in domain '"<<domain<<"'";

            /* 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_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET, (AvahiLookupFlags)0, (AvahiSServiceResolverCallback)resolve_cb, browser)))
                ofLogError(LOG_NAME) << "Failed to resolve service '" << name << "':"<<avahi_strerror(avahi_server_errno(s));

            break;

        case AVAHI_BROWSER_REMOVE:{
        	ofLogNotice(LOG_NAME) << "(Browser) REMOVE: service '" << name << "' of type '"<< type << "' in domain '"<< domain << "'";
            ofxAvahiService service;
            service.domain = domain;
            service.name = name;
            ofNotifyEvent(browser->serviceRemoveE,service);
        }break;

        case AVAHI_BROWSER_ALL_FOR_NOW:
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
        	ofLogNotice(LOG_NAME) << "(Browser)" << ((event == AVAHI_BROWSER_CACHE_EXHAUSTED) ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
            break;
    }
}
bool ofxAvahiCoreBrowser::lookup(string _type){
	AvahiServerConfig config;
	int error;
	type = _type;

	if (!(poll = avahi_simple_poll_new())) {
		ofLogError(LOG_NAME) << "Failed to create simple poll object.";
		close();
		return false;
	}
	/* Do not publish any local records */
	avahi_server_config_init(&config);
	config.publish_hinfo = 0;
	config.publish_addresses = 0;
	config.publish_workstation = 0;
	config.publish_domain = 0;
	config.use_ipv6 = 0;
	config.disallow_other_stacks = 1;
	config.allow_point_to_point = 1;

	/* Set a unicast DNS server for wide area DNS-SD */
    /*avahi_address_parse("192.168.50.1", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]);
    config.n_wide_area_servers = 1;
    config.enable_wide_area = 1;*/

	server = avahi_server_new(avahi_simple_poll_get(poll), &config, (AvahiServerCallback)server_cb, this, &error);

	avahi_server_config_free(&config);

	if (!server) {
		ofLogError(LOG_NAME) << "Failed to create server:" << avahi_strerror(error);
		close();
		return false;
	}


    /* Create the service browser */
    if (!(sb = avahi_s_service_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, type.c_str(), NULL, (AvahiLookupFlags)0, (AvahiSServiceBrowserCallback)browse_cb, this))) {
    	ofLogError(LOG_NAME) << "Failed to create service browser:" << avahi_strerror(avahi_server_errno(server));
    	close();
    	return false;
    }

	startThread(true,false);

	return true;
}
static void create_services(AvahiServer *s) {
    char r[128];
    int ret;
    assert(s);

    /* If this is the first time we're called, let's create a new entry group */
    if (!group)
        if (!(group = avahi_s_entry_group_new(s, entry_group_callback, NULL))) {
            fprintf(stderr, "avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_server_errno(s)));
            goto fail;
        }

    fprintf(stderr, "Adding service '%s'\n", name);

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

    /* Add the service for IPP */
    if ((ret = avahi_server_add_service(s, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_ipp._tcp", NULL, NULL, 651, "test=blah", r, NULL)) < 0) {
        fprintf(stderr, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret));
        goto fail;
    }

    /* Add the same service for BSD LPR */
    if ((ret = avahi_server_add_service(s, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_printer._tcp", NULL, NULL, 515, NULL)) < 0) {
        fprintf(stderr, "Failed to add _printer._tcp service: %s\n", avahi_strerror(ret));
        goto fail;
    }

    /* Add an additional (hypothetic) subtype */
    if ((ret = avahi_server_add_service_subtype(s, 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;
    }

    /* Tell the server to register the service */
    if ((ret = avahi_s_entry_group_commit(group)) < 0) {
        fprintf(stderr, "Failed to commit entry_group: %s\n", avahi_strerror(ret));
        goto fail;
    }

    return;

fail:
    avahi_simple_poll_quit(simple_poll);
}
void ControllerDiscoveryMDNS::avahi_server_callback( AvahiServer * server, AvahiServerState state, void * userdata )
{
    ControllerDiscoveryMDNS * self = ( ControllerDiscoveryMDNS * )userdata;

    switch ( state )
    {
        case AVAHI_SERVER_RUNNING:
        {
            self->create_service( server );
            break;
        }

        case AVAHI_SERVER_COLLISION:
        {
            char * new_name = avahi_alternative_host_name( avahi_server_get_host_name( server ) );

            (void)avahi_server_set_host_name( server, new_name );
            avahi_free( new_name );

            // TODO : check ret

            break;
        }

        case AVAHI_SERVER_REGISTERING:
        {
            if ( self->group )
            {
                avahi_s_entry_group_reset( self->group );
            }
            break;
        }

        case AVAHI_SERVER_FAILURE:
        {
            g_warning( "AVAHI SERVER FAILURE : %s", avahi_strerror( avahi_server_errno( server ) ) );
            break;
        }

        case AVAHI_SERVER_INVALID:
        {
            break;
        }
    }
}
int avahi_server_add_ptr(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    uint32_t ttl,
    const char *name,
    const char *dest) {

    AvahiEntry *e;

    assert(s);

    if (!(e = server_add_ptr_internal(s, g, interface, protocol, flags, ttl, name, dest)))
        return avahi_server_errno(s);

    return AVAHI_OK;
}
static void address_resolver_callback(
    AVAHI_GCC_UNUSED AvahiSAddressResolver *r,
    AvahiIfIndex iface,
    AvahiProtocol protocol,
    AvahiResolverEvent event,
    AVAHI_GCC_UNUSED const AvahiAddress *a,
    const char *hostname,
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    void* userdata) {

    Client *c = userdata;

    assert(c);

    if (event == AVAHI_RESOLVER_FAILURE)
        client_output_printf(c, "%+i %s\n", avahi_server_errno(avahi_server), avahi_strerror(avahi_server_errno(avahi_server)));
    else if (event == AVAHI_RESOLVER_FOUND)
        client_output_printf(c, "+ %i %u %s\n", iface, protocol, hostname);

    c->state = CLIENT_DEAD;
}
static void dns_server_browser_callback(
    AVAHI_GCC_UNUSED AvahiSDNSServerBrowser *b,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiBrowserEvent event,
    AVAHI_GCC_UNUSED const char *host_name,
    const AvahiAddress *a,
    uint16_t port,
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    void* userdata) {

    Client *c = userdata;
    char t[AVAHI_ADDRESS_STR_MAX];

    assert(c);

    if (!a)
        return;

    switch (event) {
        case AVAHI_BROWSER_FAILURE:
            client_output_printf(c, "%+i %s\n", avahi_server_errno(avahi_server), avahi_strerror(avahi_server_errno(avahi_server)));
            c->state = CLIENT_DEAD;
            break;

        case AVAHI_BROWSER_ALL_FOR_NOW:
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
            break;

        case AVAHI_BROWSER_NEW:
        case AVAHI_BROWSER_REMOVE:

            avahi_address_snprint(t, sizeof(t), a);
            client_output_printf(c, "%c %i %u %s %u\n", event == AVAHI_BROWSER_NEW ? '>' : '<',  interface, protocol, t, port);
            break;
    }
}
static void host_name_resolver_callback(
    AVAHI_GCC_UNUSED AvahiSHostNameResolver *r,
    AvahiIfIndex iface,
    AvahiProtocol protocol,
    AvahiResolverEvent event,
    const char *hostname,
    const AvahiAddress *a,
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    void* userdata) {

    Client *c = userdata;

    assert(c);

    if (event == AVAHI_RESOLVER_FAILURE)
        client_output_printf(c, "%+i %s\n", avahi_server_errno(avahi_server), avahi_strerror(avahi_server_errno(avahi_server)));
    else if (event == AVAHI_RESOLVER_FOUND) {
        char t[AVAHI_ADDRESS_STR_MAX];
        avahi_address_snprint(t, sizeof(t), a);
        client_output_printf(c, "+ %i %u %s %s\n", iface, protocol, hostname, t);
    }

    c->state = CLIENT_DEAD;
}
DBusHandlerResult avahi_dbus_msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
    DBusError error;
    EntryGroupInfo *i = userdata;

    assert(c);
    assert(m);
    assert(i);

    dbus_error_init(&error);

    avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
                    dbus_message_get_interface(m),
                    dbus_message_get_path(m),
                    dbus_message_get_member(m));

    /* Introspection */
    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
        return avahi_dbus_handle_introspect(c, m, "org.freedesktop.Avahi.EntryGroup.xml");

    /* Access control */
    if (strcmp(dbus_message_get_sender(m), i->client->name))
        return avahi_dbus_respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);

    if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::Free message");
            goto fail;
        }

        avahi_dbus_entry_group_free(i);
        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::Commit message");
            goto fail;
        }

        if (avahi_s_entry_group_commit(i->entry_group) < 0)
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);

        return avahi_dbus_respond_ok(c, m);


    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Reset")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::Reset message");
            goto fail;
        }

        avahi_s_entry_group_reset(i->entry_group);
        i->n_entries = 0;
        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::IsEmpty message");
            goto fail;
        }

        return avahi_dbus_respond_boolean(c, m, !!avahi_s_entry_group_is_empty(i->entry_group));

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
        AvahiEntryGroupState state;

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::GetState message");
            goto fail;
        }

        state = avahi_s_entry_group_get_state(i->entry_group);
        return avahi_dbus_respond_int32(c, m, (int32_t) state);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
        int32_t interface, protocol;
        uint32_t flags;
        char *type, *name, *domain, *host;
        uint16_t port;
        AvahiStringList *strlst = NULL;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &type,
                DBUS_TYPE_STRING, &domain,
                DBUS_TYPE_STRING, &host,
                DBUS_TYPE_UINT16, &port,
                DBUS_TYPE_INVALID) ||
            !type || !name ||
            avahi_dbus_read_strlst(m, 8, &strlst) < 0) {
            avahi_log_warn("Error parsing EntryGroup::AddService message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max) {
            avahi_string_list_free(strlst);
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);
        }

        if (domain && !*domain)
            domain = NULL;

        if (host && !*host)
            host = NULL;

        if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, host, port, strlst) < 0) {
            avahi_string_list_free(strlst);
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        avahi_string_list_free(strlst);

        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddServiceSubtype")) {

        int32_t interface, protocol;
        uint32_t flags;
        char *type, *name, *domain, *subtype;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &type,
                DBUS_TYPE_STRING, &domain,
                DBUS_TYPE_STRING, &subtype,
                DBUS_TYPE_INVALID) || !type || !name || !subtype) {
            avahi_log_warn("Error parsing EntryGroup::AddServiceSubtype message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max)
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);

        if (domain && !*domain)
            domain = NULL;

        if (avahi_server_add_service_subtype(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, subtype) < 0)
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "UpdateServiceTxt")) {
        int32_t interface, protocol;
        uint32_t flags;
        char *type, *name, *domain;
        AvahiStringList *strlst;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &type,
                DBUS_TYPE_STRING, &domain,
                DBUS_TYPE_INVALID) ||
            !type || !name ||
            avahi_dbus_read_strlst(m, 6, &strlst)) {
            avahi_log_warn("Error parsing EntryGroup::UpdateServiceTxt message");
            goto fail;
        }

        if (domain && !*domain)
            domain = NULL;

        if (avahi_server_update_service_txt_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, strlst) < 0) {
            avahi_string_list_free(strlst);
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
        }

        avahi_string_list_free(strlst);

        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
        int32_t interface, protocol;
        uint32_t flags;
        char *name, *address;
        AvahiAddress a;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &address,
                DBUS_TYPE_INVALID) || !name || !address) {
            avahi_log_warn("Error parsing EntryGroup::AddAddress message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max)
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);

        if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a)))
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);

        if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, &a) < 0)
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        return avahi_dbus_respond_ok(c, m);
    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddRecord")) {
        int32_t interface, protocol;
        uint32_t flags, ttl, size;
        uint16_t clazz, type;
        char *name;
        void *rdata;
        AvahiRecord *r;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_UINT16, &clazz,
                DBUS_TYPE_UINT16, &type,
                DBUS_TYPE_UINT32, &ttl,
                DBUS_TYPE_INVALID) || !name ||
            avahi_dbus_read_rdata (m, 7, &rdata, &size)) {
            avahi_log_warn("Error parsing EntryGroup::AddRecord message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max)
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);

        if (!avahi_is_valid_domain_name (name))
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_DOMAIN_NAME, NULL);

        if (!(r = avahi_record_new_full (name, clazz, type, ttl)))
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_NO_MEMORY, NULL);

        if (avahi_rdata_parse (r, rdata, size) < 0) {
            avahi_record_unref (r);
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_RDATA, NULL);
        }

        if (avahi_server_add(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, r) < 0) {
            avahi_record_unref (r);
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        avahi_record_unref (r);

        return avahi_dbus_respond_ok(c, m);
    }


    avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));

fail:
    if (dbus_error_is_set(&error))
        dbus_error_free(&error);

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
void ControllerDiscoveryMDNS::create_service( AvahiServer * server )
{
    if ( !group )
    {
        group = avahi_s_entry_group_new( server, avahi_entry_group_callback, this );

        if ( !group )
        {
            g_warning( "FAILED TO CREATE AVAHI ENTRY GROUP : %s", avahi_strerror( avahi_server_errno( server ) ) );
        }
    }

    if ( group )
    {
        if ( avahi_s_entry_group_is_empty( group ) )
        {
            int ret = AVAHI_OK;

            while ( true )
            {
                // TODO: this could loop forever...maybe we should bail at some stage

                ret = avahi_server_add_service( server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
                                                AvahiPublishFlags( 0 ), name.c_str(), TP_REMOTE_MDNS_SERVICE, NULL, NULL, port, NULL );

                if ( ret == AVAHI_ERR_COLLISION )
                {
                    rename();
                }
                else
                {
                    break;
                }
            }

            if ( ret != AVAHI_OK )
            {
                g_warning( "FAILED TO ADD AVAHI SERVICE : %s", avahi_strerror( ret ) );
            }
            else
            {
                while ( true )
                {
                    // TODO: this could loop forever...maybe we should bail at some stage

                    ret = avahi_server_add_service( server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
                                                    AvahiPublishFlags( 0 ), name.c_str(), TP_HTTP_MDNS_SERVICE, NULL, NULL, http_port, NULL );

                    if ( ret == AVAHI_ERR_COLLISION )
                    {
                        rename();
                    }
                    else
                    {
                        break;
                    }
                }


                if ( ret != AVAHI_OK )
                {
                    g_warning( "FAILED TO ADD AVAHI SERVICE : %s", avahi_strerror( ret ) );
                }
                else
                {
					ret = avahi_s_entry_group_commit( group );

					if ( ret != AVAHI_OK )
					{
						g_warning( "FAILED TO COMMIT AVAHI SERVICE : %s", avahi_strerror( ret ) );
					}
                }
            }
        }
    }
}
static void handle_line(Client *c, const char *s) {
    char cmd[64], arg[64];
    int n_args;

    assert(c);
    assert(s);

    if (c->state != CLIENT_IDLE)
        return;

    if ((n_args = sscanf(s, "%63s %63s", cmd, arg)) < 1 ) {
        client_output_printf(c, "%+i Failed to parse command, try \"HELP\".\n", AVAHI_ERR_INVALID_OPERATION);
        c->state = CLIENT_DEAD;
        return;
    }

    if (strcmp(cmd, "HELP") == 0) {
        client_output_printf(c,
                             "+ Available commands are:\n"
                             "+      RESOLVE-HOSTNAME <hostname>\n"
                             "+      RESOLVE-HOSTNAME-IPV6 <hostname>\n"
                             "+      RESOLVE-HOSTNAME-IPV4 <hostname>\n"
                             "+      RESOLVE-ADDRESS <address>\n"
                             "+      BROWSE-DNS-SERVERS\n"
                             "+      BROWSE-DNS-SERVERS-IPV4\n"
                             "+      BROWSE-DNS-SERVERS-IPV6\n");
        c->state = CLIENT_DEAD; }
    else if (strcmp(cmd, "F**K") == 0 && n_args == 1) {
        client_output_printf(c, "+ F**K: Go f**k yourself!\n");
        c->state = CLIENT_DEAD;
    } else if (strcmp(cmd, "RESOLVE-HOSTNAME-IPV4") == 0 && n_args == 2) {
        c->state = CLIENT_RESOLVE_HOSTNAME;
        if (!(c->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, arg, c->afquery = AVAHI_PROTO_INET, AVAHI_LOOKUP_USE_MULTICAST, host_name_resolver_callback, c)))
            goto fail;

        avahi_log_debug(__FILE__": Got %s request for '%s'.", cmd, arg);
    } else if (strcmp(cmd, "RESOLVE-HOSTNAME-IPV6") == 0 && n_args == 2) {
        c->state = CLIENT_RESOLVE_HOSTNAME;
        if (!(c->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, arg, c->afquery = AVAHI_PROTO_INET6, AVAHI_LOOKUP_USE_MULTICAST, host_name_resolver_callback, c)))
            goto fail;

        avahi_log_debug(__FILE__": Got %s request for '%s'.", cmd, arg);
    } else if (strcmp(cmd, "RESOLVE-HOSTNAME") == 0 && n_args == 2) {
        c->state = CLIENT_RESOLVE_HOSTNAME;
        if (!(c->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, arg, c->afquery = AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_USE_MULTICAST, host_name_resolver_callback, c)))
            goto fail;

        avahi_log_debug(__FILE__": Got %s request for '%s'.", cmd, arg);
    } else if (strcmp(cmd, "RESOLVE-ADDRESS") == 0 && n_args == 2) {
        AvahiAddress addr;

        if (!(avahi_address_parse(arg, AVAHI_PROTO_UNSPEC, &addr))) {
            client_output_printf(c, "%+i Failed to parse address \"%s\".\n", AVAHI_ERR_INVALID_ADDRESS, arg);
            c->state = CLIENT_DEAD;
        } else {
            c->state = CLIENT_RESOLVE_ADDRESS;
            if (!(c->address_resolver = avahi_s_address_resolver_new(avahi_server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, &addr, AVAHI_LOOKUP_USE_MULTICAST, address_resolver_callback, c)))
                goto fail;
        }

        avahi_log_debug(__FILE__": Got %s request for '%s'.", cmd, arg);

    } else if (strcmp(cmd, "BROWSE-DNS-SERVERS-IPV4") == 0 && n_args == 1) {
        c->state = CLIENT_BROWSE_DNS_SERVERS;
        if (!(c->dns_server_browser = avahi_s_dns_server_browser_new(avahi_server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, NULL, AVAHI_DNS_SERVER_RESOLVE, c->afquery = AVAHI_PROTO_INET, AVAHI_LOOKUP_USE_MULTICAST, dns_server_browser_callback, c)))
            goto fail;
        client_output_printf(c, "+ Browsing ...\n");

        avahi_log_debug(__FILE__": Got %s request.", cmd);

    } else if (strcmp(cmd, "BROWSE-DNS-SERVERS-IPV6") == 0 && n_args == 1) {
        c->state = CLIENT_BROWSE_DNS_SERVERS;
        if (!(c->dns_server_browser = avahi_s_dns_server_browser_new(avahi_server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, NULL, AVAHI_DNS_SERVER_RESOLVE, c->afquery = AVAHI_PROTO_INET6, AVAHI_LOOKUP_USE_MULTICAST, dns_server_browser_callback, c)))
            goto fail;
        client_output_printf(c, "+ Browsing ...\n");

        avahi_log_debug(__FILE__": Got %s request.", cmd);

    } else if (strcmp(cmd, "BROWSE-DNS-SERVERS") == 0 && n_args == 1) {
        c->state = CLIENT_BROWSE_DNS_SERVERS;
        if (!(c->dns_server_browser = avahi_s_dns_server_browser_new(avahi_server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, NULL, AVAHI_DNS_SERVER_RESOLVE, c->afquery = AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_USE_MULTICAST, dns_server_browser_callback, c)))
            goto fail;
        client_output_printf(c, "+ Browsing ...\n");

        avahi_log_debug(__FILE__": Got %s request.", cmd);

    } else {
        client_output_printf(c, "%+i Invalid command \"%s\", try \"HELP\".\n", AVAHI_ERR_INVALID_OPERATION, cmd);
        c->state = CLIENT_DEAD;

        avahi_log_debug(__FILE__": Got invalid request '%s'.", cmd);
    }

    return;

fail:
    client_output_printf(c, "%+i %s\n", avahi_server_errno(avahi_server), avahi_strerror(avahi_server_errno(avahi_server)));
    c->state = CLIENT_DEAD;
}
static int server_add_service_strlst_nocopy(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *name,
    const char *type,
    const char *domain,
    const char *host,
    uint16_t port,
    AvahiStringList *strlst) {

    char ptr_name[AVAHI_DOMAIN_NAME_MAX], svc_name[AVAHI_DOMAIN_NAME_MAX], enum_ptr[AVAHI_DOMAIN_NAME_MAX], *h = NULL;
    AvahiRecord *r = NULL;
    int ret = AVAHI_OK;
    AvahiEntry *srv_entry = NULL, *txt_entry = NULL, *ptr_entry = NULL, *enum_entry = NULL;
    
    assert(s);
    assert(type);
    assert(name);

    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags,
                                                                AVAHI_PUBLISH_NO_COOKIE|
                                                                AVAHI_PUBLISH_UPDATE|
                                                                AVAHI_PUBLISH_USE_WIDE_AREA|
                                                                AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !host || avahi_is_valid_fqdn(host), AVAHI_ERR_INVALID_HOST_NAME);

    if (!domain)
        domain = s->domain_name;

    if (!host)
        host = s->host_name_fqdn;

    transport_flags_from_domain(s, &flags, domain);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);
    
    if (!(h = avahi_normalize_name_strdup(host))) {
        ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
        goto fail;
    }

    if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0 ||
        (ret = avahi_service_name_join(ptr_name, sizeof(ptr_name), NULL, type, domain)) < 0 ||
        (ret = avahi_service_name_join(enum_ptr, sizeof(enum_ptr), NULL, "_services._dns-sd._udp", domain)) < 0) {
        avahi_server_set_errno(s, ret);
        goto fail;
    }

    /* Add service enumeration PTR record */
    
    if (!(ptr_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, ptr_name, svc_name))) {
        ret = avahi_server_errno(s);
        goto fail;
    }

    /* Add SRV record */
    
    if (!(r = avahi_record_new_full(svc_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV, AVAHI_DEFAULT_TTL_HOST_NAME))) {
        ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
        goto fail;
    }
    
    r->data.srv.priority = 0;
    r->data.srv.weight = 0;
    r->data.srv.port = port;
    r->data.srv.name = h;
    h = NULL;
    srv_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, r);
    avahi_record_unref(r);

    if (!srv_entry) {
        ret = avahi_server_errno(s);
        goto fail;
    }

    /* Add TXT record */

    if (!(flags & AVAHI_PUBLISH_NO_COOKIE))
        strlst = add_magic_cookie(s, strlst);
    
    txt_entry = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL, svc_name, strlst);
    strlst = NULL;

    if (!txt_entry) {
        ret = avahi_server_errno(s);
        goto fail;
    }

    /* Add service type enumeration record */
    
    if (!(enum_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, enum_ptr, ptr_name))) {
        ret = avahi_server_errno(s);
        goto fail;
    }

fail:
    if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) {
        if (srv_entry)
            avahi_entry_free(s, srv_entry);
        if (txt_entry)
            avahi_entry_free(s, txt_entry);
        if (ptr_entry)
            avahi_entry_free(s, ptr_entry);
        if (enum_entry)
            avahi_entry_free(s, enum_entry);
    }
    
    avahi_string_list_free(strlst);
    avahi_free(h);
    
    return ret;
}
Beispiel #22
0
static void add_static_service_group_to_server(StaticServiceGroup *g) {
    StaticService *s;

    assert(g);

    if (g->entry_group && !avahi_s_entry_group_is_empty(g->entry_group))
        /* This service group is already registered in the server */
        return;

    if (!g->chosen_name || (g->replace_wildcards && strstr(g->name, "%h"))) {

        avahi_free(g->chosen_name);

        if (g->replace_wildcards) {
            char label[AVAHI_LABEL_MAX];
            const char *p;

            p = avahi_server_get_host_name(avahi_server);
            avahi_unescape_label(&p, label, sizeof(label));

            g->chosen_name = replacestr(g->name, "%h", label);
        } else
            g->chosen_name = avahi_strdup(g->name);

    }

    if (!g->entry_group)
        g->entry_group = avahi_s_entry_group_new(avahi_server, entry_group_callback, g);

    assert(avahi_s_entry_group_is_empty(g->entry_group));

    for (s = g->services; s; s = s->services_next) {
        AvahiStringList *i;

        if (avahi_server_add_service_strlst(
                avahi_server,
                g->entry_group,
                s->interface, s->protocol,
                0,
                g->chosen_name, s->type, s->domain_name,
                s->host_name, s->port,
                s->txt_records) < 0) {
            avahi_log_error("Failed to add service '%s' of type '%s', ignoring service group (%s): %s",
                            g->chosen_name, s->type, g->filename,
                            avahi_strerror(avahi_server_errno(avahi_server)));
            remove_static_service_group_from_server(g);
            return;
        }

        for (i = s->subtypes; i; i = i->next) {

            if (avahi_server_add_service_subtype(
                    avahi_server,
                    g->entry_group,
                    AVAHI_IF_UNSPEC, s->protocol,
                    0,
                    g->chosen_name, s->type, s->domain_name,
                    (char*) i->text) < 0) {

                avahi_log_error("Failed to add subtype '%s' for service '%s' of type '%s', ignoring subtype (%s): %s",
                                i->text, g->chosen_name, s->type, g->filename,
                                avahi_strerror(avahi_server_errno(avahi_server)));
            }
        }
    }

    avahi_s_entry_group_commit(g->entry_group);
}
Beispiel #23
0
static void entry_group_callback(AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *eg, AvahiEntryGroupState state, void* userdata) {
    StaticServiceGroup *g = userdata;

    assert(s);
    assert(g);

    switch (state) {

        case AVAHI_ENTRY_GROUP_COLLISION: {
            char *n;

            remove_static_service_group_from_server(g);

            n = avahi_alternative_service_name(g->chosen_name);
            avahi_free(g->chosen_name);
            g->chosen_name = n;

            avahi_log_notice("Service name conflict for \"%s\" (%s), retrying with \"%s\".", g->name, g->filename, g->chosen_name);

            add_static_service_group_to_server(g);
            break;
        }

        case AVAHI_ENTRY_GROUP_ESTABLISHED:
            avahi_log_info("Service \"%s\" (%s) successfully established.", g->chosen_name, g->filename);
            break;

        case AVAHI_ENTRY_GROUP_FAILURE:
            avahi_log_warn("Failed to publish service \"%s\" (%s): %s", g->chosen_name, g->filename, avahi_strerror(avahi_server_errno(s)));
            remove_static_service_group_from_server(g);
            break;

        case AVAHI_ENTRY_GROUP_UNCOMMITED:
        case AVAHI_ENTRY_GROUP_REGISTERING:
            ;
    }
}
int avahi_server_add_address(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *name,
    AvahiAddress *a) {

    char n[AVAHI_DOMAIN_NAME_MAX];
    int ret = AVAHI_OK;
    AvahiEntry *entry = NULL, *reverse = NULL;
    AvahiRecord  *r;
    
    assert(s);
    assert(a);

    AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(a->proto), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags,
                                              AVAHI_PUBLISH_NO_REVERSE|
                                              AVAHI_PUBLISH_NO_ANNOUNCE|
                                              AVAHI_PUBLISH_NO_PROBE|
                                              AVAHI_PUBLISH_UPDATE|
                                              AVAHI_PUBLISH_USE_WIDE_AREA|
                                              AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY(s, !name || avahi_is_valid_fqdn(name), AVAHI_ERR_INVALID_HOST_NAME);

    /* Prepare the host naem */
    
    if (!name)
        name = s->host_name_fqdn;
    else {
        AVAHI_ASSERT_TRUE(avahi_normalize_name(name, n, sizeof(n)));
        name = n;
    }

    transport_flags_from_domain(s, &flags, name);
    AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);
    
    /* Create the A/AAAA record */
    
    if (a->proto == AVAHI_PROTO_INET) {

        if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME))) {
            ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
            goto finish;
        }
        
        r->data.a.address = a->data.ipv4;
        
    } else {
        assert(a->proto == AVAHI_PROTO_INET6);
            
        if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME))) {
            ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
            goto finish;
        }
        
        r->data.aaaa.address = a->data.ipv6;
    }
        
    entry = server_add_internal(s, g, interface, protocol, (flags & ~ AVAHI_PUBLISH_NO_REVERSE) | AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r);
    avahi_record_unref(r);

    if (!entry) {
        ret = avahi_server_errno(s);
        goto finish;
    }

    /* Create the reverse lookup entry */
    
    if (!(flags & AVAHI_PUBLISH_NO_REVERSE)) {
        char reverse_n[AVAHI_DOMAIN_NAME_MAX];
        avahi_reverse_lookup_name(a, reverse_n, sizeof(reverse_n));
            
        if (!(reverse = server_add_ptr_internal(s, g, interface, protocol, flags | AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL_HOST_NAME, reverse_n, name))) {
            ret = avahi_server_errno(s);
            goto finish;
        }
    }
    
finish:

    if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) {
        if (entry)
            avahi_entry_free(s, entry);
        if (reverse)
            avahi_entry_free(s, reverse);
    }

    return ret;
}
void ofxAvahiCoreBrowser::resolve_cb(
    AvahiSServiceResolver *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,
    ofxAvahiCoreBrowser* browser) {

    assert(r);

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

    switch (event) {
        case AVAHI_RESOLVER_FAILURE:
            ofLogError(LOG_NAME) << "(Resolver) Failed to resolve service '" << name << "' of type '" << type << "' in domain '" << domain << "':" << avahi_strerror(avahi_server_errno(browser->server));
            break;

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

            ofLogNotice(LOG_NAME) << "(Resolver) Service '" << name << "' of type '" << type << "' in domain '" << domain;

            avahi_address_snprint(a, sizeof(a), address);
            t = avahi_string_list_to_string(txt);
            ofLogNotice(LOG_NAME) << ofVAArgsToString(
                    "\t%s:%u (%s)\n"
                    "\tTXT=%s\n"
                    "\tcookie is %u\n"
                    "\tis_local: %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_WIDE_AREA),
                    !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
                    !!(flags & AVAHI_LOOKUP_RESULT_CACHED));

			ofxAvahiService service;
			service.domain = domain;
			service.host_name = host_name;
			service.ip = a;
			service.name = name;
			service.port = port;
			ofNotifyEvent(browser->serviceNewE,service);

            avahi_free(t);
            break;
        }
    }

    avahi_s_service_resolver_free(r);
}
Beispiel #26
0
static AvahiSEntryGroup* add_dns_servers(AvahiServer *s, AvahiSEntryGroup* g, char **l) {
    char **p;

    assert(s);
    assert(l);

    if (!g)
        g = avahi_s_entry_group_new(s, NULL, NULL);

    assert(avahi_s_entry_group_is_empty(g));

    for (p = l; *p; p++) {
        AvahiAddress a;

        if (!avahi_address_parse(*p, AVAHI_PROTO_UNSPEC, &a))
            avahi_log_warn("Failed to parse address '%s', ignoring.", *p);
        else
            if (avahi_server_add_dns_server_address(s, g, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, NULL, AVAHI_DNS_SERVER_RESOLVE, &a, 53) < 0) {
                avahi_s_entry_group_free(g);
                avahi_log_error("Failed to add DNS server address: %s", avahi_strerror(avahi_server_errno(s)));
                return NULL;
            }
    }

    avahi_s_entry_group_commit(g);

    return g;
}
Beispiel #27
0
static void server_callback(AvahiServer *s, AvahiServerState state, void *userdata) {
    DaemonConfig *c = userdata;

    assert(s);
    assert(c);

    /* This function is possibly called before the global variable
     * avahi_server has been set, therefore we do it explicitly */

    avahi_server = s;

#ifdef HAVE_DBUS
    if (c->enable_dbus && state != AVAHI_SERVER_INVALID && state != AVAHI_SERVER_FAILURE)
        dbus_protocol_server_state_changed(state);
#endif

    switch (state) {
        case AVAHI_SERVER_RUNNING:
            avahi_log_info("Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s));
            sd_notifyf(0, "STATUS=Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s));
            avahi_set_proc_title(argv0, "%s: running [%s]", argv0, avahi_server_get_host_name_fqdn(s));

            static_service_add_to_server();
            static_hosts_add_to_server();

            remove_dns_server_entry_groups();

            if (c->publish_resolv_conf && resolv_conf_name_servers && resolv_conf_name_servers[0])
                resolv_conf_entry_group = add_dns_servers(s, resolv_conf_entry_group, resolv_conf_name_servers);

            if (c->publish_dns_servers && c->publish_dns_servers[0])
                dns_servers_entry_group = add_dns_servers(s, dns_servers_entry_group, c->publish_dns_servers);

            simple_protocol_restart_queries();
            break;

        case AVAHI_SERVER_COLLISION: {
            char *n;

            static_service_remove_from_server();
            static_hosts_remove_from_server();
            remove_dns_server_entry_groups();

            n = avahi_alternative_host_name(avahi_server_get_host_name(s));

            avahi_log_warn("Host name conflict, retrying with %s", n);
            sd_notifyf(0, "STATUS=Host name conflict, retrying with %s", n);
            avahi_set_proc_title(argv0, "%s: collision [%s]", argv0, n);

            avahi_server_set_host_name(s, n);
            avahi_free(n);

            break;
        }

        case AVAHI_SERVER_FAILURE:

            avahi_log_error("Server error: %s", avahi_strerror(avahi_server_errno(s)));
            sd_notifyf(0, "STATUS=Server error: %s", avahi_strerror(avahi_server_errno(s)));

            avahi_simple_poll_quit(simple_poll_api);
            break;

        case AVAHI_SERVER_REGISTERING:

            sd_notifyf(0, "STATUS=Registering host name %s", avahi_server_get_host_name_fqdn(s));
            avahi_set_proc_title(argv0, "%s: registering [%s]", argv0, avahi_server_get_host_name_fqdn(s));

            static_service_remove_from_server();
            static_hosts_remove_from_server();
            remove_dns_server_entry_groups();

            break;

        case AVAHI_SERVER_INVALID:
            break;

    }
}
static void entry_group_callback(AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *eg, AvahiEntryGroupState state, void* userdata) {
    StaticHost *h;

    assert(s);
    assert(eg);

    h = userdata;

    switch (state) {

        case AVAHI_ENTRY_GROUP_COLLISION:
            avahi_log_error("Host name conflict for \"%s\", not established.", h->host);
            break;

        case AVAHI_ENTRY_GROUP_ESTABLISHED:
            avahi_log_notice ("Static host name \"%s\" successfully established.", h->host);
            break;

        case AVAHI_ENTRY_GROUP_FAILURE:
            avahi_log_notice ("Failed to establish static host name \"%s\": %s.", h->host, avahi_strerror (avahi_server_errno (s)));
            break;
        
        case AVAHI_ENTRY_GROUP_UNCOMMITED:
        case AVAHI_ENTRY_GROUP_REGISTERING:
            ;
    }
}