From c3575017e2137ef664e4735bd6f9ff1209653ef3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 25 Oct 2005 22:20:37 +0000 Subject: * replace AF_UNSPEC by AVAHI_PROTO_UNSPEC in client-test.c * remove some functions from the public API in avahi-common/{domain,address}.[ch] and move them into avahi-core/{domain-util,add-util}.[ch] * properly generate CNAME responses * add some more comments to server.c git-svn-id: file:///home/lennart/svn/public/avahi/trunk@871 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-core/Makefile.am | 7 +++- avahi-core/addr-util.c | 79 ++++++++++++++++++++++++++++++++++++ avahi-core/addr-util.h | 45 +++++++++++++++++++++ avahi-core/avahi-test.c | 11 ++++- avahi-core/browse.c | 2 +- avahi-core/domain-util.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++ avahi-core/domain-util.h | 47 +++++++++++++++++++++ avahi-core/rr.c | 1 + avahi-core/rr.h | 2 +- avahi-core/server.c | 103 ++++++++++++++++++++++++++++++----------------- avahi-core/socket.c | 1 - avahi-core/update-test.c | 1 + avahi-core/wide-area.c | 1 + 13 files changed, 357 insertions(+), 44 deletions(-) create mode 100644 avahi-core/addr-util.c create mode 100644 avahi-core/addr-util.h create mode 100644 avahi-core/domain-util.c create mode 100644 avahi-core/domain-util.h (limited to 'avahi-core') diff --git a/avahi-core/Makefile.am b/avahi-core/Makefile.am index 9516615..cc93265 100644 --- a/avahi-core/Makefile.am +++ b/avahi-core/Makefile.am @@ -76,7 +76,9 @@ libavahi_core_la_SOURCES = \ hashmap.c hashmap.h \ wide-area.c wide-area.h \ multicast-lookup.c multicast-lookup.h \ - querier.c querier.h + querier.c querier.h \ + addr-util.h addr-util.c \ + domain-util.h domain-util.c if HAVE_NETLINK libavahi_core_la_SOURCES += \ @@ -130,7 +132,8 @@ dns_test_SOURCES = \ log.c log.h \ util.c util.h \ rr.c rr.h \ - hashmap.c hashmap.h + hashmap.c hashmap.h \ + domain-util.c domain-util.h dns_test_CFLAGS = $(AM_CFLAGS) dns_test_LDADD = $(AM_LDADD) ../avahi-common/libavahi-common.la diff --git a/avahi-core/addr-util.c b/avahi-core/addr-util.c new file mode 100644 index 0000000..7b9bb03 --- /dev/null +++ b/avahi-core/addr-util.c @@ -0,0 +1,79 @@ +/* $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 +#include +#include +#include +#include + +#include "addr-util.h" + +AvahiAddress *avahi_address_from_sockaddr(const struct sockaddr* sa, AvahiAddress *ret_addr) { + assert(sa); + assert(ret_addr); + + assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6); + + ret_addr->proto = avahi_af_to_proto(sa->sa_family); + + if (sa->sa_family == AF_INET) + memcpy(&ret_addr->data.ipv4, &((const struct sockaddr_in*) sa)->sin_addr, sizeof(ret_addr->data.ipv4)); + else + memcpy(&ret_addr->data.ipv6, &((const struct sockaddr_in6*) sa)->sin6_addr, sizeof(ret_addr->data.ipv6)); + + return ret_addr; +} + +uint16_t avahi_port_from_sockaddr(const struct sockaddr* sa) { + assert(sa); + + assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6); + + if (sa->sa_family == AF_INET) + return ntohs(((const struct sockaddr_in*) sa)->sin_port); + else + return ntohs(((const struct sockaddr_in6*) sa)->sin6_port); +} + +int avahi_address_is_ipv4_in_ipv6(const AvahiAddress *a) { + + static const uint8_t ipv4_in_ipv6[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF + }; + + assert(a); + + if (a->proto != AVAHI_PROTO_INET6) + return 0; + + return memcmp(a->data.ipv6.address, ipv4_in_ipv6, sizeof(ipv4_in_ipv6)) == 0; +} + + + diff --git a/avahi-core/addr-util.h b/avahi-core/addr-util.h new file mode 100644 index 0000000..4134de1 --- /dev/null +++ b/avahi-core/addr-util.h @@ -0,0 +1,45 @@ +#ifndef fooaddrutilhfoo +#define fooaddrutilhfoo + +/* $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. +***/ + +#include +#include + +#include +#include + +AVAHI_C_DECL_BEGIN + +/** Make an address structture of a sockaddr structure */ +AvahiAddress *avahi_address_from_sockaddr(const struct sockaddr* sa, AvahiAddress *ret_addr); + +/** Return the port number of a sockaddr structure (either IPv4 or IPv6) */ +uint16_t avahi_port_from_sockaddr(const struct sockaddr* sa); + +/** Check whether the specified IPv6 address is in fact an + * encapsulated IPv4 address, returns 1 if yes, 0 otherwise */ +int avahi_address_is_ipv4_in_ipv6(const AvahiAddress *a); + +AVAHI_C_DECL_END + +#endif diff --git a/avahi-core/avahi-test.c b/avahi-core/avahi-test.c index 754988c..51a3a03 100644 --- a/avahi-core/avahi-test.c +++ b/avahi-core/avahi-test.c @@ -149,6 +149,7 @@ static void remove_entries(void) { static void create_entries(int new_name) { AvahiAddress a; + AvahiRecord *r; remove_entries(); @@ -185,6 +186,14 @@ static void create_entries(int new_name) { goto fail; } + r = avahi_record_new_full("cname.local", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_CNAME, AVAHI_DEFAULT_TTL); + r->data.cname.name = avahi_strdup("cocaine.local"); + + if (avahi_server_add(server, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, r) < 0) { + avahi_log_error("Failed to add CNAME record"); + goto fail; + } + avahi_s_entry_group_commit(group); return; @@ -345,7 +354,7 @@ int main(int argc, char *argv[]) { r = avahi_s_record_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, k, 0, record_browser_callback, NULL); avahi_key_unref(k); - hnr = avahi_s_host_name_resolver_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "cocaine.local", AVAHI_PROTO_UNSPEC, 0, hnr_callback, NULL); + hnr = avahi_s_host_name_resolver_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "cname.local", AVAHI_PROTO_UNSPEC, 0, hnr_callback, NULL); ar = avahi_s_address_resolver_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, avahi_address_parse("192.168.50.1", AVAHI_PROTO_INET, &a), 0, ar_callback, NULL); diff --git a/avahi-core/browse.c b/avahi-core/browse.c index 5fd3a01..cb2d326 100644 --- a/avahi-core/browse.c +++ b/avahi-core/browse.c @@ -35,6 +35,7 @@ #include "browse.h" #include "log.h" #include "querier.h" +#include "domain-util.h" #define AVAHI_LOOKUPS_PER_BROWSER_MAX 15 @@ -278,7 +279,6 @@ static void lookup_multicast_callback( lookup_handle_cname(l, interface, protocol, b->flags, r); else { /* It's a normal record, so let's call the user callback */ - assert(avahi_key_equal(b->key, l->key)); if (avahi_server_is_record_local(b->server, interface, protocol, r)) flags |= AVAHI_LOOKUP_RESULT_LOCAL; diff --git a/avahi-core/domain-util.c b/avahi-core/domain-util.c new file mode 100644 index 0000000..d4cc2ad --- /dev/null +++ b/avahi-core/domain-util.c @@ -0,0 +1,101 @@ +/* $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 +#include +#include + +#include + +#include "domain-util.h" + +char *avahi_get_host_name(char *ret_s, size_t size) { +#ifdef HOST_NAME_MAX + char t[HOST_NAME_MAX]; +#else + char t[256]; +#endif + + assert(ret_s); + assert(size > 0); + + gethostname(t, sizeof(t)); + t[sizeof(t)-1] = 0; + + return avahi_normalize_name(t, ret_s, size); +} + +char *avahi_get_host_name_strdup(void) { + char t[AVAHI_DOMAIN_NAME_MAX]; + + if (!(avahi_get_host_name(t, sizeof(t)))) + return NULL; + + return avahi_strdup(t); +} + +int avahi_binary_domain_cmp(const char *a, const char *b) { + assert(a); + assert(b); + + if (a == b) + return 0; + + for (;;) { + char ca[AVAHI_LABEL_MAX], cb[AVAHI_LABEL_MAX], *p; + int r; + + p = avahi_unescape_label(&a, ca, sizeof(ca)); + assert(p); + p = avahi_unescape_label(&b, cb, sizeof(cb)); + assert(p); + + if ((r = strcmp(ca, cb))) + return r; + + if (!*a && !*b) + return 0; + } +} + +int avahi_domain_ends_with(const char *domain, const char *suffix) { + assert(domain); + assert(suffix); + + for (;;) { + char dummy[AVAHI_LABEL_MAX], *r; + + if (*domain == 0) + return 0; + + if (avahi_domain_equal(domain, suffix)) + return 1; + + r = avahi_unescape_label(&domain, dummy, sizeof(dummy)); + assert(r); + } +} + diff --git a/avahi-core/domain-util.h b/avahi-core/domain-util.h new file mode 100644 index 0000000..01233d8 --- /dev/null +++ b/avahi-core/domain-util.h @@ -0,0 +1,47 @@ +#ifndef foodomainutilhfoo +#define foodomainutilhfoo + +/* $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. +***/ + +#include +#include + +#include +#include + +AVAHI_C_DECL_BEGIN + +/** Return the local host name. */ +char *avahi_get_host_name(char *ret_s, size_t size); + +/** Return the local host name. avahi_free() the result! */ +char *avahi_get_host_name_strdup(void); + +/** Do a binary comparison of to specified domain names, return -1, 0, or 1, depending on the order. */ +int avahi_binary_domain_cmp(const char *a, const char *b); + +/** Returns 1 if the the end labels of domain are eqal to suffix */ +int avahi_domain_ends_with(const char *domain, const char *suffix); + +AVAHI_C_DECL_END + +#endif diff --git a/avahi-core/rr.c b/avahi-core/rr.c index ef1c3d6..e7fac13 100644 --- a/avahi-core/rr.c +++ b/avahi-core/rr.c @@ -37,6 +37,7 @@ #include "log.h" #include "util.h" #include "hashmap.h" +#include "domain-util.h" AvahiKey *avahi_key_new(const char *name, uint16_t class, uint16_t type) { AvahiKey *k; diff --git a/avahi-core/rr.h b/avahi-core/rr.h index 63dc18d..21d6d63 100644 --- a/avahi-core/rr.h +++ b/avahi-core/rr.h @@ -98,7 +98,7 @@ typedef struct { struct { char *name; - } ptr; /**< Data for PTR an CNAME records */ + } ptr, ns, cname; /**< Data for PTR, NS and CNAME records */ struct { char *cpu; diff --git a/avahi-core/server.c b/avahi-core/server.c index 3edd96e..5cac056 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -45,26 +45,38 @@ #include "log.h" #include "util.h" #include "dns-srv-rr.h" +#include "addr-util.h" +#include "domain-util.h" static void enum_aux_records(AvahiServer *s, AvahiInterface *i, const char *name, uint16_t type, void (*callback)(AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata), void* userdata) { - AvahiKey *k; - AvahiEntry *e; - assert(s); assert(i); assert(name); assert(callback); - assert(type != AVAHI_DNS_TYPE_ANY); - - if (!(k = avahi_key_new(name, AVAHI_DNS_CLASS_IN, type))) - return; /** OOM */ - - for (e = avahi_hashmap_lookup(s->entries_by_key, k); e; e = e->by_key_next) - if (!e->dead && avahi_entry_is_registered(s, e, i)) - callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata); + if (type == AVAHI_DNS_TYPE_ANY) { + AvahiEntry *e; + + for (e = s->entries; e; e = e->entries_next) + if (!e->dead && + avahi_entry_is_registered(s, e, i) && + e->record->key->clazz == AVAHI_DNS_CLASS_IN && + avahi_domain_equal(name, e->record->key->name)) + callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata); - avahi_key_unref(k); + } else { + AvahiEntry *e; + AvahiKey *k; + + if (!(k = avahi_key_new(name, AVAHI_DNS_CLASS_IN, type))) + return; /** OOM */ + + for (e = avahi_hashmap_lookup(s->entries_by_key, k); e; e = e->by_key_next) + if (!e->dead && avahi_entry_is_registered(s, e, i)) + callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata); + + avahi_key_unref(k); + } } void avahi_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, void (*callback)(AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata), void* userdata) { @@ -72,6 +84,8 @@ void avahi_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, Avahi assert(i); assert(r); assert(callback); + + /* Call the specified callback far all records referenced by the one specified in *r */ if (r->key->clazz == AVAHI_DNS_CLASS_IN) { if (r->key->type == AVAHI_DNS_TYPE_PTR) { @@ -80,7 +94,8 @@ void avahi_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, Avahi } else if (r->key->type == AVAHI_DNS_TYPE_SRV) { enum_aux_records(s, i, r->data.srv.name, AVAHI_DNS_TYPE_A, callback, userdata); enum_aux_records(s, i, r->data.srv.name, AVAHI_DNS_TYPE_AAAA, callback, userdata); - } + } else if (r->key->type == AVAHI_DNS_TYPE_CNAME) + enum_aux_records(s, i, r->data.cname.name, AVAHI_DNS_TYPE_ANY, callback, userdata); } } @@ -93,17 +108,14 @@ void avahi_server_prepare_response(AvahiServer *s, AvahiInterface *i, AvahiEntry } void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, AvahiKey *k, int unicast_response) { - AvahiEntry *e; -/* char *txt; */ - assert(s); assert(i); assert(k); -/* avahi_log_debug("Posting responses matching [%s]", txt = avahi_key_to_string(k)); */ -/* avahi_free(txt); */ + /* Push all records that match the specified key to the record list */ if (avahi_key_is_pattern(k)) { + AvahiEntry *e; /* Handle ANY query */ @@ -112,6 +124,7 @@ void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, avahi_server_prepare_response(s, i, e, unicast_response, 0); } else { + AvahiEntry *e; /* Handle all other queries */ @@ -119,21 +132,40 @@ void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, if (!e->dead && avahi_entry_is_registered(s, e, i)) avahi_server_prepare_response(s, i, e, unicast_response, 0); } + + /* Look for CNAME records */ + + if ((k->clazz == AVAHI_DNS_CLASS_IN || k->clazz == AVAHI_DNS_CLASS_ANY) + && k->type != AVAHI_DNS_TYPE_CNAME && k->type != AVAHI_DNS_TYPE_ANY) { + + AvahiKey *cname_key; + + if (!(cname_key = avahi_key_new(k->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_CNAME))) + return; + + avahi_server_prepare_matching_responses(s, i, cname_key, unicast_response); + avahi_key_unref(cname_key); + } } static void withdraw_entry(AvahiServer *s, AvahiEntry *e) { assert(s); assert(e); + + /* Withdraw the specified entry, and if is part of an entry group, + * put that into COLLISION state */ + + if (e->dead) + return; if (e->group) { AvahiEntry *k; - for (k = e->group->entries; k; k = k->by_group_next) { + for (k = e->group->entries; k; k = k->by_group_next) if (!k->dead) { avahi_goodbye_entry(s, k, 0, 1); k->dead = 1; } - } e->group->n_probing = 0; @@ -152,24 +184,22 @@ static void withdraw_rrset(AvahiServer *s, AvahiKey *key) { assert(s); assert(key); - for (e = avahi_hashmap_lookup(s->entries_by_key, key); e; e = e->by_key_next) - if (!e->dead) - withdraw_entry(s, e); + /* Withdraw an entry RRSset */ + + for (e = avahi_hashmap_lookup(s->entries_by_key, key); e; e = e->by_key_next) + withdraw_entry(s, e); } static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *i) { AvahiEntry *e, *n; - char *t; int ours = 0, won = 0, lost = 0; assert(s); assert(record); assert(i); - t = avahi_record_to_string(record); - -/* avahi_log_debug("incoming_probe()"); */ - + /* Handle incoming probes and check if they conflict our own probes */ + for (e = avahi_hashmap_lookup(s->entries_by_key, record->key); e; e = n) { int cmp; n = e->by_key_next; @@ -192,17 +222,17 @@ static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface * } if (!ours) { - + char *t = avahi_record_to_string(record); + if (won) avahi_log_debug("Recieved conflicting probe [%s]. Local host won.", t); else if (lost) { avahi_log_debug("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t); withdraw_rrset(s, record->key); - }/* else */ -/* avahi_log_debug("Not conflicting probe"); */ + } + + avahi_free(t); } - - avahi_free(t); } static int handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, int unique, const AvahiAddress *a) { @@ -213,9 +243,8 @@ static int handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *recor assert(i); assert(record); - -/* avahi_log_debug("CHECKING FOR CONFLICT: [%s]", t); */ - + /* Check whether an incoming record conflicts with one of our own */ + for (e = avahi_hashmap_lookup(s->entries_by_key, record->key); e; e = n) { n = e->by_key_next; @@ -286,8 +315,6 @@ static int handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *recor } } -/* avahi_log_debug("ours=%i conflict=%i", ours, conflict); */ - if (!ours && conflict) { char *t; diff --git a/avahi-core/socket.c b/avahi-core/socket.c index fcc63fa..0487023 100644 --- a/avahi-core/socket.c +++ b/avahi-core/socket.c @@ -679,7 +679,6 @@ AvahiDnsPacket* avahi_recv_dns_packet_ipv6(int fd, struct sockaddr_in6 *ret_sa, uint8_t aux[64]; ssize_t l; int ms; - struct cmsghdr *cmsg; int found_ttl = 0, found_iface = 0; diff --git a/avahi-core/update-test.c b/avahi-core/update-test.c index bd42c75..fbfd51a 100644 --- a/avahi-core/update-test.c +++ b/avahi-core/update-test.c @@ -24,6 +24,7 @@ #endif #include +#include #include #include diff --git a/avahi-core/wide-area.c b/avahi-core/wide-area.c index 9dd1e73..d12267a 100644 --- a/avahi-core/wide-area.c +++ b/avahi-core/wide-area.c @@ -38,6 +38,7 @@ #include "log.h" #include "hashmap.h" #include "wide-area.h" +#include "addr-util.h" #define CACHE_ENTRIES_MAX 500 -- cgit