]> git.meshlink.io Git - catta/blobdiff - avahi-daemon/dbus-protocol.c
* fix bug reported bei Sebastien Estienne: bogus assert whhen service resolving fails
[catta] / avahi-daemon / dbus-protocol.c
index ab30a91cdbc657c9241d1a56c4d587d8651da8ec..0631f729f92d2656d4bf50c1efe2ef17020aad7d 100644 (file)
 #include <avahi-core/llist.h>
 #include <avahi-core/log.h>
 #include <avahi-core/core.h>
+#include <avahi-common/dbus.h>
 
 #include "dbus-protocol.h"
 #include "main.h"
 
-#define AVAHI_DBUS_NAME "org.freedesktop.Avahi"
-#define AVAHI_DBUS_INTERFACE_SERVER AVAHI_DBUS_NAME".Server"
-#define AVAHI_DBUS_PATH_SERVER "/org/freedesktop/Avahi/Server"
-#define AVAHI_DBUS_INTERFACE_ENTRY_GROUP AVAHI_DBUS_NAME".EntryGroup"
-#define AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER AVAHI_DBUS_NAME".DomainBrowser"
-#define AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER AVAHI_DBUS_NAME".ServiceTypeBrowser"
-#define AVAHI_DBUS_INTERFACE_SERVICE_BROWSER AVAHI_DBUS_NAME".ServiceBrowser"
-
-/* Needs wrapping:
-   - AvahiServiceResolver */
-
 typedef struct Server Server;
 typedef struct Client Client;
 typedef struct EntryGroupInfo EntryGroupInfo;
@@ -318,6 +308,47 @@ static DBusHandlerResult respond_path(DBusConnection *c, DBusMessage *m, const g
     return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+static DBusHandlerResult handle_introspect(DBusConnection *c, DBusMessage *m, const gchar *fname) {
+    gchar *path = NULL;
+    gchar *contents;
+    GError *gerror = NULL;
+    DBusError error;
+    
+    g_assert(c);
+    g_assert(m);
+    g_assert(fname);
+
+    dbus_error_init(&error);
+
+    if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
+        avahi_log_warn("Error parsing Introspect message: %s", error.message);
+        goto fail;
+    }
+    
+    path = g_strdup_printf("%s/%s", AVAHI_DBUS_INTROSPECTION_DIR, fname);
+
+    if (!(g_file_get_contents(path, &contents, NULL, &gerror))) {
+        avahi_log_warn("Failed to load introspection data: %s", gerror->message);
+        g_error_free(gerror);
+        g_free(path);
+        goto fail;
+    }
+
+    g_free(path);
+    
+    respond_string(c, m, contents);
+    g_free(contents);
+    
+    return DBUS_HANDLER_RESULT_HANDLED;
+
+fail:
+    if (dbus_error_is_set(&error))
+        dbus_error_free(&error);
+    
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+}
+
 static DBusHandlerResult msg_signal_filter_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
     GMainLoop *loop = userdata;
     DBusError error;
@@ -405,6 +436,10 @@ static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m,
                     dbus_message_get_path(m),
                     dbus_message_get_member(m));
 
+    /* Introspection */
+    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
+        return handle_introspect(c, m, "EntryGroup.introspect");
+    
     /* Access control */
     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
@@ -620,6 +655,10 @@ static DBusHandlerResult msg_domain_browser_impl(DBusConnection *c, DBusMessage
                     dbus_message_get_path(m),
                     dbus_message_get_member(m));
 
+    /* Introspection */
+    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
+        return handle_introspect(c, m, "DomainBrowser.introspect");
+    
     /* Access control */
     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
@@ -684,6 +723,10 @@ static DBusHandlerResult msg_service_type_browser_impl(DBusConnection *c, DBusMe
                     dbus_message_get_path(m),
                     dbus_message_get_member(m));
 
+    /* Introspection */
+    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
+        return handle_introspect(c, m, "ServiceTypeBrowser.introspect");
+    
     /* Access control */
     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
@@ -750,6 +793,10 @@ static DBusHandlerResult msg_service_browser_impl(DBusConnection *c, DBusMessage
                     dbus_message_get_path(m),
                     dbus_message_get_member(m));
 
+    /* Introspection */
+    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
+        return handle_introspect(c, m, "ServiceBrowser.introspect");
+    
     /* Access control */
     if (strcmp(dbus_message_get_sender(m), i->client->name)) 
         return respond_error(c, m, DBUS_ERROR_ACCESS_DENIED, NULL);
@@ -803,6 +850,78 @@ static void service_browser_callback(AvahiServiceBrowser *b, AvahiIfIndex interf
     dbus_message_unref(m);
 }
 
+static void service_resolver_callback(
+    AvahiServiceResolver *r,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiResolverEvent event,
+    const gchar *name,
+    const gchar *type,
+    const gchar *domain,
+    const gchar *host_name,
+    const AvahiAddress *a,
+    guint16 port,
+    AvahiStringList *txt,
+    gpointer userdata) {
+    
+    ServiceResolverInfo *i = userdata;
+    DBusMessage *reply;
+    
+    g_assert(r);
+    g_assert(i);
+
+    if (event == AVAHI_RESOLVER_FOUND) {
+        char t[256], *pt = t;
+        gint32 i_interface, i_protocol, i_aprotocol;
+        gchar **array;
+        guint n, j;
+        AvahiStringList *p;
+
+        g_assert(host_name);
+        
+        g_assert(a);
+        avahi_address_snprint(t, sizeof(t), a);
+
+        i_interface = (gint32) interface;
+        i_protocol = (gint32) protocol;
+        i_aprotocol = (gint32) a->family;
+
+        array = g_new(gchar*, (n = avahi_string_list_length(txt)));
+
+        /** FIXME: DBUS doesn't support strings that include NUL bytes (?) */
+        for (p = txt, j = n-1; p; p = p->next, j--)
+            array[j] = g_strndup((gchar*) p->text, p->size);
+        
+        reply = dbus_message_new_method_return(i->message);
+        dbus_message_append_args(
+            reply,
+            DBUS_TYPE_INT32, &i_interface,
+            DBUS_TYPE_INT32, &i_protocol,
+            DBUS_TYPE_STRING, &name,
+            DBUS_TYPE_STRING, &type,
+            DBUS_TYPE_STRING, &domain,
+            DBUS_TYPE_STRING, &host_name,
+            DBUS_TYPE_INT32, &i_aprotocol,
+            DBUS_TYPE_STRING, &pt,
+            DBUS_TYPE_UINT16, &port,
+            DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, n,
+            DBUS_TYPE_INVALID);
+
+        for (j = 0; j < n; j++)
+            g_free(array[j]);
+
+    } else {
+        g_assert(event == AVAHI_RESOLVER_TIMEOUT);
+        reply = dbus_message_new_error(i->message, "org.freedesktop.Avahi.TimeoutError", NULL);
+    }
+
+    dbus_connection_send(server->bus, reply, NULL);
+    dbus_message_unref(reply);
+
+    service_resolver_free(i);
+}
+
+
 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
     DBusError error;
 
@@ -813,7 +932,10 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
                     dbus_message_get_path(m),
                     dbus_message_get_member(m));
 
-    if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
+    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
+        return handle_introspect(c, m, "Server.introspect");
+        
+    else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostName")) {
 
         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
             avahi_log_warn("Error parsing Server::GetHostName message");
@@ -822,7 +944,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
 
         return respond_string(c, m, avahi_server_get_host_name(avahi_server));
         
-    } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetDomainName")) {
 
         if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
             avahi_log_warn("Error parsing Server::GetDomainName message");
@@ -831,7 +953,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
 
         return respond_string(c, m, avahi_server_get_domain_name(avahi_server));
 
-    } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetHostNameFqdn")) {
 
         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
             avahi_log_warn("Error parsing Server::GetHostNameFqdn message");
@@ -840,7 +962,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
     
         return respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
         
-    } if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString")) {
 
         if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
             avahi_log_warn("Error parsing Server::GetVersionString message");
@@ -848,6 +970,52 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
         }
     
         return respond_string(c, m, PACKAGE_STRING);
+
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetState")) {
+        DBusMessage *reply;
+        gint32 s;
+            
+        if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) {
+            avahi_log_warn("Error parsing Server::GetState message");
+            goto fail;
+        }
+
+        s = (gint32) avahi_server_get_state(avahi_server);
+        
+        reply = dbus_message_new_method_return(m);
+        dbus_message_append_args(reply, DBUS_TYPE_INT32, &s, DBUS_TYPE_INVALID);
+        dbus_connection_send(c, reply, NULL);
+        dbus_message_unref(reply);
+        
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeHostName")) {
+        gchar *n, * t;
+        
+        if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n || !*n) {
+            avahi_log_warn("Error parsing Server::GetAlternativeHostName message");
+            goto fail;
+        }
+
+        t = avahi_alternative_host_name(n);
+        respond_string(c, m, t);
+        g_free(t);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeServiceName")) {
+        gchar *n, *t;
+        
+        if (!(dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n || !*n) {
+            avahi_log_warn("Error parsing Server::GetAlternativeServiceName message");
+            goto fail;
+        }
+
+        t = avahi_alternative_service_name(n);
+        respond_string(c, m, t);
+        g_free(t);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
         
     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "EntryGroupNew")) {
         Client *client;
@@ -871,7 +1039,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
         i = g_new(EntryGroupInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/EntryGroup%u", client->id, i->id);
+        i->path = g_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
         AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
 
         if (!(i->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, i))) {
@@ -987,7 +1155,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
         i = g_new(DomainBrowserInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/DomainBrowser%u", client->id, i->id);
+        i->path = g_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
 
         AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
 
@@ -1032,7 +1200,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
         i = g_new(ServiceTypeBrowserInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/ServiceTypeBrowser%u", client->id, i->id);
+        i->path = g_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
 
         AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
 
@@ -1078,7 +1246,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
         i = g_new(ServiceBrowserInfo, 1);
         i->id = ++client->current_id;
         i->client = client;
-        i->path = g_strdup_printf("/org/freedesktop/Avahi/Client%u/ServiceBrowser%u", client->id, i->id);
+        i->path = g_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
 
         AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
 
@@ -1090,11 +1258,47 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void
         
         dbus_connection_register_object_path(c, i->path, &vtable, i);
         return respond_path(c, m, i->path);
+        
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "ResolveService")) {
+        Client *client;
+        gint32 interface, protocol, aprotocol;
+        gchar *name, *type, *domain;
+        ServiceResolverInfo *i;
+            
+        if (!dbus_message_get_args(
+                m, &error,
+                DBUS_TYPE_INT32, &interface,
+                DBUS_TYPE_INT32, &protocol,
+                DBUS_TYPE_STRING, &name,
+                DBUS_TYPE_STRING, &type,
+                DBUS_TYPE_STRING, &domain,
+                DBUS_TYPE_INT32, &aprotocol,
+                DBUS_TYPE_INVALID) || !name || !*name || !type || !*type) {
+            avahi_log_warn("Error parsing Server::ResolveService message");
+            goto fail;
+        }
+
+        client = client_get(dbus_message_get_sender(m), TRUE);
+
+        if (!*domain)
+            domain = NULL;
+        
+        i = g_new(ServiceResolverInfo, 1);
+        i->client = client;
+        i->message = dbus_message_ref(m);
+        AVAHI_LLIST_PREPEND(ServiceResolverInfo, service_resolvers, client->service_resolvers, i);
+
+        if (!(i->service_resolver = avahi_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, service_resolver_callback, i))) {
+            service_resolver_free(i);
+            avahi_log_warn("Failed to create service resolver");
+            goto fail;
+        }
+        
+        return DBUS_HANDLER_RESULT_HANDLED;
      }
 
     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);