From: Lennart Poettering Date: Fri, 25 Mar 2005 21:52:55 +0000 (+0000) Subject: * add announcing/goodbye X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=ad1f9d3725a300f10eca071c6fe2f2c583f51436;p=catta * add announcing/goodbye * add cache maintaince * fix a bug in prioq.c git-svn-id: file:///home/lennart/svn/public/avahi/trunk@16 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- diff --git a/Makefile b/Makefile index c9ad682..2731696 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ -#CC=gcc -CFLAGS=-g -O0 -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused +CC=gcc +CFLAGS=-g -O0 -Wall -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused LIBS=$(shell pkg-config --libs glib-2.0) all: flexmdns prioq-test -flexmdns: timeeventq.o main.o iface.o netlink.o server.o address.o util.o prioq.o cache.o rr.o dns.o socket.o psched.o +flexmdns: timeeventq.o main.o iface.o netlink.o server.o address.o util.o prioq.o cache.o rr.o dns.o socket.o psched.o announce.o $(CC) -o $@ $^ $(LIBS) #test-llist: test-llist.o diff --git a/announce.c b/announce.c new file mode 100644 index 0000000..db983d4 --- /dev/null +++ b/announce.c @@ -0,0 +1,169 @@ +#include "announce.h" +#include "util.h" + +static void remove_announcement(flxServer *s, flxAnnouncement *a) { + g_assert(s); + g_assert(a); + + flx_time_event_queue_remove(s->time_event_queue, a->time_event); + + FLX_LLIST_REMOVE(flxAnnouncement, by_interface, a->interface->announcements, a); + FLX_LLIST_REMOVE(flxAnnouncement, by_entry, a->entry->announcements, a); + + g_free(a); +} + +static void elapse_announce(flxTimeEvent *e, void *userdata) { + flxAnnouncement *a = userdata; + GTimeVal tv; + gchar *t; + + g_assert(e); + g_assert(a); + + if (a->n_announced >= 3) { + g_message("Enough announcements for record [%s]", t = flx_record_to_string(a->entry->record)); + g_free(t); + remove_announcement(a->server, a); + return; + } + + flx_interface_post_response(a->interface, a->entry->record); + a->n_announced++; + + g_message("Announcement #%i on interface %s.%i for entry [%s]", a->n_announced, a->interface->hardware->name, a->interface->protocol, t = flx_record_to_string(a->entry->record)); + g_free(t); + + flx_elapse_time(&tv, 1000, 100); + flx_time_event_queue_update(a->server->time_event_queue, a->time_event, &tv); +} + +static void new_announcement(flxServer *s, flxInterface *i, flxServerEntry *e) { + flxAnnouncement *a; + GTimeVal tv; + gchar *t; + + g_assert(s); + g_assert(i); + g_assert(e); + + if (!flx_interface_match(i, e->interface, e->protocol) || !flx_interface_relevant(i)) + return; + + /* We don't want duplicates */ + for (a = e->announcements; a; a = a->by_entry_next) + if (a->interface == i) + return; + + g_message("New announcement on interface %s.%i for entry [%s]", i->hardware->name, i->protocol, t = flx_record_to_string(e->record)); + g_free(t); + + flx_interface_post_response(i, e->record); + + a = g_new(flxAnnouncement, 1); + a->server = s; + a->interface = i; + a->entry = e; + a->n_announced = 1; + + FLX_LLIST_PREPEND(flxAnnouncement, by_interface, i->announcements, a); + FLX_LLIST_PREPEND(flxAnnouncement, by_entry, e->announcements, a); + + flx_elapse_time(&tv, 1000, 100); + a->time_event = flx_time_event_queue_add(s->time_event_queue, &tv, elapse_announce, a); +} + +void flx_announce_interface(flxServer *s, flxInterface *i) { + flxServerEntry *e; + + g_assert(s); + g_assert(i); + + if (!flx_interface_relevant(i)) + return; + + for (e = s->entries; e; e = e->entry_next) + new_announcement(s, i, e); +} + +void flx_announce_entry(flxServer *s, flxServerEntry *e) { + g_assert(s); + g_assert(e); + + if (e->interface > 0) { + + if (e->protocol != AF_UNSPEC) { + flxInterface *i; + + if ((i = flx_interface_monitor_get_interface(s->monitor, e->interface, e->protocol))) + new_announcement(s, i, e); + } else { + flxHwInterface *hw; + + if ((hw = flx_interface_monitor_get_hw_interface(s->monitor, e->interface))) { + flxInterface *i; + + for (i = hw->interfaces; i; i = i->by_hardware_next) + new_announcement(s, i, e); + } + } + } else { + flxInterface *i; + + for (i = s->monitor->interfaces; i; i = i->interface_next) + new_announcement(s, i, e); + } +} + +static flxRecord *make_goodbye_record(flxRecord *r) { + gchar *t; + + g_assert(r); + + g_message("Preparing goodbye for record [%s]", t = flx_record_to_string(r)); + g_free(t); + + return flx_record_new(r->key, r->data, r->size, 0); +} + +void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean goodbye) { + g_assert(s); + g_assert(i); + + while (i->announcements) + remove_announcement(s, i->announcements); + + if (goodbye && flx_interface_relevant(i)) { + flxServerEntry *e; + + for (e = s->entries; e; e = e->entry_next) + if (flx_interface_match(i, e->interface, e->protocol)) { + flxRecord *g = make_goodbye_record(e->record); + flx_interface_post_response(i, g); + flx_record_unref(g); + } + } +} + +void flx_goodbye_entry(flxServer *s, flxServerEntry *e, gboolean goodbye) { + g_assert(s); + g_assert(e); + + while (e->announcements) + remove_announcement(s, e->announcements); + + if (goodbye) { + flxRecord *g = make_goodbye_record(e->record); + flx_server_post_response(s, e->interface, e->protocol, g); + flx_record_unref(g); + } +} + +void flx_goodbye_all(flxServer *s, gboolean goodbye) { + flxServerEntry *e; + + g_assert(s); + + for (e = s->entries; e; e = e->entry_next) + flx_goodbye_entry(s, e, goodbye); +} diff --git a/announce.h b/announce.h new file mode 100644 index 0000000..0e65eae --- /dev/null +++ b/announce.h @@ -0,0 +1,33 @@ +#ifndef fooannouncehfoo +#define fooannouncehfoo + +#include + +typedef struct _flxAnnouncement flxAnnouncement; + +#include "llist.h" +#include "iface.h" +#include "server.h" +#include "timeeventq.h" + +struct _flxAnnouncement { + flxServer *server; + flxInterface *interface; + flxServerEntry *entry; + + flxTimeEvent *time_event; + guint n_announced; + + FLX_LLIST_FIELDS(flxAnnouncement, by_interface); + FLX_LLIST_FIELDS(flxAnnouncement, by_entry); +}; + +void flx_announce_interface(flxServer *s, flxInterface *i); +void flx_announce_entry(flxServer *s, flxServerEntry *e); + +void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean send); +void flx_goodbye_entry(flxServer *s, flxServerEntry *e, gboolean send); + +void flx_goodbye_all(flxServer *s, gboolean send); + +#endif diff --git a/cache.c b/cache.c index 9025d1d..b668d33 100644 --- a/cache.c +++ b/cache.c @@ -6,6 +6,8 @@ static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_has g_assert(c); g_assert(e); + g_message("remvoin from cache: %p %p", c, e); + if (remove_from_hash_table) { flxCacheEntry *t; t = g_hash_table_lookup(c->hash_table, e->record->key); @@ -24,14 +26,13 @@ static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_has g_free(e); } -flxCache *flx_cache_new(flxServer *server, flxInterface *iface, guchar protocol) { +flxCache *flx_cache_new(flxServer *server, flxInterface *iface) { flxCache *c; g_assert(server); c = g_new(flxCache, 1); c->server = server; c->interface = iface; - c->protocol = protocol; c->hash_table = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal); return c; @@ -119,7 +120,7 @@ static void elapse_func(flxTimeEvent *t, void *userdata) { g_message("Requesting cache entry update at %i%%.", percent); /* Request a cache update */ - flx_interface_post_query(e->cache->interface, e->cache->protocol, e->record->key); + flx_interface_post_query(e->cache->interface, e->record->key); /* Check again later */ next_expiry(e->cache, e, percent); @@ -232,15 +233,10 @@ void flx_cache_drop_record(flxCache *c, flxRecord *r) { static void func(gpointer key, gpointer data, gpointer userdata) { flxCacheEntry *e = data; flxKey *k = key; + gchar *t; - gchar *s, *t; - - s = flx_key_to_string(k); t = flx_record_to_string(e->record); - - fprintf((FILE*) userdata, "%s %s\n", s, t); - - g_free(s); + fprintf((FILE*) userdata, "%s\n", t); g_free(t); } diff --git a/cache.h b/cache.h index 263d9a1..f51e18e 100644 --- a/cache.h +++ b/cache.h @@ -40,12 +40,11 @@ struct _flxCache { flxServer *server; flxInterface *interface; - guchar protocol; GHashTable *hash_table; }; -flxCache *flx_cache_new(flxServer *server, flxInterface *interface, guchar protocol); +flxCache *flx_cache_new(flxServer *server, flxInterface *interface); void flx_cache_free(flxCache *c); flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k); diff --git a/dns.c b/dns.c index a33f1ab..726eb21 100644 --- a/dns.c +++ b/dns.c @@ -438,7 +438,7 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac memcpy(ptr_name, r->data, r->size); ptr_name[r->size] = 0; - if (!flx_dns_packet_append_uint16(p, strlen(ptr_name)) || + if (!flx_dns_packet_append_uint16(p, strlen(ptr_name)+1) || !flx_dns_packet_append_name(p, ptr_name)) return NULL; @@ -452,7 +452,7 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac memcpy(name, r->data+6, r->size-6); name[r->size-6] = 0; - if (!flx_dns_packet_append_uint16(p, strlen(name+6)) || + if (!flx_dns_packet_append_uint16(p, strlen(name+6)+1+6) || !flx_dns_packet_append_bytes(p, r->data, 6) || !flx_dns_packet_append_name(p, name)) return NULL; diff --git a/flx.h b/flx.h index ea61647..1debd89 100644 --- a/flx.h +++ b/flx.h @@ -56,7 +56,8 @@ void flx_server_add_text( void flx_server_remove(flxServer *s, gint id); -void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey *k); +void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey *key); +void flx_server_post_response(flxServer *s, gint interface, guchar protocol, flxRecord *record); const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state); diff --git a/iface.c b/iface.c index 5463895..5e6c94a 100644 --- a/iface.c +++ b/iface.c @@ -10,12 +10,13 @@ #include "netlink.h" #include "dns.h" #include "socket.h" +#include "announce.h" static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, int remove) { g_assert(m); g_assert(a); - if (!flx_address_is_relevant(a) || remove) { + if (!flx_interface_address_relevant(a) || remove) { if (a->rr_id >= 0) { flx_server_remove(m->server, a->rr_id); a->rr_id = -1; @@ -23,7 +24,7 @@ static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, in } else { if (a->rr_id < 0) { a->rr_id = flx_server_get_next_id(m->server); - flx_server_add_address(m->server, a->rr_id, a->interface->index, AF_UNSPEC, FALSE, m->server->hostname, &a->address); + flx_server_add_address(m->server, a->rr_id, a->interface->hardware->index, AF_UNSPEC, FALSE, m->server->hostname, &a->address); } } } @@ -37,18 +38,22 @@ static void update_interface_rr(flxInterfaceMonitor *m, flxInterface *i, int rem update_address_rr(m, a, remove); } +static void update_hw_interface_rr(flxInterfaceMonitor *m, flxHwInterface *hw, int remove) { + flxInterface *i; + + g_assert(m); + g_assert(hw); + + for (i = hw->interfaces; i; i = i->by_hardware_next) + update_interface_rr(m, i, remove); +} + static void free_address(flxInterfaceMonitor *m, flxInterfaceAddress *a) { g_assert(m); g_assert(a); g_assert(a->interface); - if (a->address.family == AF_INET) - a->interface->n_ipv4_addrs --; - else if (a->address.family == AF_INET6) - a->interface->n_ipv6_addrs --; - FLX_LLIST_REMOVE(flxInterfaceAddress, address, a->interface->addresses, a); - flx_server_remove(m->server, a->rr_id); g_free(a); @@ -58,32 +63,35 @@ static void free_interface(flxInterfaceMonitor *m, flxInterface *i) { g_assert(m); g_assert(i); - if (i->ipv4_scheduler) - flx_packet_scheduler_free(i->ipv4_scheduler); - if (i->ipv6_scheduler) - flx_packet_scheduler_free(i->ipv6_scheduler); - + flx_goodbye_interface(m->server, i, FALSE); + g_assert(!i->announcements); + while (i->addresses) free_address(m, i->addresses); - if (i->ipv4_cache) - flx_cache_free(i->ipv4_cache); - if (i->ipv6_cache) - flx_cache_free(i->ipv6_cache); + flx_packet_scheduler_free(i->scheduler); + flx_cache_free(i->cache); - g_assert(i->n_ipv6_addrs == 0); - g_assert(i->n_ipv4_addrs == 0); - FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i); - g_hash_table_remove(m->hash_table, &i->index); - - flx_cache_free(i->ipv4_cache); - flx_cache_free(i->ipv6_cache); + FLX_LLIST_REMOVE(flxInterface, by_hardware, i->hardware->interfaces, i); - g_free(i->name); g_free(i); } +static void free_hw_interface(flxInterfaceMonitor *m, flxHwInterface *hw) { + g_assert(m); + g_assert(hw); + + while (hw->interfaces) + free_interface(m, hw->interfaces); + + FLX_LLIST_REMOVE(flxHwInterface, hardware, m->hw_interfaces, hw); + g_hash_table_remove(m->hash_table, &hw->index); + + g_free(hw->name); + g_free(hw); +} + static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i, const flxAddress *raddr) { flxInterfaceAddress *ia; @@ -117,6 +125,59 @@ static int netlink_list_items(flxNetlink *nl, guint16 type, guint *ret_seq) { return flx_netlink_send(nl, n, ret_seq); } +static void new_interface(flxInterfaceMonitor *m, flxHwInterface *hw, guchar protocol) { + flxInterface *i; + + g_assert(m); + g_assert(hw); + g_assert(protocol != AF_UNSPEC); + + i = g_new(flxInterface, 1); + i->monitor = m; + i->hardware = hw; + i->protocol = protocol; + i->relevant = FALSE; + + FLX_LLIST_HEAD_INIT(flxInterfaceAddress, i->addresses); + FLX_LLIST_HEAD_INIT(flxAnnouncement, i->announcements); + + i->cache = flx_cache_new(m->server, i); + i->scheduler = flx_packet_scheduler_new(m->server, i); + + FLX_LLIST_PREPEND(flxInterface, by_hardware, hw->interfaces, i); + FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i); +} + +static void check_interface_relevant(flxInterfaceMonitor *m, flxInterface *i) { + gboolean b; + g_assert(m); + g_assert(i); + + b = flx_interface_relevant(i); + + if (b && !i->relevant) { + g_message("New relevant interface %s.%i", i->hardware->name, i->protocol); + + flx_announce_interface(m->server, i); + } else if (!b && i->relevant) { + g_message("Interface %s.%i no longer relevant", i->hardware->name, i->protocol); + + flx_goodbye_interface(m->server, i, FALSE); + } + + i->relevant = b; +} + +static void check_hw_interface_relevant(flxInterfaceMonitor *m, flxHwInterface *hw) { + flxInterface *i; + + g_assert(m); + g_assert(hw); + + for (i = hw->interfaces; i; i = i->by_hardware_next) + check_interface_relevant(m, i); +} + static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) { flxInterfaceMonitor *m = userdata; @@ -126,35 +187,33 @@ static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) { if (n->nlmsg_type == RTM_NEWLINK) { struct ifinfomsg *ifinfomsg = NLMSG_DATA(n); - flxInterface *i; + flxHwInterface *hw; struct rtattr *a = NULL; size_t l; - int changed; if (ifinfomsg->ifi_family != AF_UNSPEC) return; - if ((i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index))) - changed = 1; - else { - i = g_new(flxInterface, 1); - i->monitor = m; - i->name = NULL; - i->index = ifinfomsg->ifi_index; - i->addresses = NULL; - i->n_ipv4_addrs = i->n_ipv6_addrs = 0; - FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i); - g_hash_table_insert(m->hash_table, &i->index, i); - i->mtu = 1500; - i->ipv4_cache = flx_cache_new(m->server, i, AF_INET); - i->ipv6_cache = flx_cache_new(m->server, i, AF_INET6); - i->ipv4_scheduler = flx_packet_scheduler_new(m->server, i, AF_INET); - i->ipv6_scheduler = flx_packet_scheduler_new(m->server, i, AF_INET6); + if (!(hw = g_hash_table_lookup(m->hash_table, &ifinfomsg->ifi_index))) { + hw = g_new(flxHwInterface, 1); + hw->monitor = m; + hw->name = NULL; + hw->flags = 0; + hw->mtu = 1500; + hw->index = ifinfomsg->ifi_index; + + FLX_LLIST_HEAD_INIT(flxInterface, hw->interfaces); + FLX_LLIST_PREPEND(flxHwInterface, hardware, m->hw_interfaces, hw); - changed = 0; + g_hash_table_insert(m->hash_table, &hw->index, hw); + + if (m->server->fd_ipv4 >= 0) + new_interface(m, hw, AF_INET); + if (m->server->fd_ipv6 >= 0) + new_interface(m, hw, AF_INET6); } - i->flags = ifinfomsg->ifi_flags; + hw->flags = ifinfomsg->ifi_flags; l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg)); a = IFLA_RTA(ifinfomsg); @@ -162,13 +221,13 @@ static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) { while (RTA_OK(a, l)) { switch(a->rta_type) { case IFLA_IFNAME: - g_free(i->name); - i->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a)); + g_free(hw->name); + hw->name = g_strndup(RTA_DATA(a), RTA_PAYLOAD(a)); break; case IFLA_MTU: g_assert(RTA_PAYLOAD(a) == sizeof(unsigned int)); - i->mtu = *((unsigned int*) RTA_DATA(a)); + hw->mtu = *((unsigned int*) RTA_DATA(a)); break; default: @@ -178,19 +237,22 @@ static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) { a = RTA_NEXT(a, l); } - update_interface_rr(m, i, 0); + update_hw_interface_rr(m, hw, FALSE); + check_hw_interface_relevant(m, hw); + } else if (n->nlmsg_type == RTM_DELLINK) { struct ifinfomsg *ifinfomsg = NLMSG_DATA(n); + flxHwInterface *hw; flxInterface *i; if (ifinfomsg->ifi_family != AF_UNSPEC) return; - if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifinfomsg->ifi_index))) + if (!(hw = flx_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index))) return; - update_interface_rr(m, i, 1); - free_interface(m, i); + update_hw_interface_rr(m, hw, TRUE); + free_hw_interface(m, hw); } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { @@ -198,14 +260,13 @@ static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) { flxInterface *i; struct rtattr *a = NULL; size_t l; - int changed; flxAddress raddr; int raddr_valid = 0; if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6) return; - if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index))) + if (!(i = (flxInterface*) flx_interface_monitor_get_interface(m, ifaddrmsg->ifa_index, ifaddrmsg->ifa_family))) return; raddr.family = ifaddrmsg->ifa_family; @@ -228,58 +289,52 @@ static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) { default: ; } - + a = RTA_NEXT(a, l); } - + if (!raddr_valid) return; if (n->nlmsg_type == RTM_NEWADDR) { flxInterfaceAddress *addr; - if ((addr = get_address(m, i, &raddr))) - changed = 1; - else { + if (!(addr = get_address(m, i, &raddr))) { addr = g_new(flxInterfaceAddress, 1); + addr->monitor = m; addr->address = raddr; addr->interface = i; - - if (raddr.family == AF_INET) - i->n_ipv4_addrs++; - else if (raddr.family == AF_INET6) - i->n_ipv6_addrs++; - addr->rr_id = -1; FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr); - - changed = 0; } addr->flags = ifaddrmsg->ifa_flags; addr->scope = ifaddrmsg->ifa_scope; - update_address_rr(m, addr, 0); + update_address_rr(m, addr, FALSE); + check_interface_relevant(m, i); } else { flxInterfaceAddress *addr; if (!(addr = get_address(m, i, &raddr))) return; - update_address_rr(m, addr, 1); + update_address_rr(m, addr, TRUE); free_address(m, addr); + + check_interface_relevant(m, i); } } else if (n->nlmsg_type == NLMSG_DONE) { - + if (m->list == LIST_IFACE) { m->list = LIST_DONE; - if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) { + if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) g_warning("NETLINK: Failed to list addrs: %s", strerror(errno)); - } else + else m->list = LIST_ADDR; } else m->list = LIST_DONE; @@ -301,7 +356,9 @@ flxInterfaceMonitor *flx_interface_monitor_new(flxServer *s) { goto fail; m->hash_table = g_hash_table_new(g_int_hash, g_int_equal); - m->interfaces = NULL; + + FLX_LLIST_HEAD_INIT(flxInterface, m->interfaces); + FLX_LLIST_HEAD_INIT(flxHwInterface, m->hw_interfaces); if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0) goto fail; @@ -321,6 +378,11 @@ void flx_interface_monitor_free(flxInterfaceMonitor *m) { if (m->netlink) flx_netlink_free(m->netlink); + while (m->hw_interfaces) + free_hw_interface(m, m->hw_interfaces); + + g_assert(!m->interfaces); + if (m->hash_table) g_hash_table_destroy(m->hash_table); @@ -328,97 +390,102 @@ void flx_interface_monitor_free(flxInterfaceMonitor *m) { } -flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) { +flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index, guchar protocol) { + flxHwInterface *hw; + flxInterface *i; + g_assert(m); g_assert(index > 0); + g_assert(protocol != AF_UNSPEC); - return g_hash_table_lookup(m->hash_table, &index); -} - -flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) { - g_assert(m); - return m->interfaces; -} + if (!(hw = flx_interface_monitor_get_hw_interface(m, index))) + return NULL; -int flx_interface_is_relevant(flxInterface *i) { - g_assert(i); + for (i = hw->interfaces; i; i = i->by_hardware_next) + if (i->protocol == protocol) + return i; - return - (i->flags & IFF_UP) && - (i->flags & IFF_RUNNING) && - !(i->flags & IFF_LOOPBACK); + return NULL; } -int flx_address_is_relevant(flxInterfaceAddress *a) { - g_assert(a); +flxHwInterface* flx_interface_monitor_get_hw_interface(flxInterfaceMonitor *m, gint index) { + g_assert(m); + g_assert(index > 0); - return - a->scope == RT_SCOPE_UNIVERSE && - flx_interface_is_relevant(a->interface); + return g_hash_table_lookup(m->hash_table, &index); } -void flx_interface_send_packet(flxInterface *i, guchar protocol, flxDnsPacket *p) { + +void flx_interface_send_packet(flxInterface *i, flxDnsPacket *p) { g_assert(i); g_assert(p); - if (!flx_interface_is_relevant(i)) - return; - - if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0) { - g_message("sending on '%s':IPv4", i->name); - flx_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->index, p); - } + if (i->relevant) { + g_message("sending on '%s.%i'", i->hardware->name, i->protocol); - if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0) { - g_message("sending on '%s':IPv6", i->name); - flx_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->index, p); + if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0) + flx_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p); + else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0) + flx_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p); } } -void flx_interface_post_query(flxInterface *i, guchar protocol, flxKey *k) { +void flx_interface_post_query(flxInterface *i, flxKey *key) { g_assert(i); - g_assert(k); + g_assert(key); - if (!flx_interface_is_relevant(i)) - return; + if (i->relevant) + flx_packet_scheduler_post_query(i->scheduler, key); +} - if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0) - flx_packet_scheduler_post_query(i->ipv4_scheduler, k); - if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0) - flx_packet_scheduler_post_query(i->ipv6_scheduler, k); +void flx_interface_post_response(flxInterface *i, flxRecord *record) { + g_assert(i); + g_assert(record); + + if (i->relevant) + flx_packet_scheduler_post_response(i->scheduler, record); +} + +void flx_dump_caches(flxInterfaceMonitor *m, FILE *f) { + flxInterface *i; + g_assert(m); + + for (i = m->interfaces; i; i = i->interface_next) { + if (i->relevant) { + fprintf(f, ";;; INTERFACE %s.%i ;;;\n", i->hardware->name, i->protocol); + flx_cache_dump(i->cache, f); + } + } } -void flx_interface_post_response(flxInterface *i, guchar protocol, flxRecord *rr) { +gboolean flx_interface_relevant(flxInterface *i) { g_assert(i); - g_assert(rr); - if (!flx_interface_is_relevant(i)) - return; + return + (i->hardware->flags & IFF_UP) && + (i->hardware->flags & IFF_RUNNING) && + !(i->hardware->flags & IFF_LOOPBACK) && + (i->hardware->flags & IFF_MULTICAST) && + i->addresses; +} - if ((protocol == AF_INET || protocol == AF_UNSPEC) && i->n_ipv4_addrs > 0) - flx_packet_scheduler_post_response(i->ipv4_scheduler, rr); +gboolean flx_interface_address_relevant(flxInterfaceAddress *a) { + g_assert(a); - if ((protocol == AF_INET6 || protocol == AF_UNSPEC) && i->n_ipv6_addrs > 0) - flx_packet_scheduler_post_response(i->ipv6_scheduler, rr); + return a->scope == RT_SCOPE_UNIVERSE; } -void flx_dump_caches(flxServer *s, FILE *f) { - flxInterface *i; - g_assert(s); - for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next) { - if (!flx_interface_is_relevant(i)) - continue; - - if (i->n_ipv4_addrs > 0) { - fprintf(f, ";;; INTERFACE %s; IPv4 ;;;\n", i->name); - flx_cache_dump(i->ipv4_cache, f); - } +gboolean flx_interface_match(flxInterface *i, gint index, guchar protocol) { + g_assert(i); + + if (index > 0 && index != i->hardware->index) + return FALSE; - if (i->n_ipv6_addrs > 0) { - fprintf(f, ";;; INTERFACE %s; IPv6 ;;;\n", i->name); - flx_cache_dump(i->ipv6_cache, f); - } - } + if (protocol != AF_UNSPEC && protocol != i->protocol) + return FALSE; + + return TRUE; } + diff --git a/iface.h b/iface.h index 50cc98f..85e535c 100644 --- a/iface.h +++ b/iface.h @@ -3,14 +3,10 @@ #include -struct _flxInterfaceMonitor; typedef struct _flxInterfaceMonitor flxInterfaceMonitor; - -struct _flxInterfaceAddress; typedef struct _flxInterfaceAddress flxInterfaceAddress; - -struct _flxInterface; typedef struct _flxInterface flxInterface; +typedef struct _flxHwInterface flxHwInterface; #include "address.h" #include "server.h" @@ -19,6 +15,7 @@ typedef struct _flxInterface flxInterface; #include "llist.h" #include "psched.h" #include "dns.h" +#include "announce.h" struct _flxInterfaceMonitor { flxServer *server; @@ -26,55 +23,73 @@ struct _flxInterfaceMonitor { GHashTable *hash_table; FLX_LLIST_HEAD(flxInterface, interfaces); + FLX_LLIST_HEAD(flxHwInterface, hw_interfaces); guint query_addr_seq, query_link_seq; - enum { LIST_IFACE, LIST_ADDR, LIST_DONE } list; + enum { + LIST_IFACE, + LIST_ADDR, + LIST_DONE + } list; }; -struct _flxInterface { +struct _flxHwInterface { + FLX_LLIST_FIELDS(flxHwInterface, hardware); flxInterfaceMonitor *monitor; + gchar *name; gint index; guint flags; + guint mtu; - FLX_LLIST_HEAD(flxInterfaceAddress, addresses); - FLX_LLIST_FIELDS(flxInterface, interface); + FLX_LLIST_HEAD(flxInterface, interfaces); +}; - guint n_ipv6_addrs, n_ipv4_addrs; - flxCache *ipv4_cache, *ipv6_cache; +struct _flxInterface { + FLX_LLIST_FIELDS(flxInterface, interface); + FLX_LLIST_FIELDS(flxInterface, by_hardware); + flxInterfaceMonitor *monitor; + + flxHwInterface *hardware; + guchar protocol; + gboolean relevant; - guint mtu; + flxCache *cache; + flxPacketScheduler *scheduler; - flxPacketScheduler *ipv4_scheduler, *ipv6_scheduler; + FLX_LLIST_HEAD(flxInterfaceAddress, addresses); + FLX_LLIST_HEAD(flxAnnouncement, announcements); }; struct _flxInterfaceAddress { + FLX_LLIST_FIELDS(flxInterfaceAddress, address); + flxInterfaceMonitor *monitor; + guchar flags; guchar scope; flxAddress address; - flxInterface *interface; - - FLX_LLIST_FIELDS(flxInterfaceAddress, address); - gint rr_id; + flxInterface *interface; }; flxInterfaceMonitor *flx_interface_monitor_new(flxServer *server); void flx_interface_monitor_free(flxInterfaceMonitor *m); -flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index); -flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m); +flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index, guchar protocol); +flxHwInterface* flx_interface_monitor_get_hw_interface(flxInterfaceMonitor *m, gint index); + +void flx_interface_send_packet(flxInterface *i, flxDnsPacket *p); -int flx_interface_is_relevant(flxInterface *i); -int flx_address_is_relevant(flxInterfaceAddress *a); +void flx_interface_post_query(flxInterface *i, flxKey *k); +void flx_interface_post_response(flxInterface *i, flxRecord *rr); -void flx_interface_send_packet(flxInterface *i, guchar protocol, flxDnsPacket *p); +void flx_dump_caches(flxInterfaceMonitor *m, FILE *f); -void flx_interface_post_query(flxInterface *i, guchar protocol, flxKey *k); -void flx_interface_post_response(flxInterface *i, guchar protocol, flxRecord *rr); +gboolean flx_interface_relevant(flxInterface *i); +gboolean flx_interface_address_relevant(flxInterfaceAddress *a); -void flx_dump_caches(flxServer *s, FILE *f); +gboolean flx_interface_match(flxInterface *i, gint index, guchar protocol); #endif diff --git a/main.c b/main.c index 92f3491..47f3cd7 100644 --- a/main.c +++ b/main.c @@ -18,9 +18,9 @@ static gboolean send_timeout(gpointer data) { /* flx_server_post_query(flx, 0, AF_UNSPEC, k); */ /* flx_key_unref(k); */ - k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); - flx_server_post_query(flx, 0, AF_INET, k); - flx_key_unref(k); +/* k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); */ +/* flx_server_post_query(flx, 0, AF_INET, k); */ +/* flx_key_unref(k); */ return FALSE; } diff --git a/prioq-test.c b/prioq-test.c index a54c1ff..d8640c1 100644 --- a/prioq-test.c +++ b/prioq-test.c @@ -4,16 +4,41 @@ #include "prioq.h" -static gint compare(gconstpointer a, gconstpointer b) { +static gint compare_int(gconstpointer a, gconstpointer b) { gint i = GPOINTER_TO_INT(a), j = GPOINTER_TO_INT(b); return i < j ? -1 : (i > j ? 1 : 0); } +static int compare_ptr(gconstpointer a, gconstpointer b) { + return a < b ? -1 : (a > b ? 1 : 0); +} + static void rec(flxPrioQueueNode *n) { if (!n) return; + if (n->left) + g_assert(n->left->parent == n); + + if (n->right) + g_assert(n->right->parent == n); + + if (n->parent) { + g_assert(n->parent->left == n || n->parent->right == n); + + if (n->parent->left == n) + g_assert(n->next == n->parent->right); + } + + if (!n->next) { + g_assert(n->queue->last == n); + + if (n->parent && n->parent->left == n) + g_assert(n->parent->right == NULL); + } + + if (n->parent) { int a = GPOINTER_TO_INT(n->parent->data), b = GPOINTER_TO_INT(n->data); if (a > b) { @@ -27,29 +52,40 @@ static void rec(flxPrioQueueNode *n) { } int main(int argc, char *argv[]) { - flxPrioQueue *q; + flxPrioQueue *q, *q2; gint i, prev; - q = flx_prio_queue_new(compare); + q = flx_prio_queue_new(compare_int); + q2 = flx_prio_queue_new(compare_ptr); srand(time(NULL)); - flx_prio_queue_put(q, GINT_TO_POINTER(255)); - flx_prio_queue_put(q, GINT_TO_POINTER(255)); - - for (i = 0; i < 10000; i++) - flx_prio_queue_put(q, GINT_TO_POINTER(random() & 0xFFFF)); + for (i = 0; i < 10000; i++) + flx_prio_queue_put(q2, flx_prio_queue_put(q, GINT_TO_POINTER(random() & 0xFFFF))); - prev = 0; - while (q->root) { - gint v = GPOINTER_TO_INT(q->root->data); + while (q2->root) { rec(q->root); - printf("%i\n", v); - flx_prio_queue_remove(q, q->root); - g_assert(v >= prev); - prev = v; + rec(q2->root); + + g_assert(q->n_nodes == q2->n_nodes); + + printf("%i\n", GPOINTER_TO_INT(((flxPrioQueueNode*)q2->root->data)->data)); + + flx_prio_queue_remove(q, q2->root->data); + flx_prio_queue_remove(q2, q2->root); } + +/* prev = 0; */ +/* while (q->root) { */ +/* gint v = GPOINTER_TO_INT(q->root->data); */ +/* rec(q->root); */ +/* printf("%i\n", v); */ +/* flx_prio_queue_remove(q, q->root); */ +/* g_assert(v >= prev); */ +/* prev = v; */ +/* } */ + flx_prio_queue_free(q); return 0; } diff --git a/prioq.c b/prioq.c index 09d781f..9e49b81 100644 --- a/prioq.c +++ b/prioq.c @@ -45,7 +45,7 @@ static flxPrioQueueNode* get_node_at_xy(flxPrioQueue *q, guint x, guint y) { } static void exchange_nodes(flxPrioQueue *q, flxPrioQueueNode *a, flxPrioQueueNode *b) { - flxPrioQueueNode *l, *r, *p, *ap, *an, *bp, *bn; + flxPrioQueueNode *l, *r, *p, *ap, *an, *bp, *bn, *apl, *bpl; gint t; g_assert(q); g_assert(a); @@ -129,21 +129,27 @@ static void exchange_nodes(flxPrioQueue *q, flxPrioQueueNode *a, flxPrioQueueNod } } else { /* Swap parents */ - p = a->parent; + ap = a->parent; + bp = b->parent; + + if (ap) + apl = ap->left; + if (bp) + bpl = bp->left; - if ((a->parent = b->parent)) { - if (a->parent->left == b) - a->parent->left = a; - else - a->parent->right = a; + if ((a->parent = bp)) { + if (bpl == b) + bp->left = a; + else + bp->right = a; } else q->root = a; - if ((b->parent = p)) { - if (b->parent->left == a) - b->parent->left = b; + if ((b->parent = ap)) { + if (apl == a) + ap->left = b; else - b->parent->right = b; + ap->right = b; } else q->root = b; @@ -258,7 +264,7 @@ flxPrioQueueNode* flx_prio_queue_put(flxPrioQueue *q, gpointer data) { if (q->last) { g_assert(q->root); g_assert(q->n_nodes); - + n->y = q->last->y; n->x = q->last->x+1; @@ -302,7 +308,7 @@ void flx_prio_queue_remove(flxPrioQueue *q, flxPrioQueueNode *n) { if (n != q->last) { flxPrioQueueNode *replacement = q->last; exchange_nodes(q, replacement, n); - flx_prio_queue_remove(q, q->last); + flx_prio_queue_remove(q, n); flx_prio_queue_shuffle(q, replacement); return; } @@ -314,14 +320,21 @@ void flx_prio_queue_remove(flxPrioQueue *q, flxPrioQueueNode *n) { q->last = n->prev; - if (n->prev) + if (n->prev) { n->prev->next = NULL; - else + g_assert(n->parent); + } else g_assert(!n->parent); if (n->parent) { g_assert(n->prev); if (n->parent->left == n) { + if (n->parent->right != NULL) { + g_message("fuck"); + for (;;); + + } + g_assert(n->parent->right == NULL); n->parent->left = NULL; } else { @@ -332,10 +345,13 @@ void flx_prio_queue_remove(flxPrioQueue *q, flxPrioQueueNode *n) { } else { g_assert(q->root == n); g_assert(!n->prev); + g_assert(q->n_nodes == 1); q->root = NULL; } - q->n_nodes--; - g_free(n); + + g_assert(q->n_nodes > 0); + q->n_nodes--; } + diff --git a/psched.c b/psched.c index ca1e007..ebae9d3 100644 --- a/psched.c +++ b/psched.c @@ -1,7 +1,7 @@ #include "util.h" #include "psched.h" -flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i, guchar protocol) { +flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i) { flxPacketScheduler *s; g_assert(server); @@ -10,7 +10,6 @@ flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i, s = g_new(flxPacketScheduler, 1); s->server = server; s->interface = i; - s->protocol = protocol; FLX_LLIST_HEAD_INIT(flxQueryJob, s->query_jobs); FLX_LLIST_HEAD_INIT(flxResponseJob, s->response_jobs); @@ -93,7 +92,7 @@ static void query_elapse(flxTimeEvent *e, gpointer data) { return; } - p = flx_dns_packet_new_query(s->interface->mtu - 48); + p = flx_dns_packet_new_query(s->interface->hardware->mtu - 48); d = packet_add_query_job(s, p, qj); g_assert(d); n = 1; @@ -111,7 +110,7 @@ static void query_elapse(flxTimeEvent *e, gpointer data) { } flx_dns_packet_set_field(p, DNS_FIELD_QDCOUNT, n); - flx_interface_send_packet(s->interface, s->protocol, p); + flx_interface_send_packet(s->interface, p); flx_dns_packet_free(p); } @@ -186,7 +185,7 @@ static void response_elapse(flxTimeEvent *e, gpointer data) { return; } - p = flx_dns_packet_new_response(s->interface->mtu - 200); + p = flx_dns_packet_new_response(s->interface->hardware->mtu - 200); d = packet_add_response_job(s, p, rj); g_assert(d); n = 1; @@ -204,7 +203,7 @@ static void response_elapse(flxTimeEvent *e, gpointer data) { } flx_dns_packet_set_field(p, DNS_FIELD_ANCOUNT, n); - flx_interface_send_packet(s->interface, s->protocol, p); + flx_interface_send_packet(s->interface, p); flx_dns_packet_free(p); } diff --git a/psched.h b/psched.h index 90b67db..fae5d91 100644 --- a/psched.h +++ b/psched.h @@ -30,13 +30,12 @@ struct _flxPacketScheduler { flxServer *server; flxInterface *interface; - guchar protocol; FLX_LLIST_HEAD(flxQueryJob, query_jobs); FLX_LLIST_HEAD(flxResponseJob, response_jobs); }; -flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i, guchar protocol); +flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i); void flx_packet_scheduler_free(flxPacketScheduler *s); void flx_packet_scheduler_post_query(flxPacketScheduler *s, flxKey *key); diff --git a/rr.c b/rr.c index a6ecfbd..c984934 100644 --- a/rr.c +++ b/rr.c @@ -51,7 +51,6 @@ flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 t g_assert(k); g_assert(data); g_assert(size > 0); - g_assert(ttl > 0); r = g_new(flxRecord, 1); r->ref = 1; @@ -142,8 +141,7 @@ gchar *flx_record_to_string(flxRecord *r) { inet_ntop(AF_INET6, r->data, t, sizeof(t)); break; - case FLX_DNS_TYPE_PTR: - case FLX_DNS_TYPE_TXT: { + case FLX_DNS_TYPE_PTR: { size_t l; l = r->size; @@ -155,13 +153,30 @@ gchar *flx_record_to_string(flxRecord *r) { break; } + case FLX_DNS_TYPE_TXT: { + g_assert(((guchar*) r->data)[0] == r->size-1); + + memcpy(t, r->data+1, ((guchar*) r->data)[0]); + t[((guchar*) r->data)[0]] = 0; + break; + } + case FLX_DNS_TYPE_HINFO: { - char *s2; - - if ((s2 = memchr(r->data, 0, r->size))) { - s2++; - if (memchr(s2, 0, r->size - ((char*) s2 - (char*) r->data))) - snprintf(t, sizeof(t), "'%s' '%s'", (char*) r->data, s2); + gchar *s2; + gchar hi1[256], hi2[256]; + guchar len; + + if ((size_t) (len = ((guchar*) r->data)[0]) + 2 <= r->size) { + guchar len2; + memcpy(hi1, (gchar*) r->data +1, len); + hi1[len] = 0; + + if ((size_t) (len2 = ((guchar*) r->data)[len+1]) + len + 2 <= r->size) { + memcpy(hi2, (gchar*) r->data+len+2, len2); + hi2[len2] = 0; + snprintf(t, sizeof(t), "'%s' '%s'", hi1, hi2); + } + } break; @@ -183,11 +198,12 @@ gchar *flx_record_to_string(flxRecord *r) { ntohs(((guint16*) r->data)[1]), ntohs(((guint16*) r->data)[2]), k); + break; } } p = flx_key_to_string(r->key); - s = g_strdup_printf("%s %s ; ttl=%u", p, t, r->ttl); + s = g_strdup_printf("[%s %s ; ttl=%u]", p, t, r->ttl); g_free(p); return s; diff --git a/rr.h b/rr.h index d37cb64..a31b632 100644 --- a/rr.h +++ b/rr.h @@ -20,7 +20,7 @@ enum { FLX_DNS_CLASS_IN = 0x01 }; -#define FLX_DEFAULT_TTL 10 /*(120*60)*/ +#define FLX_DEFAULT_TTL (120*60) typedef struct { guint ref; diff --git a/server.c b/server.c index 2b354bd..0aaaed1 100644 --- a/server.c +++ b/server.c @@ -9,8 +9,9 @@ #include "iface.h" #include "socket.h" + static void handle_query_key(flxServer *s, flxKey *k, flxInterface *i, const flxAddress *a) { - flxEntry *e; + flxServerEntry *e; gchar *txt; g_assert(s); @@ -21,14 +22,9 @@ static void handle_query_key(flxServer *s, flxKey *k, flxInterface *i, const flx g_message("Handling query: %s", txt = flx_key_to_string(k)); g_free(txt); - for (e = g_hash_table_lookup(s->rrset_by_name, k); e; e = e->by_name_next) { - - if ((e->interface <= 0 || e->interface == i->index) && - (e->protocol == AF_UNSPEC || e->protocol == a->family)) { - - flx_interface_post_response(i, a->family, e->record); - } - } + for (e = g_hash_table_lookup(s->rrset_by_key, k); e; e = e->by_key_next) + if (flx_interface_match(i, e->interface, e->protocol)) + flx_interface_post_response(i, e->record); } static void handle_query(flxServer *s, flxDnsPacket *p, flxInterface *i, const flxAddress *a) { @@ -74,8 +70,8 @@ static void handle_response(flxServer *s, flxDnsPacket *p, flxInterface *i, cons g_message("Handling response: %s", txt = flx_record_to_string(record)); g_free(txt); - flx_cache_update(a->family == AF_INET ? i->ipv4_cache : i->ipv6_cache, record, cache_flush, a); - flx_packet_scheduler_drop_response(a->family == AF_INET ? i->ipv4_scheduler : i->ipv6_scheduler, record); + flx_cache_update(i->cache, record, cache_flush, a); + flx_packet_scheduler_drop_response(i->scheduler, record); flx_record_unref(record); } } @@ -91,13 +87,13 @@ static void dispatch_packet(flxServer *s, flxDnsPacket *p, struct sockaddr *sa, g_message("new packet recieved."); - if (!(i = flx_interface_monitor_get_interface(s->monitor, iface))) { + if (!(i = flx_interface_monitor_get_interface(s->monitor, iface, sa->sa_family))) { g_warning("Recieved packet from invalid interface."); return; } if (ttl != 255) { - g_warning("Recieved packet with invalid TTL on interface '%s'.", i->name); + g_warning("Recieved packet with invalid TTL on interface '%s.%i'.", i->hardware->name, i->protocol); return; } @@ -155,13 +151,17 @@ static gboolean work(flxServer *s) { g_assert(s); if (s->pollfd_ipv4.revents & G_IO_IN) { - if ((p = flx_recv_dns_packet_ipv4(s->fd_ipv4, &sa, &iface, &ttl))) + if ((p = flx_recv_dns_packet_ipv4(s->fd_ipv4, &sa, &iface, &ttl))) { dispatch_packet(s, p, (struct sockaddr*) &sa, iface, ttl); + flx_dns_packet_free(p); + } } if (s->pollfd_ipv6.revents & G_IO_IN) { - if ((p = flx_recv_dns_packet_ipv6(s->fd_ipv6, &sa6, &iface, &ttl))) + if ((p = flx_recv_dns_packet_ipv6(s->fd_ipv6, &sa6, &iface, &ttl))) { dispatch_packet(s, p, (struct sockaddr*) &sa6, iface, ttl); + flx_dns_packet_free(p); + } } return TRUE; @@ -205,10 +205,13 @@ static void add_default_entries(flxServer *s) { /* Fill in HINFO rr */ uname(&utsname); - hinfo = g_strdup_printf("%s%c%s%n", g_strup(utsname.machine), 0, g_strup(utsname.sysname), &length); + hinfo = g_strdup_printf("%c%s%c%s%n", + strlen(utsname.machine), g_strup(utsname.machine), + strlen(utsname.sysname), g_strup(utsname.sysname), + &length); flx_server_add_full(s, 0, 0, AF_UNSPEC, TRUE, - s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO, hinfo, length+1, FLX_DEFAULT_TTL); + s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO, hinfo, length, FLX_DEFAULT_TTL); g_free(hinfo); @@ -256,9 +259,9 @@ flxServer *flx_server_new(GMainContext *c) { s->current_id = 1; s->rrset_by_id = g_hash_table_new(g_int_hash, g_int_equal); - s->rrset_by_name = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal); + s->rrset_by_key = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal); - FLX_LLIST_HEAD_INIT(flxEntry, s->entries); + FLX_LLIST_HEAD_INIT(flxServerEntry, s->entries); s->monitor = flx_interface_monitor_new(s); s->time_event_queue = flx_time_event_queue_new(s->context); @@ -299,7 +302,7 @@ void flx_server_free(flxServer* s) { flx_server_remove(s, 0); g_hash_table_destroy(s->rrset_by_id); - g_hash_table_destroy(s->rrset_by_name); + g_hash_table_destroy(s->rrset_by_key); flx_time_event_queue_free(s->time_event_queue); @@ -331,28 +334,32 @@ void flx_server_add( gboolean unique, flxRecord *r) { - flxEntry *e, *t; + flxServerEntry *e, *t; g_assert(s); g_assert(r); - e = g_new(flxEntry, 1); + e = g_new(flxServerEntry, 1); e->record = flx_record_ref(r); e->id = id; e->interface = interface; e->protocol = protocol; e->unique = unique; - FLX_LLIST_PREPEND(flxEntry, entry, s->entries, e); + FLX_LLIST_HEAD_INIT(flxAnnouncement, e->announcements); + + FLX_LLIST_PREPEND(flxServerEntry, entry, s->entries, e); /* Insert into hash table indexed by id */ t = g_hash_table_lookup(s->rrset_by_id, &e->id); - FLX_LLIST_PREPEND(flxEntry, by_id, t, e); + FLX_LLIST_PREPEND(flxServerEntry, by_id, t, e); g_hash_table_replace(s->rrset_by_id, &e->id, t); /* Insert into hash table indexed by name */ - t = g_hash_table_lookup(s->rrset_by_name, e->record->key); - FLX_LLIST_PREPEND(flxEntry, by_name, t, e); - g_hash_table_replace(s->rrset_by_name, e->record->key, t); + t = g_hash_table_lookup(s->rrset_by_key, e->record->key); + FLX_LLIST_PREPEND(flxServerEntry, by_key, t, e); + g_hash_table_replace(s->rrset_by_key, e->record->key, t); + + flx_announce_entry(s, e); } void flx_server_add_full( @@ -379,7 +386,7 @@ void flx_server_add_full( } const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) { - flxEntry **e = (flxEntry**) state; + flxServerEntry **e = (flxServerEntry**) state; g_assert(s); g_assert(e); @@ -394,29 +401,31 @@ const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) { return flx_record_ref((*e)->record); } -static void free_entry(flxServer*s, flxEntry *e) { - flxEntry *t; +static void free_entry(flxServer*s, flxServerEntry *e) { + flxServerEntry *t; g_assert(e); + flx_goodbye_entry(s, e, TRUE); + /* Remove from linked list */ - FLX_LLIST_REMOVE(flxEntry, entry, s->entries, e); + FLX_LLIST_REMOVE(flxServerEntry, entry, s->entries, e); /* Remove from hash table indexed by id */ t = g_hash_table_lookup(s->rrset_by_id, &e->id); - FLX_LLIST_REMOVE(flxEntry, by_id, t, e); + FLX_LLIST_REMOVE(flxServerEntry, by_id, t, e); if (t) g_hash_table_replace(s->rrset_by_id, &t->id, t); else g_hash_table_remove(s->rrset_by_id, &e->id); /* Remove from hash table indexed by name */ - t = g_hash_table_lookup(s->rrset_by_name, e->record->key); - FLX_LLIST_REMOVE(flxEntry, by_name, t, e); + t = g_hash_table_lookup(s->rrset_by_key, e->record->key); + FLX_LLIST_REMOVE(flxServerEntry, by_key, t, e); if (t) - g_hash_table_replace(s->rrset_by_name, t->record->key, t); + g_hash_table_replace(s->rrset_by_key, t->record->key, t); else - g_hash_table_remove(s->rrset_by_name, e->record->key); + g_hash_table_remove(s->rrset_by_key, e->record->key); flx_record_unref(e->record); g_free(e); @@ -429,7 +438,7 @@ void flx_server_remove(flxServer *s, gint id) { while (s->entries) free_entry(s, s->entries); } else { - flxEntry *e; + flxServerEntry *e; while ((e = g_hash_table_lookup(s->rrset_by_id, &id))) free_entry(s, e); @@ -437,11 +446,11 @@ void flx_server_remove(flxServer *s, gint id) { } void flx_server_dump(flxServer *s, FILE *f) { - flxEntry *e; + flxServerEntry *e; g_assert(s); g_assert(f); - fprintf(f, ";;; ZONE DUMP FOLLOWS ;;;\n"); + fprintf(f, "\n;;; ZONE DUMP FOLLOWS ;;;\n"); for (e = s->entries; e; e = e->entry_next) { gchar *t; @@ -451,7 +460,7 @@ void flx_server_dump(flxServer *s, FILE *f) { g_free(t); } - flx_dump_caches(s, f); + flx_dump_caches(s->monitor, f); } void flx_server_add_address( @@ -507,28 +516,76 @@ void flx_server_add_text( const gchar *name, const gchar *text) { + gchar buf[256]; + guint l; + g_assert(s); g_assert(text); - flx_server_add_full(s, id, interface, protocol, unique, name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT, text, strlen(text), FLX_DEFAULT_TTL); + if ((l = strlen(text)) > 255) + buf[0] = 255; + else + buf[0] = (gchar) l; + + memcpy(buf+1, text, l); + + flx_server_add_full(s, id, interface, protocol, unique, name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT, buf, l+1, FLX_DEFAULT_TTL); } -void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey *k) { +void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey *key) { g_assert(s); - g_assert(k); - - if (interface <= 0) { + g_assert(key); + + if (interface > 0) { + if (protocol != AF_UNSPEC) { + flxInterface *i; + + if ((i = flx_interface_monitor_get_interface(s->monitor, interface, protocol))) + flx_interface_post_query(i, key); + } else { + flxHwInterface *hw; + flxInterface *i; + + if ((hw = flx_interface_monitor_get_hw_interface(s->monitor, interface))) + for (i = hw->interfaces; i; i = i->by_hardware_next) + if (flx_interface_match(i, interface, protocol)) + flx_interface_post_query(i, key); + } + + } else { flxInterface *i; + + for (i = s->monitor->interfaces; i; i = i->interface_next) + if (flx_interface_match(i, interface, protocol)) + flx_interface_post_query(i, key); + } +} - for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next) - flx_interface_post_query(i, protocol, k); +void flx_server_post_response(flxServer *s, gint interface, guchar protocol, flxRecord *record) { + g_assert(s); + g_assert(record); + + if (interface > 0) { + if (protocol != AF_UNSPEC) { + flxInterface *i; + + if ((i = flx_interface_monitor_get_interface(s->monitor, interface, protocol))) + flx_interface_post_response(i, record); + } else { + flxHwInterface *hw; + flxInterface *i; + + if ((hw = flx_interface_monitor_get_hw_interface(s->monitor, interface))) + for (i = hw->interfaces; i; i = i->by_hardware_next) + if (flx_interface_match(i, interface, protocol)) + flx_interface_post_response(i, record); + } } else { flxInterface *i; - - if (!(i = flx_interface_monitor_get_interface(s->monitor, interface))) - return; - - flx_interface_post_query(i, protocol, k); + + for (i = s->monitor->interfaces; i; i = i->interface_next) + if (flx_interface_match(i, interface, protocol)) + flx_interface_post_response(i, record); } } diff --git a/server.h b/server.h index fbd5715..b7addf6 100644 --- a/server.h +++ b/server.h @@ -1,15 +1,16 @@ #ifndef fooflxserverhfoo #define fooflxserverhfoo -typedef struct _flxEntry flxEntry; +typedef struct _flxServerEntry flxServerEntry; #include "flx.h" #include "iface.h" #include "prioq.h" #include "llist.h" #include "timeeventq.h" +#include "announce.h" -struct _flxEntry { +struct _flxServerEntry { flxRecord *record; gint id; gint interface; @@ -17,9 +18,11 @@ struct _flxEntry { gboolean unique; - FLX_LLIST_FIELDS(flxEntry, entry); - FLX_LLIST_FIELDS(flxEntry, by_name); - FLX_LLIST_FIELDS(flxEntry, by_id); + FLX_LLIST_FIELDS(flxServerEntry, entry); + FLX_LLIST_FIELDS(flxServerEntry, by_key); + FLX_LLIST_FIELDS(flxServerEntry, by_id); + + FLX_LLIST_HEAD(flxAnnouncement, announcements); }; struct _flxServer { @@ -29,9 +32,9 @@ struct _flxServer { gint current_id; GHashTable *rrset_by_id; - GHashTable *rrset_by_name; + GHashTable *rrset_by_key; - FLX_LLIST_HEAD(flxEntry, entries); + FLX_LLIST_HEAD(flxServerEntry, entries); flxTimeEventQueue *time_event_queue; @@ -44,5 +47,6 @@ struct _flxServer { }; +gboolean flx_server_entry_match_interface(flxServerEntry *e, flxInterface *i); #endif