X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-core%2Fwide-area.c;h=d5e64e57d2b65d404db8b72023217b48c6a51580;hb=9c0f9c65093cfa53d45f9b68782321eb8063a032;hp=f191074554c01bb9630b7d4c6e6f5988ff46a883;hpb=854f901f491ccda79aee11edc3d59109cb229d28;p=catta diff --git a/avahi-core/wide-area.c b/avahi-core/wide-area.c index f191074..d5e64e5 100644 --- a/avahi-core/wide-area.c +++ b/avahi-core/wide-area.c @@ -1,18 +1,16 @@ -/* $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 @@ -27,6 +25,7 @@ #include #include #include +#include #include #include @@ -47,13 +46,13 @@ typedef struct AvahiWideAreaCacheEntry AvahiWideAreaCacheEntry; struct AvahiWideAreaCacheEntry { AvahiWideAreaLookupEngine *engine; - + AvahiRecord *record; struct timeval timestamp; struct timeval expiry; AvahiTimeEvent *time_event; - + AVAHI_LLIST_FIELDS(AvahiWideAreaCacheEntry, by_key); AVAHI_LLIST_FIELDS(AvahiWideAreaCacheEntry, cache); }; @@ -61,12 +60,12 @@ struct AvahiWideAreaCacheEntry { struct AvahiWideAreaLookup { AvahiWideAreaLookupEngine *engine; int dead; - + uint32_t id; /* effectively just an uint16_t, but we need it as an index for a hash table */ AvahiTimeEvent *time_event; AvahiKey *key, *cname_key; - + int n_send; AvahiDnsPacket *packet; @@ -86,7 +85,7 @@ struct AvahiWideAreaLookupEngine { AvahiWatch *watch_ipv4, *watch_ipv6; uint16_t next_id; - + /* Cache */ AVAHI_LLIST_HEAD(AvahiWideAreaCacheEntry, cache); AvahiHashmap *cache_by_key; @@ -107,23 +106,23 @@ struct AvahiWideAreaLookupEngine { static AvahiWideAreaLookup* find_lookup(AvahiWideAreaLookupEngine *e, uint16_t id) { AvahiWideAreaLookup *l; int i = (int) id; - + assert(e); if (!(l = avahi_hashmap_lookup(e->lookups_by_id, &i))) return NULL; - + assert(l->id == id); if (l->dead) return NULL; - + return l; } static int send_to_dns_server(AvahiWideAreaLookup *l, AvahiDnsPacket *p) { AvahiAddress *a; - + assert(l); assert(p); @@ -134,21 +133,21 @@ static int send_to_dns_server(AvahiWideAreaLookup *l, AvahiDnsPacket *p) { a = &l->engine->dns_servers[l->engine->current_dns_server]; l->dns_server_used = *a; - + if (a->proto == AVAHI_PROTO_INET) { if (l->engine->fd_ipv4 < 0) return -1; - - return avahi_send_dns_packet_ipv4(l->engine->fd_ipv4, AVAHI_IF_UNSPEC, p, &a->data.ipv4, AVAHI_DNS_PORT); - + + return avahi_send_dns_packet_ipv4(l->engine->fd_ipv4, AVAHI_IF_UNSPEC, p, NULL, &a->data.ipv4, AVAHI_DNS_PORT); + } else { assert(a->proto == AVAHI_PROTO_INET6); if (l->engine->fd_ipv6 < 0) return -1; - - return avahi_send_dns_packet_ipv6(l->engine->fd_ipv6, AVAHI_IF_UNSPEC, p, &a->data.ipv6, AVAHI_DNS_PORT); + + return avahi_send_dns_packet_ipv6(l->engine->fd_ipv6, AVAHI_IF_UNSPEC, p, NULL, &a->data.ipv6, AVAHI_DNS_PORT); } } @@ -161,6 +160,17 @@ static void next_dns_server(AvahiWideAreaLookupEngine *e) { e->current_dns_server = 0; } +static void lookup_stop(AvahiWideAreaLookup *l) { + assert(l); + + l->callback = NULL; + + if (l->time_event) { + avahi_time_event_free(l->time_event); + l->time_event = NULL; + } +} + static void sender_timeout_callback(AvahiTimeEvent *e, void *userdata) { AvahiWideAreaLookup *l = userdata; struct timeval tv; @@ -175,12 +185,12 @@ static void sender_timeout_callback(AvahiTimeEvent *e, void *userdata) { /* There is no other DNS server, fail */ l->n_send = 1000; } - + if (l->n_send >= 6) { avahi_log_warn(__FILE__": Query timed out."); avahi_server_set_errno(l->engine->server, AVAHI_ERR_TIMEOUT); l->callback(l->engine, AVAHI_BROWSER_FAILURE, AVAHI_LOOKUP_RESULT_WIDE_AREA, NULL, l->userdata); - avahi_wide_area_lookup_free(l); + lookup_stop(l); return; } @@ -196,7 +206,7 @@ AvahiWideAreaLookup *avahi_wide_area_lookup_new( AvahiKey *key, AvahiWideAreaLookupCallback callback, void *userdata) { - + struct timeval tv; AvahiWideAreaLookup *l, *t; uint8_t *p; @@ -222,7 +232,7 @@ AvahiWideAreaLookup *avahi_wide_area_lookup_new( break; /* This ID is not yet used. */ l->id = e->next_id++; - + /* We keep the packet around in case we need to repeat our query */ l->packet = avahi_dns_packet_new(0); @@ -231,7 +241,7 @@ AvahiWideAreaLookup *avahi_wide_area_lookup_new( p = avahi_dns_packet_append_key(l->packet, key, 0); assert(p); - + avahi_dns_packet_set_field(l->packet, AVAHI_DNS_FIELD_QDCOUNT, 1); if (send_to_dns_server(l, l->packet) < 0) { @@ -245,7 +255,7 @@ AvahiWideAreaLookup *avahi_wide_area_lookup_new( } l->n_send = 1; - + l->time_event = avahi_time_event_new(e->server->time_event_queue, avahi_elapse_time(&tv, 500, 0), sender_timeout_callback, l); avahi_hashmap_insert(e->lookups_by_id, &l->id, l); @@ -255,25 +265,14 @@ AvahiWideAreaLookup *avahi_wide_area_lookup_new( avahi_hashmap_replace(e->lookups_by_key, avahi_key_ref(l->key), t); AVAHI_LLIST_PREPEND(AvahiWideAreaLookup, lookups, e->lookups, l); - - return l; -} - -static void lookup_stop(AvahiWideAreaLookup *l) { - assert(l); - - l->callback = NULL; - if (l->time_event) { - avahi_time_event_free(l->time_event); - l->time_event = NULL; - } + return l; } static void lookup_destroy(AvahiWideAreaLookup *l) { AvahiWideAreaLookup *t; assert(l); - + lookup_stop(l); t = avahi_hashmap_lookup(l->engine->lookups_by_key, l->key); @@ -284,7 +283,7 @@ static void lookup_destroy(AvahiWideAreaLookup *l) { avahi_hashmap_remove(l->engine->lookups_by_key, l->key); AVAHI_LLIST_REMOVE(AvahiWideAreaLookup, lookups, l->engine->lookups, l); - + avahi_hashmap_remove(l->engine->lookups_by_id, &l->id); avahi_dns_packet_free(l->packet); @@ -293,7 +292,7 @@ static void lookup_destroy(AvahiWideAreaLookup *l) { if (l->cname_key) avahi_key_unref(l->cname_key); - + avahi_free(l); } @@ -314,10 +313,10 @@ void avahi_wide_area_cleanup(AvahiWideAreaLookupEngine *e) { while (e->cleanup_dead) { e->cleanup_dead = 0; - + for (l = e->lookups; l; l = n) { n = l->lookups_next; - + if (l->dead) lookup_destroy(l); } @@ -348,7 +347,7 @@ static void cache_entry_free(AvahiWideAreaCacheEntry *c) { static void expiry_event(AvahiTimeEvent *te, void *userdata) { AvahiWideAreaCacheEntry *e = userdata; - + assert(te); assert(e); @@ -357,7 +356,7 @@ static void expiry_event(AvahiTimeEvent *te, void *userdata) { static AvahiWideAreaCacheEntry* find_record_in_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { AvahiWideAreaCacheEntry *c; - + assert(e); assert(r); @@ -370,17 +369,17 @@ static AvahiWideAreaCacheEntry* find_record_in_cache(AvahiWideAreaLookupEngine * static void run_callbacks(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { AvahiWideAreaLookup *l; - + assert(e); assert(r); for (l = avahi_hashmap_lookup(e->lookups_by_key, r->key); l; l = l->by_key_next) { if (l->dead || !l->callback) continue; - + l->callback(e, AVAHI_BROWSER_NEW, AVAHI_LOOKUP_RESULT_WIDE_AREA, r, l->userdata); } - + if (r->key->clazz == AVAHI_DNS_CLASS_IN && r->key->type == AVAHI_DNS_TYPE_CNAME) { /* It's a CNAME record, so we have to scan the all lookups to see if one matches */ @@ -389,7 +388,7 @@ static void run_callbacks(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { if (l->dead || !l->callback) continue; - + if ((key = avahi_key_new_cname(l->key))) { if (avahi_key_equal(r->key, key)) l->callback(e, AVAHI_BROWSER_NEW, AVAHI_LOOKUP_RESULT_WIDE_AREA, r, l->userdata); @@ -403,7 +402,7 @@ static void run_callbacks(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { static void add_to_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { AvahiWideAreaCacheEntry *c; int is_new; - + assert(e); assert(r); @@ -421,7 +420,7 @@ static void add_to_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { if (e->cache_n_entries >= CACHE_ENTRIES_MAX) /* Eventually we should improve the caching algorithm here */ goto finish; - + c = avahi_new(AvahiWideAreaCacheEntry, 1); c->engine = e; c->time_event = NULL; @@ -437,7 +436,7 @@ static void add_to_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { } c->record = avahi_record_ref(r); - + gettimeofday(&c->timestamp, NULL); c->expiry = c->timestamp; avahi_timeval_add(&c->expiry, r->ttl * 1000000); @@ -448,7 +447,7 @@ static void add_to_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { c->time_event = avahi_time_event_new(e->server->time_event_queue, &c->expiry, expiry_event, c); finish: - + if (is_new) run_callbacks(e, r); } @@ -478,12 +477,12 @@ static int map_dns_error(uint16_t error) { return table[error]; } -static void handle_packet(AvahiWideAreaLookupEngine *e, AvahiDnsPacket *p, AvahiAddress *a) { +static void handle_packet(AvahiWideAreaLookupEngine *e, AvahiDnsPacket *p) { AvahiWideAreaLookup *l = NULL; int i, r; AvahiBrowserEvent final_event = AVAHI_BROWSER_ALL_FOR_NOW; - + assert(e); assert(p); @@ -512,9 +511,9 @@ static void handle_packet(AvahiWideAreaLookupEngine *e, AvahiDnsPacket *p, Avahi /* Skip over the question */ for (i = (int) avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); i > 0; i--) { AvahiKey *k; - + if (!(k = avahi_dns_packet_consume_key(p, NULL))) { - avahi_log_warn(__FILE__": Wide area response packet too short."); + avahi_log_warn(__FILE__": Wide area response packet too short or invalid while reading question key. (Maybe a UTF-8 problem?)"); avahi_server_set_errno(e->server, AVAHI_ERR_INVALID_PACKET); final_event = AVAHI_BROWSER_FAILURE; goto finish; @@ -531,7 +530,7 @@ static void handle_packet(AvahiWideAreaLookupEngine *e, AvahiDnsPacket *p, Avahi AvahiRecord *rr; if (!(rr = avahi_dns_packet_consume_record(p, NULL))) { - avahi_log_warn(__FILE__": Wide area response packet too short (2)."); + avahi_log_warn(__FILE__": Wide area response packet too short or invalid while reading response record. (Maybe a UTF-8 problem?)"); avahi_server_set_errno(e->server, AVAHI_ERR_INVALID_PACKET); final_event = AVAHI_BROWSER_FAILURE; goto finish; @@ -542,7 +541,7 @@ static void handle_packet(AvahiWideAreaLookupEngine *e, AvahiDnsPacket *p, Avahi } finish: - + if (l && !l->dead) { if (l->callback) l->callback(e, final_event, AVAHI_LOOKUP_RESULT_WIDE_AREA, NULL, l->userdata); @@ -553,32 +552,24 @@ finish: static void socket_event(AVAHI_GCC_UNUSED AvahiWatch *w, int fd, AVAHI_GCC_UNUSED AvahiWatchEvent events, void *userdata) { AvahiWideAreaLookupEngine *e = userdata; - AvahiAddress a; AvahiDnsPacket *p = NULL; - - if (fd == e->fd_ipv4) { - struct sockaddr_in sa; - - if ((p = avahi_recv_dns_packet_ipv4(e->fd_ipv4, &sa, NULL, NULL, NULL))) - avahi_address_from_sockaddr((struct sockaddr*) &sa, &a); - - } else if (fd == e->fd_ipv6) { - struct sockaddr_in6 sa6; - - if ((p = avahi_recv_dns_packet_ipv6(e->fd_ipv6, &sa6, NULL, NULL, NULL))) - avahi_address_from_sockaddr((struct sockaddr*) &sa6, &a); + if (fd == e->fd_ipv4) + p = avahi_recv_dns_packet_ipv4(e->fd_ipv4, NULL, NULL, NULL, NULL, NULL); + else { + assert(fd == e->fd_ipv6); + p = avahi_recv_dns_packet_ipv6(e->fd_ipv6, NULL, NULL, NULL, NULL, NULL); } if (p) { - handle_packet(e, p, &a); + handle_packet(e, p); avahi_dns_packet_free(p); } } AvahiWideAreaLookupEngine *avahi_wide_area_engine_new(AvahiServer *s) { AvahiWideAreaLookupEngine *e; - + assert(s); e = avahi_new(AvahiWideAreaLookupEngine, 1); @@ -586,8 +577,8 @@ AvahiWideAreaLookupEngine *avahi_wide_area_engine_new(AvahiServer *s) { e->cleanup_dead = 0; /* Create sockets */ - e->fd_ipv4 = avahi_open_unicast_socket_ipv4(); - e->fd_ipv6 = avahi_open_unicast_socket_ipv6(); + e->fd_ipv4 = s->config.use_ipv4 ? avahi_open_unicast_socket_ipv4() : -1; + e->fd_ipv6 = s->config.use_ipv6 ? avahi_open_unicast_socket_ipv6() : -1; if (e->fd_ipv4 < 0 && e->fd_ipv6 < 0) { avahi_log_error(__FILE__": Failed to create wide area sockets: %s", strerror(errno)); @@ -597,12 +588,15 @@ AvahiWideAreaLookupEngine *avahi_wide_area_engine_new(AvahiServer *s) { if (e->fd_ipv4 >= 0) close(e->fd_ipv4); - + avahi_free(e); return NULL; } /* Create watches */ + + e->watch_ipv4 = e->watch_ipv6 = NULL; + if (e->fd_ipv4 >= 0) e->watch_ipv4 = s->poll_api->watch_new(e->server->poll_api, e->fd_ipv4, AVAHI_WATCH_IN, socket_event, e); if (e->fd_ipv6 >= 0) @@ -626,12 +620,12 @@ AvahiWideAreaLookupEngine *avahi_wide_area_engine_new(AvahiServer *s) { void avahi_wide_area_engine_free(AvahiWideAreaLookupEngine *e) { assert(e); - + avahi_wide_area_clear_cache(e); while (e->lookups) lookup_destroy(e->lookups); - + avahi_hashmap_free(e->cache_by_key); avahi_hashmap_free(e->lookups_by_id); avahi_hashmap_free(e->lookups_by_key); @@ -644,7 +638,7 @@ void avahi_wide_area_engine_free(AvahiWideAreaLookupEngine *e) { if (e->fd_ipv6 >= 0) close(e->fd_ipv6); - + if (e->fd_ipv4 >= 0) close(e->fd_ipv4); @@ -664,14 +658,14 @@ void avahi_wide_area_set_servers(AvahiWideAreaLookupEngine *e, const AvahiAddres assert(e); if (a) { - for (e->n_dns_servers = 0; n > 0 && e->n_dns_servers < AVAHI_WIDE_AREA_SERVERS_MAX; a++, n--) + for (e->n_dns_servers = 0; n > 0 && e->n_dns_servers < AVAHI_WIDE_AREA_SERVERS_MAX; a++, n--) if ((a->proto == AVAHI_PROTO_INET && e->fd_ipv4 >= 0) || (a->proto == AVAHI_PROTO_INET6 && e->fd_ipv6 >= 0)) e->dns_servers[e->n_dns_servers++] = *a; } else { assert(n == 0); e->n_dns_servers = 0; } - + e->current_dns_server = 0; avahi_wide_area_clear_cache(e); @@ -679,12 +673,12 @@ void avahi_wide_area_set_servers(AvahiWideAreaLookupEngine *e, const AvahiAddres void avahi_wide_area_cache_dump(AvahiWideAreaLookupEngine *e, AvahiDumpCallback callback, void* userdata) { AvahiWideAreaCacheEntry *c; - + assert(e); assert(callback); callback(";; WIDE AREA CACHE ;;; ", userdata); - + for (c = e->cache; c; c = c->cache_next) { char *t = avahi_record_to_string(c->record); callback(t, userdata); @@ -696,7 +690,7 @@ unsigned avahi_wide_area_scan_cache(AvahiWideAreaLookupEngine *e, AvahiKey *key, AvahiWideAreaCacheEntry *c; AvahiKey *cname_key; unsigned n = 0; - + assert(e); assert(key); assert(callback); @@ -712,7 +706,7 @@ unsigned avahi_wide_area_scan_cache(AvahiWideAreaLookupEngine *e, AvahiKey *key, callback(e, AVAHI_BROWSER_NEW, AVAHI_LOOKUP_RESULT_WIDE_AREA|AVAHI_LOOKUP_RESULT_CACHED, c->record, userdata); n++; } - + avahi_key_unref(cname_key); } @@ -726,4 +720,4 @@ int avahi_wide_area_has_servers(AvahiWideAreaLookupEngine *e) { } - +