X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-core%2Fwide-area.c;h=d5e64e57d2b65d404db8b72023217b48c6a51580;hb=9c0f9c65093cfa53d45f9b68782321eb8063a032;hp=f32c403c1643617ac436e41ba1df1b69a973551d;hpb=263515cd1d7b52ce2ad3dc55a93b9d6f730133f1;p=catta diff --git a/avahi-core/wide-area.c b/avahi-core/wide-area.c index f32c403..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,31 +25,34 @@ #include #include #include +#include #include #include #include -#include "server.h" +#include "internal.h" #include "browse.h" #include "socket.h" #include "log.h" #include "hashmap.h" #include "wide-area.h" +#include "addr-util.h" +#include "rr-util.h" -#define MAX_CACHE_ENTRIES 500 +#define CACHE_ENTRIES_MAX 500 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); }; @@ -59,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; @@ -84,7 +85,7 @@ struct AvahiWideAreaLookupEngine { AvahiWatch *watch_ipv4, *watch_ipv6; uint16_t next_id; - + /* Cache */ AVAHI_LLIST_HEAD(AvahiWideAreaCacheEntry, cache); AvahiHashmap *cache_by_key; @@ -97,7 +98,7 @@ struct AvahiWideAreaLookupEngine { int cleanup_dead; - AvahiAddress dns_servers[AVAHI_MAX_WIDE_AREA_SERVERS]; + AvahiAddress dns_servers[AVAHI_WIDE_AREA_SERVERS_MAX]; unsigned n_dns_servers; unsigned current_dns_server; }; @@ -105,47 +106,48 @@ 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(AvahiWideAreaLookupEngine *e, AvahiDnsPacket *p) { +static int send_to_dns_server(AvahiWideAreaLookup *l, AvahiDnsPacket *p) { AvahiAddress *a; - - assert(e); + + assert(l); assert(p); - if (e->n_dns_servers <= 0) + if (l->engine->n_dns_servers <= 0) return -1; - assert(e->current_dns_server < e->n_dns_servers); + assert(l->engine->current_dns_server < l->engine->n_dns_servers); + + a = &l->engine->dns_servers[l->engine->current_dns_server]; + l->dns_server_used = *a; - a = &e->dns_servers[e->current_dns_server]; - if (a->proto == AVAHI_PROTO_INET) { - if (e->fd_ipv4 < 0) + if (l->engine->fd_ipv4 < 0) return -1; - - return avahi_send_dns_packet_ipv4(e->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 (e->fd_ipv6 < 0) + if (l->engine->fd_ipv6 < 0) return -1; - - return avahi_send_dns_packet_ipv6(e->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); } } @@ -158,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; @@ -172,17 +185,17 @@ 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; } assert(l->packet); - send_to_dns_server(l->engine, l->packet); + send_to_dns_server(l, l->packet); l->n_send++; avahi_time_event_update(e, avahi_elapse_time(&tv, 1000, 0)); @@ -193,7 +206,7 @@ AvahiWideAreaLookup *avahi_wide_area_lookup_new( AvahiKey *key, AvahiWideAreaLookupCallback callback, void *userdata) { - + struct timeval tv; AvahiWideAreaLookup *l, *t; uint8_t *p; @@ -219,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); @@ -228,10 +241,10 @@ 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(e, l->packet) < 0) { + if (send_to_dns_server(l, l->packet) < 0) { avahi_log_error(__FILE__": Failed to send packet."); avahi_dns_packet_free(l->packet); avahi_key_unref(l->key); @@ -242,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); @@ -252,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); @@ -281,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); @@ -290,7 +292,7 @@ static void lookup_destroy(AvahiWideAreaLookup *l) { if (l->cname_key) avahi_key_unref(l->cname_key); - + avahi_free(l); } @@ -311,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); } @@ -345,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); @@ -354,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); @@ -367,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 */ @@ -386,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); @@ -400,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); @@ -415,10 +417,10 @@ static void add_to_cache(AvahiWideAreaLookupEngine *e, AvahiRecord *r) { is_new = 1; /* Enforce cache size */ - if (e->cache_n_entries >= MAX_CACHE_ENTRIES) + 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; @@ -434,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); @@ -445,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); } @@ -475,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); @@ -509,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; @@ -528,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; @@ -539,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); @@ -548,34 +550,26 @@ finish: } } -static void socket_event(AvahiWatch *w, int fd, AvahiWatchEvent events, void *userdata) { +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); @@ -583,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)); @@ -594,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) @@ -623,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); @@ -641,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); @@ -661,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_MAX_WIDE_AREA_SERVERS; 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); @@ -676,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); @@ -693,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); @@ -709,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); } @@ -723,4 +720,4 @@ int avahi_wide_area_has_servers(AvahiWideAreaLookupEngine *e) { } - +