From da69334ace7a4620e67fbf0a3eed61835d272ae3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 22 May 2005 16:53:59 +0000 Subject: [PATCH] Impelement AvahiServiceResolver git-svn-id: file:///home/lennart/svn/public/avahi/trunk@88 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-core/Makefile.am | 3 +- avahi-core/avahi-test.c | 26 +++- avahi-core/core.h | 5 +- avahi-core/resolve-service.c | 269 +++++++++++++++++++++++++++++++++++ avahi-core/server.c | 3 + avahi-core/server.h | 1 + 6 files changed, 301 insertions(+), 6 deletions(-) create mode 100644 avahi-core/resolve-service.c diff --git a/avahi-core/Makefile.am b/avahi-core/Makefile.am index 6c30809..0e73c7f 100644 --- a/avahi-core/Makefile.am +++ b/avahi-core/Makefile.am @@ -62,7 +62,8 @@ libavahi_core_la_SOURCES = \ resolve-address.c \ browse-domain.c \ browse-service-type.c \ - browse-service.c + browse-service.c \ + resolve-service.c prioq_test_SOURCES = \ prioq-test.c \ diff --git a/avahi-core/avahi-test.c b/avahi-core/avahi-test.c index e4ed4ab..805453a 100644 --- a/avahi-core/avahi-test.c +++ b/avahi-core/avahi-test.c @@ -128,7 +128,7 @@ static void hnr_callback(AvahiHostNameResolver *r, gint iface, guchar protocol, if (a) avahi_address_snprint(t, sizeof(t), a); - g_message("HNR: (%i.%i) <%s> -> %s [%s]", iface, protocol, hostname, a ? t : "n/a", event == AVAHI_BROWSER_NEW ? "found" : "timeout"); + g_message("HNR: (%i.%i) <%s> -> %s [%s]", iface, protocol, hostname, a ? t : "n/a", event == AVAHI_RESOLVER_FOUND ? "found" : "timeout"); } static void ar_callback(AvahiAddressResolver *r, gint iface, guchar protocol, AvahiBrowserEvent event, const AvahiAddress *a, const gchar *hostname, gpointer userdata) { @@ -136,7 +136,7 @@ static void ar_callback(AvahiAddressResolver *r, gint iface, guchar protocol, Av avahi_address_snprint(t, sizeof(t), a); - g_message("AR: (%i.%i) %s -> <%s> [%s]", iface, protocol, t, hostname ? hostname : "n/a", event == AVAHI_BROWSER_NEW ? "found" : "timeout"); + g_message("AR: (%i.%i) %s -> <%s> [%s]", iface, protocol, t, hostname ? hostname : "n/a", event == AVAHI_RESOLVER_FOUND ? "found" : "timeout"); } static void db_callback(AvahiDomainBrowser *b, gint iface, guchar protocol, AvahiBrowserEvent event, const gchar *domain, gpointer userdata) { @@ -152,7 +152,23 @@ static void stb_callback(AvahiServiceTypeBrowser *b, gint iface, guchar protocol static void sb_callback(AvahiServiceBrowser *b, gint iface, guchar protocol, AvahiBrowserEvent event, const gchar *name, const gchar *service_type, const gchar *domain, gpointer userdata) { g_message("SB: (%i.%i) <%s> as %s in <%s> [%s]", iface, protocol, name, service_type, domain, event == AVAHI_BROWSER_NEW ? "new" : "remove"); } - + + +static void sr_callback(AvahiServiceResolver *r, gint iface, guchar protocol, AvahiBrowserEvent event, const gchar *service_name, const gchar*service_type, const gchar*domain_name, const gchar*hostname, const AvahiAddress *a, guint16 port, AvahiStringList *txt, gpointer userdata) { + + if (event == AVAHI_RESOLVER_TIMEOUT) + g_message("SR: (%i.%i) <%s> as %s in <%s> [timeout]", iface, protocol, service_name, service_type, domain_name); + else { + gchar t[64], *s; + + avahi_address_snprint(t, sizeof(t), a); + + s = avahi_string_list_to_string(txt); + g_message("SR: (%i.%i) <%s> as %s in <%s>: %s/%s:%i (%s) [found]", iface, protocol, service_name, service_type, domain_name, hostname, t, port, s); + g_free(s); + } +} + int main(int argc, char *argv[]) { GMainLoop *loop = NULL; AvahiRecordBrowser *r; @@ -164,6 +180,7 @@ int main(int argc, char *argv[]) { AvahiDomainBrowser *db; AvahiServiceTypeBrowser *stb; AvahiServiceBrowser *sb; + AvahiServiceResolver *sr; avahi_server_config_init(&config); /* config.host_name = g_strdup("test"); */ @@ -183,6 +200,8 @@ int main(int argc, char *argv[]) { stb = avahi_service_type_browser_new(server, -1, AF_UNSPEC, NULL, stb_callback, NULL); sb = avahi_service_browser_new(server, -1, AF_UNSPEC, "_http._tcp", NULL, sb_callback, NULL); + + sr = avahi_service_resolver_new(server, -1, AF_UNSPEC, "Ecstasy HTTP", "_http._tcp", "local", AF_UNSPEC, sr_callback, NULL); loop = g_main_loop_new(NULL, FALSE); @@ -197,6 +216,7 @@ int main(int argc, char *argv[]) { avahi_address_resolver_free(ar); avahi_service_type_browser_free(stb); avahi_service_browser_free(sb); + avahi_service_resolver_free(sr); if (group) avahi_entry_group_free(group); diff --git a/avahi-core/core.h b/avahi-core/core.h index 4577584..c832e03 100644 --- a/avahi-core/core.h +++ b/avahi-core/core.h @@ -254,8 +254,9 @@ typedef void (*AvahiServiceBrowserCallback)(AvahiServiceBrowser *b, gint interfa AvahiServiceBrowser *avahi_service_browser_new(AvahiServer *server, gint interface, guchar protocol, const gchar *service_type, const gchar *domain, AvahiServiceBrowserCallback callback, gpointer userdata); void avahi_service_browser_free(AvahiServiceBrowser *b); -/* Not yet implemented */ - typedef struct AvahiServiceResolver AvahiServiceResolver; +typedef void (*AvahiServiceResolverCallback)(AvahiServiceResolver *r, gint interface, guchar 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); +AvahiServiceResolver *avahi_service_resolver_new(AvahiServer *server, gint interface, guchar protocol, const gchar *name, const gchar *type, const gchar *domain, guchar aprotocol, AvahiServiceResolverCallback calback, gpointer userdata); +void avahi_service_resolver_free(AvahiServiceResolver *r); #endif diff --git a/avahi-core/resolve-service.c b/avahi-core/resolve-service.c new file mode 100644 index 0000000..5c0c988 --- /dev/null +++ b/avahi-core/resolve-service.c @@ -0,0 +1,269 @@ +/* $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 +#endif + +#include + +#include "browse.h" +#include "util.h" + +struct AvahiServiceResolver { + AvahiServer *server; + gchar *service_name; + gchar *service_type; + gchar *domain_name; + guchar address_protocol; + + gint interface; + guchar protocol; + + AvahiRecordBrowser *record_browser_srv; + AvahiRecordBrowser *record_browser_txt; + AvahiRecordBrowser *record_browser_a; + AvahiRecordBrowser *record_browser_aaaa; + + AvahiRecord *srv_record, *txt_record, *address_record; + + AvahiServiceResolverCallback callback; + gpointer userdata; + + AvahiTimeEvent *time_event; + + AVAHI_LLIST_FIELDS(AvahiServiceResolver, resolver); +}; + +static void finish(AvahiServiceResolver *r, AvahiResolverEvent event) { + g_assert(r); + + if (r->record_browser_a) { + avahi_record_browser_free(r->record_browser_a); + r->record_browser_a = NULL; + } + + if (r->record_browser_aaaa) { + avahi_record_browser_free(r->record_browser_aaaa); + r->record_browser_aaaa = NULL; + } + + if (r->record_browser_srv) { + avahi_record_browser_free(r->record_browser_srv); + r->record_browser_srv = NULL; + } + + if (r->record_browser_txt) { + avahi_record_browser_free(r->record_browser_txt); + r->record_browser_txt = NULL; + } + + avahi_time_event_queue_remove(r->server->time_event_queue, r->time_event); + r->time_event = NULL; + + if (event == AVAHI_RESOLVER_TIMEOUT) + r->callback(r, r->interface, r->protocol, event, r->service_name, r->service_type, r->domain_name, NULL, NULL, 0, NULL, r->userdata); + else { + AvahiAddress a; + gchar sn[256], st[256]; + size_t i; + + g_assert(r->srv_record); + g_assert(r->txt_record); + g_assert(r->address_record); + + switch (r->address_record->key->type) { + case AVAHI_DNS_TYPE_A: + a.family = AF_INET; + a.data.ipv4 = r->address_record->data.a.address; + break; + + case AVAHI_DNS_TYPE_AAAA: + a.family = AF_INET6; + a.data.ipv6 = r->address_record->data.aaaa.address; + break; + + default: + g_assert(FALSE); + } + + snprintf(sn, sizeof(sn), r->service_name); + snprintf(st, sizeof(st), r->service_type); + + if ((i = strlen(sn)) > 0 && sn[i-1] == '.') + sn[i-1] = 0; + + if ((i = strlen(st)) > 0 && st[i-1] == '.') + st[i-1] = 0; + + r->callback(r, r->interface, r->protocol, event, sn, st, r->domain_name, r->srv_record->data.srv.name, &a, r->srv_record->data.srv.port, r->txt_record->data.txt.string_list, r->userdata); + + } +} + +static void record_browser_callback(AvahiRecordBrowser*rr, gint interface, guchar protocol, AvahiBrowserEvent event, AvahiRecord *record, gpointer userdata) { + AvahiServiceResolver *r = userdata; + + g_assert(rr); + g_assert(record); + g_assert(r); + + if (!(event == AVAHI_BROWSER_NEW)) + return; + + if (r->interface > 0 && interface != r->interface) + return; + + if (r->protocol != AF_UNSPEC && protocol != r->protocol) + return; + + if (r->interface <= 0) + r->interface = interface; + + if (r->protocol == AF_UNSPEC) + r->protocol = protocol; + + switch (record->key->type) { + case AVAHI_DNS_TYPE_SRV: + if (!r->srv_record) { + r->srv_record = avahi_record_ref(record); + + g_assert(!r->record_browser_a && !r->record_browser_aaaa); + + if (r->address_protocol == AF_INET || r->address_protocol == AF_UNSPEC) { + AvahiKey *k = avahi_key_new(r->srv_record->data.srv.name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A); + r->record_browser_a = avahi_record_browser_new(r->server, r->interface, r->protocol, k, record_browser_callback, r); + avahi_key_unref(k); + } + + if (r->address_protocol == AF_INET6 || r->address_protocol == AF_UNSPEC) { + AvahiKey *k = avahi_key_new(r->srv_record->data.srv.name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA); + r->record_browser_aaaa = avahi_record_browser_new(r->server, r->interface, r->protocol, k, record_browser_callback, r); + avahi_key_unref(k); + } + } + break; + + case AVAHI_DNS_TYPE_TXT: + if (!r->txt_record) + r->txt_record = avahi_record_ref(record); + break; + + case AVAHI_DNS_TYPE_A: + case AVAHI_DNS_TYPE_AAAA: + if (!r->address_record) + r->address_record = avahi_record_ref(record); + break; + + default: + g_assert(FALSE); + } + + if (r->txt_record && r->srv_record && r->address_record) + finish(r, AVAHI_RESOLVER_FOUND); +} + +static void time_event_callback(AvahiTimeEvent *e, void *userdata) { + AvahiServiceResolver *r = userdata; + + g_assert(e); + g_assert(r); + + finish(r, AVAHI_RESOLVER_TIMEOUT); +} + +AvahiServiceResolver *avahi_service_resolver_new(AvahiServer *server, gint interface, guchar protocol, const gchar *name, const gchar *type, const gchar *domain, guchar aprotocol, AvahiServiceResolverCallback callback, gpointer userdata) { + AvahiServiceResolver *r; + AvahiKey *k; + GTimeVal tv; + gchar t[256], *n; + size_t l; + + g_assert(server); + g_assert(name); + g_assert(type); + g_assert(callback); + + g_assert(aprotocol == AF_UNSPEC || aprotocol == AF_INET || aprotocol == AF_INET6); + + r = g_new(AvahiServiceResolver, 1); + r->server = server; + r->service_name = avahi_normalize_name(name); + r->service_type = avahi_normalize_name(type); + r->domain_name = avahi_normalize_name(domain); + r->callback = callback; + r->userdata = userdata; + r->address_protocol = aprotocol; + r->srv_record = r->txt_record = r->address_record = NULL; + r->interface = interface; + r->protocol = protocol; + + n = t; + l = sizeof(t); + avahi_escape_label((guint8*) name, strlen(name), &n, &l); + snprintf(n, l, ".%s%s", r->service_type, r->domain_name); + + g_message("<%s>", t); + + k = avahi_key_new(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV); + r->record_browser_srv = avahi_record_browser_new(server, interface, protocol, k, record_browser_callback, r); + avahi_key_unref(k); + + k = avahi_key_new(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT); + r->record_browser_txt = avahi_record_browser_new(server, interface, protocol, k, record_browser_callback, r); + avahi_key_unref(k); + + r->record_browser_a = r->record_browser_aaaa = NULL; + + avahi_elapse_time(&tv, 1000, 0); + r->time_event = avahi_time_event_queue_add(server->time_event_queue, &tv, time_event_callback, r); + + AVAHI_LLIST_PREPEND(AvahiServiceResolver, resolver, server->service_resolvers, r); + + return r; +} + +void avahi_service_resolver_free(AvahiServiceResolver *r) { + g_assert(r); + + AVAHI_LLIST_REMOVE(AvahiServiceResolver, resolver, r->server->service_resolvers, r); + + if (r->record_browser_srv) + avahi_record_browser_free(r->record_browser_srv); + if (r->record_browser_txt) + avahi_record_browser_free(r->record_browser_txt); + if (r->record_browser_a) + avahi_record_browser_free(r->record_browser_a); + if (r->record_browser_aaaa) + avahi_record_browser_free(r->record_browser_aaaa); + + if (r->srv_record) + avahi_record_unref(r->srv_record); + if (r->txt_record) + avahi_record_unref(r->txt_record); + if (r->address_record) + avahi_record_unref(r->address_record); + + g_free(r->service_name); + g_free(r->service_type); + g_free(r->domain_name); + g_free(r); +} diff --git a/avahi-core/server.c b/avahi-core/server.c index fd17078..fe2c5f8 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -967,6 +967,7 @@ AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, Avah AVAHI_LLIST_HEAD_INIT(AvahiDomainBrowser, s->domain_browsers); AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, s->service_type_browsers); AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, s->service_browsers); + AVAHI_LLIST_HEAD_INIT(AvahiServiceResolver, s->service_resolvers); /* Get host name */ s->host_name = s->config.host_name ? avahi_normalize_name(s->config.host_name) : avahi_get_host_name(); @@ -1015,6 +1016,8 @@ void avahi_server_free(AvahiServer* s) { avahi_service_type_browser_free(s->service_type_browsers); while (s->service_browsers) avahi_service_browser_free(s->service_browsers); + while (s->service_resolvers) + avahi_service_resolver_free(s->service_resolvers); while (s->record_browsers) avahi_record_browser_destroy(s->record_browsers); g_hash_table_destroy(s->record_browser_hashtable); diff --git a/avahi-core/server.h b/avahi-core/server.h index 0e6f2e7..fb137b0 100644 --- a/avahi-core/server.h +++ b/avahi-core/server.h @@ -82,6 +82,7 @@ struct AvahiServer { AVAHI_LLIST_HEAD(AvahiDomainBrowser, domain_browsers); AVAHI_LLIST_HEAD(AvahiServiceTypeBrowser, service_type_browsers); AVAHI_LLIST_HEAD(AvahiServiceBrowser, service_browsers); + AVAHI_LLIST_HEAD(AvahiServiceResolver, service_resolvers); gboolean need_entry_cleanup, need_group_cleanup, need_browser_cleanup; -- 2.39.5