]> git.meshlink.io Git - catta/blobdiff - avahi-daemon/dbus-protocol.c
autoconf love:
[catta] / avahi-daemon / dbus-protocol.c
index 2e3fd2f2d594d8cf8a93fd1d7f6b5330912c36f9..e74caa328ec7213c056b76de994d168351550dd2 100644 (file)
 #include <avahi-common/dbus.h>
 #include <avahi-common/llist.h>
 #include <avahi-common/malloc.h>
-#include <avahi-common/dbus.h>
 #include <avahi-common/dbus-watch-glue.h>
 #include <avahi-common/alternative.h>
 #include <avahi-common/error.h>
 #include <avahi-common/domain.h>
+#include <avahi-common/timeval.h>
 
 #include <avahi-core/log.h>
 #include <avahi-core/core.h>
 
 /* #define VALGRIND_WORKAROUND 1 */
 
+#define RECONNECT_MSEC 3000
+
 Server *server = NULL;
 
 static int disable_user_service_publishing = 0;
 
+static int dbus_connect(void);
+static void dbus_disconnect(void);
+
 static void client_free(Client *c) {
     
     assert(server);
@@ -156,6 +161,20 @@ static Client *client_get(const char *name, int create) {
     return client;
 }
 
+static void reconnect_callback(AvahiTimeout *t, AVAHI_GCC_UNUSED void *userdata) {
+    assert(!server->bus);
+
+    if (dbus_connect() < 0) {
+        struct timeval tv;
+        avahi_log_debug(__FILE__": Connection failed, retrying in %ims...", RECONNECT_MSEC);
+        avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
+        server->poll_api->timeout_update(t, &tv);
+    } else {
+        avahi_log_debug(__FILE__": Successfully reconnected.");
+        server->poll_api->timeout_update(t, NULL);
+    }
+}
+
 static DBusHandlerResult msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata) {
     DBusError error;
 
@@ -167,12 +186,24 @@ static DBusHandlerResult msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection
 /*                     dbus_message_get_member(m)); */
 
     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
-        /* No, we shouldn't quit, but until we get somewhere
-         * usefull such that we can restore our state, we will */
-        avahi_log_warn("Disconnnected from D-BUS, terminating...");
-        
-        raise(SIGQUIT); /* The signal handler will catch this and terminate the process cleanly*/
-        
+        struct timeval tv;
+
+        if (server->reconnect) {
+            avahi_log_warn("Disconnnected from D-BUS, trying to reconnect in %ims...", RECONNECT_MSEC);
+            
+            dbus_disconnect();
+            
+            avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
+            
+            if (server->reconnect_timeout)
+                server->poll_api->timeout_update(server->reconnect_timeout, &tv);
+            else
+                server->reconnect_timeout = server->poll_api->timeout_new(server->poll_api, &tv, reconnect_callback, NULL);
+        } else {
+            avahi_log_warn("Disconnnected from D-BUS, exiting.");
+            raise(SIGQUIT);
+        }
+            
         return DBUS_HANDLER_RESULT_HANDLED;
         
     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
@@ -233,6 +264,22 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
 
         return avahi_dbus_respond_string(c, m, avahi_server_get_host_name(avahi_server));
         
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "SetHostName")) {
+
+        char *name;
+        
+        if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
+            avahi_log_warn("Error parsing Server::SetHostName message");
+            goto fail;
+        }
+        
+        if (avahi_server_set_host_name(avahi_server, name) < 0) 
+            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
+
+        avahi_log_info("Changing host name to '%s'.", name);
+        
+        return avahi_dbus_respond_ok(c, m);
+        
     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
 
         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
@@ -424,7 +471,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(EntryGroupInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
+        i->path = NULL;
         i->n_entries = 0;
         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
         client->n_objects++;
@@ -434,6 +481,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
         }
 
+        i->path = avahi_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
         
@@ -567,7 +615,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(DomainBrowserInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
+        i->path = NULL;
         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
         client->n_objects++;
 
@@ -575,7 +623,8 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
             avahi_dbus_domain_browser_free(i);
             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
         }
-        
+
+        i->path = avahi_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
 
@@ -621,7 +670,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(ServiceTypeBrowserInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
+        i->path = NULL;
         AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
         client->n_objects++;
 
@@ -630,6 +679,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
         }
         
+        i->path = avahi_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
         
@@ -676,7 +726,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(ServiceBrowserInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
+        i->path = NULL;
         AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
         client->n_objects++;
 
@@ -684,7 +734,8 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
             avahi_dbus_service_browser_free(i);
             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
         }
-        
+
+        i->path = avahi_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
         
@@ -786,7 +837,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(AsyncServiceResolverInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/ServiceResolver%u", client->id, i->id);
+        i->path = NULL;
         AVAHI_LLIST_PREPEND(AsyncServiceResolverInfo, async_service_resolvers, client->async_service_resolvers, i);
         client->n_objects++;
 
@@ -797,6 +848,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
 
 /*         avahi_log_debug(__FILE__": [%s], new service resolver for <%s.%s.%s>", i->path, name, type, domain); */
         
+        i->path = avahi_strdup_printf("/Client%u/ServiceResolver%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
 
@@ -840,7 +892,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(AsyncHostNameResolverInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/HostNameResolver%u", client->id, i->id);
+        i->path = NULL;
         AVAHI_LLIST_PREPEND(AsyncHostNameResolverInfo, async_host_name_resolvers, client->async_host_name_resolvers, i);
         client->n_objects++;
 
@@ -848,7 +900,8 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
             avahi_dbus_async_host_name_resolver_free(i);
             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
         }
-        
+
+        i->path = avahi_strdup_printf("/Client%u/HostNameResolver%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
 
@@ -895,7 +948,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(AsyncAddressResolverInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/AddressResolver%u", client->id, i->id);
+        i->path = NULL;
         AVAHI_LLIST_PREPEND(AsyncAddressResolverInfo, async_address_resolvers, client->async_address_resolvers, i);
         client->n_objects++;
 
@@ -903,7 +956,8 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
             avahi_dbus_async_address_resolver_free(i);
             return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
         }
-        
+
+        i->path = avahi_strdup_printf("/Client%u/AddressResolver%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
         
@@ -953,7 +1007,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
         i = avahi_new(RecordBrowserInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = avahi_strdup_printf("/Client%u/RecordBrowser%u", client->id, i->id);
+        i->path = NULL;
         AVAHI_LLIST_PREPEND(RecordBrowserInfo, record_browsers, client->record_browsers, i);
         client->n_objects++;
 
@@ -968,6 +1022,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH
 
         avahi_key_unref(key);
         
+        i->path = avahi_strdup_printf("/Client%u/RecordBrowser%u", client->id, i->id);
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return avahi_dbus_respond_path(c, m, i->path);
     }
@@ -986,7 +1041,7 @@ void dbus_protocol_server_state_changed(AvahiServerState state) {
     int32_t t;
     const char *e;
     
-    if (!server)
+    if (!server || !server->bus)
         return;
 
     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
@@ -1004,7 +1059,7 @@ void dbus_protocol_server_state_changed(AvahiServerState state) {
     dbus_message_unref(m);
 }
 
-int dbus_protocol_setup(const AvahiPoll *poll_api, int _disable_user_service_publishing) {
+static int dbus_connect(void) {
     DBusError error;
 
     static const DBusObjectPathVTable server_vtable = {
@@ -1016,26 +1071,23 @@ int dbus_protocol_setup(const AvahiPoll *poll_api, int _disable_user_service_pub
         NULL
     };
 
-    dbus_error_init(&error);
-
-    disable_user_service_publishing = _disable_user_service_publishing;
-
-    server = avahi_new(Server, 1);
-    AVAHI_LLIST_HEAD_INIT(Clients, server->clients);
-    server->current_id = 0;
-    server->n_clients = 0;
+    assert(server);
+    assert(!server->bus);
 
+    dbus_error_init(&error);
+    
     if (!(server->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
         assert(dbus_error_is_set(&error));
         avahi_log_error("dbus_bus_get(): %s", error.message);
         goto fail;
     }
-
-    if (avahi_dbus_connection_glue(server->bus, poll_api) < 0) {
+    if (avahi_dbus_connection_glue(server->bus, server->poll_api) < 0) {
         avahi_log_error("avahi_dbus_connection_glue() failed");
         goto fail;
     }
 
+    dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
+    
     if (dbus_bus_request_name(
             server->bus,
             AVAHI_DBUS_NAME,
@@ -1054,7 +1106,7 @@ int dbus_protocol_setup(const AvahiPoll *poll_api, int _disable_user_service_pub
         goto fail;
     }
 
-    if (!(dbus_connection_add_filter(server->bus, msg_signal_filter_impl, (void*) poll_api, NULL))) {
+    if (!(dbus_connection_add_filter(server->bus, msg_signal_filter_impl, (void*) server->poll_api, NULL))) {
         avahi_log_error("dbus_connection_add_filter() failed");
         goto fail;
     }
@@ -1072,16 +1124,80 @@ int dbus_protocol_setup(const AvahiPoll *poll_api, int _disable_user_service_pub
     }
 
     return 0;
-
 fail:
+
+    if (dbus_error_is_set(&error))
+        dbus_error_free(&error);
+
     if (server->bus) {
+#ifdef HAVE_DBUS_CONNECTION_CLOSE
+        dbus_connection_close(server->bus);
+#else
         dbus_connection_disconnect(server->bus);
+#endif
         dbus_connection_unref(server->bus);
+        server->bus = NULL;
     }
 
-    if (dbus_error_is_set(&error))
-        dbus_error_free(&error);
+    return -1;
+}
+
+static void dbus_disconnect(void) {
+    assert(server);
+
+    while (server->clients)
+        client_free(server->clients);
+    
+    assert(server->n_clients == 0);
+
+    if (server->bus) {
+#ifdef HAVE_DBUS_CONNECTION_CLOSE
+        dbus_connection_close(server->bus);
+#else
+        dbus_connection_disconnect(server->bus);
+#endif
+        dbus_connection_unref(server->bus);
+        server->bus = NULL;
+    }
+}
+
+int dbus_protocol_setup(const AvahiPoll *poll_api, int _disable_user_service_publishing, int force) {
+
+    disable_user_service_publishing = _disable_user_service_publishing;
+
+    server = avahi_new(Server, 1);
+    AVAHI_LLIST_HEAD_INIT(Clients, server->clients);
+    server->current_id = 0;
+    server->n_clients = 0;
+    server->bus = NULL;
+    server->poll_api = poll_api;
+    server->reconnect_timeout = NULL;
+    server->reconnect = force;
+
+    if (dbus_connect() < 0) {
+        struct timeval tv;
+
+        if (!force)
+            goto fail;
+
+        avahi_log_warn("WARNING: Failed to contact D-Bus daemon, retrying in %ims.", RECONNECT_MSEC);
         
+        avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
+        server->reconnect_timeout = server->poll_api->timeout_new(server->poll_api, &tv, reconnect_callback, NULL);
+    }
+        
+    return 0;
+
+fail:
+    if (server->bus) {
+#ifdef HAVE_DBUS_CONNECTION_CLOSE
+        dbus_connection_close(server->bus);
+#else
+        dbus_connection_disconnect(server->bus);
+#endif
+        dbus_connection_unref(server->bus);
+    }
+
     avahi_free(server);
     server = NULL;
     return -1;
@@ -1090,17 +1206,11 @@ fail:
 void dbus_protocol_shutdown(void) {
 
     if (server) {
-    
-        while (server->clients)
-            client_free(server->clients);
-
-        assert(server->n_clients == 0);
-
-        if (server->bus) {
-            dbus_connection_disconnect(server->bus);
-            dbus_connection_unref(server->bus);
-        }
+        dbus_disconnect();
 
+        if (server->reconnect_timeout)
+            server->poll_api->timeout_free(server->reconnect_timeout);
+        
         avahi_free(server);
         server = NULL;
     }