diff options
| author | Lennart Poettering <lennart@poettering.net> | 2005-11-16 19:30:11 +0000 | 
|---|---|---|
| committer | Lennart Poettering <lennart@poettering.net> | 2005-11-16 19:30:11 +0000 | 
| commit | 9e4237ebed07d00bf1176178d1358b475d749b27 (patch) | |
| tree | 38b9fa5103733445ce69012a5c6ae65fdb043a91 | |
| parent | affa11f5bb7309fa504624a3512dce5c88ce473b (diff) | |
* Implement client API for arbitrary record browsing
* Fix memory leak in avahi-client
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@984 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe
| -rw-r--r-- | avahi-client/Makefile.am | 7 | ||||
| -rw-r--r-- | avahi-client/browser.c | 243 | ||||
| -rw-r--r-- | avahi-client/client.c | 22 | ||||
| -rw-r--r-- | avahi-client/entrygroup.c | 2 | ||||
| -rw-r--r-- | avahi-client/internal.h | 15 | ||||
| -rw-r--r-- | avahi-client/lookup.h | 65 | ||||
| -rw-r--r-- | avahi-client/rr-test.c | 113 | ||||
| -rw-r--r-- | avahi-common/dbus.h | 2 | ||||
| -rw-r--r-- | avahi-daemon/EntryGroup.introspect | 6 | ||||
| -rw-r--r-- | avahi-daemon/Makefile.am | 7 | ||||
| -rw-r--r-- | avahi-daemon/RecordBrowser.introspect | 67 | ||||
| -rw-r--r-- | avahi-daemon/Server.introspect | 13 | ||||
| -rw-r--r-- | avahi-daemon/chroot.c | 4 | ||||
| -rw-r--r-- | avahi-daemon/dbus-internal.h | 16 | ||||
| -rw-r--r-- | avahi-daemon/dbus-protocol.c | 69 | ||||
| -rw-r--r-- | avahi-daemon/dbus-record-browser.c | 158 | ||||
| -rw-r--r-- | avahi-daemon/dbus-service-browser.c | 1 | ||||
| -rw-r--r-- | avahi-daemon/dbus-util.c | 14 | ||||
| -rw-r--r-- | avahi-daemon/dbus-util.h | 2 | 
19 files changed, 812 insertions, 14 deletions
diff --git a/avahi-client/Makefile.am b/avahi-client/Makefile.am index 463ea39..aaa772a 100644 --- a/avahi-client/Makefile.am +++ b/avahi-client/Makefile.am @@ -34,7 +34,8 @@ if ENABLE_TESTS  noinst_PROGRAMS = \  	client-test \  	srv-test \ -	xdg-config-test +	xdg-config-test \ +	rr-test  endif @@ -60,6 +61,10 @@ srv_test_SOURCES = srv-test.c  srv_test_CFLAGS = $(AM_CFLAGS)   srv_test_LDADD = $(AM_LDADD) libavahi-client.la ../avahi-common/libavahi-common.la  +rr_test_SOURCES = rr-test.c +rr_test_CFLAGS = $(AM_CFLAGS)  +rr_test_LDADD = $(AM_LDADD) libavahi-client.la ../avahi-common/libavahi-common.la  +  xdg_config_test_SOURCES = xdg-config-test.c xdg-config.c xdg-config.h  xdg_config_test_CFLAGS = $(AM_CFLAGS)   xdg_config_test_LDADD = $(AM_LDADD) diff --git a/avahi-client/browser.c b/avahi-client/browser.c index c9af43f..a8a823e 100644 --- a/avahi-client/browser.c +++ b/avahi-client/browser.c @@ -348,6 +348,7 @@ fail:  }  /* AvahiServiceTypeBrowser */ +  AvahiServiceTypeBrowser* avahi_service_type_browser_new(      AvahiClient *client,      AvahiIfIndex interface, @@ -782,4 +783,246 @@ fail:      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;  } +/* AvahiRecordBrowser */ + +AvahiRecordBrowser* avahi_record_browser_new( +    AvahiClient *client, +    AvahiIfIndex interface, +    AvahiProtocol protocol, +    const char *name, +    uint16_t clazz, +    uint16_t type, +    AvahiLookupFlags flags, +    AvahiRecordBrowserCallback callback, +    void *userdata) { +     +    AvahiRecordBrowser *b = NULL; +    DBusMessage *message = NULL, *reply = NULL; +    DBusError error; +    char *path; +    int32_t i_protocol, i_interface; +    uint32_t u_flags; + +    assert(client); +    assert(name); +    assert(callback); + +    dbus_error_init(&error); + +    if (!avahi_client_is_connected(client)) { +        avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); +        goto fail; +    } + +    if (!(b = avahi_new(AvahiRecordBrowser, 1))) { +        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); +        goto fail; +    } +     +    b->client = client; +    b->callback = callback; +    b->userdata = userdata; +    b->path = NULL; +    b->name = NULL; +    b->clazz = clazz; +    b->type = type; +    b->interface = interface; +    b->protocol = protocol; + +    AVAHI_LLIST_PREPEND(AvahiRecordBrowser, record_browsers, client->record_browsers, b); + +    if (!(b->name = avahi_strdup(name))) { +        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); +        goto fail; +    } +     +    if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "RecordBrowserNew"))) { +        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); +        goto fail; +    } + +    i_interface = (int32_t) interface; +    i_protocol = (int32_t) protocol; +    u_flags = (uint32_t) flags; + +    if (!dbus_message_append_args( +            message, +            DBUS_TYPE_INT32, &i_interface, +            DBUS_TYPE_INT32, &i_protocol, +            DBUS_TYPE_STRING, &name, +            DBUS_TYPE_UINT16, &clazz, +            DBUS_TYPE_UINT16, &type, +            DBUS_TYPE_UINT32, &u_flags, +            DBUS_TYPE_INVALID)) { +        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); +        goto fail; +    } + +    if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || +        dbus_error_is_set(&error)) { +        avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); +        goto fail; +    } + +    if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || +        dbus_error_is_set(&error) || +        !path) { +        avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); +        goto fail; +    } + +    if (!(b->path = avahi_strdup(path))) { + +        /* FIXME: We don't remove the object on the server side */ + +        avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); +        goto fail; +    } + +    dbus_message_unref(message); +    dbus_message_unref(reply); +     +    return b; + +fail: +    if (dbus_error_is_set(&error)) { +        avahi_client_set_dbus_error(client, &error); +        dbus_error_free(&error); +    } + +    if (b) +        avahi_record_browser_free(b); +     +    if (message) +        dbus_message_unref(message); + +    if (reply) +        dbus_message_unref(reply); + +    return NULL; +} + +AvahiClient* avahi_record_browser_get_client (AvahiRecordBrowser *b) { +    assert(b); +    return b->client; +} + +int avahi_record_browser_free (AvahiRecordBrowser *b) { +    AvahiClient *client; +    int r = AVAHI_OK; + +    assert(b); +    client = b->client; + +    if (b->path && avahi_client_is_connected(b->client)) +        r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Free"); + +    AVAHI_LLIST_REMOVE(AvahiRecordBrowser, record_browsers, b->client->record_browsers, b); + +    avahi_free(b->path); +    avahi_free(b->name); +    avahi_free(b); +    return r; +} + +DBusHandlerResult avahi_record_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) { +    AvahiRecordBrowser *b = NULL; +    DBusError error; +    const char *path; +    char *name; +    int32_t interface, protocol; +    uint32_t flags = 0; +    uint16_t clazz, type; +    void *rdata = NULL; +    int rdata_size = 0; + +    dbus_error_init (&error); + +    if (!(path = dbus_message_get_path(message))) +        goto fail; + +    for (b = client->record_browsers; b; b = b->record_browsers_next) +        if (strcmp (b->path, path) == 0) +            break; + +    if (!b) +        goto fail; + +    interface = b->interface; +    protocol = b->protocol; +    clazz = b->clazz; +    type = b->type; +    name = b->name; + +    switch (event) { +        case AVAHI_BROWSER_NEW: +        case AVAHI_BROWSER_REMOVE: { +            DBusMessageIter iter, sub; +            int j; + +            if (!dbus_message_get_args ( +                    message, &error, +                    DBUS_TYPE_INT32, &interface, +                    DBUS_TYPE_INT32, &protocol, +                    DBUS_TYPE_STRING, &name, +                    DBUS_TYPE_UINT16, &clazz, +                    DBUS_TYPE_UINT16, &type, +                    DBUS_TYPE_INVALID) || +                dbus_error_is_set(&error)) { +                fprintf(stderr, "Failed to parse browser event.\n"); +                goto fail; +            } + + +            dbus_message_iter_init(message, &iter); + +            for (j = 0; j < 5; j++) +                dbus_message_iter_next(&iter); +     +            if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || +                dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE) +                goto fail; + +            dbus_message_iter_recurse(&iter, &sub); +            dbus_message_iter_get_fixed_array(&sub, &rdata, &rdata_size); + +            dbus_message_iter_next(&iter); +             +            if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) +                goto fail; + +            dbus_message_iter_get_basic(&iter, &flags); +             +            break; +        } + +        case AVAHI_BROWSER_CACHE_EXHAUSTED: +        case AVAHI_BROWSER_ALL_FOR_NOW: +            break; + +        case AVAHI_BROWSER_FAILURE: { +            char *etxt; +             +            if (!dbus_message_get_args( +                    message, &error, +                    DBUS_TYPE_STRING, &etxt, +                    DBUS_TYPE_INVALID) || +                dbus_error_is_set (&error)) { +                fprintf(stderr, "Failed to parse browser event.\n"); +                goto fail; +            } +             +            avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt)); +            break; +        } +    } + +    b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, name, clazz, type, rdata, (size_t) rdata_size, (AvahiLookupResultFlags) flags, b->userdata); + +    return DBUS_HANDLER_RESULT_HANDLED; + +fail: +    dbus_error_free (&error); +    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} diff --git a/avahi-client/client.c b/avahi-client/client.c index 2fd5123..54d19e5 100644 --- a/avahi-client/client.c +++ b/avahi-client/client.c @@ -260,6 +260,18 @@ static DBusHandlerResult filter_func(DBusConnection *bus, DBusMessage *message,          return avahi_address_resolver_event (client, AVAHI_RESOLVER_FOUND, message);      else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Failure"))           return avahi_address_resolver_event (client, AVAHI_RESOLVER_FAILURE, message); + +    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "ItemNew"))  +        return avahi_record_browser_event (client, AVAHI_BROWSER_NEW, message); +    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "ItemRemove"))  +        return avahi_record_browser_event (client, AVAHI_BROWSER_REMOVE, message); +    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "CacheExhausted"))  +        return avahi_record_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message); +    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "AllForNow"))  +        return avahi_record_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message); +    else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Failure"))  +        return avahi_record_browser_event (client, AVAHI_BROWSER_FAILURE, message); +      else {          fprintf(stderr, "WARNING: Unhandled message: interface=%s, path=%s, member=%s\n", @@ -446,6 +458,7 @@ AvahiClient *avahi_client_new(const AvahiPoll *poll_api, AvahiClientFlags flags,      AVAHI_LLIST_HEAD_INIT(AvahiServiceResolver, client->service_resolvers);      AVAHI_LLIST_HEAD_INIT(AvahiHostNameResolver, client->host_name_resolvers);      AVAHI_LLIST_HEAD_INIT(AvahiAddressResolver, client->address_resolvers); +    AVAHI_LLIST_HEAD_INIT(AvahiRecordBrowser, client->record_browsers);      if (!(client->bus = avahi_dbus_bus_get(&error)) || dbus_error_is_set(&error)) {          if (ret_error) @@ -558,6 +571,15 @@ void avahi_client_free(AvahiClient *client) {      while (client->service_resolvers)          avahi_service_resolver_free(client->service_resolvers); +    while (client->host_name_resolvers) +        avahi_host_name_resolver_free(client->host_name_resolvers); + +    while (client->address_resolvers) +        avahi_address_resolver_free(client->address_resolvers); + +    while (client->record_browsers) +        avahi_record_browser_free(client->record_browsers); +          if (client->bus) {          dbus_connection_disconnect(client->bus);          dbus_connection_unref(client->bus); diff --git a/avahi-client/entrygroup.c b/avahi-client/entrygroup.c index 003b17c..162f2c4 100644 --- a/avahi-client/entrygroup.c +++ b/avahi-client/entrygroup.c @@ -700,8 +700,6 @@ fail:          dbus_message_unref(reply);      return r; -     -      }  /** Add a host/address pair */ diff --git a/avahi-client/internal.h b/avahi-client/internal.h index ef629e6..7a79dd7 100644 --- a/avahi-client/internal.h +++ b/avahi-client/internal.h @@ -50,6 +50,7 @@ struct AvahiClient {      AVAHI_LLIST_HEAD(AvahiServiceResolver, service_resolvers);      AVAHI_LLIST_HEAD(AvahiHostNameResolver, host_name_resolvers);      AVAHI_LLIST_HEAD(AvahiAddressResolver, address_resolvers); +    AVAHI_LLIST_HEAD(AvahiRecordBrowser, record_browsers);  };  struct AvahiEntryGroup { @@ -138,6 +139,19 @@ struct AvahiAddressResolver {      AvahiProtocol protocol;  }; +struct AvahiRecordBrowser { +    char *path; +    AvahiClient *client; +    AvahiRecordBrowserCallback callback; +    void *userdata; +    AVAHI_LLIST_FIELDS(AvahiRecordBrowser, record_browsers); + +    char *name; +    uint16_t clazz, type; +    AvahiIfIndex interface; +    AvahiProtocol protocol; +}; +  int avahi_client_set_errno (AvahiClient *client, int error);  int avahi_client_set_dbus_error(AvahiClient *client, DBusError *error); @@ -146,6 +160,7 @@ void avahi_entry_group_set_state(AvahiEntryGroup *group, AvahiEntryGroupState st  DBusHandlerResult avahi_domain_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message);  DBusHandlerResult avahi_service_type_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message);  DBusHandlerResult avahi_service_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message); +DBusHandlerResult avahi_record_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message);  DBusHandlerResult avahi_service_resolver_event (AvahiClient *client, AvahiResolverEvent event, DBusMessage *message);  DBusHandlerResult avahi_host_name_resolver_event (AvahiClient *client, AvahiResolverEvent event, DBusMessage *message); diff --git a/avahi-client/lookup.h b/avahi-client/lookup.h index f2db9ab..e96bcf7 100644 --- a/avahi-client/lookup.h +++ b/avahi-client/lookup.h @@ -58,14 +58,41 @@ typedef struct AvahiHostNameResolver AvahiHostNameResolver;  /** An address resolver object */  typedef struct AvahiAddressResolver AvahiAddressResolver; +/** A record browser object */ +typedef struct AvahiRecordBrowser AvahiRecordBrowser; +  /** The function prototype for the callback of an AvahiDomainBrowser */ -typedef void (*AvahiDomainBrowserCallback) (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, AvahiLookupResultFlags flags, void *userdata); +typedef void (*AvahiDomainBrowserCallback) ( +    AvahiDomainBrowser *b, +    AvahiIfIndex interface, +    AvahiProtocol protocol, +    AvahiBrowserEvent event, +    const char *domain, +    AvahiLookupResultFlags flags, +    void *userdata);  /** The function prototype for the callback of an AvahiServiceBrowser */ -typedef void (*AvahiServiceBrowserCallback) (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata); +typedef void (*AvahiServiceBrowserCallback) ( +    AvahiServiceBrowser *b, +    AvahiIfIndex interface, +    AvahiProtocol protocol, +    AvahiBrowserEvent event, +    const char *name, +    const char *type, +    const char *domain, +    AvahiLookupResultFlags flags, +    void *userdata);  /** The function prototype for the callback of an AvahiServiceTypeBrowser */ -typedef void (*AvahiServiceTypeBrowserCallback) (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata); +typedef void (*AvahiServiceTypeBrowserCallback) ( +    AvahiServiceTypeBrowser *b, +    AvahiIfIndex interface, +    AvahiProtocol protocol, +    AvahiBrowserEvent event, +    const char *type, +    const char *domain, +    AvahiLookupResultFlags flags, +    void *userdata);  /** The function prototype for the callback of an AvahiServiceResolver */  typedef void (*AvahiServiceResolverCallback) ( @@ -105,6 +132,20 @@ typedef void (*AvahiAddressResolverCallback) (      AvahiLookupResultFlags flags,       void *userdata); +/** The function prototype for the callback of an AvahiRecordBrowser */ +typedef void (*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); +  /** Browse for domains on the local network */  AvahiDomainBrowser* avahi_domain_browser_new (      AvahiClient *client, @@ -207,6 +248,24 @@ AvahiClient* avahi_address_resolver_get_client (AvahiAddressResolver *);  /** Free a AvahiAddressResolver resolver object */  int avahi_address_resolver_free(AvahiAddressResolver *r); +/** Browse for records of a type on the local network */ +AvahiRecordBrowser* avahi_record_browser_new( +    AvahiClient *client, +    AvahiIfIndex interface, +    AvahiProtocol protocol, +    const char *name, +    uint16_t clazz, +    uint16_t type, +    AvahiLookupFlags flags, +    AvahiRecordBrowserCallback callback, +    void *userdata); + +/** Get the parent client of an AvahiRecordBrowser object */ +AvahiClient* avahi_record_browser_get_client(AvahiRecordBrowser *); + +/* Cleans up and frees an AvahiRecordBrowser object */ +int avahi_record_browser_free(AvahiRecordBrowser *); +  AVAHI_C_DECL_END  #endif diff --git a/avahi-client/rr-test.c b/avahi-client/rr-test.c new file mode 100644 index 0000000..9fffa5d --- /dev/null +++ b/avahi-client/rr-test.c @@ -0,0 +1,113 @@ +/* $Id$ */ + +/*** +  This file is part of avahi. +  +  avahi is free software; you can redistribute it and/or modify it +  under the terms of the GNU Lesser General Public License as +  published by the Free Software Foundation; either version 2.1 of the +  License, or (at your option) any later version. +  +  avahi is distributed in the hope that it will be useful, but WITHOUT +  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +  Public License for more details. +  +  You should have received a copy of the GNU Lesser General Public +  License along with avahi; if not, write to the Free Software +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +  USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <assert.h> + +#include <avahi-client/client.h> +#include <avahi-client/lookup.h> +#include <avahi-common/error.h> +#include <avahi-common/simple-watch.h> +#include <avahi-common/malloc.h> + +static void hexdump(const void* p, size_t size) { +    const uint8_t *c = p; +    assert(p); + +    printf("Dumping %lu bytes from %p:\n", (unsigned long) size, p); +     +    while (size > 0) { +        unsigned i; + +        for (i = 0; i < 16; i++) {  +            if (i < size) +                printf("%02x ", c[i]); +            else +                printf("   "); +        } + +        for (i = 0; i < 16; i++) { +            if (i < size) +                printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.'); +            else +                printf(" "); +        } +         +        printf("\n"); + +        c += 16; + +        if (size <= 16) +            break; +         +        size -= 16; +    } +} + +static void callback( +    AVAHI_GCC_UNUSED AvahiRecordBrowser *r, +    AVAHI_GCC_UNUSED AvahiIfIndex interface, +    AVAHI_GCC_UNUSED AvahiProtocol protocol, +    AvahiBrowserEvent event, +    const char *name, +    uint16_t clazz, +    uint16_t type, +    const void *rdata, +    size_t rdata_size, +    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, +    AVAHI_GCC_UNUSED void *userdata) { + +    fprintf(stderr, "%i name=%s class=%u type=%u\n", event, name, clazz, type); + +    if (rdata) +        hexdump(rdata, rdata_size); +} + +int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) { + +    AvahiSimplePoll *simple_poll; +    const AvahiPoll *poll_api; +    AvahiClient *client; +    AvahiRecordBrowser *r; +     +    simple_poll = avahi_simple_poll_new(); +    assert(simple_poll); +     +    poll_api = avahi_simple_poll_get(simple_poll); +    assert(poll_api); +     +    client = avahi_client_new(poll_api, 0, NULL, NULL, NULL); +    assert(client); + +    r = avahi_record_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "ecstasy.local", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_HINFO, 0, callback, simple_poll); +    assert(r); + +    avahi_simple_poll_loop(simple_poll); + +    avahi_client_free(client); +    avahi_simple_poll_free(simple_poll); + +    return 0; +} diff --git a/avahi-common/dbus.h b/avahi-common/dbus.h index 0c51b0d..790fc3c 100644 --- a/avahi-common/dbus.h +++ b/avahi-common/dbus.h @@ -39,7 +39,7 @@ AVAHI_C_DECL_BEGIN  #define AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER AVAHI_DBUS_NAME".AddressResolver"  #define AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER AVAHI_DBUS_NAME".HostNameResolver"  #define AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER AVAHI_DBUS_NAME".ServiceResolver" -#define AVAHI_DBUS_INTERFACE_RECORD_BROWSER AVAHI_DBUS_NAME.".RecordBrowser" +#define AVAHI_DBUS_INTERFACE_RECORD_BROWSER AVAHI_DBUS_NAME".RecordBrowser"  #define AVAHI_DBUS_ERR_OK "org.freedesktop.Avahi.Success"  #define AVAHI_DBUS_ERR_FAILURE "org.freedesktop.Avahi.Failure" diff --git a/avahi-daemon/EntryGroup.introspect b/avahi-daemon/EntryGroup.introspect index bf2ea13..e49bbe6 100644 --- a/avahi-daemon/EntryGroup.introspect +++ b/avahi-daemon/EntryGroup.introspect @@ -94,9 +94,9 @@        <arg name="protocol" type="i" direction="in"/>        <arg name="flags" type="u" direction="in"/>        <arg name="name" type="s" direction="in"/> -      <arg name="clazz" type="i" direction="in"/> -      <arg name="type" type="i" direction="in"/> -      <arg name="ttl" type="i" direction="in"/> +      <arg name="clazz" type="q" direction="in"/> +      <arg name="type" type="q" direction="in"/> +      <arg name="ttl" type="u" direction="in"/>        <arg name="rdata" type="ay" direction="in"/>      </method>    </interface> diff --git a/avahi-daemon/Makefile.am b/avahi-daemon/Makefile.am index 6e0ac84..23f5a97 100644 --- a/avahi-daemon/Makefile.am +++ b/avahi-daemon/Makefile.am @@ -97,7 +97,8 @@ avahi_daemon_SOURCES += \  	dbus-service-type-browser.c \  	dbus-sync-address-resolver.c \  	dbus-sync-host-name-resolver.c \ -	dbus-sync-service-resolver.c	 +	dbus-sync-service-resolver.c \ +	dbus-record-browser.c  avahi_daemon_LDADD += \  	../avahi-common/libdbus-common.la \ @@ -115,7 +116,8 @@ introspection_DATA = \  	ServiceBrowser.introspect \  	ServiceResolver.introspect \  	AddressResolver.introspect \ -	HostNameResolver.introspect +	HostNameResolver.introspect \ +	RecordBrowser.introspect  endif  endif @@ -134,6 +136,7 @@ EXTRA_DIST = \  	ServiceResolver.introspect \  	AddressResolver.introspect \  	HostNameResolver.introspect \ +	RecordBrowser.introspect \  	ssh.service \  	example.service \  	introspect.dtd \ diff --git a/avahi-daemon/RecordBrowser.introspect b/avahi-daemon/RecordBrowser.introspect new file mode 100644 index 0000000..57c1e66 --- /dev/null +++ b/avahi-daemon/RecordBrowser.introspect @@ -0,0 +1,67 @@ +<?xml version="1.0" standalone='no'?><!--*-nxml-*--> +<?xml-stylesheet type="text/xsl" href="introspect.xsl"?> +<!DOCTYPE node SYSTEM "introspect.dtd"> + +<!-- $Id$ --> + +<!-- +  This file is part of avahi. +  +  avahi is free software; you can redistribute it and/or modify it +  under the terms of the GNU Lesser General Public License as +  published by the Free Software Foundation; either version 2 of the +  License, or (at your option) any later version. + +  avahi is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with avahi; if not, write to the Free Software +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +  02111-1307 USA. +--> + +<node> +   +  <interface name="org.freedesktop.DBus.Introspectable"> +    <method name="Introspect"> +      <arg name="data" type="s" direction="out" /> +    </method> +  </interface> + +  <interface name="org.freedesktop.Avahi.RecordBrowser"> + +    <method name="Free"/> +       +    <signal name="ItemNew"> +      <arg name="interface" type="i"/> +      <arg name="protocol" type="i"/> +      <arg name="name" type="s"/> +      <arg name="clazz" type="q"/> +      <arg name="type" type="q"/> +      <arg name="rdata" type="ay"/> +      <arg name="flags" type="u"/> +    </signal> + +    <signal name="ItemRemove"> +      <arg name="interface" type="i"/> +      <arg name="protocol" type="i"/> +      <arg name="name" type="s"/> +      <arg name="clazz" type="q"/> +      <arg name="type" type="q"/> +      <arg name="rdata" type="ay"/> +      <arg name="flags" type="u"/> +    </signal> + +    <signal name="Failure"> +      <arg name="error" type="s"/> +    </signal> + +    <signal name="AllForNow"/> + +    <signal name="CacheExhausted"/> + +  </interface>  +</node> diff --git a/avahi-daemon/Server.introspect b/avahi-daemon/Server.introspect index f8d88e9..ec2f042 100644 --- a/avahi-daemon/Server.introspect +++ b/avahi-daemon/Server.introspect @@ -192,5 +192,18 @@        <arg name="path" type="o" direction="out"/>      </method> + +    <method name="RecordBrowserNew"> +      <arg name="interface" type="i" direction="in"/> +      <arg name="protocol" type="i" direction="in"/> +      <arg name="name" type="s" direction="in"/> +      <arg name="clazz" type="q" direction="in"/> +      <arg name="type" type="q" direction="in"/> +      <arg name="flags" type="u" direction="in"/> + +      <arg name="path" type="o" direction="out"/> +    </method> + +    </interface>  </node> diff --git a/avahi-daemon/chroot.c b/avahi-daemon/chroot.c index 5478bce..5ca605d 100644 --- a/avahi-daemon/chroot.c +++ b/avahi-daemon/chroot.c @@ -54,6 +54,7 @@ enum {      AVAHI_CHROOT_GET_SERVICE_BROWSER_INTROSPECT,      AVAHI_CHROOT_GET_SERVICE_RESOLVER_INTROSPECT,      AVAHI_CHROOT_GET_SERVICE_TYPE_BROWSER_INTROSPECT, +    AVAHI_CHROOT_GET_RECORD_BROWSER_INTROSPECT,  #endif      AVAHI_CHROOT_UNLINK_PID,      AVAHI_CHROOT_UNLINK_SOCKET, @@ -73,6 +74,7 @@ static const char* const get_file_name_table[AVAHI_CHROOT_MAX] = {      AVAHI_DBUS_INTROSPECTION_DIR"/ServiceBrowser.introspect",      AVAHI_DBUS_INTROSPECTION_DIR"/ServiceResolver.introspect",      AVAHI_DBUS_INTROSPECTION_DIR"/ServiceTypeBrowser.introspect", +    AVAHI_DBUS_INTROSPECTION_DIR"/RecordBrowser.introspect",  #endif      NULL,      NULL @@ -91,6 +93,7 @@ static const char *const unlink_file_name_table[AVAHI_CHROOT_MAX] = {      NULL,      NULL,      NULL, +    NULL,  #endif      AVAHI_DAEMON_RUNTIME_DIR"/pid",      AVAHI_SOCKET @@ -233,6 +236,7 @@ static int helper_main(int fd) {              case AVAHI_CHROOT_GET_SERVICE_BROWSER_INTROSPECT:              case AVAHI_CHROOT_GET_SERVICE_RESOLVER_INTROSPECT:              case AVAHI_CHROOT_GET_SERVICE_TYPE_BROWSER_INTROSPECT: +            case AVAHI_CHROOT_GET_RECORD_BROWSER_INTROSPECT:  #endif              case AVAHI_CHROOT_GET_RESOLV_CONF: {                  int payload; diff --git a/avahi-daemon/dbus-internal.h b/avahi-daemon/dbus-internal.h index 49e398d..a49dae3 100644 --- a/avahi-daemon/dbus-internal.h +++ b/avahi-daemon/dbus-internal.h @@ -43,6 +43,7 @@ typedef struct ServiceTypeBrowserInfo ServiceTypeBrowserInfo;  typedef struct ServiceBrowserInfo ServiceBrowserInfo;  typedef struct SyncServiceResolverInfo SyncServiceResolverInfo;  typedef struct AsyncServiceResolverInfo AsyncServiceResolverInfo; +typedef struct RecordBrowserInfo RecordBrowserInfo;  #define CLIENTS_MAX 256  #define OBJECTS_PER_CLIENT_MAX 50 @@ -137,6 +138,15 @@ struct AsyncServiceResolverInfo {      AVAHI_LLIST_FIELDS(AsyncServiceResolverInfo, async_service_resolvers);  }; +struct RecordBrowserInfo { +    unsigned id; +    Client *client; +    AvahiSRecordBrowser *record_browser; +    char *path; + +    AVAHI_LLIST_FIELDS(RecordBrowserInfo, record_browsers); +}; +  struct Client {      unsigned id;      char *name; @@ -154,6 +164,7 @@ struct Client {      AVAHI_LLIST_HEAD(ServiceBrowserInfo, service_browsers);      AVAHI_LLIST_HEAD(SyncServiceResolverInfo, sync_service_resolvers);      AVAHI_LLIST_HEAD(AsyncServiceResolverInfo, async_service_resolvers); +    AVAHI_LLIST_HEAD(RecordBrowserInfo, record_browsers);  };  struct Server { @@ -229,4 +240,9 @@ void avahi_dbus_async_service_resolver_callback(      void* userdata);  DBusHandlerResult avahi_dbus_msg_async_service_resolver_impl(DBusConnection *c, DBusMessage *m, void *userdata); + +void avahi_dbus_record_browser_free(RecordBrowserInfo *i); +DBusHandlerResult avahi_dbus_msg_record_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata); +void avahi_dbus_record_browser_callback(AvahiSRecordBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, AvahiRecord *record, AvahiLookupResultFlags flags, void* userdata); +  #endif diff --git a/avahi-daemon/dbus-protocol.c b/avahi-daemon/dbus-protocol.c index c6c4a67..f01837a 100644 --- a/avahi-daemon/dbus-protocol.c +++ b/avahi-daemon/dbus-protocol.c @@ -100,6 +100,9 @@ static void client_free(Client *c) {      while (c->async_service_resolvers)          avahi_dbus_async_service_resolver_free(c->async_service_resolvers); +    while (c->record_browsers) +        avahi_dbus_record_browser_free(c->record_browsers); +      assert(c->n_objects == 0);      avahi_free(c->name); @@ -143,6 +146,7 @@ static Client *client_get(const char *name, int create) {      AVAHI_LLIST_HEAD_INIT(ServiceBrowserInfo, client->service_browsers);      AVAHI_LLIST_HEAD_INIT(SyncServiceResolverInfo, client->sync_service_resolvers);      AVAHI_LLIST_HEAD_INIT(AsyncServiceResolverInfo, client->async_service_resolvers); +    AVAHI_LLIST_HEAD_INIT(RecordBrowserInfo, client->record_browsers);      AVAHI_LLIST_PREPEND(Client, clients, server->clients, client); @@ -646,7 +650,6 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH              return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);          } -          if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) {              avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);              return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL); @@ -888,6 +891,70 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAH          dbus_connection_register_object_path(c, i->path, &vtable, i);          return avahi_dbus_respond_path(c, m, i->path); +         +    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "RecordBrowserNew")) { +        Client *client; +        RecordBrowserInfo *i; +        static const DBusObjectPathVTable vtable = { +            NULL, +            avahi_dbus_msg_record_browser_impl, +            NULL, +            NULL, +            NULL, +            NULL +        }; +        int32_t interface, protocol; +        uint32_t flags; +        char *name; +        uint16_t type, clazz; +        AvahiKey *key; +         +        if (!dbus_message_get_args( +                m, &error, +                DBUS_TYPE_INT32, &interface, +                DBUS_TYPE_INT32, &protocol, +                DBUS_TYPE_STRING, &name, +                DBUS_TYPE_UINT16, &clazz, +                DBUS_TYPE_UINT16, &type, +                DBUS_TYPE_UINT32, &flags, +                DBUS_TYPE_INVALID) || !name) { +            avahi_log_warn("Error parsing Server::RecordBrowserNew message"); +            goto fail; +        } + +        if (!avahi_is_valid_domain_name(name))  +            return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_DOMAIN_NAME, NULL); + +        if (!(client = client_get(dbus_message_get_sender(m), TRUE))) { +            avahi_log_warn("Too many clients, client request failed."); +            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL); +        } + +        if (client->n_objects >= OBJECTS_PER_CLIENT_MAX) { +            avahi_log_warn("Too many objects for client '%s', client request failed.", client->name); +            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL); +        } + +        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); +        AVAHI_LLIST_PREPEND(RecordBrowserInfo, record_browsers, client->record_browsers, i); +        client->n_objects++; + +        key = avahi_key_new(name, clazz, type); +        assert(key); + +        if (!(i->record_browser = avahi_s_record_browser_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, key, (AvahiLookupFlags) flags, avahi_dbus_record_browser_callback, i))) { +            avahi_key_unref(key); +            avahi_dbus_record_browser_free(i); +            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL); +        } + +        avahi_key_unref(key); +         +        dbus_connection_register_object_path(c, i->path, &vtable, i); +        return avahi_dbus_respond_path(c, m, i->path);      }      avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m)); diff --git a/avahi-daemon/dbus-record-browser.c b/avahi-daemon/dbus-record-browser.c new file mode 100644 index 0000000..e9ac6ab --- /dev/null +++ b/avahi-daemon/dbus-record-browser.c @@ -0,0 +1,158 @@ +/* $Id$ */ + +/*** +  This file is part of avahi. +  +  avahi is free software; you can redistribute it and/or modify it +  under the terms of the GNU Lesser General Public License as +  published by the Free Software Foundation; either version 2.1 of the +  License, or (at your option) any later version. +  +  avahi is distributed in the hope that it will be useful, but WITHOUT +  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +  Public License for more details. +  +  You should have received a copy of the GNU Lesser General Public +  License along with avahi; if not, write to the Free Software +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +  USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> + +#include <avahi-common/malloc.h> +#include <avahi-common/dbus.h> +#include <avahi-common/error.h> +#include <avahi-core/log.h> + +#include "dbus-util.h" +#include "dbus-internal.h" + +void avahi_dbus_record_browser_free(RecordBrowserInfo *i) { +    assert(i); + +    if (i->record_browser) +        avahi_s_record_browser_free(i->record_browser); +    dbus_connection_unregister_object_path(server->bus, i->path); +    avahi_free(i->path); +    AVAHI_LLIST_REMOVE(RecordBrowserInfo, record_browsers, i->client->record_browsers, i); + +    i->client->n_objects--; +    assert(i->client->n_objects >= 0); + +    avahi_free(i); +} + +DBusHandlerResult avahi_dbus_msg_record_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) { +    DBusError error; +    RecordBrowserInfo *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, "RecordBrowser.Introspect"); +     +    /* 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_RECORD_BROWSER, "Free")) { + +        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) { +            avahi_log_warn("Error parsing RecordBrowser::Free message"); +            goto fail; +        } + +        avahi_dbus_record_browser_free(i); +        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 avahi_dbus_record_browser_callback( +    AvahiSRecordBrowser *b, +    AvahiIfIndex interface, +    AvahiProtocol protocol, +    AvahiBrowserEvent event, +    AvahiRecord *record, +    AvahiLookupResultFlags flags, +    void* userdata) { +     +    RecordBrowserInfo *i = userdata; +    DBusMessage *m = NULL; +    int32_t i_interface, i_protocol; +    uint32_t u_flags; +     +    assert(b); +    assert(i); + +    i_interface = (int32_t) interface; +    i_protocol = (int32_t) protocol; +    u_flags = (uint32_t) flags; + +    m = dbus_message_new_signal(i->path, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, avahi_dbus_map_browse_signal_name(event)); + +    if (event == AVAHI_BROWSER_NEW || event == AVAHI_BROWSER_REMOVE) { +        uint8_t rdata[0xFFFF]; +        size_t size; +        assert(record); +         +        if (!(dbus_message_append_args( +                  m, +                  DBUS_TYPE_INT32, &i_interface, +                  DBUS_TYPE_INT32, &i_protocol, +                  DBUS_TYPE_STRING, &record->key->name, +                  DBUS_TYPE_UINT16, &record->key->clazz, +                  DBUS_TYPE_UINT16, &record->key->type, +                  DBUS_TYPE_INVALID))) +            goto fail; +             +        if ((size = avahi_rdata_serialize(record, rdata, sizeof(rdata))) == (size_t) -1 || +            avahi_dbus_append_rdata(m, rdata, size) < 0) { +            avahi_log_debug(__FILE__": Failed to append rdata"); +            dbus_message_unref(m); +            return; +        } +         +        dbus_message_append_args( +            m, +            DBUS_TYPE_UINT32, &u_flags, +            DBUS_TYPE_INVALID); +         +    } else if (event == AVAHI_BROWSER_FAILURE) +        avahi_dbus_append_server_error(m); +     +    dbus_message_set_destination(m, i->client->name);    +    dbus_connection_send(server->bus, m, NULL); +    dbus_message_unref(m); + +    return; +     +fail: + +    if (m) +        dbus_message_unref(m); +} diff --git a/avahi-daemon/dbus-service-browser.c b/avahi-daemon/dbus-service-browser.c index 2e65f66..dc10b81 100644 --- a/avahi-daemon/dbus-service-browser.c +++ b/avahi-daemon/dbus-service-browser.c @@ -48,7 +48,6 @@ void avahi_dbus_service_browser_free(ServiceBrowserInfo *i) {      avahi_free(i);  } -  DBusHandlerResult avahi_dbus_msg_service_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {      DBusError error;      ServiceBrowserInfo *i = userdata; diff --git a/avahi-daemon/dbus-util.c b/avahi-daemon/dbus-util.c index 00d8a9d..76a6b73 100644 --- a/avahi-daemon/dbus-util.c +++ b/avahi-daemon/dbus-util.c @@ -372,3 +372,17 @@ int avahi_dbus_is_our_own_service(Client *c, AvahiIfIndex interface, AvahiProtoc      return 0;  } +int avahi_dbus_append_rdata(DBusMessage *message, const void *rdata, size_t size) { +    DBusMessageIter iter, sub; +  +    assert(message); +  +    dbus_message_iter_init_append(message, &iter); +  +    if (!(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &sub)) || +        !(dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &rdata, size)) || +        !(dbus_message_iter_close_container(&iter, &sub))) +        return -1; +     +    return 0; +} diff --git a/avahi-daemon/dbus-util.h b/avahi-daemon/dbus-util.h index b8cb211..e994915 100644 --- a/avahi-daemon/dbus-util.h +++ b/avahi-daemon/dbus-util.h @@ -54,4 +54,6 @@ int avahi_dbus_read_strlst(DBusMessage *m, int idx, AvahiStringList **l);  int avahi_dbus_is_our_own_service(Client *c, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain); +int avahi_dbus_append_rdata(DBusMessage *message, const void *rdata, size_t size); +  #endif  | 
