]> git.meshlink.io Git - catta/commitdiff
move the sources to libavahi-core/
authorLennart Poettering <lennart@poettering.net>
Fri, 6 May 2005 15:31:30 +0000 (15:31 +0000)
committerLennart Poettering <lennart@poettering.net>
Fri, 6 May 2005 15:31:30 +0000 (15:31 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@50 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

76 files changed:
Makefile [deleted file]
address.c [deleted file]
address.h [deleted file]
announce.c [deleted file]
announce.h [deleted file]
avahi.h [deleted file]
cache.c [deleted file]
cache.h [deleted file]
dns-test.c [deleted file]
dns.c [deleted file]
dns.h [deleted file]
domain-test.c [deleted file]
iface.c [deleted file]
iface.h [deleted file]
libavahi-core/Makefile [new file with mode: 0644]
libavahi-core/address.c [new file with mode: 0644]
libavahi-core/address.h [new file with mode: 0644]
libavahi-core/announce.c [new file with mode: 0644]
libavahi-core/announce.h [new file with mode: 0644]
libavahi-core/avahi.h [new file with mode: 0644]
libavahi-core/cache.c [new file with mode: 0644]
libavahi-core/cache.h [new file with mode: 0644]
libavahi-core/dns-test.c [new file with mode: 0644]
libavahi-core/dns.c [new file with mode: 0644]
libavahi-core/dns.h [new file with mode: 0644]
libavahi-core/domain-test.c [new file with mode: 0644]
libavahi-core/iface.c [new file with mode: 0644]
libavahi-core/iface.h [new file with mode: 0644]
libavahi-core/llist.h [new file with mode: 0644]
libavahi-core/main.c [new file with mode: 0644]
libavahi-core/netlink.c [new file with mode: 0644]
libavahi-core/netlink.h [new file with mode: 0644]
libavahi-core/prioq-test.c [new file with mode: 0644]
libavahi-core/prioq.c [new file with mode: 0644]
libavahi-core/prioq.h [new file with mode: 0644]
libavahi-core/psched.c [new file with mode: 0644]
libavahi-core/psched.h [new file with mode: 0644]
libavahi-core/rr.c [new file with mode: 0644]
libavahi-core/rr.h [new file with mode: 0644]
libavahi-core/server.c [new file with mode: 0644]
libavahi-core/server.h [new file with mode: 0644]
libavahi-core/socket.c [new file with mode: 0644]
libavahi-core/socket.h [new file with mode: 0644]
libavahi-core/strlst-test.c [new file with mode: 0644]
libavahi-core/strlst.c [new file with mode: 0644]
libavahi-core/strlst.h [new file with mode: 0644]
libavahi-core/subscribe.c [new file with mode: 0644]
libavahi-core/subscribe.h [new file with mode: 0644]
libavahi-core/timeeventq.c [new file with mode: 0644]
libavahi-core/timeeventq.h [new file with mode: 0644]
libavahi-core/util.c [new file with mode: 0644]
libavahi-core/util.h [new file with mode: 0644]
llist.h [deleted file]
main.c [deleted file]
netlink.c [deleted file]
netlink.h [deleted file]
prioq-test.c [deleted file]
prioq.c [deleted file]
prioq.h [deleted file]
psched.c [deleted file]
psched.h [deleted file]
rr.c [deleted file]
rr.h [deleted file]
server.c [deleted file]
server.h [deleted file]
socket.c [deleted file]
socket.h [deleted file]
strlst-test.c [deleted file]
strlst.c [deleted file]
strlst.h [deleted file]
subscribe.c [deleted file]
subscribe.h [deleted file]
timeeventq.c [deleted file]
timeeventq.h [deleted file]
util.c [deleted file]
util.h [deleted file]

diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index ff3977e..0000000
--- a/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-#CC=gcc-2.95
-CFLAGS=-g -O1 -Wall -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused
-LIBS=$(shell pkg-config --libs glib-2.0)
-
-all: strlst-test prioq-test domain-test dns-test flexmdns
-
-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 subscribe.o strlst.o
-       $(CC) -o $@ $^ $(LIBS)
-
-#test-llist: test-llist.o
-#      $(CC) -o $@ $^ $(LIBS)
-
-prioq-test: prioq-test.o prioq.o
-       $(CC) -o $@ $^ $(LIBS)
-
-strlst-test: strlst-test.o strlst.o
-       $(CC) -o $@ $^ $(LIBS)
-
-domain-test: domain-test.o util.o
-       $(CC) -o $@ $^ $(LIBS)
-
-dns-test: dns-test.o util.o dns.o rr.o strlst.o
-       $(CC) -o $@ $^ $(LIBS)
-
-*.o: *.h
-
-clean:
-       rm -f *.o flexmdns prioq-test strlst-test domain-test dns-test
diff --git a/address.c b/address.c
deleted file mode 100644 (file)
index e5f8866..0000000
--- a/address.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <string.h>
-
-#include "address.h"
-
-guint avahi_address_get_size(const AvahiAddress *a) {
-    g_assert(a);
-
-    if (a->family == AF_INET)
-        return 4;
-    else if (a->family == AF_INET6)
-        return 16;
-
-    return 0;
-}
-
-gint avahi_address_cmp(const AvahiAddress *a, const AvahiAddress *b) {
-    g_assert(a);
-    g_assert(b);
-    
-    if (a->family != b->family)
-        return -1;
-
-    return memcmp(a->data.data, b->data.data, avahi_address_get_size(a));
-}
-
-gchar *avahi_address_snprint(char *s, guint length, const AvahiAddress *a) {
-    g_assert(s);
-    g_assert(length);
-    g_assert(a);
-    return (gchar*) inet_ntop(a->family, a->data.data, s, length);
-}
-
-gchar* avahi_reverse_lookup_name_ipv4(const AvahiIPv4Address *a) {
-    guint32 n = ntohl(a->address);
-    g_assert(a);
-
-    return g_strdup_printf("%u.%u.%u.%u.in-addr.arpa", n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF, n >> 24);
-}
-
-static gchar *reverse_lookup_name_ipv6(const AvahiIPv6Address *a, const gchar *suffix) {
-    
-    return g_strdup_printf("%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%s",
-                           a->address[15] & 0xF,
-                           a->address[15] >> 4,
-                           a->address[14] & 0xF,
-                           a->address[14] >> 4,
-                           a->address[13] & 0xF,
-                           a->address[13] >> 4,
-                           a->address[12] & 0xF,
-                           a->address[12] >> 4,
-                           a->address[11] & 0xF,
-                           a->address[11] >> 4,
-                           a->address[10] & 0xF,
-                           a->address[10] >> 4,
-                           a->address[9] & 0xF,
-                           a->address[9] >> 4,
-                           a->address[8] & 0xF,
-                           a->address[8] >> 4,
-                           a->address[7] & 0xF,
-                           a->address[7] >> 4,
-                           a->address[6] & 0xF,
-                           a->address[6] >> 4,
-                           a->address[5] & 0xF,
-                           a->address[5] >> 4,
-                           a->address[4] & 0xF,
-                           a->address[4] >> 4,
-                           a->address[3] & 0xF,
-                           a->address[3] >> 4,
-                           a->address[2] & 0xF,
-                           a->address[2] >> 4,
-                           a->address[1] & 0xF,
-                           a->address[1] >> 4,
-                           a->address[0] & 0xF,
-                           a->address[0] >> 4,
-                           suffix);
-}
-
-gchar *avahi_reverse_lookup_name_ipv6_arpa(const AvahiIPv6Address *a) {
-    return reverse_lookup_name_ipv6(a, "ip6.arpa");
-}
-
-gchar *avahi_reverse_lookup_name_ipv6_int(const AvahiIPv6Address *a) {
-    return reverse_lookup_name_ipv6(a, "ip6.int");
-}
-
-AvahiAddress *avahi_address_parse(const char *s, guchar family, AvahiAddress *ret_addr) {
-    g_assert(ret_addr);
-    g_assert(s);
-
-    if (inet_pton(family, s, ret_addr->data.data) < 0)
-        return NULL;
-
-    ret_addr->family = family;
-    
-    return ret_addr;
-}
-
-AvahiAddress *avahi_address_from_sockaddr(const struct sockaddr* sa, AvahiAddress *ret_addr) {
-    g_assert(sa);
-    g_assert(ret_addr);
-
-    g_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
-
-    ret_addr->family = sa->sa_family;
-
-    if (sa->sa_family == AF_INET)
-        memcpy(&ret_addr->data.ipv4, &((struct sockaddr_in*) sa)->sin_addr, sizeof(ret_addr->data.ipv4));
-    else
-        memcpy(&ret_addr->data.ipv6, &((struct sockaddr_in6*) sa)->sin6_addr, sizeof(ret_addr->data.ipv6));
-
-    return ret_addr;
-}
-
-guint16 avahi_port_from_sockaddr(const struct sockaddr* sa) {
-    g_assert(sa);
-
-    g_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
-
-    if (sa->sa_family == AF_INET)
-        return ntohs(((struct sockaddr_in*) sa)->sin_port);
-    else
-        return ntohs(((struct sockaddr_in6*) sa)->sin6_port);
-}
diff --git a/address.h b/address.h
deleted file mode 100644 (file)
index 2eea75d..0000000
--- a/address.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef fooaddresshfoo
-#define fooaddresshfoo
-
-#include <glib.h>
-
-#include <sys/socket.h>
-
-typedef struct {
-    guint32 address;
-} AvahiIPv4Address;
-
-typedef struct {
-    guint8 address[16];
-} AvahiIPv6Address;
-
-typedef struct {
-    guchar family;
-
-    union {
-        AvahiIPv6Address ipv6;
-        AvahiIPv4Address ipv4;
-        guint8 data[0];
-    } data;
-} AvahiAddress;
-
-guint avahi_address_get_size(const AvahiAddress *a);
-gint avahi_address_cmp(const AvahiAddress *a, const AvahiAddress *b);
-
-gchar *avahi_address_snprint(char *ret_s, guint length, const AvahiAddress *a);
-
-AvahiAddress *avahi_address_parse(const char *s, guchar family, AvahiAddress *ret_addr);
-
-AvahiAddress *avahi_address_from_sockaddr(const struct sockaddr* sa, AvahiAddress *ret_addr);
-guint16 avahi_port_from_sockaddr(const struct sockaddr* sa);
-
-gchar* avahi_reverse_lookup_name_ipv4(const AvahiIPv4Address *a);
-gchar* avahi_reverse_lookup_name_ipv6_arpa(const AvahiIPv6Address *a);
-gchar* avahi_reverse_lookup_name_ipv6_int(const AvahiIPv6Address *a);
-
-#endif
diff --git a/announce.c b/announce.c
deleted file mode 100644 (file)
index 538ba2e..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-#include "announce.h"
-#include "util.h"
-
-#define AVAHI_ANNOUNCEMENT_JITTER_MSEC 250
-#define AVAHI_PROBE_JITTER_MSEC 250
-#define AVAHI_PROBE_INTERVAL_MSEC 250
-
-static void remove_announcement(AvahiServer *s, AvahiAnnouncement *a) {
-    g_assert(s);
-    g_assert(a);
-
-    if (a->time_event)
-        avahi_time_event_queue_remove(s->time_event_queue, a->time_event);
-
-    AVAHI_LLIST_REMOVE(AvahiAnnouncement, by_interface, a->interface->announcements, a);
-    AVAHI_LLIST_REMOVE(AvahiAnnouncement, by_entry, a->entry->announcements, a);
-    
-    g_free(a);
-}
-
-static void elapse_announce(AvahiTimeEvent *e, void *userdata);
-
-static void set_timeout(AvahiAnnouncement *a, const GTimeVal *tv) {
-    g_assert(a);
-
-    if (!tv) {
-        if (a->time_event) {
-            avahi_time_event_queue_remove(a->server->time_event_queue, a->time_event);
-            a->time_event = NULL;
-        }
-    } else {
-
-        if (a->time_event) 
-            avahi_time_event_queue_update(a->server->time_event_queue, a->time_event, tv);
-        else
-            a->time_event = avahi_time_event_queue_add(a->server->time_event_queue, tv, elapse_announce, a);
-    }
-}
-
-static void next_state(AvahiAnnouncement *a);
-
-void avahi_entry_group_check_probed(AvahiEntryGroup *g, gboolean immediately) {
-    AvahiEntry *e;
-    g_assert(g);
-    g_assert(!g->dead);
-
-    /* Check whether all group members have been probed */
-    
-    if (g->state != AVAHI_ENTRY_GROUP_REGISTERING || g->n_probing > 0) 
-        return;
-
-    avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_ESTABLISHED);
-
-    if (g->dead)
-        return;
-    
-    for (e = g->entries; e; e = e->entries_next) {
-        AvahiAnnouncement *a;
-        
-        for (a = e->announcements; a; a = a->by_entry_next) {
-
-            if (a->state != AVAHI_WAITING)
-                continue;
-            
-            a->state = AVAHI_ANNOUNCING;
-
-            if (immediately) {
-                /* Shortcut */
-                
-                a->n_iteration = 1;
-                next_state(a);
-            } else {
-                GTimeVal tv;
-                a->n_iteration = 0;
-                avahi_elapse_time(&tv, 0, AVAHI_ANNOUNCEMENT_JITTER_MSEC);
-                set_timeout(a, &tv);
-            }
-        }
-    }
-}
-
-static void next_state(AvahiAnnouncement *a) {
-    g_assert(a);
-
-/*     g_message("%i -- %u", a->state, a->n_iteration);   */
-    
-    if (a->state == AVAHI_WAITING) {
-
-        g_assert(a->entry->group);
-
-        avahi_entry_group_check_probed(a->entry->group, TRUE);
-        
-    } else if (a->state == AVAHI_PROBING) {
-
-        if (a->n_iteration >= 4) {
-            /* Probing done */
-            
-            gchar *t;
-
-            g_message("Enough probes for record [%s]", t = avahi_record_to_string(a->entry->record));
-            g_free(t);
-
-            if (a->entry->group) {
-                g_assert(a->entry->group->n_probing);
-                a->entry->group->n_probing--;
-            }
-            
-            if (a->entry->group && a->entry->group->state == AVAHI_ENTRY_GROUP_REGISTERING)
-                a->state = AVAHI_WAITING;
-            else {
-                a->state = AVAHI_ANNOUNCING;
-                a->n_iteration = 1;
-            }
-
-            set_timeout(a, NULL);
-            next_state(a);
-        } else {
-            GTimeVal tv;
-
-            avahi_interface_post_probe(a->interface, a->entry->record, FALSE);
-            
-            avahi_elapse_time(&tv, AVAHI_PROBE_INTERVAL_MSEC, 0);
-            set_timeout(a, &tv);
-            
-            a->n_iteration++;
-        }
-
-    } else if (a->state == AVAHI_ANNOUNCING) {
-
-        avahi_interface_post_response(a->interface, NULL, a->entry->record, a->entry->flags & AVAHI_ENTRY_UNIQUE, FALSE);
-
-        if (++a->n_iteration >= 4) {
-            gchar *t;
-            /* Announcing done */
-
-            g_message("Enough announcements for record [%s]", t = avahi_record_to_string(a->entry->record));
-            g_free(t);
-
-            a->state = AVAHI_ESTABLISHED;
-
-            set_timeout(a, NULL);
-        } else {
-            GTimeVal tv;
-            avahi_elapse_time(&tv, a->sec_delay*1000, AVAHI_ANNOUNCEMENT_JITTER_MSEC);
-        
-            if (a->n_iteration < 10)
-                a->sec_delay *= 2;
-            
-            set_timeout(a, &tv);
-        }
-    }
-}
-
-static void elapse_announce(AvahiTimeEvent *e, void *userdata) {
-    g_assert(e);
-
-    next_state(userdata);
-}
-
-AvahiAnnouncement *avahi_get_announcement(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
-    AvahiAnnouncement *a;
-    
-    g_assert(s);
-    g_assert(e);
-    g_assert(i);
-
-    for (a = e->announcements; a; a = a->by_entry_next)
-        if (a->interface == i)
-            return a;
-
-    return NULL;
-}
-
-static void new_announcement(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) {
-    AvahiAnnouncement *a;
-    GTimeVal tv;
-    gchar *t; 
-
-    g_assert(s);
-    g_assert(i);
-    g_assert(e);
-    g_assert(!e->dead);
-
-/*     g_message("NEW ANNOUNCEMENT: %s.%i [%s]", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record)); */
-/*     g_free(t); */
-    
-    if (!avahi_interface_match(i, e->interface, e->protocol) || !i->announcing || !avahi_entry_commited(e))
-        return;
-
-    /* We don't want duplicate announcements */
-    if (avahi_get_announcement(s, e, i))
-        return;
-
-    a = g_new(AvahiAnnouncement, 1);
-    a->server = s;
-    a->interface = i;
-    a->entry = e;
-
-    if ((e->flags & AVAHI_ENTRY_UNIQUE) && !(e->flags & AVAHI_ENTRY_NOPROBE))
-        a->state = AVAHI_PROBING;
-    else if (!(e->flags & AVAHI_ENTRY_NOANNOUNCE)) {
-
-        if (!e->group || e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED)
-            a->state = AVAHI_ANNOUNCING;
-        else
-            a->state = AVAHI_WAITING;
-        
-    } else
-        a->state = AVAHI_ESTABLISHED;
-
-
-    g_message("New announcement on interface %s.%i for entry [%s] state=%i", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record), a->state);
-    g_free(t);
-
-    a->n_iteration = 1;
-    a->sec_delay = 1;
-    a->time_event = NULL;
-
-    if (a->state == AVAHI_PROBING)
-        if (e->group)
-            e->group->n_probing++;
-    
-    AVAHI_LLIST_PREPEND(AvahiAnnouncement, by_interface, i->announcements, a);
-    AVAHI_LLIST_PREPEND(AvahiAnnouncement, by_entry, e->announcements, a);
-
-    if (a->state == AVAHI_PROBING) {
-        avahi_elapse_time(&tv, 0, AVAHI_PROBE_JITTER_MSEC);
-        set_timeout(a, &tv);
-    } else if (a->state == AVAHI_ANNOUNCING) {
-        avahi_elapse_time(&tv, 0, AVAHI_ANNOUNCEMENT_JITTER_MSEC);
-        set_timeout(a, &tv);
-    }
-}
-
-void avahi_announce_interface(AvahiServer *s, AvahiInterface *i) {
-    AvahiEntry *e;
-    
-    g_assert(s);
-    g_assert(i);
-
-    if (!i->announcing)
-        return;
-
-    for (e = s->entries; e; e = e->entries_next)
-        if (!e->dead)
-            new_announcement(s, i, e);
-}
-
-static void announce_walk_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
-    AvahiEntry *e = userdata;
-    
-    g_assert(m);
-    g_assert(i);
-    g_assert(e);
-    g_assert(!e->dead);
-
-    new_announcement(m->server, i, e);
-}
-
-void avahi_announce_entry(AvahiServer *s, AvahiEntry *e) {
-    g_assert(s);
-    g_assert(e);
-    g_assert(!e->dead);
-
-    avahi_interface_monitor_walk(s->monitor, e->interface, e->protocol, announce_walk_callback, e);
-}
-
-void avahi_announce_group(AvahiServer *s, AvahiEntryGroup *g) {
-    AvahiEntry *e;
-    
-    g_assert(s);
-    g_assert(g);
-
-    for (e = g->entries; e; e = e->by_group_next)
-        if (!e->dead)
-            avahi_announce_entry(s, e);
-}
-
-gboolean avahi_entry_registered(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
-    AvahiAnnouncement *a;
-
-    g_assert(s);
-    g_assert(e);
-    g_assert(i);
-    g_assert(!e->dead);
-
-    if (!(a = avahi_get_announcement(s, e, i)))
-        return FALSE;
-    
-    return a->state == AVAHI_ANNOUNCING || a->state == AVAHI_ESTABLISHED;
-}
-
-gboolean avahi_entry_registering(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
-    AvahiAnnouncement *a;
-
-    g_assert(s);
-    g_assert(e);
-    g_assert(i);
-    g_assert(!e->dead);
-
-    if (!(a = avahi_get_announcement(s, e, i)))
-        return FALSE;
-    
-    return a->state == AVAHI_PROBING || a->state == AVAHI_WAITING;
-}
-
-static AvahiRecord *make_goodbye_record(AvahiRecord *r) {
-/*     gchar *t; */
-    AvahiRecord *g;
-    
-    g_assert(r);
-
-/*     g_message("Preparing goodbye for record [%s]", t = avahi_record_to_string(r)); */
-/*     g_free(t); */
-
-    g = avahi_record_copy(r);
-    g_assert(g->ref == 1);
-    g->ttl = 0;
-
-    return g;
-}
-
-static void send_goodbye_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
-    AvahiEntry *e = userdata;
-    AvahiRecord *g;
-    
-    g_assert(m);
-    g_assert(i);
-    g_assert(e);
-    g_assert(!e->dead);
-
-    if (!avahi_interface_match(i, e->interface, e->protocol))
-        return;
-
-    if (e->flags & AVAHI_ENTRY_NOANNOUNCE)
-        return;
-
-    if (!avahi_entry_registered(m->server, e, i))
-        return;
-    
-    g = make_goodbye_record(e->record);
-    avahi_interface_post_response(i, NULL, g, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
-    avahi_record_unref(g);
-}
-    
-void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, gboolean goodbye) {
-    g_assert(s);
-    g_assert(i);
-
-/*     g_message("goodbye interface: %s.%u", i->hardware->name, i->protocol); */
-
-    if (goodbye && avahi_interface_relevant(i)) {
-        AvahiEntry *e;
-        
-        for (e = s->entries; e; e = e->entries_next)
-            if (!e->dead)
-                send_goodbye_callback(s->monitor, i, e);
-    }
-
-    while (i->announcements)
-        remove_announcement(s, i->announcements);
-
-/*     g_message("goodbye interface done: %s.%u", i->hardware->name, i->protocol); */
-
-}
-
-void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, gboolean goodbye) {
-    g_assert(s);
-    g_assert(e);
-    
-/*     g_message("goodbye entry: %p", e); */
-    
-    if (goodbye && !e->dead)
-        avahi_interface_monitor_walk(s->monitor, 0, AF_UNSPEC, send_goodbye_callback, e);
-
-    while (e->announcements)
-        remove_announcement(s, e->announcements);
-
-/*     g_message("goodbye entry done: %p", e); */
-
-}
-
-void avahi_goodbye_all(AvahiServer *s, gboolean goodbye) {
-    AvahiEntry *e;
-    
-    g_assert(s);
-
-/*     g_message("goodbye all"); */
-
-    for (e = s->entries; e; e = e->entries_next)
-        if (!e->dead)
-            avahi_goodbye_entry(s, e, goodbye);
-
-/*     g_message("goodbye all done"); */
-
-}
-
diff --git a/announce.h b/announce.h
deleted file mode 100644 (file)
index cd96977..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef fooannouncehfoo
-#define fooannouncehfoo
-
-#include <glib.h>
-
-typedef struct _AvahiAnnouncement AvahiAnnouncement;
-
-#include "llist.h"
-#include "iface.h"
-#include "server.h"
-#include "timeeventq.h"
-
-typedef enum {
-    AVAHI_PROBING,
-    AVAHI_WAITING,         /* wait for other records in group */
-    AVAHI_ANNOUNCING,
-    AVAHI_ESTABLISHED
-} AvahiAnnouncementState;
-
-struct _AvahiAnnouncement {
-    AvahiServer *server;
-    AvahiInterface *interface;
-    AvahiEntry *entry;
-
-    AvahiTimeEvent *time_event;
-
-    AvahiAnnouncementState state;
-    guint n_iteration;
-    guint sec_delay;
-
-    AVAHI_LLIST_FIELDS(AvahiAnnouncement, by_interface);
-    AVAHI_LLIST_FIELDS(AvahiAnnouncement, by_entry);
-};
-
-void avahi_announce_interface(AvahiServer *s, AvahiInterface *i);
-void avahi_announce_entry(AvahiServer *s, AvahiEntry *e);
-void avahi_announce_group(AvahiServer *s, AvahiEntryGroup *g);
-
-void avahi_entry_group_check_probed(AvahiEntryGroup *g, gboolean immediately);
-
-gboolean avahi_entry_registered(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
-gboolean avahi_entry_registering(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
-
-void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, gboolean send);
-void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, gboolean send);
-
-void avahi_goodbye_all(AvahiServer *s, gboolean send);
-
-AvahiAnnouncement *avahi_get_announcement(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
-
-#endif
diff --git a/avahi.h b/avahi.h
deleted file mode 100644 (file)
index 1c59faf..0000000
--- a/avahi.h
+++ /dev/null
@@ -1,143 +0,0 @@
-#ifndef fooAvahihfoo
-#define fooAvahihfoo
-
-#include <stdio.h>
-#include <glib.h>
-
-typedef struct _AvahiServer AvahiServer;
-typedef struct _AvahiEntry AvahiEntry;
-typedef struct _AvahiEntryGroup AvahiEntryGroup;
-
-#include "address.h"
-#include "rr.h"
-
-typedef enum {
-    AVAHI_ENTRY_NULL = 0,
-    AVAHI_ENTRY_UNIQUE = 1,
-    AVAHI_ENTRY_NOPROBE = 2,
-    AVAHI_ENTRY_NOANNOUNCE = 4
-} AvahiEntryFlags;
-
-typedef enum {
-    AVAHI_ENTRY_GROUP_UNCOMMITED,
-    AVAHI_ENTRY_GROUP_REGISTERING,
-    AVAHI_ENTRY_GROUP_ESTABLISHED,
-    AVAHI_ENTRY_GROUP_COLLISION
-} AvahiEntryGroupState;
-
-typedef void (*AvahiEntryGroupCallback) (AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata);
-
-AvahiServer *avahi_server_new(GMainContext *c);
-void avahi_server_free(AvahiServer* s);
-
-const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiEntryGroup *g, void **state);
-void avahi_server_dump(AvahiServer *s, FILE *f);
-
-AvahiEntryGroup *avahi_entry_group_new(AvahiServer *s, AvahiEntryGroupCallback callback, gpointer userdata);
-void avahi_entry_group_free(AvahiEntryGroup *g);
-void avahi_entry_group_commit(AvahiEntryGroup *g);
-AvahiEntryGroupState avahi_entry_group_get_state(AvahiEntryGroup *g);
-
-void avahi_server_add(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    AvahiRecord *r);
-
-void avahi_server_add_ptr(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    const gchar *dest);
-
-void avahi_server_add_address(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    AvahiAddress *a);
-
-void avahi_server_add_text(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    ... /* text records, terminated by NULL */);
-
-void avahi_server_add_text_va(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    va_list va);
-
-void avahi_server_add_text_strlst(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    AvahiStringList *strlst);
-
-void avahi_server_add_service(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    const gchar *type,
-    const gchar *name,
-    const gchar *domain,
-    const gchar *host,
-    guint16 port,
-    ...  /* text records, terminated by NULL */);
-
-void avahi_server_add_service_va(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    const gchar *type,
-    const gchar *name,
-    const gchar *domain,
-    const gchar *host,
-    guint16 port,
-    va_list va);
-
-void avahi_server_add_service_strlst(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    const gchar *type,
-    const gchar *name,
-    const gchar *domain,
-    const gchar *host,
-    guint16 port,
-    AvahiStringList *strlst);
-
-typedef enum {
-    AVAHI_SUBSCRIPTION_NEW,
-    AVAHI_SUBSCRIPTION_REMOVE,
-    AVAHI_SUBSCRIPTION_CHANGE
-} AvahiSubscriptionEvent;
-
-typedef struct _AvahiSubscription AvahiSubscription;
-
-typedef void (*AvahiSubscriptionCallback)(AvahiSubscription *s, AvahiRecord *record, gint interface, guchar protocol, AvahiSubscriptionEvent event, gpointer userdata);
-
-AvahiSubscription *avahi_subscription_new(AvahiServer *s, AvahiKey *key, gint interface, guchar protocol, AvahiSubscriptionCallback callback, gpointer userdata);
-void avahi_subscription_free(AvahiSubscription *s);
-
-#endif
diff --git a/cache.c b/cache.c
deleted file mode 100644 (file)
index c2d680e..0000000
--- a/cache.c
+++ /dev/null
@@ -1,346 +0,0 @@
-#include <string.h>
-
-#include "util.h"
-#include "cache.h"
-
-static void remove_entry(AvahiCache *c, AvahiCacheEntry *e) {
-    AvahiCacheEntry *t;
-
-    g_assert(c);
-    g_assert(e);
-
-/*     g_message("removing from cache: %p %p", c, e); */
-
-    /* Remove from hash table */
-    t = g_hash_table_lookup(c->hash_table, e->record->key);
-    AVAHI_LLIST_REMOVE(AvahiCacheEntry, by_key, t, e);
-    if (t)
-        g_hash_table_replace(c->hash_table, t->record->key, t);
-    else
-        g_hash_table_remove(c->hash_table, e->record->key);
-
-    /* Remove from linked list */
-    AVAHI_LLIST_REMOVE(AvahiCacheEntry, entry, c->entries, e);
-        
-    if (e->time_event)
-        avahi_time_event_queue_remove(c->server->time_event_queue, e->time_event);
-
-    avahi_subscription_notify(c->server, c->interface, e->record, AVAHI_SUBSCRIPTION_REMOVE);
-
-    avahi_record_unref(e->record);
-    
-    g_free(e);
-}
-
-AvahiCache *avahi_cache_new(AvahiServer *server, AvahiInterface *iface) {
-    AvahiCache *c;
-    g_assert(server);
-
-    c = g_new(AvahiCache, 1);
-    c->server = server;
-    c->interface = iface;
-    c->hash_table = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
-
-    AVAHI_LLIST_HEAD_INIT(AvahiCacheEntry, c->entries);
-    
-    return c;
-}
-
-void avahi_cache_free(AvahiCache *c) {
-    g_assert(c);
-
-    while (c->entries)
-        remove_entry(c, c->entries);
-    
-    g_hash_table_destroy(c->hash_table);
-    
-    g_free(c);
-}
-
-AvahiCacheEntry *avahi_cache_lookup_key(AvahiCache *c, AvahiKey *k) {
-    g_assert(c);
-    g_assert(k);
-
-    g_assert(!avahi_key_is_pattern(k));
-    
-    return g_hash_table_lookup(c->hash_table, k);
-}
-
-gpointer avahi_cache_walk(AvahiCache *c, AvahiKey *pattern, AvahiCacheWalkCallback cb, gpointer userdata) {
-    gpointer ret;
-    
-    g_assert(c);
-    g_assert(pattern);
-    g_assert(cb);
-    
-    if (avahi_key_is_pattern(pattern)) {
-        AvahiCacheEntry *e, *n;
-        
-        for (e = c->entries; e; e = n) {
-            n = e->entry_next;
-            
-            if (avahi_key_pattern_match(pattern, e->record->key))
-                if ((ret = cb(c, pattern, e, userdata)))
-                    return ret;
-        }
-        
-    } else {
-        AvahiCacheEntry *e, *n;
-
-        for (e = avahi_cache_lookup_key(c, pattern); e; e = n) {
-            n = e->by_key_next;
-                
-            if ((ret = cb(c, pattern, e, userdata)))
-                return ret;
-        }
-    }
-
-    return NULL;
-}
-
-static gpointer lookup_record_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, void *userdata) {
-    g_assert(c);
-    g_assert(pattern);
-    g_assert(e);
-
-    if (avahi_record_equal_no_ttl(e->record, userdata))
-        return e;
-
-    return NULL;
-}
-
-AvahiCacheEntry *avahi_cache_lookup_record(AvahiCache *c, AvahiRecord *r) {
-    AvahiCacheEntry *e;
-    
-    g_assert(c);
-    g_assert(r);
-
-    return avahi_cache_walk(c, r->key, lookup_record_callback, r);
-}
-
-static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, guint percent);
-
-static void elapse_func(AvahiTimeEvent *t, void *userdata) {
-    AvahiCacheEntry *e = userdata;
-    
-    g_assert(t);
-    g_assert(e);
-
-    if (e->state == AVAHI_CACHE_FINAL) {
-        remove_entry(e->cache, e);
-        g_message("Removing entry from cache due to expiration");
-    } else {
-        guint percent = 0;
-    
-        switch (e->state) {
-            case AVAHI_CACHE_VALID:
-                e->state = AVAHI_CACHE_EXPIRY1;
-                percent = 85;
-                break;
-                
-            case AVAHI_CACHE_EXPIRY1:
-                e->state = AVAHI_CACHE_EXPIRY2;
-                percent = 90;
-                break;
-            case AVAHI_CACHE_EXPIRY2:
-                e->state = AVAHI_CACHE_EXPIRY3;
-                percent = 95;
-                break;
-                
-            case AVAHI_CACHE_EXPIRY3:
-                e->state = AVAHI_CACHE_FINAL;
-                percent = 100;
-                break;
-
-            default:
-                ;
-        }
-
-        g_assert(percent > 0);
-
-        g_message("Requesting cache entry update at %i%%.", percent);
-
-        /* Request a cache update, if we are subscribed to this entry */
-        if (avahi_is_subscribed(e->cache->server, e->record->key))
-            avahi_interface_post_query(e->cache->interface, e->record->key, TRUE);
-
-        /* Check again later */
-        next_expiry(e->cache, e, percent);
-    }
-}
-
-static void update_time_event(AvahiCache *c, AvahiCacheEntry *e) {
-    g_assert(c);
-    g_assert(e);
-    
-    if (e->time_event)
-        avahi_time_event_queue_update(c->server->time_event_queue, e->time_event, &e->expiry);
-    else
-        e->time_event = avahi_time_event_queue_add(c->server->time_event_queue, &e->expiry, elapse_func, e);
-}
-
-static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, guint percent) {
-    gulong usec;
-
-    g_assert(c);
-    g_assert(e);
-    g_assert(percent > 0 && percent <= 100);
-
-    e->expiry = e->timestamp;
-
-    usec = e->record->ttl * 10000;
-
-    /* 2% jitter */
-    usec = g_random_int_range(usec*percent, usec*(percent+2));
-    
-    g_time_val_add(&e->expiry, usec);
-    update_time_event(c, e);
-}
-
-void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const AvahiAddress *a) {
-    AvahiCacheEntry *e, *t;
-    gchar *txt;
-    
-    g_assert(c);
-    g_assert(r && r->ref >= 1);
-
-    g_message("cache update: %s", (txt = avahi_record_to_string(r)));
-    g_free(txt);
-
-    if (r->ttl == 0) {
-
-        /* This is a goodbye request */
-
-        if ((e = avahi_cache_lookup_record(c, r))) {
-
-            e->state = AVAHI_CACHE_FINAL;
-            g_get_current_time(&e->timestamp);
-            e->expiry = e->timestamp;
-            g_time_val_add(&e->expiry, 1000000); /* 1s */
-            update_time_event(c, e);
-        }
-
-    } else {
-
-        /* This is an update request */
-
-        if ((t = e = avahi_cache_lookup_key(c, r->key))) {
-        
-            if (unique) {
-                
-                /* For unique records, remove all entries but one */
-                while (e->by_key_next)
-                    remove_entry(c, e->by_key_next);
-                
-            } else {
-                
-                /* For non-unique record, look for exactly the same entry */
-                for (; e; e = e->by_key_next)
-                    if (avahi_record_equal_no_ttl(e->record, r))
-                        break;
-            }
-        }
-    
-        if (e) {
-            
-/*         g_message("found matching cache entry"); */
-            
-            /* We are the first in the linked list so let's replace the hash table key with the new one */
-            if (e->by_key_prev == NULL)
-                g_hash_table_replace(c->hash_table, r->key, e);
-            
-            /* Notify subscribers */
-            if (!avahi_record_equal_no_ttl(e->record, r))
-                avahi_subscription_notify(c->server, c->interface, r, AVAHI_SUBSCRIPTION_CHANGE);    
-            
-            /* Update the record */
-            avahi_record_unref(e->record);
-            e->record = avahi_record_ref(r);
-            
-        } else {
-            /* No entry found, therefore we create a new one */
-            
-/*         g_message("couldn't find matching cache entry"); */
-            
-            e = g_new(AvahiCacheEntry, 1);
-            e->cache = c;
-            e->time_event = NULL;
-            e->record = avahi_record_ref(r);
-
-            /* Append to hash table */
-            AVAHI_LLIST_PREPEND(AvahiCacheEntry, by_key, t, e);
-            g_hash_table_replace(c->hash_table, e->record->key, t);
-
-            /* Append to linked list */
-            AVAHI_LLIST_PREPEND(AvahiCacheEntry, entry, c->entries, e);
-
-            /* Notify subscribers */
-            avahi_subscription_notify(c->server, c->interface, e->record, AVAHI_SUBSCRIPTION_NEW);
-        } 
-        
-        e->origin = *a;
-        g_get_current_time(&e->timestamp);
-        next_expiry(c, e, 80);
-        e->state = AVAHI_CACHE_VALID;
-    }
-}
-
-static gpointer drop_key_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) {
-    g_assert(c);
-    g_assert(pattern);
-    g_assert(e);
-
-    remove_entry(c, e);
-    return NULL;
-}
-
-void avahi_cache_drop_key(AvahiCache *c, AvahiKey *k) {
-    g_assert(c);
-    g_assert(k);
-
-    avahi_cache_walk(c, k, drop_key_callback, NULL);
-}
-
-void avahi_cache_drop_record(AvahiCache *c, AvahiRecord *r) {
-    AvahiCacheEntry *e;
-    
-    g_assert(c);
-    g_assert(r);
-
-    if ((e = avahi_cache_lookup_record(c, r))) 
-        remove_entry(c, e);
-}
-
-static void func(gpointer key, gpointer data, gpointer userdata) {
-    AvahiCacheEntry *e = data;
-    AvahiKey *k = key;
-    gchar *t;
-
-    t = avahi_record_to_string(e->record);
-    fprintf((FILE*) userdata, "%s\n", t);
-    g_free(t);
-}
-
-void avahi_cache_dump(AvahiCache *c, FILE *f) {
-    g_assert(c);
-    g_assert(f);
-
-    fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
-    g_hash_table_foreach(c->hash_table, func, f);
-}
-
-gboolean avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e) {
-    GTimeVal now;
-    guint age;
-    
-    g_assert(c);
-    g_assert(e);
-
-    g_get_current_time(&now);
-
-    age = avahi_timeval_diff(&now, &e->timestamp)/1000000;
-
-    g_message("age: %u, ttl/2: %u", age, e->record->ttl);
-    
-    return age >= e->record->ttl/2;
-}
diff --git a/cache.h b/cache.h
deleted file mode 100644 (file)
index de0ec9f..0000000
--- a/cache.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef foocachehfoo
-#define foocachehfoo
-
-#include <glib.h>
-
-struct _AvahiCache;
-typedef struct _AvahiCache AvahiCache;
-
-#include "prioq.h"
-#include "server.h"
-#include "llist.h"
-#include "timeeventq.h"
-
-typedef enum {
-    AVAHI_CACHE_VALID,
-    AVAHI_CACHE_EXPIRY1,
-    AVAHI_CACHE_EXPIRY2,
-    AVAHI_CACHE_EXPIRY3,
-    AVAHI_CACHE_FINAL
-} AvahiCacheEntryState;
-
-typedef struct AvahiCacheEntry AvahiCacheEntry;
-
-struct AvahiCacheEntry {
-    AvahiCache *cache;
-    AvahiRecord *record;
-    GTimeVal timestamp;
-    GTimeVal expiry;
-    
-    AvahiAddress origin;
-
-    AvahiCacheEntryState state;
-    AvahiTimeEvent *time_event;
-
-    AVAHI_LLIST_FIELDS(AvahiCacheEntry, by_key);
-    AVAHI_LLIST_FIELDS(AvahiCacheEntry, entry);
-};
-
-struct _AvahiCache {
-    AvahiServer *server;
-    
-    AvahiInterface *interface;
-    
-    GHashTable *hash_table;
-
-    AVAHI_LLIST_HEAD(AvahiCacheEntry, entries);
-};
-
-AvahiCache *avahi_cache_new(AvahiServer *server, AvahiInterface *interface);
-void avahi_cache_free(AvahiCache *c);
-
-AvahiCacheEntry *avahi_cache_lookup_key(AvahiCache *c, AvahiKey *k);
-AvahiCacheEntry *avahi_cache_lookup_record(AvahiCache *c, AvahiRecord *r);
-
-void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const AvahiAddress *a);
-
-void avahi_cache_drop_record(AvahiCache *c,  AvahiRecord *r);
-
-void avahi_cache_dump(AvahiCache *c, FILE *f);
-
-typedef gpointer AvahiCacheWalkCallback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata);
-gpointer avahi_cache_walk(AvahiCache *c, AvahiKey *pattern, AvahiCacheWalkCallback cb, gpointer userdata);
-
-gboolean avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e);
-
-#endif
diff --git a/dns-test.c b/dns-test.c
deleted file mode 100644 (file)
index d8c7b53..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "dns.h"
-#include "util.h"
-
-int main(int argc, char *argv[]) {
-    gchar t[256], *a, *b, *c, *d;
-    AvahiDnsPacket *p;
-
-    p = avahi_dns_packet_new(8000);
-
-    avahi_dns_packet_append_name(p, a = "hello.hello.hello.de.");
-    avahi_dns_packet_append_name(p, b = "this is a test.hello.de."); 
-    avahi_dns_packet_append_name(p, c = "this\\.is\\.a\\.test\\.with\\.dots.hello.de."); 
-    avahi_dns_packet_append_name(p, d = "this\\\\is another\\ \\test.hello.de."); 
-
-    avahi_hexdump(AVAHI_DNS_PACKET_DATA(p), p->size);
-
-    avahi_dns_packet_consume_name(p, t, sizeof(t));
-    g_message(">%s<", t);
-    g_assert(avahi_domain_equal(a, t));
-    
-    avahi_dns_packet_consume_name(p, t, sizeof(t));
-    g_message(">%s<", t);
-    g_assert(avahi_domain_equal(b, t));
-
-    avahi_dns_packet_consume_name(p, t, sizeof(t));
-    g_message(">%s<", t);
-    g_assert(avahi_domain_equal(c, t));
-
-    avahi_dns_packet_consume_name(p, t, sizeof(t));
-    g_message(">%s<", t);
-    g_assert(avahi_domain_equal(d, t));
-    
-    avahi_dns_packet_free(p);
-    return 0;
-}
diff --git a/dns.c b/dns.c
deleted file mode 100644 (file)
index e485ed8..0000000
--- a/dns.c
+++ /dev/null
@@ -1,749 +0,0 @@
-#include <netinet/in.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "dns.h"
-#include "util.h"
-
-AvahiDnsPacket* avahi_dns_packet_new(guint max_size) {
-    AvahiDnsPacket *p;
-
-    if (max_size <= 0)
-        max_size = AVAHI_DNS_PACKET_MAX_SIZE;
-    else if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
-        max_size = AVAHI_DNS_PACKET_HEADER_SIZE;
-    
-    p = g_malloc(sizeof(AvahiDnsPacket) + max_size);
-    p->size = p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
-    p->max_size = max_size;
-    p->name_table = NULL;
-
-    memset(AVAHI_DNS_PACKET_DATA(p), 0, p->size);
-    return p;
-}
-
-AvahiDnsPacket* avahi_dns_packet_new_query(guint max_size) {
-    AvahiDnsPacket *p;
-
-    p = avahi_dns_packet_new(max_size);
-    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
-    return p;
-}
-
-AvahiDnsPacket* avahi_dns_packet_new_response(guint max_size) {
-    AvahiDnsPacket *p;
-
-    p = avahi_dns_packet_new(max_size);
-    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
-    return p;
-}
-
-void avahi_dns_packet_free(AvahiDnsPacket *p) {
-    g_assert(p);
-
-    if (p->name_table)
-        g_hash_table_destroy(p->name_table);
-    
-    g_free(p);
-}
-
-void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v) {
-    g_assert(p);
-    g_assert(index < AVAHI_DNS_PACKET_HEADER_SIZE);
-    
-    ((guint16*) AVAHI_DNS_PACKET_DATA(p))[index] = g_htons(v);
-}
-
-guint16 avahi_dns_packet_get_field(AvahiDnsPacket *p, guint index) {
-    g_assert(p);
-    g_assert(index < AVAHI_DNS_PACKET_HEADER_SIZE);
-
-    return g_ntohs(((guint16*) AVAHI_DNS_PACKET_DATA(p))[index]);
-}
-
-/* Read the first label from string *name, unescape "\" and write it to dest */
-gchar *avahi_unescape_label(gchar *dest, guint size, const gchar **name) {
-    guint i = 0;
-    gchar *d;
-    
-    g_assert(dest);
-    g_assert(size > 0);
-    g_assert(name);
-    g_assert(*name);
-
-    d = dest;
-    
-    for (;;) {
-        if (i >= size)
-            return NULL;
-
-        if (**name == '.') {
-            (*name)++;
-            break;
-        }
-        
-        if (**name == 0)
-            break;
-        
-        if (**name == '\\') {
-            (*name) ++;
-            
-            if (**name == 0)
-                break;
-        }
-        
-        *(d++) = *((*name) ++);
-        i++;
-    }
-
-    g_assert(i < size);
-
-    *d = 0;
-
-    return dest;
-}
-
-guint8* avahi_dns_packet_append_name(AvahiDnsPacket *p, const gchar *name) {
-    guint8 *d, *saved_ptr = NULL;
-    guint saved_size;
-    
-    g_assert(p);
-    g_assert(name);
-
-    saved_size = p->size;
-    saved_ptr = avahi_dns_packet_extend(p, 0);
-    
-    while (*name) {
-        guint n;
-        guint8* prev;
-        const gchar *pname;
-        gchar label[64];
-
-        /* Check whether we can compress this name. */
-
-        if (p->name_table && (prev = g_hash_table_lookup(p->name_table, name))) {
-            guint index;
-            
-            g_assert(prev >= AVAHI_DNS_PACKET_DATA(p));
-            index = (guint) (prev - AVAHI_DNS_PACKET_DATA(p));
-
-            g_assert(index < p->size);
-
-            if (index < 0x4000) {
-                guint16 *t;
-                if (!(t = (guint16*) avahi_dns_packet_extend(p, sizeof(guint16))))
-                    return NULL;
-
-                *t = g_htons((0xC000 | index));
-                return saved_ptr;
-            }
-        }
-
-        pname = name;
-        
-        if (!(avahi_unescape_label(label, sizeof(label), &name)))
-            goto fail;
-
-        if (!(d = avahi_dns_packet_append_string(p, label)))
-            goto fail;
-
-        if (!p->name_table)
-            p->name_table = g_hash_table_new_full((GHashFunc) avahi_domain_hash, (GEqualFunc) avahi_domain_equal, g_free, NULL);
-
-        g_hash_table_insert(p->name_table, g_strdup(pname), d);
-    }
-
-    if (!(d = avahi_dns_packet_extend(p, 1)))
-        goto fail;
-    
-    *d = 0;
-
-    return saved_ptr;
-
-fail:
-    p->size = saved_size;
-    return NULL;
-}
-
-guint8* avahi_dns_packet_append_uint16(AvahiDnsPacket *p, guint16 v) {
-    guint8 *d;
-    g_assert(p);
-    
-    if (!(d = avahi_dns_packet_extend(p, sizeof(guint16))))
-        return NULL;
-    
-    *((guint16*) d) = g_htons(v);
-    return d;
-}
-
-guint8 *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, guint32 v) {
-    guint8 *d;
-    g_assert(p);
-
-    if (!(d = avahi_dns_packet_extend(p, sizeof(guint32))))
-        return NULL;
-    
-    *((guint32*) d) = g_htonl(v);
-
-    return d;
-}
-
-guint8 *avahi_dns_packet_append_bytes(AvahiDnsPacket  *p, gconstpointer b, guint l) {
-    guint8* d;
-
-    g_assert(p);
-    g_assert(b);
-    g_assert(l);
-
-    if (!(d = avahi_dns_packet_extend(p, l)))
-        return NULL;
-
-    memcpy(d, b, l);
-    return d;
-}
-
-guint8* avahi_dns_packet_append_string(AvahiDnsPacket *p, const gchar *s) {
-    guint8* d;
-    guint k;
-    
-    g_assert(p);
-    g_assert(s);
-
-    if ((k = strlen(s)) >= 255)
-        k = 255;
-    
-    if (!(d = avahi_dns_packet_extend(p, k+1)))
-        return NULL;
-
-    *d = (guint8) k;
-    memcpy(d+1, s, k);
-
-    return d;
-}
-
-guint8 *avahi_dns_packet_extend(AvahiDnsPacket *p, guint l) {
-    guint8 *d;
-    
-    g_assert(p);
-
-    if (p->size+l > p->max_size)
-        return NULL;
-    
-    d = AVAHI_DNS_PACKET_DATA(p) + p->size;
-    p->size += l;
-    
-    return d;
-}
-
-gint avahi_dns_packet_check_valid(AvahiDnsPacket *p) {
-    guint16 flags;
-    g_assert(p);
-
-    if (p->size < 12)
-        return -1;
-
-    flags = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS);
-
-    if (flags & AVAHI_DNS_FLAG_OPCODE || flags & AVAHI_DNS_FLAG_RCODE)
-        return -1;
-
-    return 0;
-}
-
-gint avahi_dns_packet_is_query(AvahiDnsPacket *p) {
-    g_assert(p);
-    
-    return !(avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_QR);
-}
-
-/* Read a label from a DNS packet, escape "\" and ".", append \0 */
-static gchar *escape_label(guint8* src, guint src_length, gchar **ret_name, guint *ret_name_length) {
-    gchar *r;
-
-    g_assert(src);
-    g_assert(ret_name);
-    g_assert(*ret_name);
-    g_assert(ret_name_length);
-    g_assert(*ret_name_length > 0);
-
-    r = *ret_name;
-
-    while (src_length > 0) {
-        if (*src == '.' || *src == '\\') {
-            if (*ret_name_length < 3)
-                return NULL;
-            
-            *((*ret_name) ++) = '\\';
-            (*ret_name_length) --;
-        }
-
-        if (*ret_name_length < 2)
-            return NULL;
-        
-        *((*ret_name)++) = *src;
-        (*ret_name_length) --;
-
-        src_length --;
-        src++;
-    }
-
-    **ret_name = 0;
-
-    return r;
-}
-
-static gint consume_labels(AvahiDnsPacket *p, guint index, gchar *ret_name, guint l) {
-    gint ret = 0;
-    int compressed = 0;
-    int first_label = 1;
-    g_assert(p && ret_name && l);
-    
-    for (;;) {
-        guint8 n;
-
-        if (index+1 > p->size)
-            return -1;
-
-        n = AVAHI_DNS_PACKET_DATA(p)[index];
-
-        if (!n) {
-            index++;
-            if (!compressed)
-                ret++;
-
-            if (l < 1)
-                return -1;
-            *ret_name = 0;
-            
-            return ret;
-            
-        } else if (n <= 63) {
-            /* Uncompressed label */
-            index++;
-            if (!compressed)
-                ret++;
-        
-            if (index + n > p->size)
-                return -1;
-
-            if ((guint) n + 1 > l)
-                return -1;
-
-            if (!first_label) {
-                *(ret_name++) = '.';
-                l--;
-            } else
-                first_label = 0;
-
-            if (!(escape_label(AVAHI_DNS_PACKET_DATA(p) + index, n, &ret_name, &l)))
-                return -1;
-
-            index += n;
-            
-            if (!compressed)
-                ret += n;
-        } else if ((n & 0xC0) == 0xC0) {
-            /* Compressed label */
-
-            if (index+2 > p->size)
-                return -1;
-
-            index = ((guint) (AVAHI_DNS_PACKET_DATA(p)[index] & ~0xC0)) << 8 | AVAHI_DNS_PACKET_DATA(p)[index+1];
-
-            if (!compressed)
-                ret += 2;
-            
-            compressed = 1;
-        } else
-            return -1;
-    }
-}
-
-gint avahi_dns_packet_consume_name(AvahiDnsPacket *p, gchar *ret_name, guint l) {
-    gint r;
-    
-    if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
-        return -1;
-
-    p->rindex += r;
-    return 0;
-}
-
-gint avahi_dns_packet_consume_uint16(AvahiDnsPacket *p, guint16 *ret_v) {
-    g_assert(p);
-    g_assert(ret_v);
-
-    if (p->rindex + sizeof(guint16) > p->size)
-        return -1;
-
-    *ret_v = g_ntohs(*((guint16*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex)));
-    p->rindex += sizeof(guint16);
-
-    return 0;
-}
-
-gint avahi_dns_packet_consume_uint32(AvahiDnsPacket *p, guint32 *ret_v) {
-    g_assert(p);
-    g_assert(ret_v);
-
-    if (p->rindex + sizeof(guint32) > p->size)
-        return -1;
-
-    *ret_v = g_ntohl(*((guint32*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex)));
-    p->rindex += sizeof(guint32);
-    
-    return 0;
-}
-
-gint avahi_dns_packet_consume_bytes(AvahiDnsPacket *p, gpointer ret_data, guint l) {
-    g_assert(p);
-    g_assert(ret_data);
-    g_assert(l > 0);
-    
-    if (p->rindex + l > p->size)
-        return -1;
-
-    memcpy(ret_data, AVAHI_DNS_PACKET_DATA(p) + p->rindex, l);
-    p->rindex += l;
-
-    return 0;
-}
-
-gint avahi_dns_packet_consume_string(AvahiDnsPacket *p, gchar *ret_string, guint l) {
-    guint k;
-    
-    g_assert(p);
-    g_assert(ret_string);
-    g_assert(l > 0);
-
-    if (p->rindex >= p->size)
-        return -1;
-
-    k = AVAHI_DNS_PACKET_DATA(p)[p->rindex];
-
-    if (p->rindex+1+k > p->size)
-        return -1;
-
-    if (l > k+1)
-        l = k+1;
-
-    memcpy(ret_string, AVAHI_DNS_PACKET_DATA(p)+p->rindex+1, l-1);
-    ret_string[l-1] = 0;
-
-    
-    p->rindex += 1+k;
-
-    return 0;
-    
-}
-
-gconstpointer avahi_dns_packet_get_rptr(AvahiDnsPacket *p) {
-    g_assert(p);
-    
-    if (p->rindex > p->size)
-        return NULL;
-
-    return AVAHI_DNS_PACKET_DATA(p) + p->rindex;
-}
-
-gint avahi_dns_packet_skip(AvahiDnsPacket *p, guint length) {
-    g_assert(p);
-
-    if (p->rindex + length > p->size)
-        return -1;
-
-    p->rindex += length;
-    return 0;
-}
-
-AvahiRecord* avahi_dns_packet_consume_record(AvahiDnsPacket *p, gboolean *ret_cache_flush) {
-    gchar name[257], buf[257];
-    guint16 type, class;
-    guint32 ttl;
-    guint16 rdlength;
-    gconstpointer data;
-    AvahiRecord *r = NULL;
-    gconstpointer start;
-
-    g_assert(p);
-    g_assert(ret_cache_flush);
-
-/*     g_message("consume_record()"); */
-
-    if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
-        avahi_dns_packet_consume_uint16(p, &type) < 0 ||
-        avahi_dns_packet_consume_uint16(p, &class) < 0 ||
-        avahi_dns_packet_consume_uint32(p, &ttl) < 0 ||
-        avahi_dns_packet_consume_uint16(p, &rdlength) < 0 ||
-        p->rindex + rdlength > p->size)
-        goto fail;
-
-/*     g_message("name = %s, rdlength = %u", name, rdlength); */
-
-    *ret_cache_flush = !!(class & AVAHI_DNS_CACHE_FLUSH);
-    class &= ~AVAHI_DNS_CACHE_FLUSH;
-    
-    start = avahi_dns_packet_get_rptr(p);
-    
-    r = avahi_record_new_full(name, class, type);
-    
-    switch (type) {
-        case AVAHI_DNS_TYPE_PTR:
-        case AVAHI_DNS_TYPE_CNAME:
-
-/*             g_message("ptr"); */
-            
-            if (avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
-                goto fail;
-
-            r->data.ptr.name = g_strdup(buf);
-            break;
-
-            
-        case AVAHI_DNS_TYPE_SRV:
-
-/*             g_message("srv"); */
-            
-            if (avahi_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 ||
-                avahi_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 ||
-                avahi_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 ||
-                avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
-                goto fail;
-            
-            r->data.srv.name = g_strdup(buf);
-            break;
-
-        case AVAHI_DNS_TYPE_HINFO:
-            
-/*             g_message("hinfo"); */
-
-            if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
-                goto fail;
-
-            r->data.hinfo.cpu = g_strdup(buf);
-
-            if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
-                goto fail;
-
-            r->data.hinfo.os = g_strdup(buf);
-            break;
-
-        case AVAHI_DNS_TYPE_TXT:
-
-/*             g_message("txt"); */
-
-            if (rdlength > 0) {
-                r->data.txt.string_list = avahi_string_list_parse(avahi_dns_packet_get_rptr(p), rdlength);
-                
-                if (avahi_dns_packet_skip(p, rdlength) < 0)
-                    goto fail;
-            } else
-                r->data.txt.string_list = NULL;
-            
-            break;
-
-        case AVAHI_DNS_TYPE_A:
-
-/*             g_message("A"); */
-
-            if (avahi_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(AvahiIPv4Address)) < 0)
-                goto fail;
-            
-            break;
-
-        case AVAHI_DNS_TYPE_AAAA:
-
-/*             g_message("aaaa"); */
-            
-            if (avahi_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(AvahiIPv6Address)) < 0)
-                goto fail;
-            
-            break;
-            
-        default:
-
-/*             g_message("generic"); */
-            
-            if (rdlength > 0) {
-
-                r->data.generic.data = g_memdup(avahi_dns_packet_get_rptr(p), rdlength);
-                
-                if (avahi_dns_packet_skip(p, rdlength) < 0)
-                    goto fail;
-            }
-
-            break;
-    }
-
-/*     g_message("%i == %u ?", (guint8*) avahi_dns_packet_get_rptr(p) - (guint8*) start, rdlength); */
-    
-    /* Check if we read enough data */
-    if ((guint8*) avahi_dns_packet_get_rptr(p) - (guint8*) start != rdlength)
-        goto fail;
-    
-    r->ttl = ttl;
-
-    return r;
-
-fail:
-    if (r)
-        avahi_record_unref(r);
-
-    return NULL;
-}
-
-AvahiKey* avahi_dns_packet_consume_key(AvahiDnsPacket *p, gboolean *ret_unicast_response) {
-    gchar name[256];
-    guint16 type, class;
-
-    g_assert(p);
-    g_assert(ret_unicast_response);
-
-    if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
-        avahi_dns_packet_consume_uint16(p, &type) < 0 ||
-        avahi_dns_packet_consume_uint16(p, &class) < 0)
-        return NULL;
-
-    *ret_unicast_response = !!(class & AVAHI_DNS_UNICAST_RESPONSE);
-    class &= ~AVAHI_DNS_UNICAST_RESPONSE;
-
-    return avahi_key_new(name, class, type);
-}
-
-guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean unicast_response) {
-    guint8 *t;
-    guint size;
-    
-    g_assert(p);
-    g_assert(k);
-
-    size = p->size;
-    
-    if (!(t = avahi_dns_packet_append_name(p, k->name)) ||
-        !avahi_dns_packet_append_uint16(p, k->type) ||
-        !avahi_dns_packet_append_uint16(p, k->class | (unicast_response ? AVAHI_DNS_UNICAST_RESPONSE : 0))) {
-        p->size = size;
-        return NULL;
-    }
-
-    return t;
-}
-
-guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush) {
-    guint8 *t, *l, *start;
-    guint size;
-
-    g_assert(p);
-    g_assert(r);
-
-    size = p->size;
-
-    if (!(t = avahi_dns_packet_append_name(p, r->key->name)) ||
-        !avahi_dns_packet_append_uint16(p, r->key->type) ||
-        !avahi_dns_packet_append_uint16(p, cache_flush ? (r->key->class | AVAHI_DNS_CACHE_FLUSH) : (r->key->class &~ AVAHI_DNS_CACHE_FLUSH)) ||
-        !avahi_dns_packet_append_uint32(p, r->ttl) ||
-        !(l = avahi_dns_packet_append_uint16(p, 0)))
-        goto fail;
-
-    start = avahi_dns_packet_extend(p, 0);
-
-    switch (r->key->type) {
-        
-        case AVAHI_DNS_TYPE_PTR:
-        case AVAHI_DNS_TYPE_CNAME :
-
-            if (!(avahi_dns_packet_append_name(p, r->data.ptr.name)))
-                goto fail;
-            
-            break;
-
-        case AVAHI_DNS_TYPE_SRV:
-
-            if (!avahi_dns_packet_append_uint16(p, r->data.srv.priority) ||
-                !avahi_dns_packet_append_uint16(p, r->data.srv.weight) ||
-                !avahi_dns_packet_append_uint16(p, r->data.srv.port) ||
-                !avahi_dns_packet_append_name(p, r->data.srv.name))
-                goto fail;
-
-            break;
-
-        case AVAHI_DNS_TYPE_HINFO:
-            if (!avahi_dns_packet_append_string(p, r->data.hinfo.cpu) ||
-                !avahi_dns_packet_append_string(p, r->data.hinfo.os))
-                goto fail;
-
-            break;
-
-        case AVAHI_DNS_TYPE_TXT: {
-
-            guint8 *data;
-            guint size;
-
-            size = avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
-
-/*             g_message("appending string: %u %p", size, r->data.txt.string_list); */
-
-            if (!(data = avahi_dns_packet_extend(p, size)))
-                goto fail;
-
-            avahi_string_list_serialize(r->data.txt.string_list, data, size);
-            break;
-        }
-
-
-        case AVAHI_DNS_TYPE_A:
-
-            if (!avahi_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address)))
-                goto fail;
-            
-            break;
-
-        case AVAHI_DNS_TYPE_AAAA:
-            
-            if (!avahi_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address)))
-                goto fail;
-            
-            break;
-            
-        default:
-
-            if (r->data.generic.size &&
-                avahi_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size))
-                goto fail;
-
-            break;
-    }
-
-
-
-    
-    size = avahi_dns_packet_extend(p, 0) - start;
-    g_assert(size <= 0xFFFF);
-
-/*     g_message("appended %u", size); */
-
-    * (guint16*) l = g_htons((guint16) size);
-    
-    return t;
-
-
-fail:
-    p->size = size;
-    return NULL;
-}
-
-gboolean avahi_dns_packet_is_empty(AvahiDnsPacket *p) {
-    g_assert(p);
-
-    return p->size <= AVAHI_DNS_PACKET_HEADER_SIZE;
-}
-
-guint avahi_dns_packet_space(AvahiDnsPacket *p) {
-    g_assert(p);
-
-    g_assert(p->size <= p->max_size);
-    
-    return p->max_size - p->size;
-}
diff --git a/dns.h b/dns.h
deleted file mode 100644 (file)
index 13d9278..0000000
--- a/dns.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef foodnshfoo
-#define foodnshfoo
-
-#include <glib.h>
-
-#include "rr.h"
-
-#define AVAHI_DNS_PACKET_MAX_SIZE 9000
-#define AVAHI_DNS_PACKET_HEADER_SIZE 12
-
-typedef struct _AvahiDnsPacket {
-    guint size, rindex, max_size;
-    GHashTable *name_table; /* for name compression */
-} AvahiDnsPacket;
-
-
-#define AVAHI_DNS_PACKET_DATA(p) (((guint8*) p) + sizeof(AvahiDnsPacket))
-
-AvahiDnsPacket* avahi_dns_packet_new(guint size);
-AvahiDnsPacket* avahi_dns_packet_new_query(guint size);
-AvahiDnsPacket* avahi_dns_packet_new_response(guint size);
-
-void avahi_dns_packet_free(AvahiDnsPacket *p);
-void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v);
-guint16 avahi_dns_packet_get_field(AvahiDnsPacket *p, guint index);
-
-guint8 *avahi_dns_packet_extend(AvahiDnsPacket *p, guint l);
-
-guint8 *avahi_dns_packet_append_uint16(AvahiDnsPacket *p, guint16 v);
-guint8 *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, guint32 v);
-guint8 *avahi_dns_packet_append_name(AvahiDnsPacket *p, const gchar *name);
-guint8 *avahi_dns_packet_append_bytes(AvahiDnsPacket  *p, gconstpointer, guint l);
-guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean unicast_response);
-guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush);
-guint8* avahi_dns_packet_append_string(AvahiDnsPacket *p, const gchar *s);
-
-gint avahi_dns_packet_is_query(AvahiDnsPacket *p);
-gint avahi_dns_packet_check_valid(AvahiDnsPacket *p);
-
-gint avahi_dns_packet_consume_uint16(AvahiDnsPacket *p, guint16 *ret_v);
-gint avahi_dns_packet_consume_uint32(AvahiDnsPacket *p, guint32 *ret_v);
-gint avahi_dns_packet_consume_name(AvahiDnsPacket *p, gchar *ret_name, guint l);
-gint avahi_dns_packet_consume_bytes(AvahiDnsPacket *p, gpointer ret_data, guint l);
-AvahiKey* avahi_dns_packet_consume_key(AvahiDnsPacket *p, gboolean *ret_unicast_response);
-AvahiRecord* avahi_dns_packet_consume_record(AvahiDnsPacket *p, gboolean *ret_cache_flush);
-gint avahi_dns_packet_consume_string(AvahiDnsPacket *p, gchar *ret_string, guint l);
-
-gconstpointer avahi_dns_packet_get_rptr(AvahiDnsPacket *p);
-
-gint avahi_dns_packet_skip(AvahiDnsPacket *p, guint length);
-
-gboolean avahi_dns_packet_is_empty(AvahiDnsPacket *p);
-guint avahi_dns_packet_space(AvahiDnsPacket *p);
-
-#define AVAHI_DNS_FIELD_ID 0
-#define AVAHI_DNS_FIELD_FLAGS 1
-#define AVAHI_DNS_FIELD_QDCOUNT 2
-#define AVAHI_DNS_FIELD_ANCOUNT 3
-#define AVAHI_DNS_FIELD_NSCOUNT 4
-#define AVAHI_DNS_FIELD_ARCOUNT 5
-
-#define AVAHI_DNS_FLAG_QR (1 << 15)
-#define AVAHI_DNS_FLAG_OPCODE (15 << 11)
-#define AVAHI_DNS_FLAG_RCODE (15)
-#define AVAHI_DNS_FLAG_TC (1 << 9)
-
-#define AVAHI_DNS_FLAGS(qr, opcode, aa, tc, rd, ra, z, ad, cd, rcode) \
-        (((guint16) !!qr << 15) |  \
-         ((guint16) (opcode & 15) << 11) | \
-         ((guint16) !!aa << 10) | \
-         ((guint16) !!tc << 9) | \
-         ((guint16) !!rd << 8) | \
-         ((guint16) !!ra << 7) | \
-         ((guint16) !!ad << 5) | \
-         ((guint16) !!cd << 4) | \
-         ((guint16) (rd & 15)))
-         
-
-gchar *avahi_unescape_label(gchar *dest, guint size, const gchar **name);
-
-#endif
-
diff --git a/domain-test.c b/domain-test.c
deleted file mode 100644 (file)
index f3deeac..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "util.h"
-
-int main(int argc, char *argv[]) {
-    gchar *s;
-    
-    g_message("host name: %s", s = avahi_get_host_name());
-    g_free(s);
-
-    g_message("%s", s = avahi_normalize_name("foo.foo."));
-    g_free(s);
-    
-    g_message("%s", s = avahi_normalize_name("foo.foo."));
-    g_free(s);
-
-
-    g_message("%i", avahi_domain_equal("\\aaa bbb\\.cccc\\\\.dee.fff.", "aaa\\ bbb\\.cccc\\\\.dee.fff"));
-
-    return 0;
-}
diff --git a/iface.c b/iface.c
deleted file mode 100644 (file)
index 519a65b..0000000
--- a/iface.c
+++ /dev/null
@@ -1,562 +0,0 @@
-#include <string.h>
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <errno.h>
-#include <net/if.h>
-
-#include "iface.h"
-#include "netlink.h"
-#include "dns.h"
-#include "socket.h"
-#include "announce.h"
-
-static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a, int remove) {
-    g_assert(m);
-    g_assert(a);
-
-    if (!avahi_interface_address_relevant(a) || remove) {
-        if (a->entry_group) {
-            avahi_entry_group_free(a->entry_group);
-            a->entry_group = NULL;
-        }
-    } else {
-        if (!a->entry_group) {
-            a->entry_group = avahi_entry_group_new(m->server, NULL, NULL);
-            avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, AF_UNSPEC, 0, NULL, &a->address);
-            avahi_entry_group_commit(a->entry_group);
-        }
-    }
-}
-
-static void update_interface_rr(AvahiInterfaceMonitor *m, AvahiInterface *i, int remove) {
-    AvahiInterfaceAddress *a;
-    g_assert(m);
-    g_assert(i);
-
-    for (a = i->addresses; a; a = a->address_next)
-        update_address_rr(m, a, remove);
-}
-
-static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, int remove) {
-    AvahiInterface *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(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a) {
-    g_assert(m);
-    g_assert(a);
-    g_assert(a->interface);
-
-    AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a);
-
-    if (a->entry_group)
-        avahi_entry_group_free(a->entry_group);
-    
-    g_free(a);
-}
-
-static void free_interface(AvahiInterfaceMonitor *m, AvahiInterface *i, gboolean send_goodbye) {
-    g_assert(m);
-    g_assert(i);
-
-    g_message("removing interface %s.%i", i->hardware->name, i->protocol);
-    avahi_goodbye_interface(m->server, i, send_goodbye);
-    g_message("flushing...");
-    avahi_packet_scheduler_flush_responses(i->scheduler);
-    g_message("done");
-    
-    g_assert(!i->announcements);
-
-    while (i->addresses)
-        free_address(m, i->addresses);
-
-    avahi_packet_scheduler_free(i->scheduler);
-    avahi_cache_free(i->cache);
-    
-    AVAHI_LLIST_REMOVE(AvahiInterface, interface, m->interfaces, i);
-    AVAHI_LLIST_REMOVE(AvahiInterface, by_hardware, i->hardware->interfaces, i);
-    
-    g_free(i);
-}
-
-static void free_hw_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, gboolean send_goodbye) {
-    g_assert(m);
-    g_assert(hw);
-
-    while (hw->interfaces)
-        free_interface(m, hw->interfaces, send_goodbye);
-
-    AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, m->hw_interfaces, hw);
-    g_hash_table_remove(m->hash_table, &hw->index);
-
-    g_free(hw->name);
-    g_free(hw);
-}
-
-static AvahiInterfaceAddress* get_address(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *raddr) {
-    AvahiInterfaceAddress *ia;
-    
-    g_assert(m);
-    g_assert(i);
-    g_assert(raddr);
-
-    for (ia = i->addresses; ia; ia = ia->address_next)
-        if (avahi_address_cmp(&ia->address, raddr) == 0)
-            return ia;
-
-    return NULL;
-}
-
-static int netlink_list_items(AvahiNetlink *nl, guint16 type, guint *ret_seq) {
-    struct nlmsghdr *n;
-    struct rtgenmsg *gen;
-    guint8 req[1024];
-    
-    memset(&req, 0, sizeof(req));
-    n = (struct nlmsghdr*) req;
-    n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
-    n->nlmsg_type = type;
-    n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
-    n->nlmsg_pid = 0;
-
-    gen = NLMSG_DATA(n);
-    memset(gen, 0, sizeof(struct rtgenmsg));
-    gen->rtgen_family = AF_UNSPEC;
-
-    return avahi_netlink_send(nl, n, ret_seq);
-}
-
-static void new_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, guchar protocol) {
-    AvahiInterface *i;
-    
-    g_assert(m);
-    g_assert(hw);
-    g_assert(protocol != AF_UNSPEC);
-
-    i = g_new(AvahiInterface, 1);
-    i->monitor = m;
-    i->hardware = hw;
-    i->protocol = protocol;
-    i->announcing = FALSE;
-
-    AVAHI_LLIST_HEAD_INIT(AvahiInterfaceAddress, i->addresses);
-    AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, i->announcements);
-
-    i->cache = avahi_cache_new(m->server, i);
-    i->scheduler = avahi_packet_scheduler_new(m->server, i);
-
-    AVAHI_LLIST_PREPEND(AvahiInterface, by_hardware, hw->interfaces, i);
-    AVAHI_LLIST_PREPEND(AvahiInterface, interface, m->interfaces, i);
-}
-
-static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i) {
-    gboolean b;
-
-    g_assert(m);
-    g_assert(i);
-
-    b = avahi_interface_relevant(i);
-
-    if (b && !i->announcing) {
-        g_message("New relevant interface %s.%i", i->hardware->name, i->protocol);
-
-        if (i->protocol == AF_INET)
-            avahi_mdns_mcast_join_ipv4 (i->hardware->index, m->server->fd_ipv4);
-        if (i->protocol == AF_INET6)
-            avahi_mdns_mcast_join_ipv6 (i->hardware->index, m->server->fd_ipv6);
-
-        i->announcing = TRUE;
-        avahi_announce_interface(m->server, i);
-    } else if (!b && i->announcing) {
-        g_message("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
-
-        avahi_goodbye_interface(m->server, i, FALSE);
-
-        if (i->protocol == AF_INET)
-            avahi_mdns_mcast_leave_ipv4 (i->hardware->index, m->server->fd_ipv4);
-        if (i->protocol == AF_INET6)
-            avahi_mdns_mcast_leave_ipv6 (i->hardware->index, m->server->fd_ipv6);
-
-        i->announcing = FALSE;
-    }
-}
-
-static void check_hw_interface_relevant(AvahiInterfaceMonitor *m, AvahiHwInterface *hw) {
-    AvahiInterface *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(AvahiNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
-    AvahiInterfaceMonitor *m = userdata;
-    
-    g_assert(m);
-    g_assert(n);
-    g_assert(m->netlink == nl);
-
-    if (n->nlmsg_type == RTM_NEWLINK) {
-        struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
-        AvahiHwInterface *hw;
-        struct rtattr *a = NULL;
-        size_t l;
-
-        if (ifinfomsg->ifi_family != AF_UNSPEC)
-            return;
-
-        if (!(hw = g_hash_table_lookup(m->hash_table, &ifinfomsg->ifi_index))) {
-            hw = g_new(AvahiHwInterface, 1);
-            hw->monitor = m;
-            hw->name = NULL;
-            hw->flags = 0;
-            hw->mtu = 1500;
-            hw->index = ifinfomsg->ifi_index;
-
-            AVAHI_LLIST_HEAD_INIT(AvahiInterface, hw->interfaces);
-            AVAHI_LLIST_PREPEND(AvahiHwInterface, hardware, m->hw_interfaces, hw);
-            
-            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);
-        }
-        
-        hw->flags = ifinfomsg->ifi_flags;
-
-        l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
-        a = IFLA_RTA(ifinfomsg);
-
-        while (RTA_OK(a, l)) {
-            switch(a->rta_type) {
-                case IFLA_IFNAME:
-                    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));
-                    hw->mtu = *((unsigned int*) RTA_DATA(a));
-                    break;
-                    
-                default:
-                    ;
-            }
-
-            a = RTA_NEXT(a, l);
-        }
-
-        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);
-        AvahiHwInterface *hw;
-        AvahiInterface *i;
-
-        if (ifinfomsg->ifi_family != AF_UNSPEC)
-            return;
-        
-        if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index)))
-            return;
-
-        update_hw_interface_rr(m, hw, TRUE);
-        free_hw_interface(m, hw, FALSE);
-        
-    } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
-
-        struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
-        AvahiInterface *i;
-        struct rtattr *a = NULL;
-        size_t l;
-        AvahiAddress raddr;
-        int raddr_valid = 0;
-
-        if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
-            return;
-
-        if (!(i = (AvahiInterface*) avahi_interface_monitor_get_interface(m, ifaddrmsg->ifa_index, ifaddrmsg->ifa_family)))
-            return;
-
-        raddr.family = ifaddrmsg->ifa_family;
-
-        l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
-        a = IFA_RTA(ifaddrmsg);
-
-        while (RTA_OK(a, l)) {
-            switch(a->rta_type) {
-                case IFA_ADDRESS:
-                    if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
-                        (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
-                        return;
-
-                    memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
-                    raddr_valid = 1;
-
-                    break;
-                    
-                default:
-                    ;
-            }
-            
-            a = RTA_NEXT(a, l);
-        }
-
-        
-        if (!raddr_valid)
-            return;
-
-        if (n->nlmsg_type == RTM_NEWADDR) {
-            AvahiInterfaceAddress *addr;
-            
-            if (!(addr = get_address(m, i, &raddr))) {
-                addr = g_new(AvahiInterfaceAddress, 1);
-                addr->monitor = m;
-                addr->address = raddr;
-                addr->interface = i;
-                addr->entry_group = NULL;
-
-                AVAHI_LLIST_PREPEND(AvahiInterfaceAddress, address, i->addresses, addr);
-            }
-            
-            addr->flags = ifaddrmsg->ifa_flags;
-            addr->scope = ifaddrmsg->ifa_scope;
-
-            update_address_rr(m, addr, FALSE);
-            check_interface_relevant(m, i);
-        } else {
-            AvahiInterfaceAddress *addr;
-            
-            if (!(addr = get_address(m, i, &raddr)))
-                return;
-
-            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)
-                g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
-            else
-                m->list = LIST_ADDR;
-        } else {
-            m->list = LIST_DONE;
-            g_message("Enumeration complete");
-        }
-        
-    } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
-        struct nlmsgerr *e = NLMSG_DATA (n);
-                    
-        if (e->error)
-            g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
-    }
-}
-
-AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *s) {
-    AvahiInterfaceMonitor *m = NULL;
-
-    m = g_new0(AvahiInterfaceMonitor, 1);
-    m->server = s;
-    if (!(m->netlink = avahi_netlink_new(s->context, G_PRIORITY_DEFAULT-10, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
-        goto fail;
-
-    m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
-
-    AVAHI_LLIST_HEAD_INIT(AvahiInterface, m->interfaces);
-    AVAHI_LLIST_HEAD_INIT(AvahiHwInterface, m->hw_interfaces);
-
-    if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
-        goto fail;
-
-    m->list = LIST_IFACE;
-
-    return m;
-
-fail:
-    avahi_interface_monitor_free(m);
-    return NULL;
-}
-
-void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) {
-    g_assert(m);
-    
-    while (m->list != LIST_DONE) {
-        if (!avahi_netlink_work(m->netlink, TRUE))
-            break;
-    } 
-}
-
-void avahi_interface_monitor_free(AvahiInterfaceMonitor *m) {
-    g_assert(m);
-
-    while (m->hw_interfaces)
-        free_hw_interface(m, m->hw_interfaces, TRUE);
-
-    g_assert(!m->interfaces);
-
-    
-    if (m->netlink)
-        avahi_netlink_free(m->netlink);
-    
-    if (m->hash_table)
-        g_hash_table_destroy(m->hash_table);
-
-    g_free(m);
-}
-
-
-AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, gint index, guchar protocol) {
-    AvahiHwInterface *hw;
-    AvahiInterface *i;
-    
-    g_assert(m);
-    g_assert(index > 0);
-    g_assert(protocol != AF_UNSPEC);
-
-    if (!(hw = avahi_interface_monitor_get_hw_interface(m, index)))
-        return NULL;
-
-    for (i = hw->interfaces; i; i = i->by_hardware_next)
-        if (i->protocol == protocol)
-            return i;
-
-    return NULL;
-}
-
-AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, gint index) {
-    g_assert(m);
-    g_assert(index > 0);
-
-    return g_hash_table_lookup(m->hash_table, &index);
-}
-
-
-void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
-    g_assert(i);
-    g_assert(p);
-
-    if (avahi_interface_relevant(i)) {
-        g_message("sending on '%s.%i'", i->hardware->name, i->protocol);
-
-        if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
-            avahi_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)
-            avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p);
-    }
-}
-
-void avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean immediately) {
-    g_assert(i);
-    g_assert(key);
-
-    if (avahi_interface_relevant(i))
-        avahi_packet_scheduler_post_query(i->scheduler, key, immediately);
-}
-
-
-void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
-    g_assert(i);
-    g_assert(record);
-
-    if (avahi_interface_relevant(i))
-        avahi_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately);
-}
-
-void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, gboolean immediately) {
-    g_assert(i);
-    g_assert(record);
-    
-    if (avahi_interface_relevant(i))
-        avahi_packet_scheduler_post_probe(i->scheduler, record, immediately);
-}
-
-void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f) {
-    AvahiInterface *i;
-    g_assert(m);
-
-    for (i = m->interfaces; i; i = i->interface_next) {
-        if (avahi_interface_relevant(i)) {
-            fprintf(f, "\n;;; INTERFACE %s.%i ;;;\n", i->hardware->name, i->protocol);
-            avahi_cache_dump(i->cache, f);
-        }
-    }
-    fprintf(f, "\n");
-}
-
-gboolean avahi_interface_relevant(AvahiInterface *i) {
-    g_assert(i);
-
-    return
-        (i->hardware->flags & IFF_UP) &&
-        (i->hardware->flags & IFF_RUNNING) &&
-        !(i->hardware->flags & IFF_LOOPBACK) &&
-        (i->hardware->flags & IFF_MULTICAST) &&
-        i->addresses;
-}
-
-gboolean avahi_interface_address_relevant(AvahiInterfaceAddress *a) { 
-    g_assert(a);
-
-    return a->scope == RT_SCOPE_UNIVERSE;
-}
-
-
-gboolean avahi_interface_match(AvahiInterface *i, gint index, guchar protocol) {
-    g_assert(i);
-    
-    if (index > 0 && index != i->hardware->index)
-        return FALSE;
-
-    if (protocol != AF_UNSPEC && protocol != i->protocol)
-        return FALSE;
-
-    return TRUE;
-}
-
-
-void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, gint interface, guchar protocol, AvahiInterfaceMonitorWalkCallback callback, gpointer userdata) {
-    g_assert(m);
-    g_assert(callback);
-    
-    if (interface > 0) {
-        if (protocol != AF_UNSPEC) {
-            AvahiInterface *i;
-            
-            if ((i = avahi_interface_monitor_get_interface(m, interface, protocol)))
-                callback(m, i, userdata);
-            
-        } else {
-            AvahiHwInterface *hw;
-            AvahiInterface *i;
-
-            if ((hw = avahi_interface_monitor_get_hw_interface(m, interface)))
-                for (i = hw->interfaces; i; i = i->by_hardware_next)
-                    if (avahi_interface_match(i, interface, protocol))
-                        callback(m, i, userdata);
-        }
-        
-    } else {
-        AvahiInterface *i;
-        
-        for (i = m->interfaces; i; i = i->interface_next)
-            if (avahi_interface_match(i, interface, protocol))
-                callback(m, i, userdata);
-    }
-}
diff --git a/iface.h b/iface.h
deleted file mode 100644 (file)
index cab4949..0000000
--- a/iface.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef fooifacehfoo
-#define fooifacehfoo
-
-#include <glib.h>
-
-typedef struct _AvahiInterfaceMonitor AvahiInterfaceMonitor;
-typedef struct _AvahiInterfaceAddress AvahiInterfaceAddress;
-typedef struct _AvahiInterface AvahiInterface;
-typedef struct _AvahiHwInterface AvahiHwInterface;
-
-#include "address.h"
-#include "server.h"
-#include "netlink.h"
-#include "cache.h"
-#include "llist.h"
-#include "psched.h"
-#include "dns.h"
-#include "announce.h"
-
-struct _AvahiInterfaceMonitor {
-    AvahiServer *server;
-    AvahiNetlink *netlink;
-    GHashTable *hash_table;
-
-    AVAHI_LLIST_HEAD(AvahiInterface, interfaces);
-    AVAHI_LLIST_HEAD(AvahiHwInterface, hw_interfaces);
-    
-    guint query_addr_seq, query_link_seq;
-    
-    enum {
-        LIST_IFACE,
-        LIST_ADDR,
-        LIST_DONE
-    } list;
-};
-
-struct _AvahiHwInterface {
-    AVAHI_LLIST_FIELDS(AvahiHwInterface, hardware);
-    AvahiInterfaceMonitor *monitor;
-
-    gchar *name;
-    gint index;
-    guint flags;
-    guint mtu;
-
-    AVAHI_LLIST_HEAD(AvahiInterface, interfaces);
-};
-
-struct _AvahiInterface {
-    AVAHI_LLIST_FIELDS(AvahiInterface, interface);
-    AVAHI_LLIST_FIELDS(AvahiInterface, by_hardware);
-    AvahiInterfaceMonitor *monitor;
-    
-    AvahiHwInterface *hardware;
-    guchar protocol;
-    gboolean announcing;
-
-    AvahiCache *cache;
-    AvahiPacketScheduler *scheduler;
-
-    AVAHI_LLIST_HEAD(AvahiInterfaceAddress, addresses);
-    AVAHI_LLIST_HEAD(AvahiAnnouncement, announcements);
-};
-
-struct _AvahiInterfaceAddress {
-    AVAHI_LLIST_FIELDS(AvahiInterfaceAddress, address);
-    AvahiInterfaceMonitor *monitor;
-    
-    guchar flags;
-    guchar scope;
-    AvahiAddress address;
-    
-    AvahiEntryGroup *entry_group;
-    AvahiInterface *interface;
-};
-
-AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *server);
-void avahi_interface_monitor_free(AvahiInterfaceMonitor *m);
-
-void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m);
-
-AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, gint index, guchar protocol);
-AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, gint index);
-
-void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p);
-
-void avahi_interface_post_query(AvahiInterface *i, AvahiKey *k, gboolean immediately);
-void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *p, gboolean immediately);
-void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
-
-void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f);
-
-gboolean avahi_interface_relevant(AvahiInterface *i);
-gboolean avahi_interface_address_relevant(AvahiInterfaceAddress *a);
-
-gboolean avahi_interface_match(AvahiInterface *i, gint index, guchar protocol);
-
-typedef void (*AvahiInterfaceMonitorWalkCallback)(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata);
-    
-void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, gint index, guchar protocol, AvahiInterfaceMonitorWalkCallback callback, gpointer userdata);
-
-#endif
diff --git a/libavahi-core/Makefile b/libavahi-core/Makefile
new file mode 100644 (file)
index 0000000..ff3977e
--- /dev/null
@@ -0,0 +1,28 @@
+#CC=gcc-2.95
+CFLAGS=-g -O1 -Wall -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused
+LIBS=$(shell pkg-config --libs glib-2.0)
+
+all: strlst-test prioq-test domain-test dns-test flexmdns
+
+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 subscribe.o strlst.o
+       $(CC) -o $@ $^ $(LIBS)
+
+#test-llist: test-llist.o
+#      $(CC) -o $@ $^ $(LIBS)
+
+prioq-test: prioq-test.o prioq.o
+       $(CC) -o $@ $^ $(LIBS)
+
+strlst-test: strlst-test.o strlst.o
+       $(CC) -o $@ $^ $(LIBS)
+
+domain-test: domain-test.o util.o
+       $(CC) -o $@ $^ $(LIBS)
+
+dns-test: dns-test.o util.o dns.o rr.o strlst.o
+       $(CC) -o $@ $^ $(LIBS)
+
+*.o: *.h
+
+clean:
+       rm -f *.o flexmdns prioq-test strlst-test domain-test dns-test
diff --git a/libavahi-core/address.c b/libavahi-core/address.c
new file mode 100644 (file)
index 0000000..e5f8866
--- /dev/null
@@ -0,0 +1,126 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "address.h"
+
+guint avahi_address_get_size(const AvahiAddress *a) {
+    g_assert(a);
+
+    if (a->family == AF_INET)
+        return 4;
+    else if (a->family == AF_INET6)
+        return 16;
+
+    return 0;
+}
+
+gint avahi_address_cmp(const AvahiAddress *a, const AvahiAddress *b) {
+    g_assert(a);
+    g_assert(b);
+    
+    if (a->family != b->family)
+        return -1;
+
+    return memcmp(a->data.data, b->data.data, avahi_address_get_size(a));
+}
+
+gchar *avahi_address_snprint(char *s, guint length, const AvahiAddress *a) {
+    g_assert(s);
+    g_assert(length);
+    g_assert(a);
+    return (gchar*) inet_ntop(a->family, a->data.data, s, length);
+}
+
+gchar* avahi_reverse_lookup_name_ipv4(const AvahiIPv4Address *a) {
+    guint32 n = ntohl(a->address);
+    g_assert(a);
+
+    return g_strdup_printf("%u.%u.%u.%u.in-addr.arpa", n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF, n >> 24);
+}
+
+static gchar *reverse_lookup_name_ipv6(const AvahiIPv6Address *a, const gchar *suffix) {
+    
+    return g_strdup_printf("%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%s",
+                           a->address[15] & 0xF,
+                           a->address[15] >> 4,
+                           a->address[14] & 0xF,
+                           a->address[14] >> 4,
+                           a->address[13] & 0xF,
+                           a->address[13] >> 4,
+                           a->address[12] & 0xF,
+                           a->address[12] >> 4,
+                           a->address[11] & 0xF,
+                           a->address[11] >> 4,
+                           a->address[10] & 0xF,
+                           a->address[10] >> 4,
+                           a->address[9] & 0xF,
+                           a->address[9] >> 4,
+                           a->address[8] & 0xF,
+                           a->address[8] >> 4,
+                           a->address[7] & 0xF,
+                           a->address[7] >> 4,
+                           a->address[6] & 0xF,
+                           a->address[6] >> 4,
+                           a->address[5] & 0xF,
+                           a->address[5] >> 4,
+                           a->address[4] & 0xF,
+                           a->address[4] >> 4,
+                           a->address[3] & 0xF,
+                           a->address[3] >> 4,
+                           a->address[2] & 0xF,
+                           a->address[2] >> 4,
+                           a->address[1] & 0xF,
+                           a->address[1] >> 4,
+                           a->address[0] & 0xF,
+                           a->address[0] >> 4,
+                           suffix);
+}
+
+gchar *avahi_reverse_lookup_name_ipv6_arpa(const AvahiIPv6Address *a) {
+    return reverse_lookup_name_ipv6(a, "ip6.arpa");
+}
+
+gchar *avahi_reverse_lookup_name_ipv6_int(const AvahiIPv6Address *a) {
+    return reverse_lookup_name_ipv6(a, "ip6.int");
+}
+
+AvahiAddress *avahi_address_parse(const char *s, guchar family, AvahiAddress *ret_addr) {
+    g_assert(ret_addr);
+    g_assert(s);
+
+    if (inet_pton(family, s, ret_addr->data.data) < 0)
+        return NULL;
+
+    ret_addr->family = family;
+    
+    return ret_addr;
+}
+
+AvahiAddress *avahi_address_from_sockaddr(const struct sockaddr* sa, AvahiAddress *ret_addr) {
+    g_assert(sa);
+    g_assert(ret_addr);
+
+    g_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+
+    ret_addr->family = sa->sa_family;
+
+    if (sa->sa_family == AF_INET)
+        memcpy(&ret_addr->data.ipv4, &((struct sockaddr_in*) sa)->sin_addr, sizeof(ret_addr->data.ipv4));
+    else
+        memcpy(&ret_addr->data.ipv6, &((struct sockaddr_in6*) sa)->sin6_addr, sizeof(ret_addr->data.ipv6));
+
+    return ret_addr;
+}
+
+guint16 avahi_port_from_sockaddr(const struct sockaddr* sa) {
+    g_assert(sa);
+
+    g_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+
+    if (sa->sa_family == AF_INET)
+        return ntohs(((struct sockaddr_in*) sa)->sin_port);
+    else
+        return ntohs(((struct sockaddr_in6*) sa)->sin6_port);
+}
diff --git a/libavahi-core/address.h b/libavahi-core/address.h
new file mode 100644 (file)
index 0000000..2eea75d
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef fooaddresshfoo
+#define fooaddresshfoo
+
+#include <glib.h>
+
+#include <sys/socket.h>
+
+typedef struct {
+    guint32 address;
+} AvahiIPv4Address;
+
+typedef struct {
+    guint8 address[16];
+} AvahiIPv6Address;
+
+typedef struct {
+    guchar family;
+
+    union {
+        AvahiIPv6Address ipv6;
+        AvahiIPv4Address ipv4;
+        guint8 data[0];
+    } data;
+} AvahiAddress;
+
+guint avahi_address_get_size(const AvahiAddress *a);
+gint avahi_address_cmp(const AvahiAddress *a, const AvahiAddress *b);
+
+gchar *avahi_address_snprint(char *ret_s, guint length, const AvahiAddress *a);
+
+AvahiAddress *avahi_address_parse(const char *s, guchar family, AvahiAddress *ret_addr);
+
+AvahiAddress *avahi_address_from_sockaddr(const struct sockaddr* sa, AvahiAddress *ret_addr);
+guint16 avahi_port_from_sockaddr(const struct sockaddr* sa);
+
+gchar* avahi_reverse_lookup_name_ipv4(const AvahiIPv4Address *a);
+gchar* avahi_reverse_lookup_name_ipv6_arpa(const AvahiIPv6Address *a);
+gchar* avahi_reverse_lookup_name_ipv6_int(const AvahiIPv6Address *a);
+
+#endif
diff --git a/libavahi-core/announce.c b/libavahi-core/announce.c
new file mode 100644 (file)
index 0000000..538ba2e
--- /dev/null
@@ -0,0 +1,397 @@
+#include "announce.h"
+#include "util.h"
+
+#define AVAHI_ANNOUNCEMENT_JITTER_MSEC 250
+#define AVAHI_PROBE_JITTER_MSEC 250
+#define AVAHI_PROBE_INTERVAL_MSEC 250
+
+static void remove_announcement(AvahiServer *s, AvahiAnnouncement *a) {
+    g_assert(s);
+    g_assert(a);
+
+    if (a->time_event)
+        avahi_time_event_queue_remove(s->time_event_queue, a->time_event);
+
+    AVAHI_LLIST_REMOVE(AvahiAnnouncement, by_interface, a->interface->announcements, a);
+    AVAHI_LLIST_REMOVE(AvahiAnnouncement, by_entry, a->entry->announcements, a);
+    
+    g_free(a);
+}
+
+static void elapse_announce(AvahiTimeEvent *e, void *userdata);
+
+static void set_timeout(AvahiAnnouncement *a, const GTimeVal *tv) {
+    g_assert(a);
+
+    if (!tv) {
+        if (a->time_event) {
+            avahi_time_event_queue_remove(a->server->time_event_queue, a->time_event);
+            a->time_event = NULL;
+        }
+    } else {
+
+        if (a->time_event) 
+            avahi_time_event_queue_update(a->server->time_event_queue, a->time_event, tv);
+        else
+            a->time_event = avahi_time_event_queue_add(a->server->time_event_queue, tv, elapse_announce, a);
+    }
+}
+
+static void next_state(AvahiAnnouncement *a);
+
+void avahi_entry_group_check_probed(AvahiEntryGroup *g, gboolean immediately) {
+    AvahiEntry *e;
+    g_assert(g);
+    g_assert(!g->dead);
+
+    /* Check whether all group members have been probed */
+    
+    if (g->state != AVAHI_ENTRY_GROUP_REGISTERING || g->n_probing > 0) 
+        return;
+
+    avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_ESTABLISHED);
+
+    if (g->dead)
+        return;
+    
+    for (e = g->entries; e; e = e->entries_next) {
+        AvahiAnnouncement *a;
+        
+        for (a = e->announcements; a; a = a->by_entry_next) {
+
+            if (a->state != AVAHI_WAITING)
+                continue;
+            
+            a->state = AVAHI_ANNOUNCING;
+
+            if (immediately) {
+                /* Shortcut */
+                
+                a->n_iteration = 1;
+                next_state(a);
+            } else {
+                GTimeVal tv;
+                a->n_iteration = 0;
+                avahi_elapse_time(&tv, 0, AVAHI_ANNOUNCEMENT_JITTER_MSEC);
+                set_timeout(a, &tv);
+            }
+        }
+    }
+}
+
+static void next_state(AvahiAnnouncement *a) {
+    g_assert(a);
+
+/*     g_message("%i -- %u", a->state, a->n_iteration);   */
+    
+    if (a->state == AVAHI_WAITING) {
+
+        g_assert(a->entry->group);
+
+        avahi_entry_group_check_probed(a->entry->group, TRUE);
+        
+    } else if (a->state == AVAHI_PROBING) {
+
+        if (a->n_iteration >= 4) {
+            /* Probing done */
+            
+            gchar *t;
+
+            g_message("Enough probes for record [%s]", t = avahi_record_to_string(a->entry->record));
+            g_free(t);
+
+            if (a->entry->group) {
+                g_assert(a->entry->group->n_probing);
+                a->entry->group->n_probing--;
+            }
+            
+            if (a->entry->group && a->entry->group->state == AVAHI_ENTRY_GROUP_REGISTERING)
+                a->state = AVAHI_WAITING;
+            else {
+                a->state = AVAHI_ANNOUNCING;
+                a->n_iteration = 1;
+            }
+
+            set_timeout(a, NULL);
+            next_state(a);
+        } else {
+            GTimeVal tv;
+
+            avahi_interface_post_probe(a->interface, a->entry->record, FALSE);
+            
+            avahi_elapse_time(&tv, AVAHI_PROBE_INTERVAL_MSEC, 0);
+            set_timeout(a, &tv);
+            
+            a->n_iteration++;
+        }
+
+    } else if (a->state == AVAHI_ANNOUNCING) {
+
+        avahi_interface_post_response(a->interface, NULL, a->entry->record, a->entry->flags & AVAHI_ENTRY_UNIQUE, FALSE);
+
+        if (++a->n_iteration >= 4) {
+            gchar *t;
+            /* Announcing done */
+
+            g_message("Enough announcements for record [%s]", t = avahi_record_to_string(a->entry->record));
+            g_free(t);
+
+            a->state = AVAHI_ESTABLISHED;
+
+            set_timeout(a, NULL);
+        } else {
+            GTimeVal tv;
+            avahi_elapse_time(&tv, a->sec_delay*1000, AVAHI_ANNOUNCEMENT_JITTER_MSEC);
+        
+            if (a->n_iteration < 10)
+                a->sec_delay *= 2;
+            
+            set_timeout(a, &tv);
+        }
+    }
+}
+
+static void elapse_announce(AvahiTimeEvent *e, void *userdata) {
+    g_assert(e);
+
+    next_state(userdata);
+}
+
+AvahiAnnouncement *avahi_get_announcement(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
+    AvahiAnnouncement *a;
+    
+    g_assert(s);
+    g_assert(e);
+    g_assert(i);
+
+    for (a = e->announcements; a; a = a->by_entry_next)
+        if (a->interface == i)
+            return a;
+
+    return NULL;
+}
+
+static void new_announcement(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) {
+    AvahiAnnouncement *a;
+    GTimeVal tv;
+    gchar *t; 
+
+    g_assert(s);
+    g_assert(i);
+    g_assert(e);
+    g_assert(!e->dead);
+
+/*     g_message("NEW ANNOUNCEMENT: %s.%i [%s]", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record)); */
+/*     g_free(t); */
+    
+    if (!avahi_interface_match(i, e->interface, e->protocol) || !i->announcing || !avahi_entry_commited(e))
+        return;
+
+    /* We don't want duplicate announcements */
+    if (avahi_get_announcement(s, e, i))
+        return;
+
+    a = g_new(AvahiAnnouncement, 1);
+    a->server = s;
+    a->interface = i;
+    a->entry = e;
+
+    if ((e->flags & AVAHI_ENTRY_UNIQUE) && !(e->flags & AVAHI_ENTRY_NOPROBE))
+        a->state = AVAHI_PROBING;
+    else if (!(e->flags & AVAHI_ENTRY_NOANNOUNCE)) {
+
+        if (!e->group || e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED)
+            a->state = AVAHI_ANNOUNCING;
+        else
+            a->state = AVAHI_WAITING;
+        
+    } else
+        a->state = AVAHI_ESTABLISHED;
+
+
+    g_message("New announcement on interface %s.%i for entry [%s] state=%i", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record), a->state);
+    g_free(t);
+
+    a->n_iteration = 1;
+    a->sec_delay = 1;
+    a->time_event = NULL;
+
+    if (a->state == AVAHI_PROBING)
+        if (e->group)
+            e->group->n_probing++;
+    
+    AVAHI_LLIST_PREPEND(AvahiAnnouncement, by_interface, i->announcements, a);
+    AVAHI_LLIST_PREPEND(AvahiAnnouncement, by_entry, e->announcements, a);
+
+    if (a->state == AVAHI_PROBING) {
+        avahi_elapse_time(&tv, 0, AVAHI_PROBE_JITTER_MSEC);
+        set_timeout(a, &tv);
+    } else if (a->state == AVAHI_ANNOUNCING) {
+        avahi_elapse_time(&tv, 0, AVAHI_ANNOUNCEMENT_JITTER_MSEC);
+        set_timeout(a, &tv);
+    }
+}
+
+void avahi_announce_interface(AvahiServer *s, AvahiInterface *i) {
+    AvahiEntry *e;
+    
+    g_assert(s);
+    g_assert(i);
+
+    if (!i->announcing)
+        return;
+
+    for (e = s->entries; e; e = e->entries_next)
+        if (!e->dead)
+            new_announcement(s, i, e);
+}
+
+static void announce_walk_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
+    AvahiEntry *e = userdata;
+    
+    g_assert(m);
+    g_assert(i);
+    g_assert(e);
+    g_assert(!e->dead);
+
+    new_announcement(m->server, i, e);
+}
+
+void avahi_announce_entry(AvahiServer *s, AvahiEntry *e) {
+    g_assert(s);
+    g_assert(e);
+    g_assert(!e->dead);
+
+    avahi_interface_monitor_walk(s->monitor, e->interface, e->protocol, announce_walk_callback, e);
+}
+
+void avahi_announce_group(AvahiServer *s, AvahiEntryGroup *g) {
+    AvahiEntry *e;
+    
+    g_assert(s);
+    g_assert(g);
+
+    for (e = g->entries; e; e = e->by_group_next)
+        if (!e->dead)
+            avahi_announce_entry(s, e);
+}
+
+gboolean avahi_entry_registered(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
+    AvahiAnnouncement *a;
+
+    g_assert(s);
+    g_assert(e);
+    g_assert(i);
+    g_assert(!e->dead);
+
+    if (!(a = avahi_get_announcement(s, e, i)))
+        return FALSE;
+    
+    return a->state == AVAHI_ANNOUNCING || a->state == AVAHI_ESTABLISHED;
+}
+
+gboolean avahi_entry_registering(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
+    AvahiAnnouncement *a;
+
+    g_assert(s);
+    g_assert(e);
+    g_assert(i);
+    g_assert(!e->dead);
+
+    if (!(a = avahi_get_announcement(s, e, i)))
+        return FALSE;
+    
+    return a->state == AVAHI_PROBING || a->state == AVAHI_WAITING;
+}
+
+static AvahiRecord *make_goodbye_record(AvahiRecord *r) {
+/*     gchar *t; */
+    AvahiRecord *g;
+    
+    g_assert(r);
+
+/*     g_message("Preparing goodbye for record [%s]", t = avahi_record_to_string(r)); */
+/*     g_free(t); */
+
+    g = avahi_record_copy(r);
+    g_assert(g->ref == 1);
+    g->ttl = 0;
+
+    return g;
+}
+
+static void send_goodbye_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
+    AvahiEntry *e = userdata;
+    AvahiRecord *g;
+    
+    g_assert(m);
+    g_assert(i);
+    g_assert(e);
+    g_assert(!e->dead);
+
+    if (!avahi_interface_match(i, e->interface, e->protocol))
+        return;
+
+    if (e->flags & AVAHI_ENTRY_NOANNOUNCE)
+        return;
+
+    if (!avahi_entry_registered(m->server, e, i))
+        return;
+    
+    g = make_goodbye_record(e->record);
+    avahi_interface_post_response(i, NULL, g, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
+    avahi_record_unref(g);
+}
+    
+void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, gboolean goodbye) {
+    g_assert(s);
+    g_assert(i);
+
+/*     g_message("goodbye interface: %s.%u", i->hardware->name, i->protocol); */
+
+    if (goodbye && avahi_interface_relevant(i)) {
+        AvahiEntry *e;
+        
+        for (e = s->entries; e; e = e->entries_next)
+            if (!e->dead)
+                send_goodbye_callback(s->monitor, i, e);
+    }
+
+    while (i->announcements)
+        remove_announcement(s, i->announcements);
+
+/*     g_message("goodbye interface done: %s.%u", i->hardware->name, i->protocol); */
+
+}
+
+void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, gboolean goodbye) {
+    g_assert(s);
+    g_assert(e);
+    
+/*     g_message("goodbye entry: %p", e); */
+    
+    if (goodbye && !e->dead)
+        avahi_interface_monitor_walk(s->monitor, 0, AF_UNSPEC, send_goodbye_callback, e);
+
+    while (e->announcements)
+        remove_announcement(s, e->announcements);
+
+/*     g_message("goodbye entry done: %p", e); */
+
+}
+
+void avahi_goodbye_all(AvahiServer *s, gboolean goodbye) {
+    AvahiEntry *e;
+    
+    g_assert(s);
+
+/*     g_message("goodbye all"); */
+
+    for (e = s->entries; e; e = e->entries_next)
+        if (!e->dead)
+            avahi_goodbye_entry(s, e, goodbye);
+
+/*     g_message("goodbye all done"); */
+
+}
+
diff --git a/libavahi-core/announce.h b/libavahi-core/announce.h
new file mode 100644 (file)
index 0000000..cd96977
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef fooannouncehfoo
+#define fooannouncehfoo
+
+#include <glib.h>
+
+typedef struct _AvahiAnnouncement AvahiAnnouncement;
+
+#include "llist.h"
+#include "iface.h"
+#include "server.h"
+#include "timeeventq.h"
+
+typedef enum {
+    AVAHI_PROBING,
+    AVAHI_WAITING,         /* wait for other records in group */
+    AVAHI_ANNOUNCING,
+    AVAHI_ESTABLISHED
+} AvahiAnnouncementState;
+
+struct _AvahiAnnouncement {
+    AvahiServer *server;
+    AvahiInterface *interface;
+    AvahiEntry *entry;
+
+    AvahiTimeEvent *time_event;
+
+    AvahiAnnouncementState state;
+    guint n_iteration;
+    guint sec_delay;
+
+    AVAHI_LLIST_FIELDS(AvahiAnnouncement, by_interface);
+    AVAHI_LLIST_FIELDS(AvahiAnnouncement, by_entry);
+};
+
+void avahi_announce_interface(AvahiServer *s, AvahiInterface *i);
+void avahi_announce_entry(AvahiServer *s, AvahiEntry *e);
+void avahi_announce_group(AvahiServer *s, AvahiEntryGroup *g);
+
+void avahi_entry_group_check_probed(AvahiEntryGroup *g, gboolean immediately);
+
+gboolean avahi_entry_registered(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
+gboolean avahi_entry_registering(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
+
+void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, gboolean send);
+void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, gboolean send);
+
+void avahi_goodbye_all(AvahiServer *s, gboolean send);
+
+AvahiAnnouncement *avahi_get_announcement(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
+
+#endif
diff --git a/libavahi-core/avahi.h b/libavahi-core/avahi.h
new file mode 100644 (file)
index 0000000..1c59faf
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef fooAvahihfoo
+#define fooAvahihfoo
+
+#include <stdio.h>
+#include <glib.h>
+
+typedef struct _AvahiServer AvahiServer;
+typedef struct _AvahiEntry AvahiEntry;
+typedef struct _AvahiEntryGroup AvahiEntryGroup;
+
+#include "address.h"
+#include "rr.h"
+
+typedef enum {
+    AVAHI_ENTRY_NULL = 0,
+    AVAHI_ENTRY_UNIQUE = 1,
+    AVAHI_ENTRY_NOPROBE = 2,
+    AVAHI_ENTRY_NOANNOUNCE = 4
+} AvahiEntryFlags;
+
+typedef enum {
+    AVAHI_ENTRY_GROUP_UNCOMMITED,
+    AVAHI_ENTRY_GROUP_REGISTERING,
+    AVAHI_ENTRY_GROUP_ESTABLISHED,
+    AVAHI_ENTRY_GROUP_COLLISION
+} AvahiEntryGroupState;
+
+typedef void (*AvahiEntryGroupCallback) (AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata);
+
+AvahiServer *avahi_server_new(GMainContext *c);
+void avahi_server_free(AvahiServer* s);
+
+const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiEntryGroup *g, void **state);
+void avahi_server_dump(AvahiServer *s, FILE *f);
+
+AvahiEntryGroup *avahi_entry_group_new(AvahiServer *s, AvahiEntryGroupCallback callback, gpointer userdata);
+void avahi_entry_group_free(AvahiEntryGroup *g);
+void avahi_entry_group_commit(AvahiEntryGroup *g);
+AvahiEntryGroupState avahi_entry_group_get_state(AvahiEntryGroup *g);
+
+void avahi_server_add(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    AvahiRecord *r);
+
+void avahi_server_add_ptr(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    const gchar *dest);
+
+void avahi_server_add_address(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    AvahiAddress *a);
+
+void avahi_server_add_text(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    ... /* text records, terminated by NULL */);
+
+void avahi_server_add_text_va(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    va_list va);
+
+void avahi_server_add_text_strlst(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    AvahiStringList *strlst);
+
+void avahi_server_add_service(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    ...  /* text records, terminated by NULL */);
+
+void avahi_server_add_service_va(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    va_list va);
+
+void avahi_server_add_service_strlst(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    AvahiStringList *strlst);
+
+typedef enum {
+    AVAHI_SUBSCRIPTION_NEW,
+    AVAHI_SUBSCRIPTION_REMOVE,
+    AVAHI_SUBSCRIPTION_CHANGE
+} AvahiSubscriptionEvent;
+
+typedef struct _AvahiSubscription AvahiSubscription;
+
+typedef void (*AvahiSubscriptionCallback)(AvahiSubscription *s, AvahiRecord *record, gint interface, guchar protocol, AvahiSubscriptionEvent event, gpointer userdata);
+
+AvahiSubscription *avahi_subscription_new(AvahiServer *s, AvahiKey *key, gint interface, guchar protocol, AvahiSubscriptionCallback callback, gpointer userdata);
+void avahi_subscription_free(AvahiSubscription *s);
+
+#endif
diff --git a/libavahi-core/cache.c b/libavahi-core/cache.c
new file mode 100644 (file)
index 0000000..c2d680e
--- /dev/null
@@ -0,0 +1,346 @@
+#include <string.h>
+
+#include "util.h"
+#include "cache.h"
+
+static void remove_entry(AvahiCache *c, AvahiCacheEntry *e) {
+    AvahiCacheEntry *t;
+
+    g_assert(c);
+    g_assert(e);
+
+/*     g_message("removing from cache: %p %p", c, e); */
+
+    /* Remove from hash table */
+    t = g_hash_table_lookup(c->hash_table, e->record->key);
+    AVAHI_LLIST_REMOVE(AvahiCacheEntry, by_key, t, e);
+    if (t)
+        g_hash_table_replace(c->hash_table, t->record->key, t);
+    else
+        g_hash_table_remove(c->hash_table, e->record->key);
+
+    /* Remove from linked list */
+    AVAHI_LLIST_REMOVE(AvahiCacheEntry, entry, c->entries, e);
+        
+    if (e->time_event)
+        avahi_time_event_queue_remove(c->server->time_event_queue, e->time_event);
+
+    avahi_subscription_notify(c->server, c->interface, e->record, AVAHI_SUBSCRIPTION_REMOVE);
+
+    avahi_record_unref(e->record);
+    
+    g_free(e);
+}
+
+AvahiCache *avahi_cache_new(AvahiServer *server, AvahiInterface *iface) {
+    AvahiCache *c;
+    g_assert(server);
+
+    c = g_new(AvahiCache, 1);
+    c->server = server;
+    c->interface = iface;
+    c->hash_table = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
+
+    AVAHI_LLIST_HEAD_INIT(AvahiCacheEntry, c->entries);
+    
+    return c;
+}
+
+void avahi_cache_free(AvahiCache *c) {
+    g_assert(c);
+
+    while (c->entries)
+        remove_entry(c, c->entries);
+    
+    g_hash_table_destroy(c->hash_table);
+    
+    g_free(c);
+}
+
+AvahiCacheEntry *avahi_cache_lookup_key(AvahiCache *c, AvahiKey *k) {
+    g_assert(c);
+    g_assert(k);
+
+    g_assert(!avahi_key_is_pattern(k));
+    
+    return g_hash_table_lookup(c->hash_table, k);
+}
+
+gpointer avahi_cache_walk(AvahiCache *c, AvahiKey *pattern, AvahiCacheWalkCallback cb, gpointer userdata) {
+    gpointer ret;
+    
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(cb);
+    
+    if (avahi_key_is_pattern(pattern)) {
+        AvahiCacheEntry *e, *n;
+        
+        for (e = c->entries; e; e = n) {
+            n = e->entry_next;
+            
+            if (avahi_key_pattern_match(pattern, e->record->key))
+                if ((ret = cb(c, pattern, e, userdata)))
+                    return ret;
+        }
+        
+    } else {
+        AvahiCacheEntry *e, *n;
+
+        for (e = avahi_cache_lookup_key(c, pattern); e; e = n) {
+            n = e->by_key_next;
+                
+            if ((ret = cb(c, pattern, e, userdata)))
+                return ret;
+        }
+    }
+
+    return NULL;
+}
+
+static gpointer lookup_record_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, void *userdata) {
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+
+    if (avahi_record_equal_no_ttl(e->record, userdata))
+        return e;
+
+    return NULL;
+}
+
+AvahiCacheEntry *avahi_cache_lookup_record(AvahiCache *c, AvahiRecord *r) {
+    AvahiCacheEntry *e;
+    
+    g_assert(c);
+    g_assert(r);
+
+    return avahi_cache_walk(c, r->key, lookup_record_callback, r);
+}
+
+static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, guint percent);
+
+static void elapse_func(AvahiTimeEvent *t, void *userdata) {
+    AvahiCacheEntry *e = userdata;
+    
+    g_assert(t);
+    g_assert(e);
+
+    if (e->state == AVAHI_CACHE_FINAL) {
+        remove_entry(e->cache, e);
+        g_message("Removing entry from cache due to expiration");
+    } else {
+        guint percent = 0;
+    
+        switch (e->state) {
+            case AVAHI_CACHE_VALID:
+                e->state = AVAHI_CACHE_EXPIRY1;
+                percent = 85;
+                break;
+                
+            case AVAHI_CACHE_EXPIRY1:
+                e->state = AVAHI_CACHE_EXPIRY2;
+                percent = 90;
+                break;
+            case AVAHI_CACHE_EXPIRY2:
+                e->state = AVAHI_CACHE_EXPIRY3;
+                percent = 95;
+                break;
+                
+            case AVAHI_CACHE_EXPIRY3:
+                e->state = AVAHI_CACHE_FINAL;
+                percent = 100;
+                break;
+
+            default:
+                ;
+        }
+
+        g_assert(percent > 0);
+
+        g_message("Requesting cache entry update at %i%%.", percent);
+
+        /* Request a cache update, if we are subscribed to this entry */
+        if (avahi_is_subscribed(e->cache->server, e->record->key))
+            avahi_interface_post_query(e->cache->interface, e->record->key, TRUE);
+
+        /* Check again later */
+        next_expiry(e->cache, e, percent);
+    }
+}
+
+static void update_time_event(AvahiCache *c, AvahiCacheEntry *e) {
+    g_assert(c);
+    g_assert(e);
+    
+    if (e->time_event)
+        avahi_time_event_queue_update(c->server->time_event_queue, e->time_event, &e->expiry);
+    else
+        e->time_event = avahi_time_event_queue_add(c->server->time_event_queue, &e->expiry, elapse_func, e);
+}
+
+static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, guint percent) {
+    gulong usec;
+
+    g_assert(c);
+    g_assert(e);
+    g_assert(percent > 0 && percent <= 100);
+
+    e->expiry = e->timestamp;
+
+    usec = e->record->ttl * 10000;
+
+    /* 2% jitter */
+    usec = g_random_int_range(usec*percent, usec*(percent+2));
+    
+    g_time_val_add(&e->expiry, usec);
+    update_time_event(c, e);
+}
+
+void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const AvahiAddress *a) {
+    AvahiCacheEntry *e, *t;
+    gchar *txt;
+    
+    g_assert(c);
+    g_assert(r && r->ref >= 1);
+
+    g_message("cache update: %s", (txt = avahi_record_to_string(r)));
+    g_free(txt);
+
+    if (r->ttl == 0) {
+
+        /* This is a goodbye request */
+
+        if ((e = avahi_cache_lookup_record(c, r))) {
+
+            e->state = AVAHI_CACHE_FINAL;
+            g_get_current_time(&e->timestamp);
+            e->expiry = e->timestamp;
+            g_time_val_add(&e->expiry, 1000000); /* 1s */
+            update_time_event(c, e);
+        }
+
+    } else {
+
+        /* This is an update request */
+
+        if ((t = e = avahi_cache_lookup_key(c, r->key))) {
+        
+            if (unique) {
+                
+                /* For unique records, remove all entries but one */
+                while (e->by_key_next)
+                    remove_entry(c, e->by_key_next);
+                
+            } else {
+                
+                /* For non-unique record, look for exactly the same entry */
+                for (; e; e = e->by_key_next)
+                    if (avahi_record_equal_no_ttl(e->record, r))
+                        break;
+            }
+        }
+    
+        if (e) {
+            
+/*         g_message("found matching cache entry"); */
+            
+            /* We are the first in the linked list so let's replace the hash table key with the new one */
+            if (e->by_key_prev == NULL)
+                g_hash_table_replace(c->hash_table, r->key, e);
+            
+            /* Notify subscribers */
+            if (!avahi_record_equal_no_ttl(e->record, r))
+                avahi_subscription_notify(c->server, c->interface, r, AVAHI_SUBSCRIPTION_CHANGE);    
+            
+            /* Update the record */
+            avahi_record_unref(e->record);
+            e->record = avahi_record_ref(r);
+            
+        } else {
+            /* No entry found, therefore we create a new one */
+            
+/*         g_message("couldn't find matching cache entry"); */
+            
+            e = g_new(AvahiCacheEntry, 1);
+            e->cache = c;
+            e->time_event = NULL;
+            e->record = avahi_record_ref(r);
+
+            /* Append to hash table */
+            AVAHI_LLIST_PREPEND(AvahiCacheEntry, by_key, t, e);
+            g_hash_table_replace(c->hash_table, e->record->key, t);
+
+            /* Append to linked list */
+            AVAHI_LLIST_PREPEND(AvahiCacheEntry, entry, c->entries, e);
+
+            /* Notify subscribers */
+            avahi_subscription_notify(c->server, c->interface, e->record, AVAHI_SUBSCRIPTION_NEW);
+        } 
+        
+        e->origin = *a;
+        g_get_current_time(&e->timestamp);
+        next_expiry(c, e, 80);
+        e->state = AVAHI_CACHE_VALID;
+    }
+}
+
+static gpointer drop_key_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) {
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+
+    remove_entry(c, e);
+    return NULL;
+}
+
+void avahi_cache_drop_key(AvahiCache *c, AvahiKey *k) {
+    g_assert(c);
+    g_assert(k);
+
+    avahi_cache_walk(c, k, drop_key_callback, NULL);
+}
+
+void avahi_cache_drop_record(AvahiCache *c, AvahiRecord *r) {
+    AvahiCacheEntry *e;
+    
+    g_assert(c);
+    g_assert(r);
+
+    if ((e = avahi_cache_lookup_record(c, r))) 
+        remove_entry(c, e);
+}
+
+static void func(gpointer key, gpointer data, gpointer userdata) {
+    AvahiCacheEntry *e = data;
+    AvahiKey *k = key;
+    gchar *t;
+
+    t = avahi_record_to_string(e->record);
+    fprintf((FILE*) userdata, "%s\n", t);
+    g_free(t);
+}
+
+void avahi_cache_dump(AvahiCache *c, FILE *f) {
+    g_assert(c);
+    g_assert(f);
+
+    fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
+    g_hash_table_foreach(c->hash_table, func, f);
+}
+
+gboolean avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e) {
+    GTimeVal now;
+    guint age;
+    
+    g_assert(c);
+    g_assert(e);
+
+    g_get_current_time(&now);
+
+    age = avahi_timeval_diff(&now, &e->timestamp)/1000000;
+
+    g_message("age: %u, ttl/2: %u", age, e->record->ttl);
+    
+    return age >= e->record->ttl/2;
+}
diff --git a/libavahi-core/cache.h b/libavahi-core/cache.h
new file mode 100644 (file)
index 0000000..de0ec9f
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef foocachehfoo
+#define foocachehfoo
+
+#include <glib.h>
+
+struct _AvahiCache;
+typedef struct _AvahiCache AvahiCache;
+
+#include "prioq.h"
+#include "server.h"
+#include "llist.h"
+#include "timeeventq.h"
+
+typedef enum {
+    AVAHI_CACHE_VALID,
+    AVAHI_CACHE_EXPIRY1,
+    AVAHI_CACHE_EXPIRY2,
+    AVAHI_CACHE_EXPIRY3,
+    AVAHI_CACHE_FINAL
+} AvahiCacheEntryState;
+
+typedef struct AvahiCacheEntry AvahiCacheEntry;
+
+struct AvahiCacheEntry {
+    AvahiCache *cache;
+    AvahiRecord *record;
+    GTimeVal timestamp;
+    GTimeVal expiry;
+    
+    AvahiAddress origin;
+
+    AvahiCacheEntryState state;
+    AvahiTimeEvent *time_event;
+
+    AVAHI_LLIST_FIELDS(AvahiCacheEntry, by_key);
+    AVAHI_LLIST_FIELDS(AvahiCacheEntry, entry);
+};
+
+struct _AvahiCache {
+    AvahiServer *server;
+    
+    AvahiInterface *interface;
+    
+    GHashTable *hash_table;
+
+    AVAHI_LLIST_HEAD(AvahiCacheEntry, entries);
+};
+
+AvahiCache *avahi_cache_new(AvahiServer *server, AvahiInterface *interface);
+void avahi_cache_free(AvahiCache *c);
+
+AvahiCacheEntry *avahi_cache_lookup_key(AvahiCache *c, AvahiKey *k);
+AvahiCacheEntry *avahi_cache_lookup_record(AvahiCache *c, AvahiRecord *r);
+
+void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const AvahiAddress *a);
+
+void avahi_cache_drop_record(AvahiCache *c,  AvahiRecord *r);
+
+void avahi_cache_dump(AvahiCache *c, FILE *f);
+
+typedef gpointer AvahiCacheWalkCallback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata);
+gpointer avahi_cache_walk(AvahiCache *c, AvahiKey *pattern, AvahiCacheWalkCallback cb, gpointer userdata);
+
+gboolean avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e);
+
+#endif
diff --git a/libavahi-core/dns-test.c b/libavahi-core/dns-test.c
new file mode 100644 (file)
index 0000000..d8c7b53
--- /dev/null
@@ -0,0 +1,35 @@
+#include "dns.h"
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+    gchar t[256], *a, *b, *c, *d;
+    AvahiDnsPacket *p;
+
+    p = avahi_dns_packet_new(8000);
+
+    avahi_dns_packet_append_name(p, a = "hello.hello.hello.de.");
+    avahi_dns_packet_append_name(p, b = "this is a test.hello.de."); 
+    avahi_dns_packet_append_name(p, c = "this\\.is\\.a\\.test\\.with\\.dots.hello.de."); 
+    avahi_dns_packet_append_name(p, d = "this\\\\is another\\ \\test.hello.de."); 
+
+    avahi_hexdump(AVAHI_DNS_PACKET_DATA(p), p->size);
+
+    avahi_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    g_assert(avahi_domain_equal(a, t));
+    
+    avahi_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    g_assert(avahi_domain_equal(b, t));
+
+    avahi_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    g_assert(avahi_domain_equal(c, t));
+
+    avahi_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    g_assert(avahi_domain_equal(d, t));
+    
+    avahi_dns_packet_free(p);
+    return 0;
+}
diff --git a/libavahi-core/dns.c b/libavahi-core/dns.c
new file mode 100644 (file)
index 0000000..e485ed8
--- /dev/null
@@ -0,0 +1,749 @@
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dns.h"
+#include "util.h"
+
+AvahiDnsPacket* avahi_dns_packet_new(guint max_size) {
+    AvahiDnsPacket *p;
+
+    if (max_size <= 0)
+        max_size = AVAHI_DNS_PACKET_MAX_SIZE;
+    else if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
+        max_size = AVAHI_DNS_PACKET_HEADER_SIZE;
+    
+    p = g_malloc(sizeof(AvahiDnsPacket) + max_size);
+    p->size = p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
+    p->max_size = max_size;
+    p->name_table = NULL;
+
+    memset(AVAHI_DNS_PACKET_DATA(p), 0, p->size);
+    return p;
+}
+
+AvahiDnsPacket* avahi_dns_packet_new_query(guint max_size) {
+    AvahiDnsPacket *p;
+
+    p = avahi_dns_packet_new(max_size);
+    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+    return p;
+}
+
+AvahiDnsPacket* avahi_dns_packet_new_response(guint max_size) {
+    AvahiDnsPacket *p;
+
+    p = avahi_dns_packet_new(max_size);
+    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+    return p;
+}
+
+void avahi_dns_packet_free(AvahiDnsPacket *p) {
+    g_assert(p);
+
+    if (p->name_table)
+        g_hash_table_destroy(p->name_table);
+    
+    g_free(p);
+}
+
+void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v) {
+    g_assert(p);
+    g_assert(index < AVAHI_DNS_PACKET_HEADER_SIZE);
+    
+    ((guint16*) AVAHI_DNS_PACKET_DATA(p))[index] = g_htons(v);
+}
+
+guint16 avahi_dns_packet_get_field(AvahiDnsPacket *p, guint index) {
+    g_assert(p);
+    g_assert(index < AVAHI_DNS_PACKET_HEADER_SIZE);
+
+    return g_ntohs(((guint16*) AVAHI_DNS_PACKET_DATA(p))[index]);
+}
+
+/* Read the first label from string *name, unescape "\" and write it to dest */
+gchar *avahi_unescape_label(gchar *dest, guint size, const gchar **name) {
+    guint i = 0;
+    gchar *d;
+    
+    g_assert(dest);
+    g_assert(size > 0);
+    g_assert(name);
+    g_assert(*name);
+
+    d = dest;
+    
+    for (;;) {
+        if (i >= size)
+            return NULL;
+
+        if (**name == '.') {
+            (*name)++;
+            break;
+        }
+        
+        if (**name == 0)
+            break;
+        
+        if (**name == '\\') {
+            (*name) ++;
+            
+            if (**name == 0)
+                break;
+        }
+        
+        *(d++) = *((*name) ++);
+        i++;
+    }
+
+    g_assert(i < size);
+
+    *d = 0;
+
+    return dest;
+}
+
+guint8* avahi_dns_packet_append_name(AvahiDnsPacket *p, const gchar *name) {
+    guint8 *d, *saved_ptr = NULL;
+    guint saved_size;
+    
+    g_assert(p);
+    g_assert(name);
+
+    saved_size = p->size;
+    saved_ptr = avahi_dns_packet_extend(p, 0);
+    
+    while (*name) {
+        guint n;
+        guint8* prev;
+        const gchar *pname;
+        gchar label[64];
+
+        /* Check whether we can compress this name. */
+
+        if (p->name_table && (prev = g_hash_table_lookup(p->name_table, name))) {
+            guint index;
+            
+            g_assert(prev >= AVAHI_DNS_PACKET_DATA(p));
+            index = (guint) (prev - AVAHI_DNS_PACKET_DATA(p));
+
+            g_assert(index < p->size);
+
+            if (index < 0x4000) {
+                guint16 *t;
+                if (!(t = (guint16*) avahi_dns_packet_extend(p, sizeof(guint16))))
+                    return NULL;
+
+                *t = g_htons((0xC000 | index));
+                return saved_ptr;
+            }
+        }
+
+        pname = name;
+        
+        if (!(avahi_unescape_label(label, sizeof(label), &name)))
+            goto fail;
+
+        if (!(d = avahi_dns_packet_append_string(p, label)))
+            goto fail;
+
+        if (!p->name_table)
+            p->name_table = g_hash_table_new_full((GHashFunc) avahi_domain_hash, (GEqualFunc) avahi_domain_equal, g_free, NULL);
+
+        g_hash_table_insert(p->name_table, g_strdup(pname), d);
+    }
+
+    if (!(d = avahi_dns_packet_extend(p, 1)))
+        goto fail;
+    
+    *d = 0;
+
+    return saved_ptr;
+
+fail:
+    p->size = saved_size;
+    return NULL;
+}
+
+guint8* avahi_dns_packet_append_uint16(AvahiDnsPacket *p, guint16 v) {
+    guint8 *d;
+    g_assert(p);
+    
+    if (!(d = avahi_dns_packet_extend(p, sizeof(guint16))))
+        return NULL;
+    
+    *((guint16*) d) = g_htons(v);
+    return d;
+}
+
+guint8 *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, guint32 v) {
+    guint8 *d;
+    g_assert(p);
+
+    if (!(d = avahi_dns_packet_extend(p, sizeof(guint32))))
+        return NULL;
+    
+    *((guint32*) d) = g_htonl(v);
+
+    return d;
+}
+
+guint8 *avahi_dns_packet_append_bytes(AvahiDnsPacket  *p, gconstpointer b, guint l) {
+    guint8* d;
+
+    g_assert(p);
+    g_assert(b);
+    g_assert(l);
+
+    if (!(d = avahi_dns_packet_extend(p, l)))
+        return NULL;
+
+    memcpy(d, b, l);
+    return d;
+}
+
+guint8* avahi_dns_packet_append_string(AvahiDnsPacket *p, const gchar *s) {
+    guint8* d;
+    guint k;
+    
+    g_assert(p);
+    g_assert(s);
+
+    if ((k = strlen(s)) >= 255)
+        k = 255;
+    
+    if (!(d = avahi_dns_packet_extend(p, k+1)))
+        return NULL;
+
+    *d = (guint8) k;
+    memcpy(d+1, s, k);
+
+    return d;
+}
+
+guint8 *avahi_dns_packet_extend(AvahiDnsPacket *p, guint l) {
+    guint8 *d;
+    
+    g_assert(p);
+
+    if (p->size+l > p->max_size)
+        return NULL;
+    
+    d = AVAHI_DNS_PACKET_DATA(p) + p->size;
+    p->size += l;
+    
+    return d;
+}
+
+gint avahi_dns_packet_check_valid(AvahiDnsPacket *p) {
+    guint16 flags;
+    g_assert(p);
+
+    if (p->size < 12)
+        return -1;
+
+    flags = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS);
+
+    if (flags & AVAHI_DNS_FLAG_OPCODE || flags & AVAHI_DNS_FLAG_RCODE)
+        return -1;
+
+    return 0;
+}
+
+gint avahi_dns_packet_is_query(AvahiDnsPacket *p) {
+    g_assert(p);
+    
+    return !(avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_QR);
+}
+
+/* Read a label from a DNS packet, escape "\" and ".", append \0 */
+static gchar *escape_label(guint8* src, guint src_length, gchar **ret_name, guint *ret_name_length) {
+    gchar *r;
+
+    g_assert(src);
+    g_assert(ret_name);
+    g_assert(*ret_name);
+    g_assert(ret_name_length);
+    g_assert(*ret_name_length > 0);
+
+    r = *ret_name;
+
+    while (src_length > 0) {
+        if (*src == '.' || *src == '\\') {
+            if (*ret_name_length < 3)
+                return NULL;
+            
+            *((*ret_name) ++) = '\\';
+            (*ret_name_length) --;
+        }
+
+        if (*ret_name_length < 2)
+            return NULL;
+        
+        *((*ret_name)++) = *src;
+        (*ret_name_length) --;
+
+        src_length --;
+        src++;
+    }
+
+    **ret_name = 0;
+
+    return r;
+}
+
+static gint consume_labels(AvahiDnsPacket *p, guint index, gchar *ret_name, guint l) {
+    gint ret = 0;
+    int compressed = 0;
+    int first_label = 1;
+    g_assert(p && ret_name && l);
+    
+    for (;;) {
+        guint8 n;
+
+        if (index+1 > p->size)
+            return -1;
+
+        n = AVAHI_DNS_PACKET_DATA(p)[index];
+
+        if (!n) {
+            index++;
+            if (!compressed)
+                ret++;
+
+            if (l < 1)
+                return -1;
+            *ret_name = 0;
+            
+            return ret;
+            
+        } else if (n <= 63) {
+            /* Uncompressed label */
+            index++;
+            if (!compressed)
+                ret++;
+        
+            if (index + n > p->size)
+                return -1;
+
+            if ((guint) n + 1 > l)
+                return -1;
+
+            if (!first_label) {
+                *(ret_name++) = '.';
+                l--;
+            } else
+                first_label = 0;
+
+            if (!(escape_label(AVAHI_DNS_PACKET_DATA(p) + index, n, &ret_name, &l)))
+                return -1;
+
+            index += n;
+            
+            if (!compressed)
+                ret += n;
+        } else if ((n & 0xC0) == 0xC0) {
+            /* Compressed label */
+
+            if (index+2 > p->size)
+                return -1;
+
+            index = ((guint) (AVAHI_DNS_PACKET_DATA(p)[index] & ~0xC0)) << 8 | AVAHI_DNS_PACKET_DATA(p)[index+1];
+
+            if (!compressed)
+                ret += 2;
+            
+            compressed = 1;
+        } else
+            return -1;
+    }
+}
+
+gint avahi_dns_packet_consume_name(AvahiDnsPacket *p, gchar *ret_name, guint l) {
+    gint r;
+    
+    if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
+        return -1;
+
+    p->rindex += r;
+    return 0;
+}
+
+gint avahi_dns_packet_consume_uint16(AvahiDnsPacket *p, guint16 *ret_v) {
+    g_assert(p);
+    g_assert(ret_v);
+
+    if (p->rindex + sizeof(guint16) > p->size)
+        return -1;
+
+    *ret_v = g_ntohs(*((guint16*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex)));
+    p->rindex += sizeof(guint16);
+
+    return 0;
+}
+
+gint avahi_dns_packet_consume_uint32(AvahiDnsPacket *p, guint32 *ret_v) {
+    g_assert(p);
+    g_assert(ret_v);
+
+    if (p->rindex + sizeof(guint32) > p->size)
+        return -1;
+
+    *ret_v = g_ntohl(*((guint32*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex)));
+    p->rindex += sizeof(guint32);
+    
+    return 0;
+}
+
+gint avahi_dns_packet_consume_bytes(AvahiDnsPacket *p, gpointer ret_data, guint l) {
+    g_assert(p);
+    g_assert(ret_data);
+    g_assert(l > 0);
+    
+    if (p->rindex + l > p->size)
+        return -1;
+
+    memcpy(ret_data, AVAHI_DNS_PACKET_DATA(p) + p->rindex, l);
+    p->rindex += l;
+
+    return 0;
+}
+
+gint avahi_dns_packet_consume_string(AvahiDnsPacket *p, gchar *ret_string, guint l) {
+    guint k;
+    
+    g_assert(p);
+    g_assert(ret_string);
+    g_assert(l > 0);
+
+    if (p->rindex >= p->size)
+        return -1;
+
+    k = AVAHI_DNS_PACKET_DATA(p)[p->rindex];
+
+    if (p->rindex+1+k > p->size)
+        return -1;
+
+    if (l > k+1)
+        l = k+1;
+
+    memcpy(ret_string, AVAHI_DNS_PACKET_DATA(p)+p->rindex+1, l-1);
+    ret_string[l-1] = 0;
+
+    
+    p->rindex += 1+k;
+
+    return 0;
+    
+}
+
+gconstpointer avahi_dns_packet_get_rptr(AvahiDnsPacket *p) {
+    g_assert(p);
+    
+    if (p->rindex > p->size)
+        return NULL;
+
+    return AVAHI_DNS_PACKET_DATA(p) + p->rindex;
+}
+
+gint avahi_dns_packet_skip(AvahiDnsPacket *p, guint length) {
+    g_assert(p);
+
+    if (p->rindex + length > p->size)
+        return -1;
+
+    p->rindex += length;
+    return 0;
+}
+
+AvahiRecord* avahi_dns_packet_consume_record(AvahiDnsPacket *p, gboolean *ret_cache_flush) {
+    gchar name[257], buf[257];
+    guint16 type, class;
+    guint32 ttl;
+    guint16 rdlength;
+    gconstpointer data;
+    AvahiRecord *r = NULL;
+    gconstpointer start;
+
+    g_assert(p);
+    g_assert(ret_cache_flush);
+
+/*     g_message("consume_record()"); */
+
+    if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
+        avahi_dns_packet_consume_uint16(p, &type) < 0 ||
+        avahi_dns_packet_consume_uint16(p, &class) < 0 ||
+        avahi_dns_packet_consume_uint32(p, &ttl) < 0 ||
+        avahi_dns_packet_consume_uint16(p, &rdlength) < 0 ||
+        p->rindex + rdlength > p->size)
+        goto fail;
+
+/*     g_message("name = %s, rdlength = %u", name, rdlength); */
+
+    *ret_cache_flush = !!(class & AVAHI_DNS_CACHE_FLUSH);
+    class &= ~AVAHI_DNS_CACHE_FLUSH;
+    
+    start = avahi_dns_packet_get_rptr(p);
+    
+    r = avahi_record_new_full(name, class, type);
+    
+    switch (type) {
+        case AVAHI_DNS_TYPE_PTR:
+        case AVAHI_DNS_TYPE_CNAME:
+
+/*             g_message("ptr"); */
+            
+            if (avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
+                goto fail;
+
+            r->data.ptr.name = g_strdup(buf);
+            break;
+
+            
+        case AVAHI_DNS_TYPE_SRV:
+
+/*             g_message("srv"); */
+            
+            if (avahi_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 ||
+                avahi_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 ||
+                avahi_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 ||
+                avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
+                goto fail;
+            
+            r->data.srv.name = g_strdup(buf);
+            break;
+
+        case AVAHI_DNS_TYPE_HINFO:
+            
+/*             g_message("hinfo"); */
+
+            if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
+                goto fail;
+
+            r->data.hinfo.cpu = g_strdup(buf);
+
+            if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
+                goto fail;
+
+            r->data.hinfo.os = g_strdup(buf);
+            break;
+
+        case AVAHI_DNS_TYPE_TXT:
+
+/*             g_message("txt"); */
+
+            if (rdlength > 0) {
+                r->data.txt.string_list = avahi_string_list_parse(avahi_dns_packet_get_rptr(p), rdlength);
+                
+                if (avahi_dns_packet_skip(p, rdlength) < 0)
+                    goto fail;
+            } else
+                r->data.txt.string_list = NULL;
+            
+            break;
+
+        case AVAHI_DNS_TYPE_A:
+
+/*             g_message("A"); */
+
+            if (avahi_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(AvahiIPv4Address)) < 0)
+                goto fail;
+            
+            break;
+
+        case AVAHI_DNS_TYPE_AAAA:
+
+/*             g_message("aaaa"); */
+            
+            if (avahi_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(AvahiIPv6Address)) < 0)
+                goto fail;
+            
+            break;
+            
+        default:
+
+/*             g_message("generic"); */
+            
+            if (rdlength > 0) {
+
+                r->data.generic.data = g_memdup(avahi_dns_packet_get_rptr(p), rdlength);
+                
+                if (avahi_dns_packet_skip(p, rdlength) < 0)
+                    goto fail;
+            }
+
+            break;
+    }
+
+/*     g_message("%i == %u ?", (guint8*) avahi_dns_packet_get_rptr(p) - (guint8*) start, rdlength); */
+    
+    /* Check if we read enough data */
+    if ((guint8*) avahi_dns_packet_get_rptr(p) - (guint8*) start != rdlength)
+        goto fail;
+    
+    r->ttl = ttl;
+
+    return r;
+
+fail:
+    if (r)
+        avahi_record_unref(r);
+
+    return NULL;
+}
+
+AvahiKey* avahi_dns_packet_consume_key(AvahiDnsPacket *p, gboolean *ret_unicast_response) {
+    gchar name[256];
+    guint16 type, class;
+
+    g_assert(p);
+    g_assert(ret_unicast_response);
+
+    if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
+        avahi_dns_packet_consume_uint16(p, &type) < 0 ||
+        avahi_dns_packet_consume_uint16(p, &class) < 0)
+        return NULL;
+
+    *ret_unicast_response = !!(class & AVAHI_DNS_UNICAST_RESPONSE);
+    class &= ~AVAHI_DNS_UNICAST_RESPONSE;
+
+    return avahi_key_new(name, class, type);
+}
+
+guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean unicast_response) {
+    guint8 *t;
+    guint size;
+    
+    g_assert(p);
+    g_assert(k);
+
+    size = p->size;
+    
+    if (!(t = avahi_dns_packet_append_name(p, k->name)) ||
+        !avahi_dns_packet_append_uint16(p, k->type) ||
+        !avahi_dns_packet_append_uint16(p, k->class | (unicast_response ? AVAHI_DNS_UNICAST_RESPONSE : 0))) {
+        p->size = size;
+        return NULL;
+    }
+
+    return t;
+}
+
+guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush) {
+    guint8 *t, *l, *start;
+    guint size;
+
+    g_assert(p);
+    g_assert(r);
+
+    size = p->size;
+
+    if (!(t = avahi_dns_packet_append_name(p, r->key->name)) ||
+        !avahi_dns_packet_append_uint16(p, r->key->type) ||
+        !avahi_dns_packet_append_uint16(p, cache_flush ? (r->key->class | AVAHI_DNS_CACHE_FLUSH) : (r->key->class &~ AVAHI_DNS_CACHE_FLUSH)) ||
+        !avahi_dns_packet_append_uint32(p, r->ttl) ||
+        !(l = avahi_dns_packet_append_uint16(p, 0)))
+        goto fail;
+
+    start = avahi_dns_packet_extend(p, 0);
+
+    switch (r->key->type) {
+        
+        case AVAHI_DNS_TYPE_PTR:
+        case AVAHI_DNS_TYPE_CNAME :
+
+            if (!(avahi_dns_packet_append_name(p, r->data.ptr.name)))
+                goto fail;
+            
+            break;
+
+        case AVAHI_DNS_TYPE_SRV:
+
+            if (!avahi_dns_packet_append_uint16(p, r->data.srv.priority) ||
+                !avahi_dns_packet_append_uint16(p, r->data.srv.weight) ||
+                !avahi_dns_packet_append_uint16(p, r->data.srv.port) ||
+                !avahi_dns_packet_append_name(p, r->data.srv.name))
+                goto fail;
+
+            break;
+
+        case AVAHI_DNS_TYPE_HINFO:
+            if (!avahi_dns_packet_append_string(p, r->data.hinfo.cpu) ||
+                !avahi_dns_packet_append_string(p, r->data.hinfo.os))
+                goto fail;
+
+            break;
+
+        case AVAHI_DNS_TYPE_TXT: {
+
+            guint8 *data;
+            guint size;
+
+            size = avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
+
+/*             g_message("appending string: %u %p", size, r->data.txt.string_list); */
+
+            if (!(data = avahi_dns_packet_extend(p, size)))
+                goto fail;
+
+            avahi_string_list_serialize(r->data.txt.string_list, data, size);
+            break;
+        }
+
+
+        case AVAHI_DNS_TYPE_A:
+
+            if (!avahi_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address)))
+                goto fail;
+            
+            break;
+
+        case AVAHI_DNS_TYPE_AAAA:
+            
+            if (!avahi_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address)))
+                goto fail;
+            
+            break;
+            
+        default:
+
+            if (r->data.generic.size &&
+                avahi_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size))
+                goto fail;
+
+            break;
+    }
+
+
+
+    
+    size = avahi_dns_packet_extend(p, 0) - start;
+    g_assert(size <= 0xFFFF);
+
+/*     g_message("appended %u", size); */
+
+    * (guint16*) l = g_htons((guint16) size);
+    
+    return t;
+
+
+fail:
+    p->size = size;
+    return NULL;
+}
+
+gboolean avahi_dns_packet_is_empty(AvahiDnsPacket *p) {
+    g_assert(p);
+
+    return p->size <= AVAHI_DNS_PACKET_HEADER_SIZE;
+}
+
+guint avahi_dns_packet_space(AvahiDnsPacket *p) {
+    g_assert(p);
+
+    g_assert(p->size <= p->max_size);
+    
+    return p->max_size - p->size;
+}
diff --git a/libavahi-core/dns.h b/libavahi-core/dns.h
new file mode 100644 (file)
index 0000000..13d9278
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef foodnshfoo
+#define foodnshfoo
+
+#include <glib.h>
+
+#include "rr.h"
+
+#define AVAHI_DNS_PACKET_MAX_SIZE 9000
+#define AVAHI_DNS_PACKET_HEADER_SIZE 12
+
+typedef struct _AvahiDnsPacket {
+    guint size, rindex, max_size;
+    GHashTable *name_table; /* for name compression */
+} AvahiDnsPacket;
+
+
+#define AVAHI_DNS_PACKET_DATA(p) (((guint8*) p) + sizeof(AvahiDnsPacket))
+
+AvahiDnsPacket* avahi_dns_packet_new(guint size);
+AvahiDnsPacket* avahi_dns_packet_new_query(guint size);
+AvahiDnsPacket* avahi_dns_packet_new_response(guint size);
+
+void avahi_dns_packet_free(AvahiDnsPacket *p);
+void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v);
+guint16 avahi_dns_packet_get_field(AvahiDnsPacket *p, guint index);
+
+guint8 *avahi_dns_packet_extend(AvahiDnsPacket *p, guint l);
+
+guint8 *avahi_dns_packet_append_uint16(AvahiDnsPacket *p, guint16 v);
+guint8 *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, guint32 v);
+guint8 *avahi_dns_packet_append_name(AvahiDnsPacket *p, const gchar *name);
+guint8 *avahi_dns_packet_append_bytes(AvahiDnsPacket  *p, gconstpointer, guint l);
+guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean unicast_response);
+guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush);
+guint8* avahi_dns_packet_append_string(AvahiDnsPacket *p, const gchar *s);
+
+gint avahi_dns_packet_is_query(AvahiDnsPacket *p);
+gint avahi_dns_packet_check_valid(AvahiDnsPacket *p);
+
+gint avahi_dns_packet_consume_uint16(AvahiDnsPacket *p, guint16 *ret_v);
+gint avahi_dns_packet_consume_uint32(AvahiDnsPacket *p, guint32 *ret_v);
+gint avahi_dns_packet_consume_name(AvahiDnsPacket *p, gchar *ret_name, guint l);
+gint avahi_dns_packet_consume_bytes(AvahiDnsPacket *p, gpointer ret_data, guint l);
+AvahiKey* avahi_dns_packet_consume_key(AvahiDnsPacket *p, gboolean *ret_unicast_response);
+AvahiRecord* avahi_dns_packet_consume_record(AvahiDnsPacket *p, gboolean *ret_cache_flush);
+gint avahi_dns_packet_consume_string(AvahiDnsPacket *p, gchar *ret_string, guint l);
+
+gconstpointer avahi_dns_packet_get_rptr(AvahiDnsPacket *p);
+
+gint avahi_dns_packet_skip(AvahiDnsPacket *p, guint length);
+
+gboolean avahi_dns_packet_is_empty(AvahiDnsPacket *p);
+guint avahi_dns_packet_space(AvahiDnsPacket *p);
+
+#define AVAHI_DNS_FIELD_ID 0
+#define AVAHI_DNS_FIELD_FLAGS 1
+#define AVAHI_DNS_FIELD_QDCOUNT 2
+#define AVAHI_DNS_FIELD_ANCOUNT 3
+#define AVAHI_DNS_FIELD_NSCOUNT 4
+#define AVAHI_DNS_FIELD_ARCOUNT 5
+
+#define AVAHI_DNS_FLAG_QR (1 << 15)
+#define AVAHI_DNS_FLAG_OPCODE (15 << 11)
+#define AVAHI_DNS_FLAG_RCODE (15)
+#define AVAHI_DNS_FLAG_TC (1 << 9)
+
+#define AVAHI_DNS_FLAGS(qr, opcode, aa, tc, rd, ra, z, ad, cd, rcode) \
+        (((guint16) !!qr << 15) |  \
+         ((guint16) (opcode & 15) << 11) | \
+         ((guint16) !!aa << 10) | \
+         ((guint16) !!tc << 9) | \
+         ((guint16) !!rd << 8) | \
+         ((guint16) !!ra << 7) | \
+         ((guint16) !!ad << 5) | \
+         ((guint16) !!cd << 4) | \
+         ((guint16) (rd & 15)))
+         
+
+gchar *avahi_unescape_label(gchar *dest, guint size, const gchar **name);
+
+#endif
+
diff --git a/libavahi-core/domain-test.c b/libavahi-core/domain-test.c
new file mode 100644 (file)
index 0000000..f3deeac
--- /dev/null
@@ -0,0 +1,19 @@
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+    gchar *s;
+    
+    g_message("host name: %s", s = avahi_get_host_name());
+    g_free(s);
+
+    g_message("%s", s = avahi_normalize_name("foo.foo."));
+    g_free(s);
+    
+    g_message("%s", s = avahi_normalize_name("foo.foo."));
+    g_free(s);
+
+
+    g_message("%i", avahi_domain_equal("\\aaa bbb\\.cccc\\\\.dee.fff.", "aaa\\ bbb\\.cccc\\\\.dee.fff"));
+
+    return 0;
+}
diff --git a/libavahi-core/iface.c b/libavahi-core/iface.c
new file mode 100644 (file)
index 0000000..519a65b
--- /dev/null
@@ -0,0 +1,562 @@
+#include <string.h>
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <errno.h>
+#include <net/if.h>
+
+#include "iface.h"
+#include "netlink.h"
+#include "dns.h"
+#include "socket.h"
+#include "announce.h"
+
+static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a, int remove) {
+    g_assert(m);
+    g_assert(a);
+
+    if (!avahi_interface_address_relevant(a) || remove) {
+        if (a->entry_group) {
+            avahi_entry_group_free(a->entry_group);
+            a->entry_group = NULL;
+        }
+    } else {
+        if (!a->entry_group) {
+            a->entry_group = avahi_entry_group_new(m->server, NULL, NULL);
+            avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, AF_UNSPEC, 0, NULL, &a->address);
+            avahi_entry_group_commit(a->entry_group);
+        }
+    }
+}
+
+static void update_interface_rr(AvahiInterfaceMonitor *m, AvahiInterface *i, int remove) {
+    AvahiInterfaceAddress *a;
+    g_assert(m);
+    g_assert(i);
+
+    for (a = i->addresses; a; a = a->address_next)
+        update_address_rr(m, a, remove);
+}
+
+static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, int remove) {
+    AvahiInterface *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(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a) {
+    g_assert(m);
+    g_assert(a);
+    g_assert(a->interface);
+
+    AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a);
+
+    if (a->entry_group)
+        avahi_entry_group_free(a->entry_group);
+    
+    g_free(a);
+}
+
+static void free_interface(AvahiInterfaceMonitor *m, AvahiInterface *i, gboolean send_goodbye) {
+    g_assert(m);
+    g_assert(i);
+
+    g_message("removing interface %s.%i", i->hardware->name, i->protocol);
+    avahi_goodbye_interface(m->server, i, send_goodbye);
+    g_message("flushing...");
+    avahi_packet_scheduler_flush_responses(i->scheduler);
+    g_message("done");
+    
+    g_assert(!i->announcements);
+
+    while (i->addresses)
+        free_address(m, i->addresses);
+
+    avahi_packet_scheduler_free(i->scheduler);
+    avahi_cache_free(i->cache);
+    
+    AVAHI_LLIST_REMOVE(AvahiInterface, interface, m->interfaces, i);
+    AVAHI_LLIST_REMOVE(AvahiInterface, by_hardware, i->hardware->interfaces, i);
+    
+    g_free(i);
+}
+
+static void free_hw_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, gboolean send_goodbye) {
+    g_assert(m);
+    g_assert(hw);
+
+    while (hw->interfaces)
+        free_interface(m, hw->interfaces, send_goodbye);
+
+    AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, m->hw_interfaces, hw);
+    g_hash_table_remove(m->hash_table, &hw->index);
+
+    g_free(hw->name);
+    g_free(hw);
+}
+
+static AvahiInterfaceAddress* get_address(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *raddr) {
+    AvahiInterfaceAddress *ia;
+    
+    g_assert(m);
+    g_assert(i);
+    g_assert(raddr);
+
+    for (ia = i->addresses; ia; ia = ia->address_next)
+        if (avahi_address_cmp(&ia->address, raddr) == 0)
+            return ia;
+
+    return NULL;
+}
+
+static int netlink_list_items(AvahiNetlink *nl, guint16 type, guint *ret_seq) {
+    struct nlmsghdr *n;
+    struct rtgenmsg *gen;
+    guint8 req[1024];
+    
+    memset(&req, 0, sizeof(req));
+    n = (struct nlmsghdr*) req;
+    n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+    n->nlmsg_type = type;
+    n->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+    n->nlmsg_pid = 0;
+
+    gen = NLMSG_DATA(n);
+    memset(gen, 0, sizeof(struct rtgenmsg));
+    gen->rtgen_family = AF_UNSPEC;
+
+    return avahi_netlink_send(nl, n, ret_seq);
+}
+
+static void new_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, guchar protocol) {
+    AvahiInterface *i;
+    
+    g_assert(m);
+    g_assert(hw);
+    g_assert(protocol != AF_UNSPEC);
+
+    i = g_new(AvahiInterface, 1);
+    i->monitor = m;
+    i->hardware = hw;
+    i->protocol = protocol;
+    i->announcing = FALSE;
+
+    AVAHI_LLIST_HEAD_INIT(AvahiInterfaceAddress, i->addresses);
+    AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, i->announcements);
+
+    i->cache = avahi_cache_new(m->server, i);
+    i->scheduler = avahi_packet_scheduler_new(m->server, i);
+
+    AVAHI_LLIST_PREPEND(AvahiInterface, by_hardware, hw->interfaces, i);
+    AVAHI_LLIST_PREPEND(AvahiInterface, interface, m->interfaces, i);
+}
+
+static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i) {
+    gboolean b;
+
+    g_assert(m);
+    g_assert(i);
+
+    b = avahi_interface_relevant(i);
+
+    if (b && !i->announcing) {
+        g_message("New relevant interface %s.%i", i->hardware->name, i->protocol);
+
+        if (i->protocol == AF_INET)
+            avahi_mdns_mcast_join_ipv4 (i->hardware->index, m->server->fd_ipv4);
+        if (i->protocol == AF_INET6)
+            avahi_mdns_mcast_join_ipv6 (i->hardware->index, m->server->fd_ipv6);
+
+        i->announcing = TRUE;
+        avahi_announce_interface(m->server, i);
+    } else if (!b && i->announcing) {
+        g_message("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
+
+        avahi_goodbye_interface(m->server, i, FALSE);
+
+        if (i->protocol == AF_INET)
+            avahi_mdns_mcast_leave_ipv4 (i->hardware->index, m->server->fd_ipv4);
+        if (i->protocol == AF_INET6)
+            avahi_mdns_mcast_leave_ipv6 (i->hardware->index, m->server->fd_ipv6);
+
+        i->announcing = FALSE;
+    }
+}
+
+static void check_hw_interface_relevant(AvahiInterfaceMonitor *m, AvahiHwInterface *hw) {
+    AvahiInterface *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(AvahiNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
+    AvahiInterfaceMonitor *m = userdata;
+    
+    g_assert(m);
+    g_assert(n);
+    g_assert(m->netlink == nl);
+
+    if (n->nlmsg_type == RTM_NEWLINK) {
+        struct ifinfomsg *ifinfomsg = NLMSG_DATA(n);
+        AvahiHwInterface *hw;
+        struct rtattr *a = NULL;
+        size_t l;
+
+        if (ifinfomsg->ifi_family != AF_UNSPEC)
+            return;
+
+        if (!(hw = g_hash_table_lookup(m->hash_table, &ifinfomsg->ifi_index))) {
+            hw = g_new(AvahiHwInterface, 1);
+            hw->monitor = m;
+            hw->name = NULL;
+            hw->flags = 0;
+            hw->mtu = 1500;
+            hw->index = ifinfomsg->ifi_index;
+
+            AVAHI_LLIST_HEAD_INIT(AvahiInterface, hw->interfaces);
+            AVAHI_LLIST_PREPEND(AvahiHwInterface, hardware, m->hw_interfaces, hw);
+            
+            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);
+        }
+        
+        hw->flags = ifinfomsg->ifi_flags;
+
+        l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
+        a = IFLA_RTA(ifinfomsg);
+
+        while (RTA_OK(a, l)) {
+            switch(a->rta_type) {
+                case IFLA_IFNAME:
+                    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));
+                    hw->mtu = *((unsigned int*) RTA_DATA(a));
+                    break;
+                    
+                default:
+                    ;
+            }
+
+            a = RTA_NEXT(a, l);
+        }
+
+        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);
+        AvahiHwInterface *hw;
+        AvahiInterface *i;
+
+        if (ifinfomsg->ifi_family != AF_UNSPEC)
+            return;
+        
+        if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index)))
+            return;
+
+        update_hw_interface_rr(m, hw, TRUE);
+        free_hw_interface(m, hw, FALSE);
+        
+    } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
+
+        struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n);
+        AvahiInterface *i;
+        struct rtattr *a = NULL;
+        size_t l;
+        AvahiAddress raddr;
+        int raddr_valid = 0;
+
+        if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6)
+            return;
+
+        if (!(i = (AvahiInterface*) avahi_interface_monitor_get_interface(m, ifaddrmsg->ifa_index, ifaddrmsg->ifa_family)))
+            return;
+
+        raddr.family = ifaddrmsg->ifa_family;
+
+        l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg));
+        a = IFA_RTA(ifaddrmsg);
+
+        while (RTA_OK(a, l)) {
+            switch(a->rta_type) {
+                case IFA_ADDRESS:
+                    if ((raddr.family == AF_INET6 && RTA_PAYLOAD(a) != 16) ||
+                        (raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
+                        return;
+
+                    memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
+                    raddr_valid = 1;
+
+                    break;
+                    
+                default:
+                    ;
+            }
+            
+            a = RTA_NEXT(a, l);
+        }
+
+        
+        if (!raddr_valid)
+            return;
+
+        if (n->nlmsg_type == RTM_NEWADDR) {
+            AvahiInterfaceAddress *addr;
+            
+            if (!(addr = get_address(m, i, &raddr))) {
+                addr = g_new(AvahiInterfaceAddress, 1);
+                addr->monitor = m;
+                addr->address = raddr;
+                addr->interface = i;
+                addr->entry_group = NULL;
+
+                AVAHI_LLIST_PREPEND(AvahiInterfaceAddress, address, i->addresses, addr);
+            }
+            
+            addr->flags = ifaddrmsg->ifa_flags;
+            addr->scope = ifaddrmsg->ifa_scope;
+
+            update_address_rr(m, addr, FALSE);
+            check_interface_relevant(m, i);
+        } else {
+            AvahiInterfaceAddress *addr;
+            
+            if (!(addr = get_address(m, i, &raddr)))
+                return;
+
+            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)
+                g_warning("NETLINK: Failed to list addrs: %s", strerror(errno));
+            else
+                m->list = LIST_ADDR;
+        } else {
+            m->list = LIST_DONE;
+            g_message("Enumeration complete");
+        }
+        
+    } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
+        struct nlmsgerr *e = NLMSG_DATA (n);
+                    
+        if (e->error)
+            g_warning("NETLINK: Failed to browse: %s", strerror(-e->error));
+    }
+}
+
+AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *s) {
+    AvahiInterfaceMonitor *m = NULL;
+
+    m = g_new0(AvahiInterfaceMonitor, 1);
+    m->server = s;
+    if (!(m->netlink = avahi_netlink_new(s->context, G_PRIORITY_DEFAULT-10, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, callback, m)))
+        goto fail;
+
+    m->hash_table = g_hash_table_new(g_int_hash, g_int_equal);
+
+    AVAHI_LLIST_HEAD_INIT(AvahiInterface, m->interfaces);
+    AVAHI_LLIST_HEAD_INIT(AvahiHwInterface, m->hw_interfaces);
+
+    if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0)
+        goto fail;
+
+    m->list = LIST_IFACE;
+
+    return m;
+
+fail:
+    avahi_interface_monitor_free(m);
+    return NULL;
+}
+
+void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) {
+    g_assert(m);
+    
+    while (m->list != LIST_DONE) {
+        if (!avahi_netlink_work(m->netlink, TRUE))
+            break;
+    } 
+}
+
+void avahi_interface_monitor_free(AvahiInterfaceMonitor *m) {
+    g_assert(m);
+
+    while (m->hw_interfaces)
+        free_hw_interface(m, m->hw_interfaces, TRUE);
+
+    g_assert(!m->interfaces);
+
+    
+    if (m->netlink)
+        avahi_netlink_free(m->netlink);
+    
+    if (m->hash_table)
+        g_hash_table_destroy(m->hash_table);
+
+    g_free(m);
+}
+
+
+AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, gint index, guchar protocol) {
+    AvahiHwInterface *hw;
+    AvahiInterface *i;
+    
+    g_assert(m);
+    g_assert(index > 0);
+    g_assert(protocol != AF_UNSPEC);
+
+    if (!(hw = avahi_interface_monitor_get_hw_interface(m, index)))
+        return NULL;
+
+    for (i = hw->interfaces; i; i = i->by_hardware_next)
+        if (i->protocol == protocol)
+            return i;
+
+    return NULL;
+}
+
+AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, gint index) {
+    g_assert(m);
+    g_assert(index > 0);
+
+    return g_hash_table_lookup(m->hash_table, &index);
+}
+
+
+void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
+    g_assert(i);
+    g_assert(p);
+
+    if (avahi_interface_relevant(i)) {
+        g_message("sending on '%s.%i'", i->hardware->name, i->protocol);
+
+        if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
+            avahi_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)
+            avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p);
+    }
+}
+
+void avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean immediately) {
+    g_assert(i);
+    g_assert(key);
+
+    if (avahi_interface_relevant(i))
+        avahi_packet_scheduler_post_query(i->scheduler, key, immediately);
+}
+
+
+void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+    g_assert(i);
+    g_assert(record);
+
+    if (avahi_interface_relevant(i))
+        avahi_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately);
+}
+
+void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, gboolean immediately) {
+    g_assert(i);
+    g_assert(record);
+    
+    if (avahi_interface_relevant(i))
+        avahi_packet_scheduler_post_probe(i->scheduler, record, immediately);
+}
+
+void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f) {
+    AvahiInterface *i;
+    g_assert(m);
+
+    for (i = m->interfaces; i; i = i->interface_next) {
+        if (avahi_interface_relevant(i)) {
+            fprintf(f, "\n;;; INTERFACE %s.%i ;;;\n", i->hardware->name, i->protocol);
+            avahi_cache_dump(i->cache, f);
+        }
+    }
+    fprintf(f, "\n");
+}
+
+gboolean avahi_interface_relevant(AvahiInterface *i) {
+    g_assert(i);
+
+    return
+        (i->hardware->flags & IFF_UP) &&
+        (i->hardware->flags & IFF_RUNNING) &&
+        !(i->hardware->flags & IFF_LOOPBACK) &&
+        (i->hardware->flags & IFF_MULTICAST) &&
+        i->addresses;
+}
+
+gboolean avahi_interface_address_relevant(AvahiInterfaceAddress *a) { 
+    g_assert(a);
+
+    return a->scope == RT_SCOPE_UNIVERSE;
+}
+
+
+gboolean avahi_interface_match(AvahiInterface *i, gint index, guchar protocol) {
+    g_assert(i);
+    
+    if (index > 0 && index != i->hardware->index)
+        return FALSE;
+
+    if (protocol != AF_UNSPEC && protocol != i->protocol)
+        return FALSE;
+
+    return TRUE;
+}
+
+
+void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, gint interface, guchar protocol, AvahiInterfaceMonitorWalkCallback callback, gpointer userdata) {
+    g_assert(m);
+    g_assert(callback);
+    
+    if (interface > 0) {
+        if (protocol != AF_UNSPEC) {
+            AvahiInterface *i;
+            
+            if ((i = avahi_interface_monitor_get_interface(m, interface, protocol)))
+                callback(m, i, userdata);
+            
+        } else {
+            AvahiHwInterface *hw;
+            AvahiInterface *i;
+
+            if ((hw = avahi_interface_monitor_get_hw_interface(m, interface)))
+                for (i = hw->interfaces; i; i = i->by_hardware_next)
+                    if (avahi_interface_match(i, interface, protocol))
+                        callback(m, i, userdata);
+        }
+        
+    } else {
+        AvahiInterface *i;
+        
+        for (i = m->interfaces; i; i = i->interface_next)
+            if (avahi_interface_match(i, interface, protocol))
+                callback(m, i, userdata);
+    }
+}
diff --git a/libavahi-core/iface.h b/libavahi-core/iface.h
new file mode 100644 (file)
index 0000000..cab4949
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef fooifacehfoo
+#define fooifacehfoo
+
+#include <glib.h>
+
+typedef struct _AvahiInterfaceMonitor AvahiInterfaceMonitor;
+typedef struct _AvahiInterfaceAddress AvahiInterfaceAddress;
+typedef struct _AvahiInterface AvahiInterface;
+typedef struct _AvahiHwInterface AvahiHwInterface;
+
+#include "address.h"
+#include "server.h"
+#include "netlink.h"
+#include "cache.h"
+#include "llist.h"
+#include "psched.h"
+#include "dns.h"
+#include "announce.h"
+
+struct _AvahiInterfaceMonitor {
+    AvahiServer *server;
+    AvahiNetlink *netlink;
+    GHashTable *hash_table;
+
+    AVAHI_LLIST_HEAD(AvahiInterface, interfaces);
+    AVAHI_LLIST_HEAD(AvahiHwInterface, hw_interfaces);
+    
+    guint query_addr_seq, query_link_seq;
+    
+    enum {
+        LIST_IFACE,
+        LIST_ADDR,
+        LIST_DONE
+    } list;
+};
+
+struct _AvahiHwInterface {
+    AVAHI_LLIST_FIELDS(AvahiHwInterface, hardware);
+    AvahiInterfaceMonitor *monitor;
+
+    gchar *name;
+    gint index;
+    guint flags;
+    guint mtu;
+
+    AVAHI_LLIST_HEAD(AvahiInterface, interfaces);
+};
+
+struct _AvahiInterface {
+    AVAHI_LLIST_FIELDS(AvahiInterface, interface);
+    AVAHI_LLIST_FIELDS(AvahiInterface, by_hardware);
+    AvahiInterfaceMonitor *monitor;
+    
+    AvahiHwInterface *hardware;
+    guchar protocol;
+    gboolean announcing;
+
+    AvahiCache *cache;
+    AvahiPacketScheduler *scheduler;
+
+    AVAHI_LLIST_HEAD(AvahiInterfaceAddress, addresses);
+    AVAHI_LLIST_HEAD(AvahiAnnouncement, announcements);
+};
+
+struct _AvahiInterfaceAddress {
+    AVAHI_LLIST_FIELDS(AvahiInterfaceAddress, address);
+    AvahiInterfaceMonitor *monitor;
+    
+    guchar flags;
+    guchar scope;
+    AvahiAddress address;
+    
+    AvahiEntryGroup *entry_group;
+    AvahiInterface *interface;
+};
+
+AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *server);
+void avahi_interface_monitor_free(AvahiInterfaceMonitor *m);
+
+void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m);
+
+AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, gint index, guchar protocol);
+AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, gint index);
+
+void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p);
+
+void avahi_interface_post_query(AvahiInterface *i, AvahiKey *k, gboolean immediately);
+void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *p, gboolean immediately);
+void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+
+void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f);
+
+gboolean avahi_interface_relevant(AvahiInterface *i);
+gboolean avahi_interface_address_relevant(AvahiInterfaceAddress *a);
+
+gboolean avahi_interface_match(AvahiInterface *i, gint index, guchar protocol);
+
+typedef void (*AvahiInterfaceMonitorWalkCallback)(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata);
+    
+void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, gint index, guchar protocol, AvahiInterfaceMonitorWalkCallback callback, gpointer userdata);
+
+#endif
diff --git a/libavahi-core/llist.h b/libavahi-core/llist.h
new file mode 100644 (file)
index 0000000..16a16b6
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef foollistfoo
+#define foollistfoo
+
+#include <glib.h>
+
+/* Some macros for maintaining doubly linked lists */
+
+/* The head of the linked list. Use this in the structure that shall
+ * contain the head of the linked list */
+#define AVAHI_LLIST_HEAD(t,name) t *name
+
+/* The pointers in the linked list's items. Use this in the item structure */
+#define AVAHI_LLIST_FIELDS(t,name) t *name##_next, *name##_prev
+
+/* Initialize the list's head */
+#define AVAHI_LLIST_HEAD_INIT(t,head) do { (head) = NULL; } while(0)
+
+/* Initialize a list item */
+#define AVAHI_LLIST_INIT(t,name,item) do { \
+                               t *_item = (item); \
+                               g_assert(_item); \
+                               _item->name##_prev = _item->name##_next = NULL; \
+                               } while(0)
+
+/* Prepend an item to the list */
+#define AVAHI_LLIST_PREPEND(t,name,head,item) do { \
+                                        t **_head = &(head), *_item = (item); \
+                                        g_assert(_item); \
+                                        if ((_item->name##_next = *_head)) \
+                                           _item->name##_next->name##_prev = _item; \
+                                        _item->name##_prev = NULL; \
+                                        *_head = _item; \
+                                        } while (0)
+
+/* Remove an item from the list */
+#define AVAHI_LLIST_REMOVE(t,name,head,item) do { \
+                                    t **_head = &(head), *_item = (item); \
+                                    g_assert(_item); \
+                                    if (_item->name##_next) \
+                                       _item->name##_next->name##_prev = _item->name##_prev; \
+                                    if (_item->name##_prev) \
+                                       _item->name##_prev->name##_next = _item->name##_next; \
+                                    else {\
+                                       g_assert(*_head == _item); \
+                                       *_head = _item->name##_next; \
+                                    } \
+                                    _item->name##_next = _item->name##_prev = NULL; \
+                                    } while(0)
+
+#endif
diff --git a/libavahi-core/main.c b/libavahi-core/main.c
new file mode 100644 (file)
index 0000000..9699329
--- /dev/null
@@ -0,0 +1,74 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "avahi.h"
+
+static gboolean quit_timeout(gpointer data) {
+    g_main_loop_quit(data);
+    return FALSE;
+}
+
+static gboolean dump_timeout(gpointer data) {
+    AvahiServer *Avahi = data;
+    avahi_server_dump(Avahi, stdout);
+    return TRUE;
+}
+
+static void subscription(AvahiSubscription *s, AvahiRecord *r, gint interface, guchar protocol, AvahiSubscriptionEvent event, gpointer userdata) {
+    gchar *t;
+    
+    g_assert(s);
+    g_assert(r);
+    g_assert(interface > 0);
+    g_assert(protocol != AF_UNSPEC);
+
+    g_message("SUBSCRIPTION: record [%s] on %i.%i is %s", t = avahi_record_to_string(r), interface, protocol,
+              event == AVAHI_SUBSCRIPTION_NEW ? "new" : (event == AVAHI_SUBSCRIPTION_CHANGE ? "changed" : "removed"));
+
+    g_free(t);
+}
+
+static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
+    g_message("entry group state: %i", state);
+}
+
+int main(int argc, char *argv[]) {
+    AvahiServer *avahi;
+    gchar *r;
+    GMainLoop *loop = NULL;
+    AvahiSubscription *s;
+    AvahiKey *k;
+    AvahiEntryGroup *g;
+
+    avahi = avahi_server_new(NULL);
+
+/*     g = avahi_entry_group_new(avahi, entry_group_callback, NULL);  */
+    
+/*    avahi_server_add_text(avahi, g, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, NULL, "hallo", NULL); */
+/*      avahi_server_add_service(avahi, g, 0, AF_UNSPEC, "_http._tcp", "gurke", NULL, NULL, 80, "foo", NULL);  */
+    
+/*     avahi_entry_group_commit(g);  */
+
+    avahi_server_dump(avahi, stdout);
+    
+    
+/*     k = avahi_key_new("ecstasy.local.", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_ANY); */
+/*     s = avahi_subscription_new(avahi, k, 0, AF_UNSPEC, subscription, NULL); */
+/*     avahi_key_unref(k); */
+
+    loop = g_main_loop_new(NULL, FALSE);
+    
+  /*   g_timeout_add(1000*20, dump_timeout, Avahi); */
+/*     g_timeout_add(1000*30, quit_timeout, loop); */
+    
+    g_main_loop_run(loop);
+    g_main_loop_unref(loop);
+
+/*     avahi_subscription_free(s); */
+    /* avahi_entry_group_free(g);  */
+    avahi_server_free(avahi);
+    
+    return 0;
+}
diff --git a/libavahi-core/netlink.c b/libavahi-core/netlink.c
new file mode 100644 (file)
index 0000000..1289749
--- /dev/null
@@ -0,0 +1,162 @@
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "netlink.h"
+
+struct _AvahiNetlink {
+    GMainContext *context;
+    gint fd;
+    guint seq;
+    GPollFD poll_fd;
+    GSource *source;
+    void (*callback) (AvahiNetlink *nl, struct nlmsghdr *n, gpointer userdata);
+    gpointer userdata;
+};
+
+gboolean avahi_netlink_work(AvahiNetlink *nl, gboolean block) {
+    g_assert(nl);
+
+    for (;;) {
+        guint8 replybuf[64*1024];
+        ssize_t bytes;
+        struct nlmsghdr *p = (struct nlmsghdr *) replybuf;
+
+        if ((bytes = recv(nl->fd, replybuf, sizeof(replybuf), block ? 0 : MSG_DONTWAIT)) < 0) {
+
+            if (errno == EAGAIN || errno == EINTR)
+                break;
+
+            g_warning("NETLINK: recv() failed");
+            return FALSE;
+        }
+
+        if (nl->callback) {
+            for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
+                if (!NLMSG_OK(p, (size_t) bytes)) {
+                    g_warning("NETLINK: packet truncated");
+                    return FALSE;
+                }
+
+                nl->callback(nl, p, nl->userdata);
+            }
+        }
+
+        if (block)
+            break;
+    }
+
+    return TRUE;
+}
+
+static gboolean prepare_func(GSource *source, gint *timeout) {
+    g_assert(source);
+    g_assert(timeout);
+    
+    *timeout = -1;
+    return FALSE;
+}
+
+static gboolean check_func(GSource *source) {
+    AvahiNetlink* nl;
+    g_assert(source);
+
+    nl = *((AvahiNetlink**) (((guint8*) source) + sizeof(GSource)));
+    g_assert(nl);
+    
+    return nl->poll_fd.revents & (G_IO_IN|G_IO_HUP|G_IO_ERR);
+}
+
+static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
+    AvahiNetlink* nl;
+    g_assert(source);
+
+    nl = *((AvahiNetlink**) (((guint8*) source) + sizeof(GSource)));
+    g_assert(nl);
+    
+    return avahi_netlink_work(nl, FALSE);
+}
+
+AvahiNetlink *avahi_netlink_new(GMainContext *context, gint priority, guint32 groups, void (*cb) (AvahiNetlink *nl, struct nlmsghdr *n, gpointer userdata), gpointer userdata) {
+    int fd;
+    struct sockaddr_nl addr;
+    AvahiNetlink *nl;
+
+    static GSourceFuncs source_funcs = {
+        prepare_func,
+        check_func,
+        dispatch_func,
+        NULL,
+        NULL,
+        NULL
+    };
+    
+    g_assert(context);
+    g_assert(cb);
+
+    if ((fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
+        g_critical("NETLINK: socket(PF_NETLINK): %s", strerror(errno));
+        return NULL;
+    }
+    
+    memset(&addr, 0, sizeof(addr));
+    addr.nl_family = AF_NETLINK;
+    addr.nl_groups = groups;
+    addr.nl_pid = getpid();
+
+    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(fd);
+        g_critical("bind(): %s", strerror(errno));
+        return NULL;
+    }
+
+    nl = g_new(AvahiNetlink, 1);
+    nl->context = context;
+    g_main_context_ref(context);
+    nl->fd = fd;
+    nl->seq = 0;
+    nl->callback = cb;
+    nl->userdata = userdata;
+
+    nl->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(AvahiNetlink*));
+    *((AvahiNetlink**) (((guint8*) nl->source) + sizeof(GSource))) = nl;
+
+    g_source_set_priority(nl->source, priority);
+    
+    memset(&nl->poll_fd, 0, sizeof(GPollFD));
+    nl->poll_fd.fd = fd;
+    nl->poll_fd.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+    g_source_add_poll(nl->source, &nl->poll_fd);
+    
+    g_source_attach(nl->source, nl->context);
+    
+    return nl;
+}
+
+void avahi_netlink_free(AvahiNetlink *nl) {
+    g_assert(nl);
+    
+    g_source_destroy(nl->source);
+    g_source_unref(nl->source);
+    g_main_context_unref(nl->context);
+    close(nl->fd);
+    g_free(nl);
+}
+
+int avahi_netlink_send(AvahiNetlink *nl, struct nlmsghdr *m, guint *ret_seq) {
+    g_assert(nl);
+    g_assert(m);
+    
+    m->nlmsg_seq = nl->seq++;
+    m->nlmsg_flags |= NLM_F_ACK;
+
+    if (send(nl->fd, m, m->nlmsg_len, 0) < 0) {
+        g_warning("NETLINK: send(): %s\n", strerror(errno));
+        return -1;
+    }
+
+    if (ret_seq)
+        *ret_seq = m->nlmsg_seq;
+
+    return 0;
+}
diff --git a/libavahi-core/netlink.h b/libavahi-core/netlink.h
new file mode 100644 (file)
index 0000000..8066aae
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef foonetlinkhfoo
+#define foonetlinkhfoo
+
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+
+#include <glib.h>
+
+struct _AvahiNetlink;
+typedef struct _AvahiNetlink AvahiNetlink;
+
+AvahiNetlink *avahi_netlink_new(GMainContext *c, gint priority, guint32 groups, void (*cb) (AvahiNetlink *n, struct nlmsghdr *m, gpointer userdata), gpointer userdata);
+void avahi_netlink_free(AvahiNetlink *n);
+
+int avahi_netlink_send(AvahiNetlink *n, struct nlmsghdr *m, guint *ret_seq);
+
+gboolean avahi_netlink_work(AvahiNetlink *n, gboolean block);
+
+#endif
diff --git a/libavahi-core/prioq-test.c b/libavahi-core/prioq-test.c
new file mode 100644 (file)
index 0000000..53a8383
--- /dev/null
@@ -0,0 +1,91 @@
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "prioq.h"
+
+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(AvahiPrioQueueNode *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) {
+            printf("%i <= %i: NO\n", a, b);
+            abort();
+        }
+    }
+
+    rec(n->left);
+    rec(n->right);
+}
+
+int main(int argc, char *argv[]) {
+    AvahiPrioQueue *q, *q2;
+    gint i, prev;
+
+    q = avahi_prio_queue_new(compare_int);
+    q2 = avahi_prio_queue_new(compare_ptr);
+
+    srand(time(NULL));
+
+    for (i = 0; i < 10000; i++)
+        avahi_prio_queue_put(q2, avahi_prio_queue_put(q, GINT_TO_POINTER(random() & 0xFFFF)));
+
+    while (q2->root) {
+        rec(q->root);
+        rec(q2->root);
+
+        g_assert(q->n_nodes == q2->n_nodes);
+
+        printf("%i\n", GPOINTER_TO_INT(((AvahiPrioQueueNode*)q2->root->data)->data));
+        
+        avahi_prio_queue_remove(q, q2->root->data);
+        avahi_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); */
+/*         avahi_prio_queue_remove(q, q->root); */
+/*         g_assert(v >= prev); */
+/*         prev = v; */
+/*     } */
+
+    avahi_prio_queue_free(q);
+    return 0;
+}
diff --git a/libavahi-core/prioq.c b/libavahi-core/prioq.c
new file mode 100644 (file)
index 0000000..2eedf27
--- /dev/null
@@ -0,0 +1,359 @@
+#include "prioq.h"
+
+AvahiPrioQueue* avahi_prio_queue_new(gint (*compare) (gconstpointer a, gconstpointer b)) {
+    AvahiPrioQueue *q;
+    g_assert(compare);
+
+    q = g_new(AvahiPrioQueue, 1);
+    q->root = q->last = NULL;
+    q->n_nodes = 0;
+    q->compare = compare;
+    return q;
+}
+
+void avahi_prio_queue_free(AvahiPrioQueue *q) {
+    g_assert(q);
+
+    while (q->last)
+        avahi_prio_queue_remove(q, q->last);
+
+    g_assert(!q->n_nodes);
+    g_free(q);
+}
+
+static AvahiPrioQueueNode* get_node_at_xy(AvahiPrioQueue *q, guint x, guint y) {
+    guint r;
+    AvahiPrioQueueNode *n;
+    g_assert(q);
+
+    n = q->root;
+    g_assert(n);
+
+    for (r = 0; r < y; r++) {
+        g_assert(n);
+        
+        if ((x >> (y-r-1)) & 1)
+            n = n->right;
+        else
+            n = n->left;
+    }
+
+    g_assert(n->x == x);
+    g_assert(n->y == y);
+
+    return n;
+}
+
+static void exchange_nodes(AvahiPrioQueue *q, AvahiPrioQueueNode *a, AvahiPrioQueueNode *b) {
+    AvahiPrioQueueNode *l, *r, *p, *ap, *an, *bp, *bn;
+    gint t;
+    g_assert(q);
+    g_assert(a);
+    g_assert(b);
+    g_assert(a != b);
+
+    /* Swap positions */
+    t = a->x; a->x = b->x; b->x = t;
+    t = a->y; a->y = b->y; b->y = t;
+
+    if (a->parent == b) {
+        /* B is parent of A */
+        
+        p = b->parent;
+        b->parent = a;
+
+        if ((a->parent = p)) {
+            if (a->parent->left == b)
+                a->parent->left = a;
+            else
+                a->parent->right = a;
+        } else
+            q->root = a;
+
+        if (b->left == a) {
+            if ((b->left = a->left))
+                b->left->parent = b;
+            a->left = b;
+
+            r = a->right;
+            if ((a->right = b->right))
+                a->right->parent = a;
+            if ((b->right = r))
+                b->right->parent = b;
+            
+        } else {
+            if ((b->right = a->right))
+                b->right->parent = b;
+            a->right = b;
+
+            l = a->left;
+            if ((a->left = b->left))
+                a->left->parent = a;
+            if ((b->left = l))
+                b->left->parent = b;
+        }
+    } else if (b->parent == a) {
+        /* A ist parent of B */
+        
+        p = a->parent;
+        a->parent = b;
+
+        if ((b->parent = p)) {
+            if (b->parent->left == a)
+                b->parent->left = b;
+            else
+                b->parent->right = b;
+        } else
+            q->root = b;
+
+        if (a->left == b) {
+            if ((a->left = b->left))
+                a->left->parent = a;
+            b->left = a;
+
+            r = a->right;
+            if ((a->right = b->right))
+                a->right->parent = a;
+            if ((b->right = r))
+                b->right->parent = b;
+        } else {
+            if ((a->right = b->right))
+                a->right->parent = a;
+            b->right = a;
+
+            l = a->left;
+            if ((a->left = b->left))
+                a->left->parent = a;
+            if ((b->left = l))
+                b->left->parent = b;
+        }
+    } else {
+        AvahiPrioQueueNode *apl = NULL, *bpl = NULL;
+        
+        /* Swap parents */
+        ap = a->parent;
+        bp = b->parent;
+
+        if (ap)
+            apl = ap->left;
+        if (bp)
+            bpl = bp->left;
+        
+        if ((a->parent = bp)) {
+            if (bpl == b)
+                bp->left = a;
+            else 
+                bp->right = a;
+        } else
+            q->root = a;
+                
+        if ((b->parent = ap)) {
+            if (apl == a)
+                ap->left = b;
+            else
+                ap->right = b;
+        } else
+            q->root = b;
+
+        /* Swap children */
+        l = a->left; 
+        r = a->right; 
+
+        if ((a->left = b->left))
+            a->left->parent = a;
+
+        if ((b->left = l))
+            b->left->parent = b;
+
+        if ((a->right = b->right))
+            a->right->parent = a;
+
+        if ((b->right = r))
+            b->right->parent = b;
+    }
+    
+    /* Swap siblings */
+    ap = a->prev; an = a->next;
+    bp = b->prev; bn = b->next;
+
+    if (a->next == b) {
+        /* A is predecessor of B */
+        a->prev = b;
+        b->next = a;
+
+        if ((a->next = bn))
+            a->next->prev = a;
+        else
+            q->last = a;
+
+        if ((b->prev = ap))
+            b->prev->next = b;
+        
+    } else if (b->next == a) {
+        /* B is predecessor of A */
+        a->next = b;
+        b->prev = a;
+
+        if ((a->prev = bp))
+            a->prev->next = a;
+
+        if ((b->next = an))
+            b->next->prev = b;
+        else
+            q->last = b;
+
+    } else {
+        /* A is no neighbour of B */
+
+        if ((a->prev = bp))
+            a->prev->next = a;
+        
+        if ((a->next = bn))
+            a->next->prev = a;
+        else
+            q->last = a;
+        
+        if ((b->prev = ap))
+            b->prev->next = b;
+        
+        if ((b->next = an))
+            b->next->prev = b;
+        else
+            q->last = b;
+    }
+}
+
+/* Move a node to the correct position */
+void avahi_prio_queue_shuffle(AvahiPrioQueue *q, AvahiPrioQueueNode *n) {
+    g_assert(q);
+    g_assert(n);
+
+    /* Move up until the position is OK */
+    while (n->parent && q->compare(n->parent->data, n->data) > 0)
+        exchange_nodes(q, n, n->parent);
+
+    /* Move down until the position is OK */
+    for (;;) {
+        AvahiPrioQueueNode *min;
+
+        if (!(min = n->left)) {
+            /* No children */
+            g_assert(!n->right);
+            break;
+        }
+
+        if (n->right && q->compare(n->right->data, min->data) < 0)
+            min = n->right;
+
+        /* min now contains the smaller one of our two children */
+
+        if (q->compare(n->data, min->data) <= 0)
+            /* Order OK */
+            break;
+
+        exchange_nodes(q, n, min);
+    }
+}
+
+AvahiPrioQueueNode* avahi_prio_queue_put(AvahiPrioQueue *q, gpointer data) {
+    AvahiPrioQueueNode *n;
+    g_assert(q);
+
+    n = g_new(AvahiPrioQueueNode, 1);
+    n->queue = q;
+    n->data = data;
+
+    if (q->last) {
+        g_assert(q->root);
+        g_assert(q->n_nodes);
+         
+        n->y = q->last->y;
+        n->x = q->last->x+1;
+
+        if (n->x >= ((guint) 1 << n->y)) {
+            n->x = 0;
+            n->y++;
+        }
+
+        q->last->next = n;
+        n->prev = q->last;
+        
+        g_assert(n->y > 0);
+        n->parent = get_node_at_xy(q, n->x/2, n->y-1);
+
+        if (n->x & 1)
+            n->parent->right = n;
+        else
+            n->parent->left = n;
+    } else {
+        g_assert(!q->root);
+        g_assert(!q->n_nodes);
+        
+        n->y = n->x = 0;
+        q->root = n;
+        n->prev = n->parent = NULL;
+    }
+
+    n->next = n->left = n->right = NULL;
+    q->last = n;
+    q->n_nodes++;
+
+    avahi_prio_queue_shuffle(q, n);
+
+    return n;
+}
+
+void avahi_prio_queue_remove(AvahiPrioQueue *q, AvahiPrioQueueNode *n) {
+    g_assert(q);
+    g_assert(n);
+
+    if (n != q->last) {
+        AvahiPrioQueueNode *replacement = q->last;
+        exchange_nodes(q, replacement, n);
+        avahi_prio_queue_remove(q, n);
+        avahi_prio_queue_shuffle(q, replacement);
+        return;
+    }
+
+    g_assert(n == q->last);
+    g_assert(!n->next);
+    g_assert(!n->left);
+    g_assert(!n->right);
+
+    q->last = n->prev;
+    
+    if (n->prev) {
+        n->prev->next = NULL;
+        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 {
+            g_assert(n->parent->right == n);
+            g_assert(n->parent->left != NULL);
+            n->parent->right = NULL;
+        }
+    } else {
+        g_assert(q->root == n);
+        g_assert(!n->prev);
+        g_assert(q->n_nodes == 1);
+        q->root = NULL;
+    }
+
+    g_free(n);
+
+    g_assert(q->n_nodes > 0);
+    q->n_nodes--;
+}
+
diff --git a/libavahi-core/prioq.h b/libavahi-core/prioq.h
new file mode 100644 (file)
index 0000000..6b5babb
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef fooprioqhfoo
+#define fooprioqhfoo
+
+#include <glib.h>
+
+struct _AvahiPrioQueue;
+typedef struct _AvahiPrioQueue AvahiPrioQueue;
+
+struct _AvahiPrioQueueNode;
+typedef struct _AvahiPrioQueueNode AvahiPrioQueueNode;
+
+struct _AvahiPrioQueue {
+    AvahiPrioQueueNode *root, *last;
+    
+    guint n_nodes;
+    gint (*compare) (gconstpointer a, gconstpointer b);
+};
+
+struct _AvahiPrioQueueNode {
+    AvahiPrioQueue *queue;
+    gpointer data;
+    guint x, y;
+
+    AvahiPrioQueueNode *left, *right, *parent, *next, *prev;
+};
+
+AvahiPrioQueue* avahi_prio_queue_new(gint (*compare) (gconstpointer a, gconstpointer b));
+void avahi_prio_queue_free(AvahiPrioQueue *q);
+
+AvahiPrioQueueNode* avahi_prio_queue_put(AvahiPrioQueue *q, gpointer data);
+void avahi_prio_queue_remove(AvahiPrioQueue *q, AvahiPrioQueueNode *n);
+
+void avahi_prio_queue_shuffle(AvahiPrioQueue *q, AvahiPrioQueueNode *n);
+
+#endif
diff --git a/libavahi-core/psched.c b/libavahi-core/psched.c
new file mode 100644 (file)
index 0000000..faa2fa9
--- /dev/null
@@ -0,0 +1,715 @@
+#include <string.h>
+
+#include "util.h"
+#include "psched.h"
+
+#define AVAHI_QUERY_HISTORY_MSEC 100
+#define AVAHI_QUERY_DEFER_MSEC 100
+#define AVAHI_RESPONSE_HISTORY_MSEC 700
+#define AVAHI_RESPONSE_DEFER_MSEC 20
+#define AVAHI_RESPONSE_JITTER_MSEC 100
+#define AVAHI_PROBE_DEFER_MSEC 70
+
+AvahiPacketScheduler *avahi_packet_scheduler_new(AvahiServer *server, AvahiInterface *i) {
+    AvahiPacketScheduler *s;
+
+    g_assert(server);
+    g_assert(i);
+
+    s = g_new(AvahiPacketScheduler, 1);
+    s->server = server;
+    s->interface = i;
+
+    AVAHI_LLIST_HEAD_INIT(AvahiQueryJob, s->query_jobs);
+    AVAHI_LLIST_HEAD_INIT(AvahiResponseJob, s->response_jobs);
+    AVAHI_LLIST_HEAD_INIT(AvahiKnownAnswer, s->known_answers);
+    AVAHI_LLIST_HEAD_INIT(AvahiProbeJob, s->probe_jobs);
+    
+    return s;
+}
+
+static void query_job_free(AvahiPacketScheduler *s, AvahiQueryJob *qj) {
+    g_assert(qj);
+
+    if (qj->time_event)
+        avahi_time_event_queue_remove(qj->scheduler->server->time_event_queue, qj->time_event);
+
+    AVAHI_LLIST_REMOVE(AvahiQueryJob, jobs, s->query_jobs, qj);
+    
+    avahi_key_unref(qj->key);
+    g_free(qj);
+}
+
+static void response_job_free(AvahiPacketScheduler *s, AvahiResponseJob *rj) {
+    g_assert(rj);
+
+    if (rj->time_event)
+        avahi_time_event_queue_remove(rj->scheduler->server->time_event_queue, rj->time_event);
+
+    AVAHI_LLIST_REMOVE(AvahiResponseJob, jobs, s->response_jobs, rj);
+
+    avahi_record_unref(rj->record);
+    g_free(rj);
+}
+
+static void probe_job_free(AvahiPacketScheduler *s, AvahiProbeJob *pj) {
+    g_assert(pj);
+
+    if (pj->time_event)
+        avahi_time_event_queue_remove(pj->scheduler->server->time_event_queue, pj->time_event);
+
+    AVAHI_LLIST_REMOVE(AvahiProbeJob, jobs, s->probe_jobs, pj);
+
+    avahi_record_unref(pj->record);
+    g_free(pj);
+}
+
+void avahi_packet_scheduler_free(AvahiPacketScheduler *s) {
+    AvahiQueryJob *qj;
+    AvahiResponseJob *rj;
+    AvahiProbeJob *pj;
+    AvahiTimeEvent *e;
+
+    g_assert(s);
+
+    g_assert(!s->known_answers);
+    
+    while ((qj = s->query_jobs))
+        query_job_free(s, qj);
+    while ((rj = s->response_jobs))
+        response_job_free(s, rj);
+    while ((pj = s->probe_jobs))
+        probe_job_free(s, pj);
+
+    g_free(s);
+}
+
+static gpointer known_answer_walk_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) {
+    AvahiPacketScheduler *s = userdata;
+    AvahiKnownAnswer *ka;
+    
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+    g_assert(s);
+
+    if (avahi_cache_entry_half_ttl(c, e))
+        return NULL;
+    
+    ka = g_new0(AvahiKnownAnswer, 1);
+    ka->scheduler = s;
+    ka->record = avahi_record_ref(e->record);
+
+    AVAHI_LLIST_PREPEND(AvahiKnownAnswer, known_answer, s->known_answers, ka);
+    return NULL;
+}
+
+static guint8* packet_add_query_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiQueryJob *qj) {
+    guint8 *d;
+
+    g_assert(s);
+    g_assert(p);
+    g_assert(qj);
+
+    if ((d = avahi_dns_packet_append_key(p, qj->key, FALSE))) {
+        GTimeVal tv;
+
+        qj->done = 1;
+
+        /* Drop query after some time from history */
+        avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0);
+        avahi_time_event_queue_update(s->server->time_event_queue, qj->time_event, &tv);
+
+        g_get_current_time(&qj->delivery);
+
+        /* Add all matching known answers to the list */
+        avahi_cache_walk(s->interface->cache, qj->key, known_answer_walk_callback, s);
+    }
+
+    return d;
+}
+
+static void append_known_answers_and_send(AvahiPacketScheduler *s, AvahiDnsPacket *p) {
+    AvahiKnownAnswer *ka;
+    guint n;
+    g_assert(s);
+    g_assert(p);
+
+    n = 0;
+    
+    while ((ka = s->known_answers)) {
+
+        while (!avahi_dns_packet_append_record(p, ka->record, FALSE)) {
+
+            g_assert(!avahi_dns_packet_is_empty(p));
+
+            avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) | AVAHI_DNS_FLAG_TC);
+            avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ANCOUNT, n);
+            avahi_interface_send_packet(s->interface, p);
+            avahi_dns_packet_free(p);
+
+            p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+            n = 0;
+        }
+
+        AVAHI_LLIST_REMOVE(AvahiKnownAnswer, known_answer, s->known_answers, ka);
+        avahi_record_unref(ka->record);
+        g_free(ka);
+        
+        n++;
+    }
+    
+    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ANCOUNT, n);
+    avahi_interface_send_packet(s->interface, p);
+    avahi_dns_packet_free(p);
+}
+
+static void query_elapse(AvahiTimeEvent *e, gpointer data) {
+    AvahiQueryJob *qj = data;
+    AvahiPacketScheduler *s;
+    AvahiDnsPacket *p;
+    guint n;
+    guint8 *d;
+
+    g_assert(qj);
+    s = qj->scheduler;
+
+    if (qj->done) {
+        /* Lets remove it  from the history */
+        query_job_free(s, qj);
+        return;
+    }
+
+    g_assert(!s->known_answers);
+    
+    p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+    d = packet_add_query_job(s, p, qj);
+    g_assert(d);
+    n = 1;
+
+    /* Try to fill up packet with more queries, if available */
+    for (qj = s->query_jobs; qj; qj = qj->jobs_next) {
+
+        if (qj->done)
+            continue;
+
+        if (!packet_add_query_job(s, p, qj))
+            break;
+
+        n++;
+    }
+
+    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, n);
+
+    /* Now add known answers */
+    append_known_answers_and_send(s, p);
+}
+
+AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) {
+    AvahiQueryJob *qj;
+    
+    g_assert(s);
+    g_assert(key);
+
+    qj = g_new(AvahiQueryJob, 1);
+    qj->scheduler = s;
+    qj->key = avahi_key_ref(key);
+    qj->done = FALSE;
+    qj->time_event = NULL;
+    
+    AVAHI_LLIST_PREPEND(AvahiQueryJob, jobs, s->query_jobs, qj);
+
+    return qj;
+}
+
+void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) {
+    GTimeVal tv;
+    AvahiQueryJob *qj;
+    
+    g_assert(s);
+    g_assert(key);
+
+    avahi_elapse_time(&tv, immediately ? 0 : AVAHI_QUERY_DEFER_MSEC, 0);
+
+    for (qj = s->query_jobs; qj; qj = qj->jobs_next) {
+
+        if (avahi_key_equal(qj->key, key)) {
+
+            glong d = avahi_timeval_diff(&tv, &qj->delivery);
+
+            /* Duplicate questions suppression */
+            if (d >= 0 && d <= AVAHI_QUERY_HISTORY_MSEC*1000) {
+                g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
+                return;
+            }
+            
+            query_job_free(s, qj);
+            break;
+        }
+
+    }
+    
+    qj = query_job_new(s, key);
+    qj->delivery = tv;
+    qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &qj->delivery, query_elapse, qj);
+}
+
+static guint8* packet_add_response_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) {
+    guint8 *d;
+
+    g_assert(s);
+    g_assert(p);
+    g_assert(rj);
+
+    if ((d = avahi_dns_packet_append_record(p, rj->record, rj->flush_cache))) {
+        GTimeVal tv;
+
+        rj->done = 1;
+
+        /* Drop response after some time from history */
+        avahi_elapse_time(&tv, AVAHI_RESPONSE_HISTORY_MSEC, 0);
+        avahi_time_event_queue_update(s->server->time_event_queue, rj->time_event, &tv);
+
+        g_get_current_time(&rj->delivery);
+    }
+
+    return d;
+}
+
+static void send_response_packet(AvahiPacketScheduler *s, AvahiResponseJob *rj) {
+    AvahiDnsPacket *p;
+    guint n;
+
+    g_assert(s);
+
+    p = avahi_dns_packet_new_response(s->interface->hardware->mtu - 200);
+    n = 0;
+
+    /* If a job was specified, put it in the packet. */
+    if (rj) {
+        guint8 *d;
+        d = packet_add_response_job(s, p, rj);
+        g_assert(d);
+        n++;
+    }
+
+    /* Try to fill up packet with more responses, if available */
+    for (rj = s->response_jobs; rj; rj = rj->jobs_next) {
+
+        if (rj->done)
+            continue;
+
+        if (!packet_add_response_job(s, p, rj))
+            break;
+
+        n++;
+    }
+
+    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ANCOUNT, n);
+    avahi_interface_send_packet(s->interface, p);
+    avahi_dns_packet_free(p);
+}
+
+static void response_elapse(AvahiTimeEvent *e, gpointer data) {
+    AvahiResponseJob *rj = data;
+    AvahiPacketScheduler *s;
+
+    g_assert(rj);
+    s = rj->scheduler;
+
+    if (rj->done) {
+        /* Lets remove it  from the history */
+        response_job_free(s, rj);
+        return;
+    }
+
+    send_response_packet(s, rj);
+}
+
+static AvahiResponseJob* look_for_response(AvahiPacketScheduler *s, AvahiRecord *record) {
+    AvahiResponseJob *rj;
+
+    g_assert(s);
+    g_assert(record);
+
+    for (rj = s->response_jobs; rj; rj = rj->jobs_next)
+        if (avahi_record_equal_no_ttl(rj->record, record))
+            return rj;
+
+    return NULL;
+}
+
+static AvahiResponseJob* response_job_new(AvahiPacketScheduler *s, AvahiRecord *record) {
+    AvahiResponseJob *rj;
+    
+    g_assert(s);
+    g_assert(record);
+
+    rj = g_new(AvahiResponseJob, 1);
+    rj->scheduler = s;
+    rj->record = avahi_record_ref(record);
+    rj->done = FALSE;
+    rj->time_event = NULL;
+    rj->address_valid = FALSE;
+    rj->flush_cache = FALSE;
+    
+    AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->response_jobs, rj);
+
+    return rj;
+}
+
+void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+    AvahiResponseJob *rj;
+    GTimeVal tv;
+    gchar *t;
+    
+    g_assert(s);
+    g_assert(record);
+
+    g_assert(!avahi_key_is_pattern(record->key));
+    
+    avahi_elapse_time(&tv, immediately ? 0 : AVAHI_RESPONSE_DEFER_MSEC, immediately ? 0 : AVAHI_RESPONSE_JITTER_MSEC);
+    
+    /* Don't send out duplicates */
+    
+    if ((rj = look_for_response(s, record))) {
+        glong d;
+
+        d = avahi_timeval_diff(&tv, &rj->delivery);
+        
+        /* If there's already a matching packet in our history or in
+         * the schedule, we do nothing. */
+        if (!!record->ttl == !!rj->record->ttl &&
+            d >= 0 && d <= AVAHI_RESPONSE_HISTORY_MSEC*1000) {
+            g_message("WARNING! DUPLICATE RESPONSE SUPPRESSION ACTIVE!");
+
+            /* This job is no longer specific to a single querier, so
+             * make sure it isn't suppressed by known answer
+             * suppresion */
+
+            if (rj->address_valid && (!a || avahi_address_cmp(a, &rj->address) != 0))
+                rj->address_valid = FALSE;
+
+            rj->flush_cache = flush_cache;
+            
+            return;
+        }
+
+        /* Either one was a goodbye packet, but the other was not, so
+         * let's drop the older one. */
+        response_job_free(s, rj);
+    }
+
+/*     g_message("ACCEPTED NEW RESPONSE [%s]", t = avahi_record_to_string(record)); */
+/*     g_free(t); */
+
+    /* Create a new job and schedule it */
+    rj = response_job_new(s, record);
+    rj->flush_cache = flush_cache;
+    rj->delivery = tv;
+    rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &rj->delivery, response_elapse, rj);
+
+    /* Store the address of the host this messages is intended to, so
+       that we can drop this job in case a truncated message with
+       known answer suppresion entries is recieved */
+
+    if ((rj->address_valid = !!a))
+        rj->address = *a;
+}
+
+void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) {
+    GTimeVal tv;
+    AvahiQueryJob *qj;
+    
+    g_assert(s);
+    g_assert(key);
+
+    /* This function is called whenever an incoming query was
+     * receieved. We drop all scheduled queries which match here. The
+     * keyword is "DUPLICATE QUESTION SUPPRESION". */
+
+    for (qj = s->query_jobs; qj; qj = qj->jobs_next)
+        if (avahi_key_equal(qj->key, key)) {
+
+            if (qj->done)
+                return;
+
+            goto mark_done;
+        }
+
+
+    /* No matching job was found. Add the query to the history */
+    qj = query_job_new(s, key);
+
+mark_done:
+    qj->done = TRUE;
+
+    /* Drop the query after some time */
+    avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0);
+    qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, query_elapse, qj);
+
+    g_get_current_time(&qj->delivery);
+}
+
+void response_job_set_elapse_time(AvahiPacketScheduler *s, AvahiResponseJob *rj, guint msec, guint jitter) {
+    GTimeVal tv;
+
+    g_assert(s);
+    g_assert(rj);
+
+    avahi_elapse_time(&tv, msec, jitter);
+
+    if (rj->time_event)
+        avahi_time_event_queue_update(s->server->time_event_queue, rj->time_event, &tv);
+    else
+        rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, response_elapse, rj);
+    
+}
+
+void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record) {
+    AvahiResponseJob *rj;
+    
+    g_assert(s);
+    g_assert(record);
+
+    /* This function is called whenever an incoming response was
+     * receieved. We drop all scheduled responses which match
+     * here. The keyword is "DUPLICATE ANSWER SUPPRESION". */
+    
+    for (rj = s->response_jobs; rj; rj = rj->jobs_next)
+        if (avahi_record_equal_no_ttl(rj->record, record)) {
+
+            if (rj->done) {
+
+                if (!!record->ttl == !!rj->record->ttl) {
+                    /* An entry like this is already in our history,
+                     * so let's get out of here! */
+                    
+                    return;
+                    
+                } else {
+                    /* Either one was a goodbye packet but other was
+                     * none. We remove the history entry, and add a
+                     * new one */
+                    
+                    response_job_free(s, rj);
+                    break;
+                }
+        
+            } else {
+
+                if (!!record->ttl == !!rj->record->ttl) {
+
+                    /* The incoming packet matches our scheduled
+                     * record, so let's mark that one as done */
+
+                    goto mark_done;
+                    
+                } else {
+
+                    /* Either one was a goodbye packet but other was
+                     * none. We ignore the incoming packet. */
+
+                    return;
+                }
+            }
+        }
+
+    /* No matching job was found. Add the query to the history */
+    rj = response_job_new(s, record);
+
+mark_done:
+    rj->done = TRUE;
+                    
+    /* Drop response after 500ms from history */
+    response_job_set_elapse_time(s, rj, AVAHI_RESPONSE_HISTORY_MSEC, 0);
+
+    g_get_current_time(&rj->delivery);
+}
+
+void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *a) {
+    AvahiResponseJob *rj;
+    
+    g_assert(s);
+    g_assert(record);
+    g_assert(a);
+
+    for (rj = s->response_jobs; rj; rj = rj->jobs_next) {
+
+        g_assert(record->ttl > 0);
+        g_assert(rj->record->ttl/2);
+        
+        if (avahi_record_equal_no_ttl(rj->record, record))
+            if (rj->address_valid)
+                if (avahi_address_cmp(&rj->address, a))
+                    if (record->ttl >= rj->record->ttl/2) {
+
+            /* Let's suppress it */
+
+            response_job_free(s, rj);
+            break;
+        }
+    }
+}
+
+void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s) {
+    AvahiResponseJob *rj;
+    
+    g_assert(s);
+
+    /* Send all scheduled responses, ignoring the scheduled time */
+    
+    for (rj = s->response_jobs; rj; rj = rj->jobs_next)
+        if (!rj->done)
+            send_response_packet(s, rj);
+}
+
+static AvahiProbeJob* probe_job_new(AvahiPacketScheduler *s, AvahiRecord *record) {
+    AvahiProbeJob *pj;
+    
+    g_assert(s);
+    g_assert(record);
+
+    pj = g_new(AvahiProbeJob, 1);
+    pj->scheduler = s;
+    pj->record = avahi_record_ref(record);
+    pj->time_event = NULL;
+    pj->chosen = FALSE;
+    
+    AVAHI_LLIST_PREPEND(AvahiProbeJob, jobs, s->probe_jobs, pj);
+
+    return pj;
+}
+
+static guint8* packet_add_probe_query(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiProbeJob *pj) {
+    guint size;
+    guint8 *ret;
+    AvahiKey *k;
+
+    g_assert(s);
+    g_assert(p);
+    g_assert(pj);
+
+    g_assert(!pj->chosen);
+    
+    /* Estimate the size for this record */
+    size =
+        avahi_key_get_estimate_size(pj->record->key) +
+        avahi_record_get_estimate_size(pj->record);
+
+    /* Too large */
+    if (size > avahi_dns_packet_space(p))
+        return NULL;
+
+    /* Create the probe query */
+    k = avahi_key_new(pj->record->key->name, pj->record->key->class, AVAHI_DNS_TYPE_ANY);
+    ret = avahi_dns_packet_append_key(p, k, FALSE);
+    g_assert(ret);
+
+    /* Mark this job for addition to the packet */
+    pj->chosen = TRUE;
+
+    /* Scan for more jobs whith matching key pattern */
+    for (pj = s->probe_jobs; pj; pj = pj->jobs_next) {
+        if (pj->chosen)
+            continue;
+
+        /* Does the record match the probe? */
+        if (k->class != pj->record->key->class || !avahi_domain_equal(k->name, pj->record->key->name))
+            continue;
+        
+        /* This job wouldn't fit in */
+        if (avahi_record_get_estimate_size(pj->record) > avahi_dns_packet_space(p))
+            break;
+
+        /* Mark this job for addition to the packet */
+        pj->chosen = TRUE;
+    }
+
+    avahi_key_unref(k);
+            
+    return ret;
+}
+
+static void probe_elapse(AvahiTimeEvent *e, gpointer data) {
+    AvahiProbeJob *pj = data, *next;
+    AvahiPacketScheduler *s;
+    AvahiDnsPacket *p;
+    guint n;
+    guint8 *d;
+
+    g_assert(pj);
+    s = pj->scheduler;
+
+    p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+
+    /* Add the import probe */
+    if (!packet_add_probe_query(s, p, pj)) {
+        g_warning("Record too large! ---");
+        avahi_dns_packet_free(p);
+        return;
+    }
+
+    n = 1;
+    
+    /* Try to fill up packet with more probes, if available */
+    for (pj = s->probe_jobs; pj; pj = pj->jobs_next) {
+
+        if (pj->chosen)
+            continue;
+        
+        if (!packet_add_probe_query(s, p, pj))
+            break;
+        
+        n++;
+    }
+
+    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, n);
+
+    n = 0;
+
+    /* Now add the chosen records to the authorative section */
+    for (pj = s->probe_jobs; pj; pj = next) {
+
+        next = pj->jobs_next;
+
+        if (!pj->chosen)
+            continue;
+
+        if (!avahi_dns_packet_append_record(p, pj->record, TRUE)) {
+            g_warning("Bad probe size estimate!");
+
+            /* Unmark all following jobs */
+            for (; pj; pj = pj->jobs_next)
+                pj->chosen = FALSE;
+            
+            break;
+        }
+
+        probe_job_free(s, pj);
+        
+        n ++;
+    }
+    
+    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_NSCOUNT, n);
+
+    /* Send it now */
+    avahi_interface_send_packet(s->interface, p);
+    avahi_dns_packet_free(p);
+}
+
+void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately) {
+    AvahiProbeJob *pj;
+    GTimeVal tv;
+    
+    g_assert(s);
+    g_assert(record);
+    g_assert(!avahi_key_is_pattern(record->key));
+    
+    avahi_elapse_time(&tv, immediately ? 0 : AVAHI_PROBE_DEFER_MSEC, 0);
+
+    /* Create a new job and schedule it */
+    pj = probe_job_new(s, record);
+    pj->delivery = tv;
+    pj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &pj->delivery, probe_elapse, pj);
+}
diff --git a/libavahi-core/psched.h b/libavahi-core/psched.h
new file mode 100644 (file)
index 0000000..8f5e77c
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef foopschedhfoo
+#define foopschedhfoo
+
+typedef struct _AvahiQueryJob AvahiQueryJob;
+typedef struct _AvahiResponseJob AvahiResponseJob;
+typedef struct _AvahiPacketScheduler AvahiPacketScheduler;
+typedef struct _AvahiKnownAnswer AvahiKnownAnswer;
+typedef struct _AvahiProbeJob AvahiProbeJob;
+
+#include "timeeventq.h"
+#include "rr.h"
+#include "llist.h"
+#include "iface.h"
+
+struct _AvahiQueryJob {
+    AvahiPacketScheduler *scheduler;
+    AvahiTimeEvent *time_event;
+    AvahiKey *key;
+    gboolean done;
+    GTimeVal delivery;
+    AVAHI_LLIST_FIELDS(AvahiQueryJob, jobs);
+};
+
+struct _AvahiResponseJob {
+    AvahiPacketScheduler *scheduler;
+    AvahiTimeEvent *time_event;
+    AvahiRecord *record;
+    AvahiAddress address;
+    gboolean address_valid;
+    gboolean done;
+    GTimeVal delivery;
+    gboolean flush_cache;
+    AVAHI_LLIST_FIELDS(AvahiResponseJob, jobs);
+};
+
+struct _AvahiKnownAnswer {
+    AvahiPacketScheduler *scheduler;
+    AvahiRecord *record;
+
+    AVAHI_LLIST_FIELDS(AvahiKnownAnswer, known_answer);
+};
+
+struct _AvahiProbeJob {
+    AvahiPacketScheduler *scheduler;
+    AvahiTimeEvent *time_event;
+    AvahiRecord *record;
+
+    gboolean chosen; /* Use for packet assembling */
+    GTimeVal delivery;
+    
+    AVAHI_LLIST_FIELDS(AvahiProbeJob, jobs);
+};
+
+struct _AvahiPacketScheduler {
+    AvahiServer *server;
+    
+    AvahiInterface *interface;
+
+    AVAHI_LLIST_HEAD(AvahiQueryJob, query_jobs);
+    AVAHI_LLIST_HEAD(AvahiResponseJob, response_jobs);
+    AVAHI_LLIST_HEAD(AvahiKnownAnswer, known_answers);
+    AVAHI_LLIST_HEAD(AvahiProbeJob, probe_jobs);
+};
+
+AvahiPacketScheduler *avahi_packet_scheduler_new(AvahiServer *server, AvahiInterface *i);
+void avahi_packet_scheduler_free(AvahiPacketScheduler *s);
+
+void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately);
+void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately);
+
+void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key);
+void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record);
+void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *a);
+
+void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s);
+
+#endif
diff --git a/libavahi-core/rr.c b/libavahi-core/rr.c
new file mode 100644 (file)
index 0000000..f4102dd
--- /dev/null
@@ -0,0 +1,556 @@
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "util.h"
+#include "rr.h"
+#include "dns.h"
+
+AvahiKey *avahi_key_new(const gchar *name, guint16 class, guint16 type) {
+    AvahiKey *k;
+    g_assert(name);
+
+    k = g_new(AvahiKey, 1);
+    k->ref = 1;
+    k->name = avahi_normalize_name(name);    
+    k->class = class;
+    k->type = type;
+
+/*     g_message("%p %% ref=1", k); */
+    
+    return k;
+}
+
+AvahiKey *avahi_key_ref(AvahiKey *k) {
+    g_assert(k);
+    g_assert(k->ref >= 1);
+
+    k->ref++;
+
+/*     g_message("%p ++ ref=%i", k, k->ref); */
+
+    return k;
+}
+
+void avahi_key_unref(AvahiKey *k) {
+    g_assert(k);
+    g_assert(k->ref >= 1);
+
+/*     g_message("%p -- ref=%i", k, k->ref-1); */
+    
+    if ((--k->ref) <= 0) {
+        g_free(k->name);
+        g_free(k);
+    }
+}
+
+AvahiRecord *avahi_record_new(AvahiKey *k) {
+    AvahiRecord *r;
+    
+    g_assert(k);
+    
+    r = g_new(AvahiRecord, 1);
+    r->ref = 1;
+    r->key = avahi_key_ref(k);
+
+    memset(&r->data, 0, sizeof(r->data));
+
+    r->ttl = AVAHI_DEFAULT_TTL;
+
+    return r;
+}
+
+AvahiRecord *avahi_record_new_full(const gchar *name, guint16 class, guint16 type) {
+    AvahiRecord *r;
+    AvahiKey *k;
+
+    g_assert(name);
+    
+    k = avahi_key_new(name, class, type);
+    r = avahi_record_new(k);
+    avahi_key_unref(k);
+
+    return r;
+}
+
+AvahiRecord *avahi_record_ref(AvahiRecord *r) {
+    g_assert(r);
+    g_assert(r->ref >= 1);
+
+    r->ref++;
+    return r;
+}
+
+void avahi_record_unref(AvahiRecord *r) {
+    g_assert(r);
+    g_assert(r->ref >= 1);
+
+    if ((--r->ref) <= 0) {
+        switch (r->key->type) {
+
+            case AVAHI_DNS_TYPE_SRV:
+                g_free(r->data.srv.name);
+                break;
+
+            case AVAHI_DNS_TYPE_PTR:
+            case AVAHI_DNS_TYPE_CNAME:
+                g_free(r->data.ptr.name);
+                break;
+
+            case AVAHI_DNS_TYPE_HINFO:
+                g_free(r->data.hinfo.cpu);
+                g_free(r->data.hinfo.os);
+                break;
+
+            case AVAHI_DNS_TYPE_TXT:
+                avahi_string_list_free(r->data.txt.string_list);
+                break;
+
+            case AVAHI_DNS_TYPE_A:
+            case AVAHI_DNS_TYPE_AAAA:
+                break;
+            
+            default:
+                g_free(r->data.generic.data);
+        }
+        
+        avahi_key_unref(r->key);
+        g_free(r);
+    }
+}
+
+const gchar *avahi_dns_class_to_string(guint16 class) {
+    if (class & AVAHI_DNS_CACHE_FLUSH) 
+        return "FLUSH";
+    
+    if (class == AVAHI_DNS_CLASS_IN)
+        return "IN";
+
+    return NULL;
+}
+
+const gchar *avahi_dns_type_to_string(guint16 type) {
+    switch (type) {
+        case AVAHI_DNS_TYPE_CNAME:
+            return "CNAME";
+        case AVAHI_DNS_TYPE_A:
+            return "A";
+        case AVAHI_DNS_TYPE_AAAA:
+            return "AAAA";
+        case AVAHI_DNS_TYPE_PTR:
+            return "PTR";
+        case AVAHI_DNS_TYPE_HINFO:
+            return "HINFO";
+        case AVAHI_DNS_TYPE_TXT:
+            return "TXT";
+        case AVAHI_DNS_TYPE_SRV:
+            return "SRV";
+        case AVAHI_DNS_TYPE_ANY:
+            return "ANY";
+        default:
+            return NULL;
+    }
+}
+
+
+gchar *avahi_key_to_string(const AvahiKey *k) {
+    return g_strdup_printf("%s\t%s\t%s",
+                           k->name,
+                           avahi_dns_class_to_string(k->class),
+                           avahi_dns_type_to_string(k->type));
+}
+
+gchar *avahi_record_to_string(const AvahiRecord *r) {
+    gchar *p, *s;
+    char buf[257], *t = NULL, *d = NULL;
+
+    switch (r->key->type) {
+        case AVAHI_DNS_TYPE_A:
+            inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
+            break;
+            
+        case AVAHI_DNS_TYPE_AAAA:
+            inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
+            break;
+            
+        case AVAHI_DNS_TYPE_PTR:
+        case AVAHI_DNS_TYPE_CNAME :
+
+            t = r->data.ptr.name;
+            break;
+
+        case AVAHI_DNS_TYPE_TXT:
+            t = d = avahi_string_list_to_string(r->data.txt.string_list);
+            break;
+
+        case AVAHI_DNS_TYPE_HINFO:
+
+            snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os);
+            break;
+
+        case AVAHI_DNS_TYPE_SRV:
+
+            snprintf(t = buf, sizeof(buf), "%u %u %u %s",
+                     r->data.srv.priority,
+                     r->data.srv.weight,
+                     r->data.srv.port,
+                     r->data.srv.name);
+
+            break;
+    }
+
+    p = avahi_key_to_string(r->key);
+    s = g_strdup_printf("%s %s ; ttl=%u", p, t ? t : "<unparsable>", r->ttl);
+    g_free(p);
+    g_free(d);
+    
+    return s;
+}
+
+gboolean avahi_key_equal(const AvahiKey *a, const AvahiKey *b) {
+    g_assert(a);
+    g_assert(b);
+
+    if (a == b)
+        return TRUE;
+    
+/*     g_message("equal: %p %p", a, b); */
+    
+    return avahi_domain_equal(a->name, b->name) &&
+        a->type == b->type &&
+        a->class == b->class;
+}
+
+gboolean avahi_key_pattern_match(const AvahiKey *pattern, const AvahiKey *k) {
+    g_assert(pattern);
+    g_assert(k);
+
+/*     g_message("equal: %p %p", a, b); */
+
+    g_assert(!avahi_key_is_pattern(k));
+
+    if (pattern == k)
+        return TRUE;
+    
+    return avahi_domain_equal(pattern->name, k->name) &&
+        (pattern->type == k->type || pattern->type == AVAHI_DNS_TYPE_ANY) &&
+        pattern->class == k->class;
+}
+
+gboolean avahi_key_is_pattern(const AvahiKey *k) {
+    g_assert(k);
+
+    return k->type == AVAHI_DNS_TYPE_ANY;
+}
+
+
+guint avahi_key_hash(const AvahiKey *k) {
+    g_assert(k);
+
+    return avahi_domain_hash(k->name) + k->type + k->class;
+}
+
+static gboolean rdata_equal(const AvahiRecord *a, const AvahiRecord *b) {
+    g_assert(a);
+    g_assert(b);
+    g_assert(a->key->type == b->key->type);
+
+/*     t = avahi_record_to_string(a); */
+/*     g_message("comparing %s", t); */
+/*     g_free(t); */
+
+/*     t = avahi_record_to_string(b); */
+/*     g_message("and %s", t); */
+/*     g_free(t); */
+
+    
+    switch (a->key->type) {
+        case AVAHI_DNS_TYPE_SRV:
+            return
+                a->data.srv.priority == b->data.srv.priority &&
+                a->data.srv.weight == b->data.srv.weight &&
+                a->data.srv.port == b->data.srv.port &&
+                avahi_domain_equal(a->data.srv.name, b->data.srv.name);
+
+        case AVAHI_DNS_TYPE_PTR:
+        case AVAHI_DNS_TYPE_CNAME:
+            return avahi_domain_equal(a->data.ptr.name, b->data.ptr.name);
+
+        case AVAHI_DNS_TYPE_HINFO:
+            return
+                !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) &&
+                !strcmp(a->data.hinfo.os, b->data.hinfo.os);
+
+        case AVAHI_DNS_TYPE_TXT:
+            return avahi_string_list_equal(a->data.txt.string_list, b->data.txt.string_list);
+
+        case AVAHI_DNS_TYPE_A:
+            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address)) == 0;
+
+        case AVAHI_DNS_TYPE_AAAA:
+            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address)) == 0;
+
+        default:
+            return a->data.generic.size == b->data.generic.size &&
+                (a->data.generic.size == 0 || memcmp(a->data.generic.data, b->data.generic.data, a->data.generic.size) == 0);
+    }
+    
+}
+
+gboolean avahi_record_equal_no_ttl(const AvahiRecord *a, const AvahiRecord *b) {
+    g_assert(a);
+    g_assert(b);
+
+    if (a == b)
+        return TRUE;
+
+    return
+        avahi_key_equal(a->key, b->key) &&
+        rdata_equal(a, b);
+}
+
+
+AvahiRecord *avahi_record_copy(AvahiRecord *r) {
+    AvahiRecord *copy;
+
+    copy = g_new(AvahiRecord, 1);
+    copy->ref = 1;
+    copy->key = avahi_key_ref(r->key);
+    copy->ttl = r->ttl;
+
+    switch (r->key->type) {
+        case AVAHI_DNS_TYPE_PTR:
+        case AVAHI_DNS_TYPE_CNAME:
+            copy->data.ptr.name = g_strdup(r->data.ptr.name);
+            break;
+
+        case AVAHI_DNS_TYPE_SRV:
+            copy->data.srv.priority = r->data.srv.priority;
+            copy->data.srv.weight = r->data.srv.weight;
+            copy->data.srv.port = r->data.srv.port;
+            copy->data.srv.name = g_strdup(r->data.srv.name);
+            break;
+
+        case AVAHI_DNS_TYPE_HINFO:
+            copy->data.hinfo.os = g_strdup(r->data.hinfo.os);
+            copy->data.hinfo.cpu = g_strdup(r->data.hinfo.cpu);
+            break;
+
+        case AVAHI_DNS_TYPE_TXT:
+            copy->data.txt.string_list = avahi_string_list_copy(r->data.txt.string_list);
+            break;
+
+        case AVAHI_DNS_TYPE_A:
+            copy->data.a.address = r->data.a.address;
+            break;
+
+        case AVAHI_DNS_TYPE_AAAA:
+            copy->data.aaaa.address = r->data.aaaa.address;
+            break;
+
+        default:
+            copy->data.generic.data = g_memdup(r->data.generic.data, r->data.generic.size);
+            copy->data.generic.size = r->data.generic.size;
+            break;
+                
+    }
+
+    return copy;
+}
+
+
+guint avahi_key_get_estimate_size(AvahiKey *k) {
+    g_assert(k);
+
+    return strlen(k->name)+1+4;
+}
+
+guint avahi_record_get_estimate_size(AvahiRecord *r) {
+    guint n;
+    g_assert(r);
+
+    n = avahi_key_get_estimate_size(r->key) + 4 + 2;
+
+    switch (r->key->type) {
+        case AVAHI_DNS_TYPE_PTR:
+        case AVAHI_DNS_TYPE_CNAME:
+            n += strlen(r->data.ptr.name) + 1;
+            break;
+
+        case AVAHI_DNS_TYPE_SRV:
+            n += 6 + strlen(r->data.srv.name) + 1;
+            break;
+
+        case AVAHI_DNS_TYPE_HINFO:
+            n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1;
+            break;
+
+        case AVAHI_DNS_TYPE_TXT:
+            n += avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
+            break;
+
+        case AVAHI_DNS_TYPE_A:
+            n += sizeof(AvahiIPv4Address);
+            break;
+
+        case AVAHI_DNS_TYPE_AAAA:
+            n += sizeof(AvahiIPv6Address);
+            break;
+
+        default:
+            n += r->data.generic.size;
+    }
+
+    return n;
+}
+
+static gint lexicographical_memcmp(gconstpointer a, size_t al, gconstpointer b, size_t bl) {
+    size_t c;
+    gint ret;
+    
+    g_assert(a);
+    g_assert(b);
+
+    c = al < bl ? al : bl;
+    if ((ret = memcmp(a, b, c)) != 0)
+        return ret;
+
+    if (al == bl)
+        return 0;
+    else
+        return al == c ? 1 : -1;
+}
+
+static gint uint16_cmp(guint16 a, guint16 b) {
+    return a == b ? 0 : (a < b ? a : b);
+}
+
+static gint lexicographical_domain_cmp(const gchar *a, const gchar *b) {
+    g_assert(a);
+    g_assert(b);
+    
+
+    for (;;) {
+        gchar t1[64];
+        gchar t2[64];
+        size_t al, bl;
+        gint r;
+
+        if (!a && !b)
+            return 0;
+
+        if (a && !b)
+            return 1;
+
+        if (b && !a)
+            return -1;
+        
+        avahi_unescape_label(t1, sizeof(t1), &a);
+        avahi_unescape_label(t2, sizeof(t2), &b);
+
+        al = strlen(t1);
+        bl = strlen(t2);
+        
+        if (al != bl) 
+            return al < bl ? -1 : 1;
+
+        if ((r =  strcmp(t1, t2)) != 0)
+            return r;
+    }
+}
+
+gint avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b) {
+    g_assert(a);
+    g_assert(b);
+
+    if (a == b)
+        return 0;
+    
+/*     gchar *t; */
+
+/*     g_message("comparing [%s]", t = avahi_record_to_string(a)); */
+/*     g_free(t); */
+
+/*     g_message("and [%s]", t = avahi_record_to_string(b)); */
+/*     g_free(t); */
+
+    if (a->key->class < b->key->class)
+        return -1;
+    else if (a->key->class > b->key->class)
+        return 1;
+
+    if (a->key->type < b->key->type)
+        return -1;
+    else if (a->key->type > b->key->type)
+        return 1;
+
+    switch (a->key->type) {
+
+        case AVAHI_DNS_TYPE_PTR:
+        case AVAHI_DNS_TYPE_CNAME:
+            return lexicographical_domain_cmp(a->data.ptr.name, b->data.ptr.name);
+
+        case AVAHI_DNS_TYPE_SRV: {
+            gint r;
+            if ((r = uint16_cmp(a->data.srv.priority, b->data.srv.priority)) == 0 &&
+                (r = uint16_cmp(a->data.srv.weight, b->data.srv.weight)) == 0 &&
+                (r = uint16_cmp(a->data.srv.port, b->data.srv.port)) == 0)
+                r = lexicographical_domain_cmp(a->data.srv.name, b->data.srv.name);
+            
+            return r;
+        }
+
+        case AVAHI_DNS_TYPE_HINFO: {
+            size_t al = strlen(a->data.hinfo.cpu), bl = strlen(b->data.hinfo.cpu);
+            gint r;
+
+            if (al != bl)
+                return al < bl ? -1 : 1;
+
+            if ((r = strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu)) != 0)
+                return r;
+
+            al = strlen(a->data.hinfo.os), bl = strlen(b->data.hinfo.os);
+
+            if (al != bl)
+                return al < bl ? -1 : 1;
+
+            if ((r = strcmp(a->data.hinfo.os, b->data.hinfo.os)) != 0)
+                return r;
+
+            return 0;
+
+        }
+
+        case AVAHI_DNS_TYPE_TXT: {
+
+            guint8 *ma, *mb;
+            guint asize, bsize;
+            gint r;
+
+            ma = g_new(guint8, asize = avahi_string_list_serialize(a->data.txt.string_list, NULL, 0));
+            mb = g_new(guint8, bsize = avahi_string_list_serialize(b->data.txt.string_list, NULL, 0));
+            avahi_string_list_serialize(a->data.txt.string_list, ma, asize);
+            avahi_string_list_serialize(a->data.txt.string_list, mb, bsize);
+
+            r = lexicographical_memcmp(ma, asize, mb, bsize);
+            g_free(ma);
+            g_free(mb);
+
+            return r;
+        }
+        
+        case AVAHI_DNS_TYPE_A:
+            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address));
+
+        case AVAHI_DNS_TYPE_AAAA:
+            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address));
+
+        default:
+            return lexicographical_memcmp(a->data.generic.data, a->data.generic.size,
+                                          b->data.generic.data, b->data.generic.size);
+    }
+    
+}
diff --git a/libavahi-core/rr.h b/libavahi-core/rr.h
new file mode 100644 (file)
index 0000000..6f1a8cb
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef foorrhfoo
+#define foorrhfoo
+
+#include <glib.h>
+
+#include "strlst.h"
+#include "address.h"
+
+enum {
+    AVAHI_DNS_TYPE_A = 0x01,
+    AVAHI_DNS_TYPE_NS = 0x02,
+    AVAHI_DNS_TYPE_CNAME = 0x05,
+    AVAHI_DNS_TYPE_SOA = 0x06,
+    AVAHI_DNS_TYPE_PTR = 0x0C,
+    AVAHI_DNS_TYPE_HINFO = 0x0D,
+    AVAHI_DNS_TYPE_MX = 0x0F,
+    AVAHI_DNS_TYPE_TXT = 0x10,
+    AVAHI_DNS_TYPE_AAAA = 0x1C,
+    AVAHI_DNS_TYPE_SRV = 0x21,
+    AVAHI_DNS_TYPE_ANY = 0xFF
+};
+
+enum {
+    AVAHI_DNS_CLASS_IN = 0x01,
+    AVAHI_DNS_CACHE_FLUSH = 0x8000,
+    AVAHI_DNS_UNICAST_RESPONSE = 0x8000
+};
+
+#define AVAHI_DEFAULT_TTL (120*60)
+
+typedef struct {
+    guint ref;
+    gchar *name;
+    guint16 class;
+    guint16 type;
+} AvahiKey;
+
+typedef struct  {
+    guint ref;
+    AvahiKey *key;
+    
+    guint32 ttl;
+
+    union {
+        struct {
+            gpointer data;
+            guint16 size;
+        } generic;
+
+        struct {
+            guint16 priority;
+            guint16 weight;
+            guint16 port;
+            gchar *name;
+        } srv;
+
+        struct {
+            gchar *name;
+        } ptr; /* and cname */
+
+        struct {
+            gchar *cpu;
+            gchar *os;
+        } hinfo;
+
+        struct {
+            AvahiStringList *string_list;
+        } txt;
+
+        struct {
+            AvahiIPv4Address address;
+        } a;
+
+        struct {
+            AvahiIPv6Address address;
+        } aaaa;
+
+    } data;
+    
+} AvahiRecord;
+
+AvahiKey *avahi_key_new(const gchar *name, guint16 class, guint16 type);
+AvahiKey *avahi_key_ref(AvahiKey *k);
+void avahi_key_unref(AvahiKey *k);
+
+gboolean avahi_key_equal(const AvahiKey *a, const AvahiKey *b);  /* Treat AVAHI_DNS_CLASS_ANY like any other type */
+gboolean avahi_key_pattern_match(const AvahiKey *pattern, const AvahiKey *k); /* If pattern.type is AVAHI_DNS_CLASS_ANY, k.type is ignored */
+
+gboolean avahi_key_is_pattern(const AvahiKey *k);
+
+guint avahi_key_hash(const AvahiKey *k);
+
+AvahiRecord *avahi_record_new(AvahiKey *k);
+AvahiRecord *avahi_record_new_full(const gchar *name, guint16 class, guint16 type);
+AvahiRecord *avahi_record_ref(AvahiRecord *r);
+void avahi_record_unref(AvahiRecord *r);
+
+const gchar *avahi_dns_class_to_string(guint16 class);
+const gchar *avahi_dns_type_to_string(guint16 type);
+
+gchar *avahi_key_to_string(const AvahiKey *k); /* g_free() the result! */
+gchar *avahi_record_to_string(const AvahiRecord *r);  /* g_free() the result! */
+
+gboolean avahi_record_equal_no_ttl(const AvahiRecord *a, const AvahiRecord *b);
+
+AvahiRecord *avahi_record_copy(AvahiRecord *r);
+
+/* returns a maximum estimate for the space that is needed to store
+ * this key in a DNS packet */
+guint avahi_key_get_estimate_size(AvahiKey *k);
+
+/* ditto */
+guint avahi_record_get_estimate_size(AvahiRecord *r);
+
+gint avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b);
+
+#endif
diff --git a/libavahi-core/server.c b/libavahi-core/server.c
new file mode 100644 (file)
index 0000000..b17b142
--- /dev/null
@@ -0,0 +1,1014 @@
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "server.h"
+#include "util.h"
+#include "iface.h"
+#include "socket.h"
+#include "subscribe.h"
+
+static void free_entry(AvahiServer*s, AvahiEntry *e) {
+    AvahiEntry *t;
+
+    g_assert(s);
+    g_assert(e);
+
+    avahi_goodbye_entry(s, e, TRUE);
+
+    /* Remove from linked list */
+    AVAHI_LLIST_REMOVE(AvahiEntry, entries, s->entries, e);
+
+    /* Remove from hash table indexed by name */
+    t = g_hash_table_lookup(s->entries_by_key, e->record->key);
+    AVAHI_LLIST_REMOVE(AvahiEntry, by_key, t, e);
+    if (t)
+        g_hash_table_replace(s->entries_by_key, t->record->key, t);
+    else
+        g_hash_table_remove(s->entries_by_key, e->record->key);
+
+    /* Remove from associated group */
+    if (e->group)
+        AVAHI_LLIST_REMOVE(AvahiEntry, by_group, e->group->entries, e);
+
+    avahi_record_unref(e->record);
+    g_free(e);
+}
+
+static void free_group(AvahiServer *s, AvahiEntryGroup *g) {
+    g_assert(s);
+    g_assert(g);
+
+    while (g->entries)
+        free_entry(s, g->entries);
+
+    AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, s->groups, g);
+    g_free(g);
+}
+
+static void cleanup_dead(AvahiServer *s) {
+    AvahiEntryGroup *g, *ng;
+    AvahiEntry *e, *ne;
+    g_assert(s);
+
+
+    if (s->need_group_cleanup) {
+        for (g = s->groups; g; g = ng) {
+            ng = g->groups_next;
+            
+            if (g->dead)
+                free_group(s, g);
+        }
+
+        s->need_group_cleanup = FALSE;
+    }
+
+    if (s->need_entry_cleanup) {
+        for (e = s->entries; e; e = ne) {
+            ne = e->entries_next;
+            
+            if (e->dead)
+                free_entry(s, e);
+        }
+
+        s->need_entry_cleanup = FALSE;
+    }
+}
+
+static void handle_query_key(AvahiServer *s, AvahiKey *k, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) {
+    AvahiEntry *e;
+    gchar *txt;
+    
+    g_assert(s);
+    g_assert(k);
+    g_assert(i);
+    g_assert(a);
+
+    g_message("Handling query: %s", txt = avahi_key_to_string(k));
+    g_free(txt);
+
+    avahi_packet_scheduler_incoming_query(i->scheduler, k);
+
+    if (k->type == AVAHI_DNS_TYPE_ANY) {
+
+        /* Handle ANY query */
+        
+        for (e = s->entries; e; e = e->entries_next)
+            if (!e->dead && avahi_key_pattern_match(k, e->record->key) && avahi_entry_registered(s, e, i))
+                avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE);
+    } else {
+
+        /* Handle all other queries */
+        
+        for (e = g_hash_table_lookup(s->entries_by_key, k); e; e = e->by_key_next)
+            if (!e->dead && avahi_entry_registered(s, e, i))
+                avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE);
+    }
+}
+
+static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
+    g_assert(s);
+    g_assert(e);
+
+    
+    if (e->group) {
+        AvahiEntry *k;
+        
+        for (k = e->group->entries; k; k = k->by_group_next) {
+            avahi_goodbye_entry(s, k, FALSE);
+            k->dead = TRUE;
+        }
+        
+        avahi_entry_group_change_state(e->group, AVAHI_ENTRY_GROUP_COLLISION);
+    } else {
+        avahi_goodbye_entry(s, e, FALSE);
+        e->dead = TRUE;
+    }
+
+    s->need_entry_cleanup = TRUE;
+}
+
+static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *i) {
+    AvahiEntry *e, *n;
+    gchar *t;
+    
+    g_assert(s);
+    g_assert(record);
+    g_assert(i);
+
+    t = avahi_record_to_string(record);
+
+/*     g_message("PROBE: [%s]", t); */
+    
+    for (e = g_hash_table_lookup(s->entries_by_key, record->key); e; e = n) {
+        n = e->by_key_next;
+
+        if (e->dead || avahi_record_equal_no_ttl(record, e->record))
+            continue;
+
+        if (avahi_entry_registering(s, e, i)) {
+            gint cmp;
+
+            if ((cmp = avahi_record_lexicographical_compare(record, e->record)) > 0) {
+                withdraw_entry(s, e);
+                g_message("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t);
+            } else if (cmp < 0)
+                g_message("Recieved conflicting probe [%s]. Local host won.", t);
+
+        }
+    }
+
+    g_free(t);
+}
+
+static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) {
+    guint n;
+    
+    g_assert(s);
+    g_assert(p);
+    g_assert(i);
+    g_assert(a);
+
+    /* Handle the questions */
+    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n --) {
+        AvahiKey *key;
+        gboolean unicast_response = FALSE;
+
+        if (!(key = avahi_dns_packet_consume_key(p, &unicast_response))) {
+            g_warning("Packet too short (1)");
+            return;
+        }
+
+        handle_query_key(s, key, i, a, port, legacy_unicast, unicast_response);
+        avahi_key_unref(key);
+    }
+
+    /* Known Answer Suppression */
+    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT); n > 0; n --) {
+        AvahiRecord *record;
+        gboolean unique = FALSE;
+
+        if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
+            g_warning("Packet too short (2)");
+            return;
+        }
+
+        avahi_packet_scheduler_incoming_known_answer(i->scheduler, record, a);
+        avahi_record_unref(record);
+    }
+
+    /* Probe record */
+    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT); n > 0; n --) {
+        AvahiRecord *record;
+        gboolean unique = FALSE;
+
+        if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
+            g_warning("Packet too short (3)");
+            return;
+        }
+
+        if (record->key->type != AVAHI_DNS_TYPE_ANY)
+            incoming_probe(s, record, i);
+        
+        avahi_record_unref(record);
+    }
+}
+
+static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, gboolean unique, const AvahiAddress *a) {
+    gboolean valid = TRUE;
+    AvahiEntry *e, *n;
+    gchar *t;
+    
+    g_assert(s);
+    g_assert(i);
+    g_assert(record);
+
+    t = avahi_record_to_string(record);
+
+/*     g_message("CHECKING FOR CONFLICT: [%s]", t); */
+
+    for (e = g_hash_table_lookup(s->entries_by_key, record->key); e; e = n) {
+        n = e->by_key_next;
+
+        if (e->dead)
+            continue;
+        
+        if (avahi_entry_registered(s, e, i)) {
+
+            gboolean equal = avahi_record_equal_no_ttl(record, e->record);
+                
+            /* Check whether there is a unique record conflict */
+            if (!equal && ((e->flags & AVAHI_ENTRY_UNIQUE) || unique)) {
+                gint cmp;
+                
+                /* The lexicographically later data wins. */
+                if ((cmp = avahi_record_lexicographical_compare(record, e->record)) > 0) {
+                    g_message("Recieved conflicting record [%s]. Local host lost. Withdrawing.", t);
+                    withdraw_entry(s, e);
+                } else if (cmp < 0) {
+                    /* Tell the other host that our entry is lexicographically later */
+
+                    g_message("Recieved conflicting record [%s]. Local host won. Refreshing.", t);
+
+                    valid = FALSE;
+                    avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
+                }
+                
+                /* Check wheter there is a TTL conflict */
+            } else if (equal && record->ttl <= e->record->ttl/2) {
+                /* Correct the TTL */
+                valid = FALSE;
+                avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
+                g_message("Recieved record with bad TTL [%s]. Refreshing.", t);
+            }
+            
+        } else if (avahi_entry_registering(s, e, i)) {
+
+            if (!avahi_record_equal_no_ttl(record, e->record) && ((e->flags & AVAHI_ENTRY_UNIQUE) || unique)) {
+
+                /* We are currently registering a matching record, but
+                 * someone else already claimed it, so let's
+                 * withdraw */
+                
+                g_message("Recieved conflicting record [%s] with local record to be. Withdrawing.", t);
+                withdraw_entry(s, e);
+            }
+        }
+    }
+
+    g_free(t);
+
+    return valid;
+}
+
+static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a) {
+    guint n;
+    
+    g_assert(s);
+    g_assert(p);
+    g_assert(i);
+    g_assert(a);
+    
+    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) +
+             avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT); n > 0; n--) {
+        AvahiRecord *record;
+        gboolean cache_flush = FALSE;
+        gchar *txt;
+        
+        if (!(record = avahi_dns_packet_consume_record(p, &cache_flush))) {
+            g_warning("Packet too short (4)");
+            return;
+        }
+
+        if (record->key->type != AVAHI_DNS_TYPE_ANY) {
+
+            g_message("Handling response: %s", txt = avahi_record_to_string(record));
+            g_free(txt);
+            
+            if (handle_conflict(s, i, record, cache_flush, a)) {
+                avahi_cache_update(i->cache, record, cache_flush, a);
+                avahi_packet_scheduler_incoming_response(i->scheduler, record);
+            }
+        }
+            
+        avahi_record_unref(record);
+    }
+}
+
+static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr *sa, gint iface, gint ttl) {
+    AvahiInterface *i;
+    AvahiAddress a;
+    guint16 port;
+    
+    g_assert(s);
+    g_assert(p);
+    g_assert(sa);
+    g_assert(iface > 0);
+
+    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, sa->sa_family))) {
+        g_warning("Recieved packet from invalid interface.");
+        return;
+    }
+
+    g_message("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol);
+
+    if (sa->sa_family == AF_INET6) {
+        static const guint8 ipv4_in_ipv6[] = {
+            0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
+            0xFF, 0xFF, 0xFF, 0xFF };
+
+        /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
+
+        if (memcmp(((struct sockaddr_in6*) sa)->sin6_addr.s6_addr, ipv4_in_ipv6, sizeof(ipv4_in_ipv6)) == 0)
+            return;
+    }
+
+    if (avahi_dns_packet_check_valid(p) < 0) {
+        g_warning("Recieved invalid packet.");
+        return;
+    }
+
+    port = avahi_port_from_sockaddr(sa);
+    avahi_address_from_sockaddr(sa, &a);
+
+    if (avahi_dns_packet_is_query(p)) {
+        gboolean legacy_unicast = FALSE;
+
+        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT) == 0 ||
+            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT) != 0) {
+            g_warning("Invalid query packet.");
+            return;
+        }
+
+        if (port != AVAHI_MDNS_PORT) {
+            /* Legacy Unicast */
+
+            if ((avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) != 0 ||
+                 avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) != 0)) {
+                g_warning("Invalid legacy unicast query packet.");
+                return;
+            }
+        
+            legacy_unicast = TRUE;
+        }
+
+        handle_query(s, p, i, &a, port, legacy_unicast);
+        
+        g_message("Handled query");
+    } else {
+
+        if (port != AVAHI_MDNS_PORT) {
+            g_warning("Recieved repsonse with invalid source port %u on interface '%s.%i'", port, i->hardware->name, i->protocol);
+            return;
+        }
+
+        if (ttl != 255) {
+            g_warning("Recieved response with invalid TTL %u on interface '%s.%i'.", ttl, i->hardware->name, i->protocol);
+            if (!s->ignore_bad_ttl)
+                return;
+        }
+
+        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT) != 0 ||
+            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) == 0 ||
+            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) != 0) {
+            g_warning("Invalid response packet.");
+            return;
+        }
+
+        handle_response(s, p, i, &a);
+        g_message("Handled response");
+    }
+}
+
+static void work(AvahiServer *s) {
+    struct sockaddr_in6 sa6;
+    struct sockaddr_in sa;
+    AvahiDnsPacket *p;
+    gint iface = -1;
+    guint8 ttl;
+        
+    g_assert(s);
+
+    if (s->pollfd_ipv4.revents & G_IO_IN) {
+        if ((p = avahi_recv_dns_packet_ipv4(s->fd_ipv4, &sa, &iface, &ttl))) {
+            dispatch_packet(s, p, (struct sockaddr*) &sa, iface, ttl);
+            avahi_dns_packet_free(p);
+        }
+    }
+
+    if (s->pollfd_ipv6.revents & G_IO_IN) {
+        if ((p = avahi_recv_dns_packet_ipv6(s->fd_ipv6, &sa6, &iface, &ttl))) {
+            dispatch_packet(s, p, (struct sockaddr*) &sa6, iface, ttl);
+            avahi_dns_packet_free(p);
+        }
+    }
+}
+
+static gboolean prepare_func(GSource *source, gint *timeout) {
+    g_assert(source);
+    g_assert(timeout);
+    
+    *timeout = -1;
+    return FALSE;
+}
+
+static gboolean check_func(GSource *source) {
+    AvahiServer* s;
+    g_assert(source);
+
+    s = *((AvahiServer**) (((guint8*) source) + sizeof(GSource)));
+    g_assert(s);
+    
+    return (s->pollfd_ipv4.revents | s->pollfd_ipv6.revents) & (G_IO_IN | G_IO_HUP | G_IO_ERR);
+}
+
+static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
+    AvahiServer* s;
+    g_assert(source);
+
+    s = *((AvahiServer**) (((guint8*) source) + sizeof(GSource)));
+    g_assert(s);
+
+    work(s);
+    cleanup_dead(s);
+
+    return TRUE;
+}
+
+static void add_default_entries(AvahiServer *s) {
+    gint length = 0;
+    struct utsname utsname;
+    gchar *hinfo;
+    AvahiAddress a;
+    AvahiRecord *r;
+    
+    g_assert(s);
+    
+    /* Fill in HINFO rr */
+    r = avahi_record_new_full(s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_HINFO);
+    uname(&utsname);
+    r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine));
+    r->data.hinfo.os = g_strdup(g_strup(utsname.sysname));
+    avahi_server_add(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, r);
+    avahi_record_unref(r);
+
+    /* Add localhost entries */
+    avahi_address_parse("127.0.0.1", AF_INET, &a);
+    avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE|AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "localhost", &a);
+
+    avahi_address_parse("::1", AF_INET6, &a);
+    avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE|AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "ip6-localhost", &a);
+}
+
+AvahiServer *avahi_server_new(GMainContext *c) {
+    gchar *hn, *e;
+    AvahiServer *s;
+    
+    static GSourceFuncs source_funcs = {
+        prepare_func,
+        check_func,
+        dispatch_func,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    s = g_new(AvahiServer, 1);
+
+    s->ignore_bad_ttl = FALSE;
+    s->need_entry_cleanup = s->need_group_cleanup = FALSE;
+    
+    s->fd_ipv4 = avahi_open_socket_ipv4();
+    s->fd_ipv6 = avahi_open_socket_ipv6();
+    
+    if (s->fd_ipv6 < 0 && s->fd_ipv4 < 0) {
+        g_critical("Failed to create IP sockets.\n");
+        g_free(s);
+        return NULL;
+    }
+
+    if (s->fd_ipv4 < 0)
+        g_message("Failed to create IPv4 socket, proceeding in IPv6 only mode");
+    else if (s->fd_ipv6 < 0)
+        g_message("Failed to create IPv6 socket, proceeding in IPv4 only mode");
+    
+    if (c)
+        g_main_context_ref(s->context = c);
+    else
+        s->context = g_main_context_default();
+    
+    AVAHI_LLIST_HEAD_INIT(AvahiEntry, s->entries);
+    s->entries_by_key = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
+    AVAHI_LLIST_HEAD_INIT(AvahiGroup, s->groups);
+
+    AVAHI_LLIST_HEAD_INIT(AvahiSubscription, s->subscriptions);
+    s->subscription_hashtable = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
+
+    /* Get host name */
+    hn = avahi_get_host_name();
+    hn[strcspn(hn, ".")] = 0;
+
+    s->hostname = g_strdup_printf("%s.local.", hn);
+    g_free(hn);
+
+    s->time_event_queue = avahi_time_event_queue_new(s->context, G_PRIORITY_DEFAULT+10); /* Slightly less priority than the FDs */
+    s->monitor = avahi_interface_monitor_new(s);
+    avahi_interface_monitor_sync(s->monitor);
+    add_default_entries(s);
+    
+    /* Prepare IO source registration */
+    s->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(AvahiServer*));
+    *((AvahiServer**) (((guint8*) s->source) + sizeof(GSource))) = s;
+
+    memset(&s->pollfd_ipv4, 0, sizeof(s->pollfd_ipv4));
+    s->pollfd_ipv4.fd = s->fd_ipv4;
+    s->pollfd_ipv4.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+    g_source_add_poll(s->source, &s->pollfd_ipv4);
+    
+    memset(&s->pollfd_ipv6, 0, sizeof(s->pollfd_ipv6));
+    s->pollfd_ipv6.fd = s->fd_ipv6;
+    s->pollfd_ipv6.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+    g_source_add_poll(s->source, &s->pollfd_ipv6);
+
+    g_source_attach(s->source, s->context);
+
+    return s;
+}
+
+void avahi_server_free(AvahiServer* s) {
+    g_assert(s);
+
+    while(s->entries)
+        free_entry(s, s->entries);
+
+    avahi_interface_monitor_free(s->monitor);
+
+    while (s->groups)
+        free_group(s, s->groups);
+
+    while (s->subscriptions)
+        avahi_subscription_free(s->subscriptions);
+    g_hash_table_destroy(s->subscription_hashtable);
+
+    g_hash_table_destroy(s->entries_by_key);
+
+    avahi_time_event_queue_free(s->time_event_queue);
+
+    if (s->fd_ipv4 >= 0)
+        close(s->fd_ipv4);
+    if (s->fd_ipv6 >= 0)
+        close(s->fd_ipv6);
+    
+    g_free(s->hostname);
+
+    g_source_destroy(s->source);
+    g_source_unref(s->source);
+    g_main_context_unref(s->context);
+
+    g_free(s);
+}
+
+void avahi_server_add(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    AvahiRecord *r) {
+    
+    AvahiEntry *e, *t;
+    g_assert(s);
+    g_assert(r);
+
+    g_assert(r->key->type != AVAHI_DNS_TYPE_ANY);
+
+    e = g_new(AvahiEntry, 1);
+    e->server = s;
+    e->record = avahi_record_ref(r);
+    e->group = g;
+    e->interface = interface;
+    e->protocol = protocol;
+    e->flags = flags;
+    e->dead = FALSE;
+
+    AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, e->announcements);
+
+    AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e);
+
+    /* Insert into hash table indexed by name */
+    t = g_hash_table_lookup(s->entries_by_key, e->record->key);
+    AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e);
+    g_hash_table_replace(s->entries_by_key, e->record->key, t);
+
+    /* Insert into group list */
+    if (g)
+        AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); 
+
+    avahi_announce_entry(s, e);
+}
+const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiEntryGroup *g, void **state) {
+    AvahiEntry **e = (AvahiEntry**) state;
+    g_assert(s);
+    g_assert(e);
+
+    if (!*e)
+        *e = g ? g->entries : s->entries;
+    
+    while (*e && (*e)->dead)
+        *e = g ? (*e)->by_group_next : (*e)->entries_next;
+        
+    if (!*e)
+        return NULL;
+
+    return avahi_record_ref((*e)->record);
+}
+
+void avahi_server_dump(AvahiServer *s, FILE *f) {
+    AvahiEntry *e;
+    g_assert(s);
+    g_assert(f);
+
+    fprintf(f, "\n;;; ZONE DUMP FOLLOWS ;;;\n");
+
+    for (e = s->entries; e; e = e->entries_next) {
+        gchar *t;
+
+        if (e->dead)
+            continue;
+        
+        t = avahi_record_to_string(e->record);
+        fprintf(f, "%s ; iface=%i proto=%i\n", t, e->interface, e->protocol);
+        g_free(t);
+    }
+
+    avahi_dump_caches(s->monitor, f);
+}
+
+void avahi_server_add_ptr(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    const gchar *dest) {
+
+    AvahiRecord *r;
+
+    g_assert(dest);
+
+    r = avahi_record_new_full(name ? name : s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR);
+    r->data.ptr.name = avahi_normalize_name(dest);
+    avahi_server_add(s, g, interface, protocol, flags, r);
+    avahi_record_unref(r);
+}
+
+void avahi_server_add_address(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    AvahiAddress *a) {
+
+    gchar *n = NULL;
+    g_assert(s);
+    g_assert(a);
+
+    name = name ? (n = avahi_normalize_name(name)) : s->hostname;
+    
+    if (a->family == AF_INET) {
+        gchar *reverse;
+        AvahiRecord  *r;
+
+        r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A);
+        r->data.a.address = a->data.ipv4;
+        avahi_server_add(s, g, interface, protocol, flags, r);
+        avahi_record_unref(r);
+        
+        reverse = avahi_reverse_lookup_name_ipv4(&a->data.ipv4);
+        g_assert(reverse);
+        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
+        g_free(reverse);
+        
+    } else {
+        gchar *reverse;
+        AvahiRecord *r;
+            
+        r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA);
+        r->data.aaaa.address = a->data.ipv6;
+        avahi_server_add(s, g, interface, protocol, flags, r);
+        avahi_record_unref(r);
+
+        reverse = avahi_reverse_lookup_name_ipv6_arpa(&a->data.ipv6);
+        g_assert(reverse);
+        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
+        g_free(reverse);
+    
+        reverse = avahi_reverse_lookup_name_ipv6_int(&a->data.ipv6);
+        g_assert(reverse);
+        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
+        g_free(reverse);
+    }
+    
+    g_free(n);
+}
+
+void avahi_server_add_text_strlst(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    AvahiStringList *strlst) {
+
+    AvahiRecord *r;
+    
+    g_assert(s);
+    
+    r = avahi_record_new_full(name ? name : s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT);
+    r->data.txt.string_list = strlst;
+    avahi_server_add(s, g, interface, protocol, flags, r);
+    avahi_record_unref(r);
+}
+
+void avahi_server_add_text_va(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    va_list va) {
+    
+    g_assert(s);
+
+    avahi_server_add_text_strlst(s, g, interface, protocol, flags, name, avahi_string_list_new_va(va));
+}
+
+void avahi_server_add_text(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    AvahiEntryFlags flags,
+    const gchar *name,
+    ...) {
+
+    va_list va;
+    
+    g_assert(s);
+
+    va_start(va, name);
+    avahi_server_add_text_va(s, g, interface, protocol, flags, name, va);
+    va_end(va);
+}
+
+static void escape_service_name(gchar *d, guint size, const gchar *s) {
+    g_assert(d);
+    g_assert(size);
+    g_assert(s);
+
+    while (*s && size >= 2) {
+        if (*s == '.' || *s == '\\') {
+            if (size < 3)
+                break;
+
+            *(d++) = '\\';
+            size--;
+        }
+            
+        *(d++) = *(s++);
+        size--;
+    }
+
+    g_assert(size > 0);
+    *(d++) = 0;
+}
+
+void avahi_server_add_service_strlst(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    AvahiStringList *strlst) {
+
+    gchar ptr_name[256], svc_name[256], ename[64], enum_ptr[256];
+    AvahiRecord *r;
+    
+    g_assert(s);
+    g_assert(type);
+    g_assert(name);
+
+    escape_service_name(ename, sizeof(ename), name);
+
+    if (domain) {
+        while (domain[0] == '.')
+            domain++;
+    } else
+        domain = "local";
+
+    if (!host)
+        host = s->hostname;
+
+    snprintf(ptr_name, sizeof(ptr_name), "%s.%s", type, domain);
+    snprintf(svc_name, sizeof(svc_name), "%s.%s.%s", ename, type, domain);
+    
+    avahi_server_add_ptr(s, g, interface, protocol, AVAHI_ENTRY_NULL, ptr_name, svc_name);
+
+    r = avahi_record_new_full(svc_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV);
+    r->data.srv.priority = 0;
+    r->data.srv.weight = 0;
+    r->data.srv.port = port;
+    r->data.srv.name = avahi_normalize_name(host);
+    avahi_server_add(s, g, interface, protocol, AVAHI_ENTRY_UNIQUE, r);
+    avahi_record_unref(r);
+
+    avahi_server_add_text_strlst(s, g, interface, protocol, AVAHI_ENTRY_UNIQUE, svc_name, strlst);
+
+    snprintf(enum_ptr, sizeof(enum_ptr), "_services._dns-sd._udp.%s", domain);
+    avahi_server_add_ptr(s, g, interface, protocol, AVAHI_ENTRY_NULL, enum_ptr, ptr_name);
+}
+
+void avahi_server_add_service_va(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    va_list va){
+
+    g_assert(s);
+    g_assert(type);
+    g_assert(name);
+
+    avahi_server_add_service(s, g, interface, protocol, type, name, domain, host, port, avahi_string_list_new_va(va));
+}
+
+void avahi_server_add_service(
+    AvahiServer *s,
+    AvahiEntryGroup *g,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    ... ){
+
+    va_list va;
+    
+    g_assert(s);
+    g_assert(type);
+    g_assert(name);
+
+    va_start(va, port);
+    avahi_server_add_service_va(s, g, interface, protocol, type, name, domain, host, port, va);
+    va_end(va);
+}
+
+static void post_query_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
+    AvahiKey *k = userdata;
+
+    g_assert(m);
+    g_assert(i);
+    g_assert(k);
+
+    avahi_interface_post_query(i, k, FALSE);
+}
+
+void avahi_server_post_query(AvahiServer *s, gint interface, guchar protocol, AvahiKey *key) {
+    g_assert(s);
+    g_assert(key);
+
+    avahi_interface_monitor_walk(s->monitor, interface, protocol, post_query_callback, key);
+}
+
+struct tmpdata {
+    AvahiRecord *record;
+    gboolean flush_cache;
+};
+
+static void post_response_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
+    struct tmpdata *tmpdata = userdata;
+
+    g_assert(m);
+    g_assert(i);
+    g_assert(tmpdata);
+
+    avahi_interface_post_response(i, NULL, tmpdata->record, tmpdata->flush_cache, FALSE);
+}
+
+void avahi_server_post_response(AvahiServer *s, gint interface, guchar protocol, AvahiRecord *record, gboolean flush_cache) {
+    struct tmpdata tmpdata;
+    
+    g_assert(s);
+    g_assert(record);
+
+    tmpdata.record = record;
+    tmpdata.flush_cache = flush_cache;
+
+    avahi_interface_monitor_walk(s->monitor, interface, protocol, post_response_callback, &tmpdata);
+}
+
+void avahi_entry_group_change_state(AvahiEntryGroup *g, AvahiEntryGroupState state) {
+    g_assert(g);
+
+    g->state = state;
+    
+    if (g->callback) {
+        g->callback(g->server, g, state, g->userdata);
+        return;
+    }
+}
+
+AvahiEntryGroup *avahi_entry_group_new(AvahiServer *s, AvahiEntryGroupCallback callback, gpointer userdata) {
+    AvahiEntryGroup *g;
+    
+    g_assert(s);
+
+    g = g_new(AvahiEntryGroup, 1);
+    g->server = s;
+    g->callback = callback;
+    g->userdata = userdata;
+    g->dead = FALSE;
+    g->state = AVAHI_ENTRY_GROUP_UNCOMMITED;
+    g->n_probing = 0;
+    AVAHI_LLIST_HEAD_INIT(AvahiEntry, g->entries);
+
+    AVAHI_LLIST_PREPEND(AvahiEntryGroup, groups, s->groups, g);
+    return g;
+}
+
+void avahi_entry_group_free(AvahiEntryGroup *g) {
+    g_assert(g);
+    g_assert(g->server);
+
+    g->dead = TRUE;
+    g->server->need_group_cleanup = TRUE;
+}
+
+void avahi_entry_group_commit(AvahiEntryGroup *g) {
+    AvahiEntry *e;
+    
+    g_assert(g);
+    g_assert(!g->dead);
+
+    if (g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)
+        return;
+
+    avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING);
+    avahi_announce_group(g->server, g);
+    avahi_entry_group_check_probed(g, FALSE);
+}
+
+gboolean avahi_entry_commited(AvahiEntry *e) {
+    g_assert(e);
+    g_assert(!e->dead);
+
+    return !e->group ||
+        e->group->state == AVAHI_ENTRY_GROUP_REGISTERING ||
+        e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED;
+}
+
+AvahiEntryGroupState avahi_entry_group_get_state(AvahiEntryGroup *g) {
+    g_assert(g);
+    g_assert(!g->dead);
+
+    return g->state;
+}
diff --git a/libavahi-core/server.h b/libavahi-core/server.h
new file mode 100644 (file)
index 0000000..9f7ef51
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef fooAvahiserverhfoo
+#define fooAvahiserverhfoo
+
+#include "avahi.h"
+#include "iface.h"
+#include "prioq.h"
+#include "llist.h"
+#include "timeeventq.h"
+#include "announce.h"
+#include "subscribe.h"
+
+struct _AvahiEntry {
+    AvahiServer *server;
+    AvahiEntryGroup *group;
+
+    gboolean dead;
+    
+    AvahiEntryFlags flags;
+    AvahiRecord *record;
+    gint interface;
+    guchar protocol;
+
+    AVAHI_LLIST_FIELDS(AvahiEntry, entries);
+    AVAHI_LLIST_FIELDS(AvahiEntry, by_key);
+    AVAHI_LLIST_FIELDS(AvahiEntry, by_group);
+    
+    AVAHI_LLIST_HEAD(AvahiAnnouncement, announcements);
+};
+
+struct _AvahiEntryGroup {
+    AvahiServer *server;
+    gboolean dead;
+
+    AvahiEntryGroupState state;
+    gpointer userdata;
+    AvahiEntryGroupCallback callback;
+
+    guint n_probing;
+    
+    AVAHI_LLIST_FIELDS(AvahiEntryGroup, groups);
+    AVAHI_LLIST_HEAD(AvahiEntry, entries);
+};
+
+struct _AvahiServer {
+    GMainContext *context;
+    AvahiInterfaceMonitor *monitor;
+
+    AVAHI_LLIST_HEAD(AvahiEntry, entries);
+    GHashTable *entries_by_key;
+
+    AVAHI_LLIST_HEAD(AvahiEntryGroup, groups);
+    
+    AVAHI_LLIST_HEAD(AvahiSubscription, subscriptions);
+    GHashTable *subscription_hashtable;
+
+    gboolean need_entry_cleanup, need_group_cleanup;
+    
+    AvahiTimeEventQueue *time_event_queue;
+    
+    gchar *hostname;
+
+    gint fd_ipv4, fd_ipv6;
+
+    GPollFD pollfd_ipv4, pollfd_ipv6;
+    GSource *source;
+
+    gboolean ignore_bad_ttl;
+};
+
+gboolean avahi_server_entry_match_interface(AvahiEntry *e, AvahiInterface *i);
+
+void avahi_server_post_query(AvahiServer *s, gint interface, guchar protocol, AvahiKey *key);
+void avahi_server_post_response(AvahiServer *s, gint interface, guchar protocol, AvahiRecord *record, gboolean flush_cache);
+
+void avahi_entry_group_change_state(AvahiEntryGroup *g, AvahiEntryGroupState state);
+
+gboolean avahi_entry_commited(AvahiEntry *e);
+
+#endif
diff --git a/libavahi-core/socket.c b/libavahi-core/socket.c
new file mode 100644 (file)
index 0000000..1ef8131
--- /dev/null
@@ -0,0 +1,488 @@
+#include <inttypes.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "dns.h"
+#include "util.h"
+#include "socket.h"
+
+static void mdns_mcast_group_ipv4(struct sockaddr_in *ret_sa) {
+    g_assert(ret_sa);
+
+    memset(ret_sa, 0, sizeof(struct sockaddr_in));
+    
+    ret_sa->sin_family = AF_INET;
+    ret_sa->sin_port = htons(AVAHI_MDNS_PORT);
+    inet_pton(AF_INET, "224.0.0.251", &ret_sa->sin_addr);
+}
+
+static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
+
+    g_assert(ret_sa);
+
+    memset(ret_sa, 0, sizeof(struct sockaddr_in6));
+    
+    ret_sa->sin6_family = AF_INET6;
+    ret_sa->sin6_port = htons(AVAHI_MDNS_PORT);
+    inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
+}
+
+int avahi_mdns_mcast_join_ipv4 (int index, int fd)
+{
+    struct ip_mreqn mreq; 
+    struct sockaddr_in sa;
+
+    mdns_mcast_group_ipv4 (&sa);
+    memset(&mreq, 0, sizeof(mreq));
+    mreq.imr_multiaddr = sa.sin_addr;
+    mreq.imr_ifindex = index;
+    if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
+        g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
+        return -1;
+    } 
+
+    return 0;
+}
+
+int avahi_mdns_mcast_join_ipv6 (int index, int fd)
+{
+    struct ipv6_mreq mreq6; 
+    struct sockaddr_in6 sa6;
+
+    mdns_mcast_group_ipv6 (&sa6);
+
+    memset(&mreq6, 0, sizeof(mreq6));
+    mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
+    mreq6.ipv6mr_interface = index;
+
+    if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
+        g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+int avahi_mdns_mcast_leave_ipv4 (int index, int fd)
+{
+    struct ip_mreqn mreq; 
+    struct sockaddr_in sa;
+    
+    mdns_mcast_group_ipv4 (&sa);
+    memset(&mreq, 0, sizeof(mreq));
+    mreq.imr_multiaddr = sa.sin_addr;
+    mreq.imr_ifindex = index;
+    if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
+        g_warning("IP_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+int avahi_mdns_mcast_leave_ipv6 (int index, int fd)
+{
+    struct ipv6_mreq mreq6; 
+    struct sockaddr_in6 sa6;
+
+    mdns_mcast_group_ipv6 (&sa6);
+
+    memset(&mreq6, 0, sizeof(mreq6));
+    mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
+    mreq6.ipv6mr_interface = index;
+
+    if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
+        g_warning("IPV6_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+gint avahi_open_socket_ipv4(void) {
+    struct sockaddr_in sa, local;
+    int fd = -1, ttl, yes;
+        
+    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        g_warning("socket() failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    ttl = 255;
+    if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
+        g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    ttl = 255;
+    if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
+        g_warning("IP_TTL failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    yes = 1;
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+        g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    yes = 1;
+    if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+        g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    
+    memset(&local, 0, sizeof(local));
+    local.sin_family = AF_INET;
+    local.sin_port = htons(AVAHI_MDNS_PORT);
+    
+    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
+        g_warning("bind() failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    yes = 1;
+    if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
+        g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    yes = 1;
+    if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
+        g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    if (avahi_set_cloexec(fd) < 0) {
+        g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    if (avahi_set_nonblock(fd) < 0) {
+        g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    return fd;
+
+fail:
+    if (fd >= 0)
+        close(fd);
+
+    return -1;
+}
+
+gint avahi_open_socket_ipv6(void) {
+    struct sockaddr_in6 sa, local;
+    int fd = -1, ttl, yes;
+
+    mdns_mcast_group_ipv6(&sa);
+        
+    if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+        g_warning("socket() failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    ttl = 255;
+    if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
+        g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    ttl = 255;
+    if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
+        g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    yes = 1;
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+        g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    yes = 1;
+    if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
+        g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    yes = 1;
+    if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+        g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    memset(&local, 0, sizeof(local));
+    local.sin6_family = AF_INET6;
+    local.sin6_port = htons(AVAHI_MDNS_PORT);
+    
+    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
+        g_warning("bind() failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    yes = 1;
+    if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
+        g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    yes = 1;
+    if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
+        g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    if (avahi_set_cloexec(fd) < 0) {
+        g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
+        goto fail;
+    }
+    
+    if (avahi_set_nonblock(fd) < 0) {
+        g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
+        goto fail;
+    }
+
+    return fd;
+
+fail:
+    if (fd >= 0)
+        close(fd);
+
+    return -1;
+}
+
+static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
+    g_assert(fd >= 0);
+    g_assert(msg);
+
+    for (;;) {
+    
+        if (sendmsg(fd, msg, flags) >= 0)
+            break;
+        
+        if (errno != EAGAIN) {
+            g_message("sendmsg() failed: %s\n", strerror(errno));
+            return -1;
+        }
+        
+        if (avahi_wait_for_write(fd) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p) {
+    struct sockaddr_in sa;
+    struct msghdr msg;
+    struct iovec io;
+    struct cmsghdr *cmsg;
+    struct in_pktinfo *pkti;
+    uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
+    int i, n;
+
+    g_assert(fd >= 0);
+    g_assert(p);
+    g_assert(avahi_dns_packet_check_valid(p) >= 0);
+
+    mdns_mcast_group_ipv4(&sa);
+
+    memset(&io, 0, sizeof(io));
+    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
+    io.iov_len = p->size;
+
+    memset(cmsg_data, 0, sizeof(cmsg_data));
+    cmsg = (struct cmsghdr*) cmsg_data;
+    cmsg->cmsg_len = sizeof(cmsg_data);
+    cmsg->cmsg_level = IPPROTO_IP;
+    cmsg->cmsg_type = IP_PKTINFO;
+
+    pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
+    pkti->ipi_ifindex = interface;
+    
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_name = &sa;
+    msg.msg_namelen = sizeof(sa);
+    msg.msg_iov = &io;
+    msg.msg_iovlen = 1;
+    msg.msg_control = cmsg_data;
+    msg.msg_controllen = sizeof(cmsg_data);
+    msg.msg_flags = 0;
+
+    return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
+}
+
+gint avahi_send_dns_packet_ipv6(gint fd, gint interface, AvahiDnsPacket *p) {
+    struct sockaddr_in6 sa;
+    struct msghdr msg;
+    struct iovec io;
+    struct cmsghdr *cmsg;
+    struct in6_pktinfo *pkti;
+    uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
+    int i, n;
+
+    g_assert(fd >= 0);
+    g_assert(p);
+    g_assert(avahi_dns_packet_check_valid(p) >= 0);
+
+    mdns_mcast_group_ipv6(&sa);
+
+    memset(&io, 0, sizeof(io));
+    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
+    io.iov_len = p->size;
+
+    memset(cmsg_data, 0, sizeof(cmsg_data));
+    cmsg = (struct cmsghdr*) cmsg_data;
+    cmsg->cmsg_len = sizeof(cmsg_data);
+    cmsg->cmsg_level = IPPROTO_IPV6;
+    cmsg->cmsg_type = IPV6_PKTINFO;
+
+    pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
+    pkti->ipi6_ifindex = interface;
+    
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_name = &sa;
+    msg.msg_namelen = sizeof(sa);
+    msg.msg_iov = &io;
+    msg.msg_iovlen = 1;
+    msg.msg_control = cmsg_data;
+    msg.msg_controllen = sizeof(cmsg_data);
+    msg.msg_flags = 0;
+
+    return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
+}
+
+AvahiDnsPacket* avahi_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
+    AvahiDnsPacket *p= NULL;
+    struct msghdr msg;
+    struct iovec io;
+    uint8_t aux[64];
+    ssize_t l;
+    struct cmsghdr *cmsg;
+    gboolean found_ttl = FALSE, found_iface = FALSE;
+
+    g_assert(fd >= 0);
+    g_assert(ret_sa);
+    g_assert(ret_iface);
+    g_assert(ret_ttl);
+
+    p = avahi_dns_packet_new(0);
+
+    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
+    io.iov_len = p->max_size;
+    
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_name = ret_sa;
+    msg.msg_namelen = sizeof(struct sockaddr_in);
+    msg.msg_iov = &io;
+    msg.msg_iovlen = 1;
+    msg.msg_control = aux;
+    msg.msg_controllen = sizeof(aux);
+    msg.msg_flags = 0;
+    
+    if ((l = recvmsg(fd, &msg, 0)) < 0)
+        goto fail;
+
+    p->size = (size_t) l;
+    
+    *ret_ttl = 0;
+        
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
+        if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
+            *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
+            found_ttl = TRUE;
+        }
+            
+        if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
+            *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
+            found_iface = TRUE;
+        }
+    }
+
+    g_assert(found_iface);
+    g_assert(found_ttl);
+
+    return p;
+
+fail:
+    if (p)
+        avahi_dns_packet_free(p);
+
+    return NULL;
+}
+
+AvahiDnsPacket* avahi_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
+    AvahiDnsPacket *p = NULL;
+    struct msghdr msg;
+    struct iovec io;
+    uint8_t aux[64];
+    ssize_t l;
+    struct cmsghdr *cmsg;
+    gboolean found_ttl = FALSE, found_iface = FALSE;
+
+    g_assert(fd >= 0);
+    g_assert(ret_sa);
+    g_assert(ret_iface);
+    g_assert(ret_ttl);
+
+    p = avahi_dns_packet_new(0);
+
+    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
+    io.iov_len = p->max_size;
+    
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_name = ret_sa;
+    msg.msg_namelen = sizeof(struct sockaddr_in6);
+    msg.msg_iov = &io;
+    msg.msg_iovlen = 1;
+    msg.msg_control = aux;
+    msg.msg_controllen = sizeof(aux);
+    msg.msg_flags = 0;
+    
+    if ((l = recvmsg(fd, &msg, 0)) < 0)
+        goto fail;
+
+    p->size = (size_t) l;
+    
+    *ret_ttl = 0;
+
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+        if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
+            *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
+            found_ttl = TRUE;
+        }
+            
+        if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+            *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
+            found_iface = TRUE;
+        }
+    }
+
+    g_assert(found_iface);
+    g_assert(found_ttl);
+
+    return p;
+
+fail:
+    if (p)
+        avahi_dns_packet_free(p);
+
+    return NULL;
+}
+
diff --git a/libavahi-core/socket.h b/libavahi-core/socket.h
new file mode 100644 (file)
index 0000000..2baa122
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef foosockethfoo
+#define foosockethfoo
+
+#include <netinet/in.h>
+
+#include "dns.h"
+
+#define AVAHI_MDNS_PORT 5353
+
+
+
+gint avahi_open_socket_ipv4(void);
+gint avahi_open_socket_ipv6(void);
+
+gint avahi_send_dns_packet_ipv4(gint fd, gint iface, AvahiDnsPacket *p);
+gint avahi_send_dns_packet_ipv6(gint fd, gint iface, AvahiDnsPacket *p);
+
+AvahiDnsPacket *avahi_recv_dns_packet_ipv4(gint fd, struct sockaddr_in*ret_sa, gint *ret_iface, guint8 *ret_ttl);
+AvahiDnsPacket *avahi_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6*ret_sa, gint *ret_iface, guint8 *ret_ttl);
+
+int avahi_mdns_mcast_join_ipv4(int index, int fd);
+int avahi_mdns_mcast_join_ipv6(int index, int fd);
+
+int avahi_mdns_mcast_leave_ipv4(int index, int fd);
+int avahi_mdns_mcast_leave_ipv6(int index, int fd);
+
+#endif
diff --git a/libavahi-core/strlst-test.c b/libavahi-core/strlst-test.c
new file mode 100644 (file)
index 0000000..5e28ce2
--- /dev/null
@@ -0,0 +1,58 @@
+#include <glib.h>
+#include <stdio.h>
+
+#include "strlst.h"
+
+int main(int argc, char *argv[]) {
+    gchar *t;
+    guint8 data[1024];
+    AvahiStringList *a = NULL, *b;
+    guint size, n;
+
+    a = avahi_string_list_add(a, "start");
+    a = avahi_string_list_add(a, "foo");
+    a = avahi_string_list_add(a, "bar");
+    a = avahi_string_list_add(a, "quux");
+    a = avahi_string_list_add_arbitrary(a, "null\0null", 9);
+    a = avahi_string_list_add(a, "end");
+
+    t = avahi_string_list_to_string(a);
+    printf("--%s--\n", t);
+    g_free(t);
+
+    size = avahi_string_list_serialize(a, data, sizeof(data));
+
+    printf("%u\n", size);
+
+    for (t = (gchar*) data, n = 0; n < size; n++, t++) {
+        if (*t <= 32)
+            printf("(%u)", *t);
+        else
+            printf("%c", *t);
+    }
+
+    printf("\n");
+    
+    b = avahi_string_list_parse(data, size);
+
+    g_assert(avahi_string_list_equal(a, b));
+    
+    t = avahi_string_list_to_string(b);
+    printf("--%s--\n", t);
+    g_free(t);
+
+    avahi_string_list_free(b);
+
+    b = avahi_string_list_copy(a);
+
+    g_assert(avahi_string_list_equal(a, b));
+
+    t = avahi_string_list_to_string(b);
+    printf("--%s--\n", t);
+    g_free(t);
+    
+    avahi_string_list_free(a);
+    avahi_string_list_free(b);
+    
+    return 0;
+}
diff --git a/libavahi-core/strlst.c b/libavahi-core/strlst.c
new file mode 100644 (file)
index 0000000..f2d76e4
--- /dev/null
@@ -0,0 +1,218 @@
+#include <string.h>
+#include <stdarg.h>
+
+#include "strlst.h"
+
+AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const guint8*text, guint size) {
+    AvahiStringList *n;
+
+    g_assert(text);
+
+    n = g_malloc(sizeof(AvahiStringList) + size);
+    n->next = l;
+    memcpy(n->text, text, n->size = size);
+    
+    return n;
+}
+
+AvahiStringList *avahi_string_list_add(AvahiStringList *l, const gchar *text) {
+    g_assert(text);
+
+    return avahi_string_list_add_arbitrary(l, (const guint8*) text, strlen(text));
+}
+
+AvahiStringList *avahi_string_list_parse(gconstpointer data, guint size) {
+    AvahiStringList *r = NULL;
+    const guint8 *c;
+    g_assert(data);
+
+    c = data;
+    for (;;) {
+        guint k;
+        
+        if (size < 1)
+            break;
+
+        k = *(c++);
+        r = avahi_string_list_add_arbitrary(r, c, k);
+        c += k;
+
+        size -= 1 + k;
+    }
+
+    return r;
+}
+
+void avahi_string_list_free(AvahiStringList *l) {
+    AvahiStringList *n;
+
+    while (l) {
+        n = l->next;
+        g_free(l);
+        l = n;
+    }
+}
+
+static AvahiStringList* string_list_reverse(AvahiStringList *l) {
+    AvahiStringList *r = NULL, *n;
+
+    while (l) {
+        n = l->next;
+        l->next = r;
+        r = l;
+        l = n;
+    }
+
+    return r;
+}
+
+gchar* avahi_string_list_to_string(AvahiStringList *l) {
+    AvahiStringList *n;
+    guint s = 0;
+    gchar *t, *e;
+
+    l = string_list_reverse(l);
+    
+    for (n = l; n; n = n->next) {
+        if (n != l)
+            s ++;
+
+        s += n->size+3;
+    }
+
+    t = e = g_new(gchar, s);
+
+    for (n = l; n; n = n->next) {
+        if (n != l)
+            *(e++) = ' ';
+
+        *(e++) = '"';
+        strncpy(e, n->text, n->size);
+        e[n->size] = 0;
+        e = strchr(e, 0);
+        *(e++) = '"';
+    }
+
+    l = string_list_reverse(l);
+
+    *e = 0;
+
+    return t;
+}
+
+guint avahi_string_list_serialize(AvahiStringList *l, gpointer data, guint size) {
+    guint used = 0;
+
+    if (data) {
+        guint8 *c;
+        AvahiStringList *n;
+    
+        g_assert(data);
+        
+        l = string_list_reverse(l);
+        c = data;
+        
+        for (n = l; n; n = n->next) {
+            guint k;
+            if (size < 1)
+                break;
+            
+            k = n->size;
+            if (k > 255)
+                k = 255;
+            
+            if (k > size-1)
+                k = size-1;
+            
+            *(c++) = k;
+            memcpy(c, n->text, k);
+            c += k;
+            
+            used += 1+ k;
+        }
+        
+        l = string_list_reverse(l);
+    } else {
+        AvahiStringList *n;
+
+        for (n = l; n; n = n->next) {
+            guint k;
+        
+            k = n->size;
+            if (k > 255)
+                k = 255;
+            
+            used += 1+k;
+        }
+    }
+
+    return used;
+}
+
+gboolean avahi_string_list_equal(AvahiStringList *a, AvahiStringList *b) {
+
+    for (;;) {
+        if (!a && !b)
+            return TRUE;
+
+        if (!a || !b)
+            return FALSE;
+
+        if (a->size != b->size)
+            return FALSE;
+
+        if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
+            return FALSE;
+
+        a = a->next;
+        b = b->next;
+    }
+}
+
+AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
+    va_list va;
+
+    va_start(va, r);
+    r = avahi_string_list_add_many_va(r, va);
+    va_end(va);
+    
+    return r;
+}
+
+AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
+    const gchar *txt;
+
+    while ((txt = va_arg(va, const gchar*)))
+        r = avahi_string_list_add(r, txt);
+
+    return r;
+}
+
+
+AvahiStringList *avahi_string_list_new(const gchar *txt, ...) {
+    va_list va;
+    AvahiStringList *r = NULL;
+
+    if (txt) {
+        r = avahi_string_list_add(r, txt);
+
+        va_start(va, txt);
+        r = avahi_string_list_add_many_va(r, va);
+        va_end(va);
+    }
+
+    return r;
+}
+
+AvahiStringList *avahi_string_list_new_va(va_list va) {
+    return avahi_string_list_add_many_va(NULL, va);
+}
+
+AvahiStringList *avahi_string_list_copy(AvahiStringList *l) {
+    AvahiStringList *r = NULL;
+
+    for (; l; l = l->next)
+        r = avahi_string_list_add_arbitrary(r, l->text, l->size);
+
+    return string_list_reverse(r);
+}
diff --git a/libavahi-core/strlst.h b/libavahi-core/strlst.h
new file mode 100644 (file)
index 0000000..22cdc88
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef footxtlisthfoo
+#define footxtlisthfoo
+
+#include <glib.h>
+
+typedef struct _AvahiStringList AvahiStringList;
+
+struct _AvahiStringList {
+    AvahiStringList *next;
+    guint size;
+    guint8 text[1];
+};
+
+AvahiStringList *avahi_string_list_new(const gchar *txt, ...);
+AvahiStringList *avahi_string_list_new_va(va_list va);
+
+void avahi_string_list_free(AvahiStringList *l);
+
+AvahiStringList *avahi_string_list_add(AvahiStringList *l, const gchar *text);
+AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const guint8 *text, guint size);
+AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...);
+AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va);
+
+gchar* avahi_string_list_to_string(AvahiStringList *l);
+
+guint avahi_string_list_serialize(AvahiStringList *l, gpointer data, guint size);
+AvahiStringList *avahi_string_list_parse(gconstpointer data, guint size);
+
+gboolean avahi_string_list_equal(AvahiStringList *a, AvahiStringList *b);
+
+AvahiStringList *avahi_string_list_copy(AvahiStringList *l);
+
+#endif
+
diff --git a/libavahi-core/subscribe.c b/libavahi-core/subscribe.c
new file mode 100644 (file)
index 0000000..902e966
--- /dev/null
@@ -0,0 +1,134 @@
+#include "subscribe.h"
+#include "util.h"
+
+static void elapse(AvahiTimeEvent *e, void *userdata) {
+    AvahiSubscription *s = userdata;
+    GTimeVal tv;
+    gchar *t;
+    
+    g_assert(s);
+
+    avahi_server_post_query(s->server, s->interface, s->protocol, s->key);
+
+    if (s->n_query++ <= 8)
+        s->sec_delay *= 2;
+
+    g_message("%i. Continuous querying for %s", s->n_query, t = avahi_key_to_string(s->key));
+    g_free(t);
+    
+    avahi_elapse_time(&tv, s->sec_delay*1000, 0);
+    avahi_time_event_queue_update(s->server->time_event_queue, s->time_event, &tv);
+}
+
+struct cbdata {
+    AvahiSubscription *subscription;
+    AvahiInterface *interface;
+};
+
+static gpointer scan_cache_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) {
+    struct cbdata *cbdata = userdata;
+
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+    g_assert(cbdata);
+
+    cbdata->subscription->callback(
+        cbdata->subscription,
+        e->record,
+        cbdata->interface->hardware->index,
+        cbdata->interface->protocol,
+        AVAHI_SUBSCRIPTION_NEW,
+        cbdata->subscription->userdata);
+
+    return NULL;
+}
+
+static void scan_interface_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
+    AvahiSubscription *s = userdata;
+    struct cbdata cbdata = { s, i };
+
+    g_assert(m);
+    g_assert(i);
+    g_assert(s);
+
+    avahi_cache_walk(i->cache, s->key, scan_cache_callback, &cbdata);
+}
+
+AvahiSubscription *avahi_subscription_new(AvahiServer *server, AvahiKey *key, gint interface, guchar protocol, AvahiSubscriptionCallback callback, gpointer userdata) {
+    AvahiSubscription *s, *t;
+    GTimeVal tv;
+
+    g_assert(server);
+    g_assert(key);
+    g_assert(callback);
+
+    g_assert(!avahi_key_is_pattern(key));
+    
+    s = g_new(AvahiSubscription, 1);
+    s->server = server;
+    s->key = avahi_key_ref(key);
+    s->interface = interface;
+    s->protocol = protocol;
+    s->callback = callback;
+    s->userdata = userdata;
+    s->n_query = 1;
+    s->sec_delay = 1;
+
+    avahi_server_post_query(s->server, s->interface, s->protocol, s->key);
+    
+    avahi_elapse_time(&tv, s->sec_delay*1000, 0);
+    s->time_event = avahi_time_event_queue_add(server->time_event_queue, &tv, elapse, s);
+
+    AVAHI_LLIST_PREPEND(AvahiSubscription, subscriptions, server->subscriptions, s);
+
+    /* Add the new entry to the subscription hash table */
+    t = g_hash_table_lookup(server->subscription_hashtable, key);
+    AVAHI_LLIST_PREPEND(AvahiSubscription, by_key, t, s);
+    g_hash_table_replace(server->subscription_hashtable, key, t);
+
+    /* Scan the caches */
+    avahi_interface_monitor_walk(s->server->monitor, s->interface, s->protocol, scan_interface_callback, s);
+    
+    return s;
+}
+
+void avahi_subscription_free(AvahiSubscription *s) {
+    AvahiSubscription *t;
+    
+    g_assert(s);
+
+    AVAHI_LLIST_REMOVE(AvahiSubscription, subscriptions, s->server->subscriptions, s);
+
+    t = g_hash_table_lookup(s->server->subscription_hashtable, s->key);
+    AVAHI_LLIST_REMOVE(AvahiSubscription, by_key, t, s);
+    if (t)
+        g_hash_table_replace(s->server->subscription_hashtable, t->key, t);
+    else
+        g_hash_table_remove(s->server->subscription_hashtable, s->key);
+    
+    avahi_time_event_queue_remove(s->server->time_event_queue, s->time_event);
+    avahi_key_unref(s->key);
+
+    
+    g_free(s);
+}
+
+void avahi_subscription_notify(AvahiServer *server, AvahiInterface *i, AvahiRecord *record, AvahiSubscriptionEvent event) {
+    AvahiSubscription *s;
+    AvahiKey *pattern;
+    
+    g_assert(server);
+    g_assert(record);
+
+    for (s = g_hash_table_lookup(server->subscription_hashtable, record->key); s; s = s->by_key_next)
+        if (avahi_interface_match(i, s->interface, s->protocol))
+            s->callback(s, record, i->hardware->index, i->protocol, event, s->userdata);
+}
+
+gboolean avahi_is_subscribed(AvahiServer *server, AvahiKey *k) {
+    g_assert(server);
+    g_assert(k);
+
+    return !!g_hash_table_lookup(server->subscription_hashtable, k);
+}
diff --git a/libavahi-core/subscribe.h b/libavahi-core/subscribe.h
new file mode 100644 (file)
index 0000000..2cb1528
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef foosubscribehfoo
+#define foosubscribehfoo
+
+#include "llist.h"
+#include "avahi.h"
+#include "subscribe.h"
+#include "timeeventq.h"
+#include "server.h"
+
+struct _AvahiSubscription {
+    AvahiServer *server;
+    AvahiKey *key;
+    gint interface;
+    guchar protocol;
+    gint n_query;
+    guint sec_delay;
+
+    AvahiTimeEvent *time_event;
+
+    AvahiSubscriptionCallback callback;
+    gpointer userdata;
+
+    AVAHI_LLIST_FIELDS(AvahiSubscription, subscriptions);
+    AVAHI_LLIST_FIELDS(AvahiSubscription, by_key);
+};
+
+void avahi_subscription_notify(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, AvahiSubscriptionEvent event);
+
+gboolean avahi_is_subscribed(AvahiServer *s, AvahiKey *k);
+
+#endif
diff --git a/libavahi-core/timeeventq.c b/libavahi-core/timeeventq.c
new file mode 100644 (file)
index 0000000..fc84157
--- /dev/null
@@ -0,0 +1,160 @@
+#include "timeeventq.h"
+#include "util.h"
+
+static gint compare(gconstpointer _a, gconstpointer _b) {
+    const AvahiTimeEvent *a = _a,  *b = _b;
+
+    return avahi_timeval_compare(&a->expiry, &b->expiry);
+}
+
+static gboolean prepare_func(GSource *source, gint *timeout) {
+    AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
+    AvahiTimeEvent *e;
+    GTimeVal now;
+
+    g_assert(source);
+    g_assert(timeout);
+
+    if (!q->prioq->root) {
+        *timeout = -1;
+        return FALSE;
+    }
+    
+    e = q->prioq->root->data;
+    g_assert(e);
+
+    g_source_get_current_time(source, &now);
+
+    if (avahi_timeval_compare(&now, &e->expiry) >= 0) {
+        *timeout = -1;
+        return TRUE;
+    }
+
+    *timeout = (gint) (avahi_timeval_diff(&e->expiry, &now)/1000);
+    
+    return FALSE;
+}
+
+static gboolean check_func(GSource *source) {
+    AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
+    AvahiTimeEvent *e;
+    GTimeVal now;
+
+    g_assert(source);
+
+    if (!q->prioq->root)
+        return FALSE;
+
+    e = q->prioq->root->data;
+    g_assert(e);
+
+    g_source_get_current_time(source, &now);
+    
+    return avahi_timeval_compare(&now, &e->expiry) >= 0;
+}
+
+static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
+    AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
+    GTimeVal now;
+
+    g_assert(source);
+
+    g_source_get_current_time(source, &now);
+
+    while (q->prioq->root) {
+        AvahiTimeEvent *e = q->prioq->root->data;
+
+        if (avahi_timeval_compare(&now, &e->expiry) < 0)
+            break;
+
+        g_assert(e->callback);
+        e->callback(e, e->userdata);
+    }
+
+    return TRUE;
+}
+
+AvahiTimeEventQueue* avahi_time_event_queue_new(GMainContext *context, gint priority) {
+    AvahiTimeEventQueue *q;
+
+    static GSourceFuncs source_funcs = {
+        prepare_func,
+        check_func,
+        dispatch_func,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    q = (AvahiTimeEventQueue*) g_source_new(&source_funcs, sizeof(AvahiTimeEventQueue));
+    q->prioq = avahi_prio_queue_new(compare);
+
+    g_source_set_priority((GSource*) q, priority);
+    
+    g_source_attach(&q->source, context);
+    
+    return q;
+}
+
+void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
+    g_assert(q);
+
+    while (q->prioq->root)
+        avahi_time_event_queue_remove(q, q->prioq->root->data);
+    avahi_prio_queue_free(q->prioq);
+
+    g_source_destroy(&q->source);
+    g_source_unref(&q->source);
+}
+
+AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const GTimeVal *timeval, void (*callback)(AvahiTimeEvent *e, void *userdata), void *userdata) {
+    AvahiTimeEvent *e;
+    
+    g_assert(q);
+    g_assert(timeval);
+    g_assert(callback);
+    g_assert(userdata);
+
+    e = g_new(AvahiTimeEvent, 1);
+    e->queue = q;
+    e->expiry = *timeval;
+    e->callback = callback;
+    e->userdata = userdata;
+
+    e->node = avahi_prio_queue_put(q->prioq, e);
+    
+    return e;
+}
+
+void avahi_time_event_queue_remove(AvahiTimeEventQueue *q, AvahiTimeEvent *e) {
+    g_assert(q);
+    g_assert(e);
+    g_assert(e->queue == q);
+
+    avahi_prio_queue_remove(q->prioq, e->node);
+    g_free(e);
+}
+
+void avahi_time_event_queue_update(AvahiTimeEventQueue *q, AvahiTimeEvent *e, const GTimeVal *timeval) {
+    g_assert(q);
+    g_assert(e);
+    g_assert(e->queue == q);
+
+    e->expiry = *timeval;
+
+    avahi_prio_queue_shuffle(q->prioq, e->node);
+}
+
+AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q) {
+    g_assert(q);
+
+    return q->prioq->root ? q->prioq->root->data : NULL;
+}
+
+AvahiTimeEvent* avahi_time_event_next(AvahiTimeEvent *e) {
+    g_assert(e);
+
+    return e->node->next->data;
+}
+
+
diff --git a/libavahi-core/timeeventq.h b/libavahi-core/timeeventq.h
new file mode 100644 (file)
index 0000000..69ff860
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef footimeeventqhfoo
+#define footimeeventqhfoo
+
+typedef struct _AvahiTimeEventQueue AvahiTimeEventQueue;
+typedef struct _AvahiTimeEvent AvahiTimeEvent;
+
+#include "prioq.h"
+
+struct _AvahiTimeEvent {
+    AvahiTimeEventQueue *queue;
+    AvahiPrioQueueNode *node;
+    GTimeVal expiry;
+    void (*callback)(AvahiTimeEvent *e, void *userdata);
+    void *userdata;
+};
+
+struct _AvahiTimeEventQueue {
+    GSource source;
+    AvahiPrioQueue *prioq;
+};
+
+AvahiTimeEventQueue* avahi_time_event_queue_new(GMainContext *context, gint priority);
+void avahi_time_event_queue_free(AvahiTimeEventQueue *q);
+
+AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const GTimeVal *timeval, void (*callback)(AvahiTimeEvent *e, void *userdata), void *userdata);
+void avahi_time_event_queue_remove(AvahiTimeEventQueue *q, AvahiTimeEvent *e);
+
+void avahi_time_event_queue_update(AvahiTimeEventQueue *q, AvahiTimeEvent *e, const GTimeVal *timeval);
+
+AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q);
+AvahiTimeEvent* avahi_time_event_next(AvahiTimeEvent *e);
+
+
+
+
+#endif
diff --git a/libavahi-core/util.c b/libavahi-core/util.c
new file mode 100644 (file)
index 0000000..270a48f
--- /dev/null
@@ -0,0 +1,214 @@
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "util.h"
+
+gchar *avahi_get_host_name(void) {
+#ifdef HOST_NAME_MAX
+    char t[HOST_NAME_MAX];
+#else
+    char t[256];
+#endif
+    gethostname(t, sizeof(t));
+    t[sizeof(t)-1] = 0;
+    return avahi_normalize_name(t);
+}
+
+gchar *avahi_normalize_name(const gchar *s) {
+    size_t l;
+    g_assert(s);
+
+    l = strlen(s);
+
+    if (!l)
+        return g_strdup(".");
+
+    if (s[l-1] == '.')
+        return g_strdup(s);
+    
+    return g_strdup_printf("%s.", s);
+}
+
+gint avahi_timeval_compare(const GTimeVal *a, const GTimeVal *b) {
+    g_assert(a);
+    g_assert(b);
+
+    if (a->tv_sec < b->tv_sec)
+        return -1;
+
+    if (a->tv_sec > b->tv_sec)
+        return 1;
+
+    if (a->tv_usec < b->tv_usec)
+        return -1;
+
+    if (a->tv_usec > b->tv_usec)
+        return 1;
+
+    return 0;
+}
+
+glong avahi_timeval_diff(const GTimeVal *a, const GTimeVal *b) {
+    g_assert(a);
+    g_assert(b);
+
+    if (avahi_timeval_compare(a, b) < 0)
+        return avahi_timeval_diff(b, a);
+
+    return ((glong) a->tv_sec - b->tv_sec)*1000000 + a->tv_usec - b->tv_usec;
+}
+
+
+gint avahi_set_cloexec(gint fd) {
+    gint n;
+
+    g_assert(fd >= 0);
+    
+    if ((n = fcntl(fd, F_GETFD)) < 0)
+        return -1;
+
+    if (n & FD_CLOEXEC)
+        return 0;
+
+    return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
+}
+
+gint avahi_set_nonblock(gint fd) {
+    gint n;
+
+    g_assert(fd >= 0);
+
+    if ((n = fcntl(fd, F_GETFL)) < 0)
+        return -1;
+
+    if (n & O_NONBLOCK)
+        return 0;
+
+    return fcntl(fd, F_SETFL, n|O_NONBLOCK);
+}
+
+gint avahi_wait_for_write(gint fd) {
+    fd_set fds;
+    gint r;
+    
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+    
+    if ((r = select(fd+1, NULL, &fds, NULL, NULL)) < 0) {
+        g_message("select() failed: %s", strerror(errno));
+
+        return -1;
+    }
+    
+    g_assert(r > 0);
+
+    return 0;
+}
+
+GTimeVal *avahi_elapse_time(GTimeVal *tv, guint msec, guint jitter) {
+    g_assert(tv);
+
+    g_get_current_time(tv);
+
+    if (msec)
+        g_time_val_add(tv, msec*1000);
+
+    if (jitter)
+        g_time_val_add(tv, g_random_int_range(0, jitter) * 1000);
+        
+    return tv;
+}
+
+gint avahi_age(const GTimeVal *a) {
+    GTimeVal now;
+    
+    g_assert(a);
+
+    g_get_current_time(&now);
+
+    return avahi_timeval_diff(&now, a);
+}
+
+gboolean avahi_domain_cmp(const gchar *a, const gchar *b) {
+    int escaped_a = 0, escaped_b = 0;
+    g_assert(a);
+    g_assert(b);
+
+    for (;;) {
+        /* Check for escape characters "\" */
+        if ((escaped_a = *a == '\\'))
+            a ++;
+
+        if ((escaped_b = *b == '\\'))
+            b++;
+
+        /* Check for string end */
+        if (*a == 0 && *b == 0)
+            return 0;
+        
+        if (*a == 0 && !escaped_b && *b == '.' && *(b+1) == 0)
+            return 0;
+
+        if (!escaped_a && *a == '.' && *(a+1) == 0 && *b == 0)
+            return 0;
+
+        /* Compare characters */
+        if (escaped_a == escaped_b && *a != *b)
+            return *a < *b ? -1 : 1;
+
+        /* Next characters */
+        a++;
+        b++;
+        
+    }
+}
+
+gboolean avahi_domain_equal(const gchar *a, const gchar *b) {
+    return avahi_domain_cmp(a, b) == 0;
+}
+
+guint avahi_domain_hash(const gchar *p) {
+    char t[256];
+    strncpy(t, p, sizeof(t)-1);
+    t[sizeof(t)-1] = 0;
+
+    return g_int_hash(t);
+}
+
+void avahi_hexdump(gconstpointer p, guint size) {
+    const guint8 *c = p;
+    g_assert(p);
+
+    printf("Dumping %u bytes from %p:\n", size, p);
+    
+    while (size > 0) {
+        guint i;
+
+        for (i = 0; i < 16; i++) { 
+            if (i < size)
+                printf("%02x ", c[i]);
+            else
+                printf("   ");
+        }
+
+        for (i = 0; i < 16; i++) {
+            if (i < size)
+                printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
+            else
+                printf(" ");
+        }
+        
+        printf("\n");
+
+        c += 16;
+
+        if (size <= 16)
+            break;
+        
+        size -= 16;
+    }
+}
diff --git a/libavahi-core/util.h b/libavahi-core/util.h
new file mode 100644 (file)
index 0000000..7755ee2
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef fooutilhfoo
+#define fooutilhfoo
+
+#include <glib.h>
+
+gchar *avahi_normalize_name(const gchar *s); /* g_free() the result! */
+gchar *avahi_get_host_name(void); /* g_free() the result! */
+
+gint avahi_timeval_compare(const GTimeVal *a, const GTimeVal *b);
+glong avahi_timeval_diff(const GTimeVal *a, const GTimeVal *b);
+
+gint avahi_set_cloexec(gint fd);
+gint avahi_set_nonblock(gint fd);
+gint avahi_wait_for_write(gint fd);
+
+GTimeVal *avahi_elapse_time(GTimeVal *tv, guint msec, guint jitter);
+
+gint avahi_age(const GTimeVal *a);
+
+guint avahi_domain_hash(const gchar *p);
+gboolean avahi_domain_cmp(const gchar *a, const gchar *b);
+gboolean avahi_domain_equal(const gchar *a, const gchar *b);
+
+void avahi_hexdump(gconstpointer p, guint size);
+
+#endif
diff --git a/llist.h b/llist.h
deleted file mode 100644 (file)
index 16a16b6..0000000
--- a/llist.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef foollistfoo
-#define foollistfoo
-
-#include <glib.h>
-
-/* Some macros for maintaining doubly linked lists */
-
-/* The head of the linked list. Use this in the structure that shall
- * contain the head of the linked list */
-#define AVAHI_LLIST_HEAD(t,name) t *name
-
-/* The pointers in the linked list's items. Use this in the item structure */
-#define AVAHI_LLIST_FIELDS(t,name) t *name##_next, *name##_prev
-
-/* Initialize the list's head */
-#define AVAHI_LLIST_HEAD_INIT(t,head) do { (head) = NULL; } while(0)
-
-/* Initialize a list item */
-#define AVAHI_LLIST_INIT(t,name,item) do { \
-                               t *_item = (item); \
-                               g_assert(_item); \
-                               _item->name##_prev = _item->name##_next = NULL; \
-                               } while(0)
-
-/* Prepend an item to the list */
-#define AVAHI_LLIST_PREPEND(t,name,head,item) do { \
-                                        t **_head = &(head), *_item = (item); \
-                                        g_assert(_item); \
-                                        if ((_item->name##_next = *_head)) \
-                                           _item->name##_next->name##_prev = _item; \
-                                        _item->name##_prev = NULL; \
-                                        *_head = _item; \
-                                        } while (0)
-
-/* Remove an item from the list */
-#define AVAHI_LLIST_REMOVE(t,name,head,item) do { \
-                                    t **_head = &(head), *_item = (item); \
-                                    g_assert(_item); \
-                                    if (_item->name##_next) \
-                                       _item->name##_next->name##_prev = _item->name##_prev; \
-                                    if (_item->name##_prev) \
-                                       _item->name##_prev->name##_next = _item->name##_next; \
-                                    else {\
-                                       g_assert(*_head == _item); \
-                                       *_head = _item->name##_next; \
-                                    } \
-                                    _item->name##_next = _item->name##_prev = NULL; \
-                                    } while(0)
-
-#endif
diff --git a/main.c b/main.c
deleted file mode 100644 (file)
index 9699329..0000000
--- a/main.c
+++ /dev/null
@@ -1,74 +0,0 @@
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-
-#include "avahi.h"
-
-static gboolean quit_timeout(gpointer data) {
-    g_main_loop_quit(data);
-    return FALSE;
-}
-
-static gboolean dump_timeout(gpointer data) {
-    AvahiServer *Avahi = data;
-    avahi_server_dump(Avahi, stdout);
-    return TRUE;
-}
-
-static void subscription(AvahiSubscription *s, AvahiRecord *r, gint interface, guchar protocol, AvahiSubscriptionEvent event, gpointer userdata) {
-    gchar *t;
-    
-    g_assert(s);
-    g_assert(r);
-    g_assert(interface > 0);
-    g_assert(protocol != AF_UNSPEC);
-
-    g_message("SUBSCRIPTION: record [%s] on %i.%i is %s", t = avahi_record_to_string(r), interface, protocol,
-              event == AVAHI_SUBSCRIPTION_NEW ? "new" : (event == AVAHI_SUBSCRIPTION_CHANGE ? "changed" : "removed"));
-
-    g_free(t);
-}
-
-static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
-    g_message("entry group state: %i", state);
-}
-
-int main(int argc, char *argv[]) {
-    AvahiServer *avahi;
-    gchar *r;
-    GMainLoop *loop = NULL;
-    AvahiSubscription *s;
-    AvahiKey *k;
-    AvahiEntryGroup *g;
-
-    avahi = avahi_server_new(NULL);
-
-/*     g = avahi_entry_group_new(avahi, entry_group_callback, NULL);  */
-    
-/*    avahi_server_add_text(avahi, g, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, NULL, "hallo", NULL); */
-/*      avahi_server_add_service(avahi, g, 0, AF_UNSPEC, "_http._tcp", "gurke", NULL, NULL, 80, "foo", NULL);  */
-    
-/*     avahi_entry_group_commit(g);  */
-
-    avahi_server_dump(avahi, stdout);
-    
-    
-/*     k = avahi_key_new("ecstasy.local.", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_ANY); */
-/*     s = avahi_subscription_new(avahi, k, 0, AF_UNSPEC, subscription, NULL); */
-/*     avahi_key_unref(k); */
-
-    loop = g_main_loop_new(NULL, FALSE);
-    
-  /*   g_timeout_add(1000*20, dump_timeout, Avahi); */
-/*     g_timeout_add(1000*30, quit_timeout, loop); */
-    
-    g_main_loop_run(loop);
-    g_main_loop_unref(loop);
-
-/*     avahi_subscription_free(s); */
-    /* avahi_entry_group_free(g);  */
-    avahi_server_free(avahi);
-    
-    return 0;
-}
diff --git a/netlink.c b/netlink.c
deleted file mode 100644 (file)
index 1289749..0000000
--- a/netlink.c
+++ /dev/null
@@ -1,162 +0,0 @@
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#include "netlink.h"
-
-struct _AvahiNetlink {
-    GMainContext *context;
-    gint fd;
-    guint seq;
-    GPollFD poll_fd;
-    GSource *source;
-    void (*callback) (AvahiNetlink *nl, struct nlmsghdr *n, gpointer userdata);
-    gpointer userdata;
-};
-
-gboolean avahi_netlink_work(AvahiNetlink *nl, gboolean block) {
-    g_assert(nl);
-
-    for (;;) {
-        guint8 replybuf[64*1024];
-        ssize_t bytes;
-        struct nlmsghdr *p = (struct nlmsghdr *) replybuf;
-
-        if ((bytes = recv(nl->fd, replybuf, sizeof(replybuf), block ? 0 : MSG_DONTWAIT)) < 0) {
-
-            if (errno == EAGAIN || errno == EINTR)
-                break;
-
-            g_warning("NETLINK: recv() failed");
-            return FALSE;
-        }
-
-        if (nl->callback) {
-            for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
-                if (!NLMSG_OK(p, (size_t) bytes)) {
-                    g_warning("NETLINK: packet truncated");
-                    return FALSE;
-                }
-
-                nl->callback(nl, p, nl->userdata);
-            }
-        }
-
-        if (block)
-            break;
-    }
-
-    return TRUE;
-}
-
-static gboolean prepare_func(GSource *source, gint *timeout) {
-    g_assert(source);
-    g_assert(timeout);
-    
-    *timeout = -1;
-    return FALSE;
-}
-
-static gboolean check_func(GSource *source) {
-    AvahiNetlink* nl;
-    g_assert(source);
-
-    nl = *((AvahiNetlink**) (((guint8*) source) + sizeof(GSource)));
-    g_assert(nl);
-    
-    return nl->poll_fd.revents & (G_IO_IN|G_IO_HUP|G_IO_ERR);
-}
-
-static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
-    AvahiNetlink* nl;
-    g_assert(source);
-
-    nl = *((AvahiNetlink**) (((guint8*) source) + sizeof(GSource)));
-    g_assert(nl);
-    
-    return avahi_netlink_work(nl, FALSE);
-}
-
-AvahiNetlink *avahi_netlink_new(GMainContext *context, gint priority, guint32 groups, void (*cb) (AvahiNetlink *nl, struct nlmsghdr *n, gpointer userdata), gpointer userdata) {
-    int fd;
-    struct sockaddr_nl addr;
-    AvahiNetlink *nl;
-
-    static GSourceFuncs source_funcs = {
-        prepare_func,
-        check_func,
-        dispatch_func,
-        NULL,
-        NULL,
-        NULL
-    };
-    
-    g_assert(context);
-    g_assert(cb);
-
-    if ((fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
-        g_critical("NETLINK: socket(PF_NETLINK): %s", strerror(errno));
-        return NULL;
-    }
-    
-    memset(&addr, 0, sizeof(addr));
-    addr.nl_family = AF_NETLINK;
-    addr.nl_groups = groups;
-    addr.nl_pid = getpid();
-
-    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        close(fd);
-        g_critical("bind(): %s", strerror(errno));
-        return NULL;
-    }
-
-    nl = g_new(AvahiNetlink, 1);
-    nl->context = context;
-    g_main_context_ref(context);
-    nl->fd = fd;
-    nl->seq = 0;
-    nl->callback = cb;
-    nl->userdata = userdata;
-
-    nl->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(AvahiNetlink*));
-    *((AvahiNetlink**) (((guint8*) nl->source) + sizeof(GSource))) = nl;
-
-    g_source_set_priority(nl->source, priority);
-    
-    memset(&nl->poll_fd, 0, sizeof(GPollFD));
-    nl->poll_fd.fd = fd;
-    nl->poll_fd.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
-    g_source_add_poll(nl->source, &nl->poll_fd);
-    
-    g_source_attach(nl->source, nl->context);
-    
-    return nl;
-}
-
-void avahi_netlink_free(AvahiNetlink *nl) {
-    g_assert(nl);
-    
-    g_source_destroy(nl->source);
-    g_source_unref(nl->source);
-    g_main_context_unref(nl->context);
-    close(nl->fd);
-    g_free(nl);
-}
-
-int avahi_netlink_send(AvahiNetlink *nl, struct nlmsghdr *m, guint *ret_seq) {
-    g_assert(nl);
-    g_assert(m);
-    
-    m->nlmsg_seq = nl->seq++;
-    m->nlmsg_flags |= NLM_F_ACK;
-
-    if (send(nl->fd, m, m->nlmsg_len, 0) < 0) {
-        g_warning("NETLINK: send(): %s\n", strerror(errno));
-        return -1;
-    }
-
-    if (ret_seq)
-        *ret_seq = m->nlmsg_seq;
-
-    return 0;
-}
diff --git a/netlink.h b/netlink.h
deleted file mode 100644 (file)
index 8066aae..0000000
--- a/netlink.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef foonetlinkhfoo
-#define foonetlinkhfoo
-
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/netlink.h>
-
-#include <glib.h>
-
-struct _AvahiNetlink;
-typedef struct _AvahiNetlink AvahiNetlink;
-
-AvahiNetlink *avahi_netlink_new(GMainContext *c, gint priority, guint32 groups, void (*cb) (AvahiNetlink *n, struct nlmsghdr *m, gpointer userdata), gpointer userdata);
-void avahi_netlink_free(AvahiNetlink *n);
-
-int avahi_netlink_send(AvahiNetlink *n, struct nlmsghdr *m, guint *ret_seq);
-
-gboolean avahi_netlink_work(AvahiNetlink *n, gboolean block);
-
-#endif
diff --git a/prioq-test.c b/prioq-test.c
deleted file mode 100644 (file)
index 53a8383..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <time.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "prioq.h"
-
-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(AvahiPrioQueueNode *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) {
-            printf("%i <= %i: NO\n", a, b);
-            abort();
-        }
-    }
-
-    rec(n->left);
-    rec(n->right);
-}
-
-int main(int argc, char *argv[]) {
-    AvahiPrioQueue *q, *q2;
-    gint i, prev;
-
-    q = avahi_prio_queue_new(compare_int);
-    q2 = avahi_prio_queue_new(compare_ptr);
-
-    srand(time(NULL));
-
-    for (i = 0; i < 10000; i++)
-        avahi_prio_queue_put(q2, avahi_prio_queue_put(q, GINT_TO_POINTER(random() & 0xFFFF)));
-
-    while (q2->root) {
-        rec(q->root);
-        rec(q2->root);
-
-        g_assert(q->n_nodes == q2->n_nodes);
-
-        printf("%i\n", GPOINTER_TO_INT(((AvahiPrioQueueNode*)q2->root->data)->data));
-        
-        avahi_prio_queue_remove(q, q2->root->data);
-        avahi_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); */
-/*         avahi_prio_queue_remove(q, q->root); */
-/*         g_assert(v >= prev); */
-/*         prev = v; */
-/*     } */
-
-    avahi_prio_queue_free(q);
-    return 0;
-}
diff --git a/prioq.c b/prioq.c
deleted file mode 100644 (file)
index 2eedf27..0000000
--- a/prioq.c
+++ /dev/null
@@ -1,359 +0,0 @@
-#include "prioq.h"
-
-AvahiPrioQueue* avahi_prio_queue_new(gint (*compare) (gconstpointer a, gconstpointer b)) {
-    AvahiPrioQueue *q;
-    g_assert(compare);
-
-    q = g_new(AvahiPrioQueue, 1);
-    q->root = q->last = NULL;
-    q->n_nodes = 0;
-    q->compare = compare;
-    return q;
-}
-
-void avahi_prio_queue_free(AvahiPrioQueue *q) {
-    g_assert(q);
-
-    while (q->last)
-        avahi_prio_queue_remove(q, q->last);
-
-    g_assert(!q->n_nodes);
-    g_free(q);
-}
-
-static AvahiPrioQueueNode* get_node_at_xy(AvahiPrioQueue *q, guint x, guint y) {
-    guint r;
-    AvahiPrioQueueNode *n;
-    g_assert(q);
-
-    n = q->root;
-    g_assert(n);
-
-    for (r = 0; r < y; r++) {
-        g_assert(n);
-        
-        if ((x >> (y-r-1)) & 1)
-            n = n->right;
-        else
-            n = n->left;
-    }
-
-    g_assert(n->x == x);
-    g_assert(n->y == y);
-
-    return n;
-}
-
-static void exchange_nodes(AvahiPrioQueue *q, AvahiPrioQueueNode *a, AvahiPrioQueueNode *b) {
-    AvahiPrioQueueNode *l, *r, *p, *ap, *an, *bp, *bn;
-    gint t;
-    g_assert(q);
-    g_assert(a);
-    g_assert(b);
-    g_assert(a != b);
-
-    /* Swap positions */
-    t = a->x; a->x = b->x; b->x = t;
-    t = a->y; a->y = b->y; b->y = t;
-
-    if (a->parent == b) {
-        /* B is parent of A */
-        
-        p = b->parent;
-        b->parent = a;
-
-        if ((a->parent = p)) {
-            if (a->parent->left == b)
-                a->parent->left = a;
-            else
-                a->parent->right = a;
-        } else
-            q->root = a;
-
-        if (b->left == a) {
-            if ((b->left = a->left))
-                b->left->parent = b;
-            a->left = b;
-
-            r = a->right;
-            if ((a->right = b->right))
-                a->right->parent = a;
-            if ((b->right = r))
-                b->right->parent = b;
-            
-        } else {
-            if ((b->right = a->right))
-                b->right->parent = b;
-            a->right = b;
-
-            l = a->left;
-            if ((a->left = b->left))
-                a->left->parent = a;
-            if ((b->left = l))
-                b->left->parent = b;
-        }
-    } else if (b->parent == a) {
-        /* A ist parent of B */
-        
-        p = a->parent;
-        a->parent = b;
-
-        if ((b->parent = p)) {
-            if (b->parent->left == a)
-                b->parent->left = b;
-            else
-                b->parent->right = b;
-        } else
-            q->root = b;
-
-        if (a->left == b) {
-            if ((a->left = b->left))
-                a->left->parent = a;
-            b->left = a;
-
-            r = a->right;
-            if ((a->right = b->right))
-                a->right->parent = a;
-            if ((b->right = r))
-                b->right->parent = b;
-        } else {
-            if ((a->right = b->right))
-                a->right->parent = a;
-            b->right = a;
-
-            l = a->left;
-            if ((a->left = b->left))
-                a->left->parent = a;
-            if ((b->left = l))
-                b->left->parent = b;
-        }
-    } else {
-        AvahiPrioQueueNode *apl = NULL, *bpl = NULL;
-        
-        /* Swap parents */
-        ap = a->parent;
-        bp = b->parent;
-
-        if (ap)
-            apl = ap->left;
-        if (bp)
-            bpl = bp->left;
-        
-        if ((a->parent = bp)) {
-            if (bpl == b)
-                bp->left = a;
-            else 
-                bp->right = a;
-        } else
-            q->root = a;
-                
-        if ((b->parent = ap)) {
-            if (apl == a)
-                ap->left = b;
-            else
-                ap->right = b;
-        } else
-            q->root = b;
-
-        /* Swap children */
-        l = a->left; 
-        r = a->right; 
-
-        if ((a->left = b->left))
-            a->left->parent = a;
-
-        if ((b->left = l))
-            b->left->parent = b;
-
-        if ((a->right = b->right))
-            a->right->parent = a;
-
-        if ((b->right = r))
-            b->right->parent = b;
-    }
-    
-    /* Swap siblings */
-    ap = a->prev; an = a->next;
-    bp = b->prev; bn = b->next;
-
-    if (a->next == b) {
-        /* A is predecessor of B */
-        a->prev = b;
-        b->next = a;
-
-        if ((a->next = bn))
-            a->next->prev = a;
-        else
-            q->last = a;
-
-        if ((b->prev = ap))
-            b->prev->next = b;
-        
-    } else if (b->next == a) {
-        /* B is predecessor of A */
-        a->next = b;
-        b->prev = a;
-
-        if ((a->prev = bp))
-            a->prev->next = a;
-
-        if ((b->next = an))
-            b->next->prev = b;
-        else
-            q->last = b;
-
-    } else {
-        /* A is no neighbour of B */
-
-        if ((a->prev = bp))
-            a->prev->next = a;
-        
-        if ((a->next = bn))
-            a->next->prev = a;
-        else
-            q->last = a;
-        
-        if ((b->prev = ap))
-            b->prev->next = b;
-        
-        if ((b->next = an))
-            b->next->prev = b;
-        else
-            q->last = b;
-    }
-}
-
-/* Move a node to the correct position */
-void avahi_prio_queue_shuffle(AvahiPrioQueue *q, AvahiPrioQueueNode *n) {
-    g_assert(q);
-    g_assert(n);
-
-    /* Move up until the position is OK */
-    while (n->parent && q->compare(n->parent->data, n->data) > 0)
-        exchange_nodes(q, n, n->parent);
-
-    /* Move down until the position is OK */
-    for (;;) {
-        AvahiPrioQueueNode *min;
-
-        if (!(min = n->left)) {
-            /* No children */
-            g_assert(!n->right);
-            break;
-        }
-
-        if (n->right && q->compare(n->right->data, min->data) < 0)
-            min = n->right;
-
-        /* min now contains the smaller one of our two children */
-
-        if (q->compare(n->data, min->data) <= 0)
-            /* Order OK */
-            break;
-
-        exchange_nodes(q, n, min);
-    }
-}
-
-AvahiPrioQueueNode* avahi_prio_queue_put(AvahiPrioQueue *q, gpointer data) {
-    AvahiPrioQueueNode *n;
-    g_assert(q);
-
-    n = g_new(AvahiPrioQueueNode, 1);
-    n->queue = q;
-    n->data = data;
-
-    if (q->last) {
-        g_assert(q->root);
-        g_assert(q->n_nodes);
-         
-        n->y = q->last->y;
-        n->x = q->last->x+1;
-
-        if (n->x >= ((guint) 1 << n->y)) {
-            n->x = 0;
-            n->y++;
-        }
-
-        q->last->next = n;
-        n->prev = q->last;
-        
-        g_assert(n->y > 0);
-        n->parent = get_node_at_xy(q, n->x/2, n->y-1);
-
-        if (n->x & 1)
-            n->parent->right = n;
-        else
-            n->parent->left = n;
-    } else {
-        g_assert(!q->root);
-        g_assert(!q->n_nodes);
-        
-        n->y = n->x = 0;
-        q->root = n;
-        n->prev = n->parent = NULL;
-    }
-
-    n->next = n->left = n->right = NULL;
-    q->last = n;
-    q->n_nodes++;
-
-    avahi_prio_queue_shuffle(q, n);
-
-    return n;
-}
-
-void avahi_prio_queue_remove(AvahiPrioQueue *q, AvahiPrioQueueNode *n) {
-    g_assert(q);
-    g_assert(n);
-
-    if (n != q->last) {
-        AvahiPrioQueueNode *replacement = q->last;
-        exchange_nodes(q, replacement, n);
-        avahi_prio_queue_remove(q, n);
-        avahi_prio_queue_shuffle(q, replacement);
-        return;
-    }
-
-    g_assert(n == q->last);
-    g_assert(!n->next);
-    g_assert(!n->left);
-    g_assert(!n->right);
-
-    q->last = n->prev;
-    
-    if (n->prev) {
-        n->prev->next = NULL;
-        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 {
-            g_assert(n->parent->right == n);
-            g_assert(n->parent->left != NULL);
-            n->parent->right = NULL;
-        }
-    } else {
-        g_assert(q->root == n);
-        g_assert(!n->prev);
-        g_assert(q->n_nodes == 1);
-        q->root = NULL;
-    }
-
-    g_free(n);
-
-    g_assert(q->n_nodes > 0);
-    q->n_nodes--;
-}
-
diff --git a/prioq.h b/prioq.h
deleted file mode 100644 (file)
index 6b5babb..0000000
--- a/prioq.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef fooprioqhfoo
-#define fooprioqhfoo
-
-#include <glib.h>
-
-struct _AvahiPrioQueue;
-typedef struct _AvahiPrioQueue AvahiPrioQueue;
-
-struct _AvahiPrioQueueNode;
-typedef struct _AvahiPrioQueueNode AvahiPrioQueueNode;
-
-struct _AvahiPrioQueue {
-    AvahiPrioQueueNode *root, *last;
-    
-    guint n_nodes;
-    gint (*compare) (gconstpointer a, gconstpointer b);
-};
-
-struct _AvahiPrioQueueNode {
-    AvahiPrioQueue *queue;
-    gpointer data;
-    guint x, y;
-
-    AvahiPrioQueueNode *left, *right, *parent, *next, *prev;
-};
-
-AvahiPrioQueue* avahi_prio_queue_new(gint (*compare) (gconstpointer a, gconstpointer b));
-void avahi_prio_queue_free(AvahiPrioQueue *q);
-
-AvahiPrioQueueNode* avahi_prio_queue_put(AvahiPrioQueue *q, gpointer data);
-void avahi_prio_queue_remove(AvahiPrioQueue *q, AvahiPrioQueueNode *n);
-
-void avahi_prio_queue_shuffle(AvahiPrioQueue *q, AvahiPrioQueueNode *n);
-
-#endif
diff --git a/psched.c b/psched.c
deleted file mode 100644 (file)
index faa2fa9..0000000
--- a/psched.c
+++ /dev/null
@@ -1,715 +0,0 @@
-#include <string.h>
-
-#include "util.h"
-#include "psched.h"
-
-#define AVAHI_QUERY_HISTORY_MSEC 100
-#define AVAHI_QUERY_DEFER_MSEC 100
-#define AVAHI_RESPONSE_HISTORY_MSEC 700
-#define AVAHI_RESPONSE_DEFER_MSEC 20
-#define AVAHI_RESPONSE_JITTER_MSEC 100
-#define AVAHI_PROBE_DEFER_MSEC 70
-
-AvahiPacketScheduler *avahi_packet_scheduler_new(AvahiServer *server, AvahiInterface *i) {
-    AvahiPacketScheduler *s;
-
-    g_assert(server);
-    g_assert(i);
-
-    s = g_new(AvahiPacketScheduler, 1);
-    s->server = server;
-    s->interface = i;
-
-    AVAHI_LLIST_HEAD_INIT(AvahiQueryJob, s->query_jobs);
-    AVAHI_LLIST_HEAD_INIT(AvahiResponseJob, s->response_jobs);
-    AVAHI_LLIST_HEAD_INIT(AvahiKnownAnswer, s->known_answers);
-    AVAHI_LLIST_HEAD_INIT(AvahiProbeJob, s->probe_jobs);
-    
-    return s;
-}
-
-static void query_job_free(AvahiPacketScheduler *s, AvahiQueryJob *qj) {
-    g_assert(qj);
-
-    if (qj->time_event)
-        avahi_time_event_queue_remove(qj->scheduler->server->time_event_queue, qj->time_event);
-
-    AVAHI_LLIST_REMOVE(AvahiQueryJob, jobs, s->query_jobs, qj);
-    
-    avahi_key_unref(qj->key);
-    g_free(qj);
-}
-
-static void response_job_free(AvahiPacketScheduler *s, AvahiResponseJob *rj) {
-    g_assert(rj);
-
-    if (rj->time_event)
-        avahi_time_event_queue_remove(rj->scheduler->server->time_event_queue, rj->time_event);
-
-    AVAHI_LLIST_REMOVE(AvahiResponseJob, jobs, s->response_jobs, rj);
-
-    avahi_record_unref(rj->record);
-    g_free(rj);
-}
-
-static void probe_job_free(AvahiPacketScheduler *s, AvahiProbeJob *pj) {
-    g_assert(pj);
-
-    if (pj->time_event)
-        avahi_time_event_queue_remove(pj->scheduler->server->time_event_queue, pj->time_event);
-
-    AVAHI_LLIST_REMOVE(AvahiProbeJob, jobs, s->probe_jobs, pj);
-
-    avahi_record_unref(pj->record);
-    g_free(pj);
-}
-
-void avahi_packet_scheduler_free(AvahiPacketScheduler *s) {
-    AvahiQueryJob *qj;
-    AvahiResponseJob *rj;
-    AvahiProbeJob *pj;
-    AvahiTimeEvent *e;
-
-    g_assert(s);
-
-    g_assert(!s->known_answers);
-    
-    while ((qj = s->query_jobs))
-        query_job_free(s, qj);
-    while ((rj = s->response_jobs))
-        response_job_free(s, rj);
-    while ((pj = s->probe_jobs))
-        probe_job_free(s, pj);
-
-    g_free(s);
-}
-
-static gpointer known_answer_walk_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) {
-    AvahiPacketScheduler *s = userdata;
-    AvahiKnownAnswer *ka;
-    
-    g_assert(c);
-    g_assert(pattern);
-    g_assert(e);
-    g_assert(s);
-
-    if (avahi_cache_entry_half_ttl(c, e))
-        return NULL;
-    
-    ka = g_new0(AvahiKnownAnswer, 1);
-    ka->scheduler = s;
-    ka->record = avahi_record_ref(e->record);
-
-    AVAHI_LLIST_PREPEND(AvahiKnownAnswer, known_answer, s->known_answers, ka);
-    return NULL;
-}
-
-static guint8* packet_add_query_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiQueryJob *qj) {
-    guint8 *d;
-
-    g_assert(s);
-    g_assert(p);
-    g_assert(qj);
-
-    if ((d = avahi_dns_packet_append_key(p, qj->key, FALSE))) {
-        GTimeVal tv;
-
-        qj->done = 1;
-
-        /* Drop query after some time from history */
-        avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0);
-        avahi_time_event_queue_update(s->server->time_event_queue, qj->time_event, &tv);
-
-        g_get_current_time(&qj->delivery);
-
-        /* Add all matching known answers to the list */
-        avahi_cache_walk(s->interface->cache, qj->key, known_answer_walk_callback, s);
-    }
-
-    return d;
-}
-
-static void append_known_answers_and_send(AvahiPacketScheduler *s, AvahiDnsPacket *p) {
-    AvahiKnownAnswer *ka;
-    guint n;
-    g_assert(s);
-    g_assert(p);
-
-    n = 0;
-    
-    while ((ka = s->known_answers)) {
-
-        while (!avahi_dns_packet_append_record(p, ka->record, FALSE)) {
-
-            g_assert(!avahi_dns_packet_is_empty(p));
-
-            avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) | AVAHI_DNS_FLAG_TC);
-            avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ANCOUNT, n);
-            avahi_interface_send_packet(s->interface, p);
-            avahi_dns_packet_free(p);
-
-            p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
-            n = 0;
-        }
-
-        AVAHI_LLIST_REMOVE(AvahiKnownAnswer, known_answer, s->known_answers, ka);
-        avahi_record_unref(ka->record);
-        g_free(ka);
-        
-        n++;
-    }
-    
-    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ANCOUNT, n);
-    avahi_interface_send_packet(s->interface, p);
-    avahi_dns_packet_free(p);
-}
-
-static void query_elapse(AvahiTimeEvent *e, gpointer data) {
-    AvahiQueryJob *qj = data;
-    AvahiPacketScheduler *s;
-    AvahiDnsPacket *p;
-    guint n;
-    guint8 *d;
-
-    g_assert(qj);
-    s = qj->scheduler;
-
-    if (qj->done) {
-        /* Lets remove it  from the history */
-        query_job_free(s, qj);
-        return;
-    }
-
-    g_assert(!s->known_answers);
-    
-    p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
-    d = packet_add_query_job(s, p, qj);
-    g_assert(d);
-    n = 1;
-
-    /* Try to fill up packet with more queries, if available */
-    for (qj = s->query_jobs; qj; qj = qj->jobs_next) {
-
-        if (qj->done)
-            continue;
-
-        if (!packet_add_query_job(s, p, qj))
-            break;
-
-        n++;
-    }
-
-    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, n);
-
-    /* Now add known answers */
-    append_known_answers_and_send(s, p);
-}
-
-AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) {
-    AvahiQueryJob *qj;
-    
-    g_assert(s);
-    g_assert(key);
-
-    qj = g_new(AvahiQueryJob, 1);
-    qj->scheduler = s;
-    qj->key = avahi_key_ref(key);
-    qj->done = FALSE;
-    qj->time_event = NULL;
-    
-    AVAHI_LLIST_PREPEND(AvahiQueryJob, jobs, s->query_jobs, qj);
-
-    return qj;
-}
-
-void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) {
-    GTimeVal tv;
-    AvahiQueryJob *qj;
-    
-    g_assert(s);
-    g_assert(key);
-
-    avahi_elapse_time(&tv, immediately ? 0 : AVAHI_QUERY_DEFER_MSEC, 0);
-
-    for (qj = s->query_jobs; qj; qj = qj->jobs_next) {
-
-        if (avahi_key_equal(qj->key, key)) {
-
-            glong d = avahi_timeval_diff(&tv, &qj->delivery);
-
-            /* Duplicate questions suppression */
-            if (d >= 0 && d <= AVAHI_QUERY_HISTORY_MSEC*1000) {
-                g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
-                return;
-            }
-            
-            query_job_free(s, qj);
-            break;
-        }
-
-    }
-    
-    qj = query_job_new(s, key);
-    qj->delivery = tv;
-    qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &qj->delivery, query_elapse, qj);
-}
-
-static guint8* packet_add_response_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) {
-    guint8 *d;
-
-    g_assert(s);
-    g_assert(p);
-    g_assert(rj);
-
-    if ((d = avahi_dns_packet_append_record(p, rj->record, rj->flush_cache))) {
-        GTimeVal tv;
-
-        rj->done = 1;
-
-        /* Drop response after some time from history */
-        avahi_elapse_time(&tv, AVAHI_RESPONSE_HISTORY_MSEC, 0);
-        avahi_time_event_queue_update(s->server->time_event_queue, rj->time_event, &tv);
-
-        g_get_current_time(&rj->delivery);
-    }
-
-    return d;
-}
-
-static void send_response_packet(AvahiPacketScheduler *s, AvahiResponseJob *rj) {
-    AvahiDnsPacket *p;
-    guint n;
-
-    g_assert(s);
-
-    p = avahi_dns_packet_new_response(s->interface->hardware->mtu - 200);
-    n = 0;
-
-    /* If a job was specified, put it in the packet. */
-    if (rj) {
-        guint8 *d;
-        d = packet_add_response_job(s, p, rj);
-        g_assert(d);
-        n++;
-    }
-
-    /* Try to fill up packet with more responses, if available */
-    for (rj = s->response_jobs; rj; rj = rj->jobs_next) {
-
-        if (rj->done)
-            continue;
-
-        if (!packet_add_response_job(s, p, rj))
-            break;
-
-        n++;
-    }
-
-    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ANCOUNT, n);
-    avahi_interface_send_packet(s->interface, p);
-    avahi_dns_packet_free(p);
-}
-
-static void response_elapse(AvahiTimeEvent *e, gpointer data) {
-    AvahiResponseJob *rj = data;
-    AvahiPacketScheduler *s;
-
-    g_assert(rj);
-    s = rj->scheduler;
-
-    if (rj->done) {
-        /* Lets remove it  from the history */
-        response_job_free(s, rj);
-        return;
-    }
-
-    send_response_packet(s, rj);
-}
-
-static AvahiResponseJob* look_for_response(AvahiPacketScheduler *s, AvahiRecord *record) {
-    AvahiResponseJob *rj;
-
-    g_assert(s);
-    g_assert(record);
-
-    for (rj = s->response_jobs; rj; rj = rj->jobs_next)
-        if (avahi_record_equal_no_ttl(rj->record, record))
-            return rj;
-
-    return NULL;
-}
-
-static AvahiResponseJob* response_job_new(AvahiPacketScheduler *s, AvahiRecord *record) {
-    AvahiResponseJob *rj;
-    
-    g_assert(s);
-    g_assert(record);
-
-    rj = g_new(AvahiResponseJob, 1);
-    rj->scheduler = s;
-    rj->record = avahi_record_ref(record);
-    rj->done = FALSE;
-    rj->time_event = NULL;
-    rj->address_valid = FALSE;
-    rj->flush_cache = FALSE;
-    
-    AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->response_jobs, rj);
-
-    return rj;
-}
-
-void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
-    AvahiResponseJob *rj;
-    GTimeVal tv;
-    gchar *t;
-    
-    g_assert(s);
-    g_assert(record);
-
-    g_assert(!avahi_key_is_pattern(record->key));
-    
-    avahi_elapse_time(&tv, immediately ? 0 : AVAHI_RESPONSE_DEFER_MSEC, immediately ? 0 : AVAHI_RESPONSE_JITTER_MSEC);
-    
-    /* Don't send out duplicates */
-    
-    if ((rj = look_for_response(s, record))) {
-        glong d;
-
-        d = avahi_timeval_diff(&tv, &rj->delivery);
-        
-        /* If there's already a matching packet in our history or in
-         * the schedule, we do nothing. */
-        if (!!record->ttl == !!rj->record->ttl &&
-            d >= 0 && d <= AVAHI_RESPONSE_HISTORY_MSEC*1000) {
-            g_message("WARNING! DUPLICATE RESPONSE SUPPRESSION ACTIVE!");
-
-            /* This job is no longer specific to a single querier, so
-             * make sure it isn't suppressed by known answer
-             * suppresion */
-
-            if (rj->address_valid && (!a || avahi_address_cmp(a, &rj->address) != 0))
-                rj->address_valid = FALSE;
-
-            rj->flush_cache = flush_cache;
-            
-            return;
-        }
-
-        /* Either one was a goodbye packet, but the other was not, so
-         * let's drop the older one. */
-        response_job_free(s, rj);
-    }
-
-/*     g_message("ACCEPTED NEW RESPONSE [%s]", t = avahi_record_to_string(record)); */
-/*     g_free(t); */
-
-    /* Create a new job and schedule it */
-    rj = response_job_new(s, record);
-    rj->flush_cache = flush_cache;
-    rj->delivery = tv;
-    rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &rj->delivery, response_elapse, rj);
-
-    /* Store the address of the host this messages is intended to, so
-       that we can drop this job in case a truncated message with
-       known answer suppresion entries is recieved */
-
-    if ((rj->address_valid = !!a))
-        rj->address = *a;
-}
-
-void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) {
-    GTimeVal tv;
-    AvahiQueryJob *qj;
-    
-    g_assert(s);
-    g_assert(key);
-
-    /* This function is called whenever an incoming query was
-     * receieved. We drop all scheduled queries which match here. The
-     * keyword is "DUPLICATE QUESTION SUPPRESION". */
-
-    for (qj = s->query_jobs; qj; qj = qj->jobs_next)
-        if (avahi_key_equal(qj->key, key)) {
-
-            if (qj->done)
-                return;
-
-            goto mark_done;
-        }
-
-
-    /* No matching job was found. Add the query to the history */
-    qj = query_job_new(s, key);
-
-mark_done:
-    qj->done = TRUE;
-
-    /* Drop the query after some time */
-    avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0);
-    qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, query_elapse, qj);
-
-    g_get_current_time(&qj->delivery);
-}
-
-void response_job_set_elapse_time(AvahiPacketScheduler *s, AvahiResponseJob *rj, guint msec, guint jitter) {
-    GTimeVal tv;
-
-    g_assert(s);
-    g_assert(rj);
-
-    avahi_elapse_time(&tv, msec, jitter);
-
-    if (rj->time_event)
-        avahi_time_event_queue_update(s->server->time_event_queue, rj->time_event, &tv);
-    else
-        rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, response_elapse, rj);
-    
-}
-
-void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record) {
-    AvahiResponseJob *rj;
-    
-    g_assert(s);
-    g_assert(record);
-
-    /* This function is called whenever an incoming response was
-     * receieved. We drop all scheduled responses which match
-     * here. The keyword is "DUPLICATE ANSWER SUPPRESION". */
-    
-    for (rj = s->response_jobs; rj; rj = rj->jobs_next)
-        if (avahi_record_equal_no_ttl(rj->record, record)) {
-
-            if (rj->done) {
-
-                if (!!record->ttl == !!rj->record->ttl) {
-                    /* An entry like this is already in our history,
-                     * so let's get out of here! */
-                    
-                    return;
-                    
-                } else {
-                    /* Either one was a goodbye packet but other was
-                     * none. We remove the history entry, and add a
-                     * new one */
-                    
-                    response_job_free(s, rj);
-                    break;
-                }
-        
-            } else {
-
-                if (!!record->ttl == !!rj->record->ttl) {
-
-                    /* The incoming packet matches our scheduled
-                     * record, so let's mark that one as done */
-
-                    goto mark_done;
-                    
-                } else {
-
-                    /* Either one was a goodbye packet but other was
-                     * none. We ignore the incoming packet. */
-
-                    return;
-                }
-            }
-        }
-
-    /* No matching job was found. Add the query to the history */
-    rj = response_job_new(s, record);
-
-mark_done:
-    rj->done = TRUE;
-                    
-    /* Drop response after 500ms from history */
-    response_job_set_elapse_time(s, rj, AVAHI_RESPONSE_HISTORY_MSEC, 0);
-
-    g_get_current_time(&rj->delivery);
-}
-
-void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *a) {
-    AvahiResponseJob *rj;
-    
-    g_assert(s);
-    g_assert(record);
-    g_assert(a);
-
-    for (rj = s->response_jobs; rj; rj = rj->jobs_next) {
-
-        g_assert(record->ttl > 0);
-        g_assert(rj->record->ttl/2);
-        
-        if (avahi_record_equal_no_ttl(rj->record, record))
-            if (rj->address_valid)
-                if (avahi_address_cmp(&rj->address, a))
-                    if (record->ttl >= rj->record->ttl/2) {
-
-            /* Let's suppress it */
-
-            response_job_free(s, rj);
-            break;
-        }
-    }
-}
-
-void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s) {
-    AvahiResponseJob *rj;
-    
-    g_assert(s);
-
-    /* Send all scheduled responses, ignoring the scheduled time */
-    
-    for (rj = s->response_jobs; rj; rj = rj->jobs_next)
-        if (!rj->done)
-            send_response_packet(s, rj);
-}
-
-static AvahiProbeJob* probe_job_new(AvahiPacketScheduler *s, AvahiRecord *record) {
-    AvahiProbeJob *pj;
-    
-    g_assert(s);
-    g_assert(record);
-
-    pj = g_new(AvahiProbeJob, 1);
-    pj->scheduler = s;
-    pj->record = avahi_record_ref(record);
-    pj->time_event = NULL;
-    pj->chosen = FALSE;
-    
-    AVAHI_LLIST_PREPEND(AvahiProbeJob, jobs, s->probe_jobs, pj);
-
-    return pj;
-}
-
-static guint8* packet_add_probe_query(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiProbeJob *pj) {
-    guint size;
-    guint8 *ret;
-    AvahiKey *k;
-
-    g_assert(s);
-    g_assert(p);
-    g_assert(pj);
-
-    g_assert(!pj->chosen);
-    
-    /* Estimate the size for this record */
-    size =
-        avahi_key_get_estimate_size(pj->record->key) +
-        avahi_record_get_estimate_size(pj->record);
-
-    /* Too large */
-    if (size > avahi_dns_packet_space(p))
-        return NULL;
-
-    /* Create the probe query */
-    k = avahi_key_new(pj->record->key->name, pj->record->key->class, AVAHI_DNS_TYPE_ANY);
-    ret = avahi_dns_packet_append_key(p, k, FALSE);
-    g_assert(ret);
-
-    /* Mark this job for addition to the packet */
-    pj->chosen = TRUE;
-
-    /* Scan for more jobs whith matching key pattern */
-    for (pj = s->probe_jobs; pj; pj = pj->jobs_next) {
-        if (pj->chosen)
-            continue;
-
-        /* Does the record match the probe? */
-        if (k->class != pj->record->key->class || !avahi_domain_equal(k->name, pj->record->key->name))
-            continue;
-        
-        /* This job wouldn't fit in */
-        if (avahi_record_get_estimate_size(pj->record) > avahi_dns_packet_space(p))
-            break;
-
-        /* Mark this job for addition to the packet */
-        pj->chosen = TRUE;
-    }
-
-    avahi_key_unref(k);
-            
-    return ret;
-}
-
-static void probe_elapse(AvahiTimeEvent *e, gpointer data) {
-    AvahiProbeJob *pj = data, *next;
-    AvahiPacketScheduler *s;
-    AvahiDnsPacket *p;
-    guint n;
-    guint8 *d;
-
-    g_assert(pj);
-    s = pj->scheduler;
-
-    p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
-
-    /* Add the import probe */
-    if (!packet_add_probe_query(s, p, pj)) {
-        g_warning("Record too large! ---");
-        avahi_dns_packet_free(p);
-        return;
-    }
-
-    n = 1;
-    
-    /* Try to fill up packet with more probes, if available */
-    for (pj = s->probe_jobs; pj; pj = pj->jobs_next) {
-
-        if (pj->chosen)
-            continue;
-        
-        if (!packet_add_probe_query(s, p, pj))
-            break;
-        
-        n++;
-    }
-
-    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, n);
-
-    n = 0;
-
-    /* Now add the chosen records to the authorative section */
-    for (pj = s->probe_jobs; pj; pj = next) {
-
-        next = pj->jobs_next;
-
-        if (!pj->chosen)
-            continue;
-
-        if (!avahi_dns_packet_append_record(p, pj->record, TRUE)) {
-            g_warning("Bad probe size estimate!");
-
-            /* Unmark all following jobs */
-            for (; pj; pj = pj->jobs_next)
-                pj->chosen = FALSE;
-            
-            break;
-        }
-
-        probe_job_free(s, pj);
-        
-        n ++;
-    }
-    
-    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_NSCOUNT, n);
-
-    /* Send it now */
-    avahi_interface_send_packet(s->interface, p);
-    avahi_dns_packet_free(p);
-}
-
-void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately) {
-    AvahiProbeJob *pj;
-    GTimeVal tv;
-    
-    g_assert(s);
-    g_assert(record);
-    g_assert(!avahi_key_is_pattern(record->key));
-    
-    avahi_elapse_time(&tv, immediately ? 0 : AVAHI_PROBE_DEFER_MSEC, 0);
-
-    /* Create a new job and schedule it */
-    pj = probe_job_new(s, record);
-    pj->delivery = tv;
-    pj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &pj->delivery, probe_elapse, pj);
-}
diff --git a/psched.h b/psched.h
deleted file mode 100644 (file)
index 8f5e77c..0000000
--- a/psched.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef foopschedhfoo
-#define foopschedhfoo
-
-typedef struct _AvahiQueryJob AvahiQueryJob;
-typedef struct _AvahiResponseJob AvahiResponseJob;
-typedef struct _AvahiPacketScheduler AvahiPacketScheduler;
-typedef struct _AvahiKnownAnswer AvahiKnownAnswer;
-typedef struct _AvahiProbeJob AvahiProbeJob;
-
-#include "timeeventq.h"
-#include "rr.h"
-#include "llist.h"
-#include "iface.h"
-
-struct _AvahiQueryJob {
-    AvahiPacketScheduler *scheduler;
-    AvahiTimeEvent *time_event;
-    AvahiKey *key;
-    gboolean done;
-    GTimeVal delivery;
-    AVAHI_LLIST_FIELDS(AvahiQueryJob, jobs);
-};
-
-struct _AvahiResponseJob {
-    AvahiPacketScheduler *scheduler;
-    AvahiTimeEvent *time_event;
-    AvahiRecord *record;
-    AvahiAddress address;
-    gboolean address_valid;
-    gboolean done;
-    GTimeVal delivery;
-    gboolean flush_cache;
-    AVAHI_LLIST_FIELDS(AvahiResponseJob, jobs);
-};
-
-struct _AvahiKnownAnswer {
-    AvahiPacketScheduler *scheduler;
-    AvahiRecord *record;
-
-    AVAHI_LLIST_FIELDS(AvahiKnownAnswer, known_answer);
-};
-
-struct _AvahiProbeJob {
-    AvahiPacketScheduler *scheduler;
-    AvahiTimeEvent *time_event;
-    AvahiRecord *record;
-
-    gboolean chosen; /* Use for packet assembling */
-    GTimeVal delivery;
-    
-    AVAHI_LLIST_FIELDS(AvahiProbeJob, jobs);
-};
-
-struct _AvahiPacketScheduler {
-    AvahiServer *server;
-    
-    AvahiInterface *interface;
-
-    AVAHI_LLIST_HEAD(AvahiQueryJob, query_jobs);
-    AVAHI_LLIST_HEAD(AvahiResponseJob, response_jobs);
-    AVAHI_LLIST_HEAD(AvahiKnownAnswer, known_answers);
-    AVAHI_LLIST_HEAD(AvahiProbeJob, probe_jobs);
-};
-
-AvahiPacketScheduler *avahi_packet_scheduler_new(AvahiServer *server, AvahiInterface *i);
-void avahi_packet_scheduler_free(AvahiPacketScheduler *s);
-
-void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately);
-void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
-void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately);
-
-void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key);
-void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record);
-void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *a);
-
-void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s);
-
-#endif
diff --git a/rr.c b/rr.c
deleted file mode 100644 (file)
index f4102dd..0000000
--- a/rr.c
+++ /dev/null
@@ -1,556 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include "util.h"
-#include "rr.h"
-#include "dns.h"
-
-AvahiKey *avahi_key_new(const gchar *name, guint16 class, guint16 type) {
-    AvahiKey *k;
-    g_assert(name);
-
-    k = g_new(AvahiKey, 1);
-    k->ref = 1;
-    k->name = avahi_normalize_name(name);    
-    k->class = class;
-    k->type = type;
-
-/*     g_message("%p %% ref=1", k); */
-    
-    return k;
-}
-
-AvahiKey *avahi_key_ref(AvahiKey *k) {
-    g_assert(k);
-    g_assert(k->ref >= 1);
-
-    k->ref++;
-
-/*     g_message("%p ++ ref=%i", k, k->ref); */
-
-    return k;
-}
-
-void avahi_key_unref(AvahiKey *k) {
-    g_assert(k);
-    g_assert(k->ref >= 1);
-
-/*     g_message("%p -- ref=%i", k, k->ref-1); */
-    
-    if ((--k->ref) <= 0) {
-        g_free(k->name);
-        g_free(k);
-    }
-}
-
-AvahiRecord *avahi_record_new(AvahiKey *k) {
-    AvahiRecord *r;
-    
-    g_assert(k);
-    
-    r = g_new(AvahiRecord, 1);
-    r->ref = 1;
-    r->key = avahi_key_ref(k);
-
-    memset(&r->data, 0, sizeof(r->data));
-
-    r->ttl = AVAHI_DEFAULT_TTL;
-
-    return r;
-}
-
-AvahiRecord *avahi_record_new_full(const gchar *name, guint16 class, guint16 type) {
-    AvahiRecord *r;
-    AvahiKey *k;
-
-    g_assert(name);
-    
-    k = avahi_key_new(name, class, type);
-    r = avahi_record_new(k);
-    avahi_key_unref(k);
-
-    return r;
-}
-
-AvahiRecord *avahi_record_ref(AvahiRecord *r) {
-    g_assert(r);
-    g_assert(r->ref >= 1);
-
-    r->ref++;
-    return r;
-}
-
-void avahi_record_unref(AvahiRecord *r) {
-    g_assert(r);
-    g_assert(r->ref >= 1);
-
-    if ((--r->ref) <= 0) {
-        switch (r->key->type) {
-
-            case AVAHI_DNS_TYPE_SRV:
-                g_free(r->data.srv.name);
-                break;
-
-            case AVAHI_DNS_TYPE_PTR:
-            case AVAHI_DNS_TYPE_CNAME:
-                g_free(r->data.ptr.name);
-                break;
-
-            case AVAHI_DNS_TYPE_HINFO:
-                g_free(r->data.hinfo.cpu);
-                g_free(r->data.hinfo.os);
-                break;
-
-            case AVAHI_DNS_TYPE_TXT:
-                avahi_string_list_free(r->data.txt.string_list);
-                break;
-
-            case AVAHI_DNS_TYPE_A:
-            case AVAHI_DNS_TYPE_AAAA:
-                break;
-            
-            default:
-                g_free(r->data.generic.data);
-        }
-        
-        avahi_key_unref(r->key);
-        g_free(r);
-    }
-}
-
-const gchar *avahi_dns_class_to_string(guint16 class) {
-    if (class & AVAHI_DNS_CACHE_FLUSH) 
-        return "FLUSH";
-    
-    if (class == AVAHI_DNS_CLASS_IN)
-        return "IN";
-
-    return NULL;
-}
-
-const gchar *avahi_dns_type_to_string(guint16 type) {
-    switch (type) {
-        case AVAHI_DNS_TYPE_CNAME:
-            return "CNAME";
-        case AVAHI_DNS_TYPE_A:
-            return "A";
-        case AVAHI_DNS_TYPE_AAAA:
-            return "AAAA";
-        case AVAHI_DNS_TYPE_PTR:
-            return "PTR";
-        case AVAHI_DNS_TYPE_HINFO:
-            return "HINFO";
-        case AVAHI_DNS_TYPE_TXT:
-            return "TXT";
-        case AVAHI_DNS_TYPE_SRV:
-            return "SRV";
-        case AVAHI_DNS_TYPE_ANY:
-            return "ANY";
-        default:
-            return NULL;
-    }
-}
-
-
-gchar *avahi_key_to_string(const AvahiKey *k) {
-    return g_strdup_printf("%s\t%s\t%s",
-                           k->name,
-                           avahi_dns_class_to_string(k->class),
-                           avahi_dns_type_to_string(k->type));
-}
-
-gchar *avahi_record_to_string(const AvahiRecord *r) {
-    gchar *p, *s;
-    char buf[257], *t = NULL, *d = NULL;
-
-    switch (r->key->type) {
-        case AVAHI_DNS_TYPE_A:
-            inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
-            break;
-            
-        case AVAHI_DNS_TYPE_AAAA:
-            inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
-            break;
-            
-        case AVAHI_DNS_TYPE_PTR:
-        case AVAHI_DNS_TYPE_CNAME :
-
-            t = r->data.ptr.name;
-            break;
-
-        case AVAHI_DNS_TYPE_TXT:
-            t = d = avahi_string_list_to_string(r->data.txt.string_list);
-            break;
-
-        case AVAHI_DNS_TYPE_HINFO:
-
-            snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os);
-            break;
-
-        case AVAHI_DNS_TYPE_SRV:
-
-            snprintf(t = buf, sizeof(buf), "%u %u %u %s",
-                     r->data.srv.priority,
-                     r->data.srv.weight,
-                     r->data.srv.port,
-                     r->data.srv.name);
-
-            break;
-    }
-
-    p = avahi_key_to_string(r->key);
-    s = g_strdup_printf("%s %s ; ttl=%u", p, t ? t : "<unparsable>", r->ttl);
-    g_free(p);
-    g_free(d);
-    
-    return s;
-}
-
-gboolean avahi_key_equal(const AvahiKey *a, const AvahiKey *b) {
-    g_assert(a);
-    g_assert(b);
-
-    if (a == b)
-        return TRUE;
-    
-/*     g_message("equal: %p %p", a, b); */
-    
-    return avahi_domain_equal(a->name, b->name) &&
-        a->type == b->type &&
-        a->class == b->class;
-}
-
-gboolean avahi_key_pattern_match(const AvahiKey *pattern, const AvahiKey *k) {
-    g_assert(pattern);
-    g_assert(k);
-
-/*     g_message("equal: %p %p", a, b); */
-
-    g_assert(!avahi_key_is_pattern(k));
-
-    if (pattern == k)
-        return TRUE;
-    
-    return avahi_domain_equal(pattern->name, k->name) &&
-        (pattern->type == k->type || pattern->type == AVAHI_DNS_TYPE_ANY) &&
-        pattern->class == k->class;
-}
-
-gboolean avahi_key_is_pattern(const AvahiKey *k) {
-    g_assert(k);
-
-    return k->type == AVAHI_DNS_TYPE_ANY;
-}
-
-
-guint avahi_key_hash(const AvahiKey *k) {
-    g_assert(k);
-
-    return avahi_domain_hash(k->name) + k->type + k->class;
-}
-
-static gboolean rdata_equal(const AvahiRecord *a, const AvahiRecord *b) {
-    g_assert(a);
-    g_assert(b);
-    g_assert(a->key->type == b->key->type);
-
-/*     t = avahi_record_to_string(a); */
-/*     g_message("comparing %s", t); */
-/*     g_free(t); */
-
-/*     t = avahi_record_to_string(b); */
-/*     g_message("and %s", t); */
-/*     g_free(t); */
-
-    
-    switch (a->key->type) {
-        case AVAHI_DNS_TYPE_SRV:
-            return
-                a->data.srv.priority == b->data.srv.priority &&
-                a->data.srv.weight == b->data.srv.weight &&
-                a->data.srv.port == b->data.srv.port &&
-                avahi_domain_equal(a->data.srv.name, b->data.srv.name);
-
-        case AVAHI_DNS_TYPE_PTR:
-        case AVAHI_DNS_TYPE_CNAME:
-            return avahi_domain_equal(a->data.ptr.name, b->data.ptr.name);
-
-        case AVAHI_DNS_TYPE_HINFO:
-            return
-                !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) &&
-                !strcmp(a->data.hinfo.os, b->data.hinfo.os);
-
-        case AVAHI_DNS_TYPE_TXT:
-            return avahi_string_list_equal(a->data.txt.string_list, b->data.txt.string_list);
-
-        case AVAHI_DNS_TYPE_A:
-            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address)) == 0;
-
-        case AVAHI_DNS_TYPE_AAAA:
-            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address)) == 0;
-
-        default:
-            return a->data.generic.size == b->data.generic.size &&
-                (a->data.generic.size == 0 || memcmp(a->data.generic.data, b->data.generic.data, a->data.generic.size) == 0);
-    }
-    
-}
-
-gboolean avahi_record_equal_no_ttl(const AvahiRecord *a, const AvahiRecord *b) {
-    g_assert(a);
-    g_assert(b);
-
-    if (a == b)
-        return TRUE;
-
-    return
-        avahi_key_equal(a->key, b->key) &&
-        rdata_equal(a, b);
-}
-
-
-AvahiRecord *avahi_record_copy(AvahiRecord *r) {
-    AvahiRecord *copy;
-
-    copy = g_new(AvahiRecord, 1);
-    copy->ref = 1;
-    copy->key = avahi_key_ref(r->key);
-    copy->ttl = r->ttl;
-
-    switch (r->key->type) {
-        case AVAHI_DNS_TYPE_PTR:
-        case AVAHI_DNS_TYPE_CNAME:
-            copy->data.ptr.name = g_strdup(r->data.ptr.name);
-            break;
-
-        case AVAHI_DNS_TYPE_SRV:
-            copy->data.srv.priority = r->data.srv.priority;
-            copy->data.srv.weight = r->data.srv.weight;
-            copy->data.srv.port = r->data.srv.port;
-            copy->data.srv.name = g_strdup(r->data.srv.name);
-            break;
-
-        case AVAHI_DNS_TYPE_HINFO:
-            copy->data.hinfo.os = g_strdup(r->data.hinfo.os);
-            copy->data.hinfo.cpu = g_strdup(r->data.hinfo.cpu);
-            break;
-
-        case AVAHI_DNS_TYPE_TXT:
-            copy->data.txt.string_list = avahi_string_list_copy(r->data.txt.string_list);
-            break;
-
-        case AVAHI_DNS_TYPE_A:
-            copy->data.a.address = r->data.a.address;
-            break;
-
-        case AVAHI_DNS_TYPE_AAAA:
-            copy->data.aaaa.address = r->data.aaaa.address;
-            break;
-
-        default:
-            copy->data.generic.data = g_memdup(r->data.generic.data, r->data.generic.size);
-            copy->data.generic.size = r->data.generic.size;
-            break;
-                
-    }
-
-    return copy;
-}
-
-
-guint avahi_key_get_estimate_size(AvahiKey *k) {
-    g_assert(k);
-
-    return strlen(k->name)+1+4;
-}
-
-guint avahi_record_get_estimate_size(AvahiRecord *r) {
-    guint n;
-    g_assert(r);
-
-    n = avahi_key_get_estimate_size(r->key) + 4 + 2;
-
-    switch (r->key->type) {
-        case AVAHI_DNS_TYPE_PTR:
-        case AVAHI_DNS_TYPE_CNAME:
-            n += strlen(r->data.ptr.name) + 1;
-            break;
-
-        case AVAHI_DNS_TYPE_SRV:
-            n += 6 + strlen(r->data.srv.name) + 1;
-            break;
-
-        case AVAHI_DNS_TYPE_HINFO:
-            n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1;
-            break;
-
-        case AVAHI_DNS_TYPE_TXT:
-            n += avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
-            break;
-
-        case AVAHI_DNS_TYPE_A:
-            n += sizeof(AvahiIPv4Address);
-            break;
-
-        case AVAHI_DNS_TYPE_AAAA:
-            n += sizeof(AvahiIPv6Address);
-            break;
-
-        default:
-            n += r->data.generic.size;
-    }
-
-    return n;
-}
-
-static gint lexicographical_memcmp(gconstpointer a, size_t al, gconstpointer b, size_t bl) {
-    size_t c;
-    gint ret;
-    
-    g_assert(a);
-    g_assert(b);
-
-    c = al < bl ? al : bl;
-    if ((ret = memcmp(a, b, c)) != 0)
-        return ret;
-
-    if (al == bl)
-        return 0;
-    else
-        return al == c ? 1 : -1;
-}
-
-static gint uint16_cmp(guint16 a, guint16 b) {
-    return a == b ? 0 : (a < b ? a : b);
-}
-
-static gint lexicographical_domain_cmp(const gchar *a, const gchar *b) {
-    g_assert(a);
-    g_assert(b);
-    
-
-    for (;;) {
-        gchar t1[64];
-        gchar t2[64];
-        size_t al, bl;
-        gint r;
-
-        if (!a && !b)
-            return 0;
-
-        if (a && !b)
-            return 1;
-
-        if (b && !a)
-            return -1;
-        
-        avahi_unescape_label(t1, sizeof(t1), &a);
-        avahi_unescape_label(t2, sizeof(t2), &b);
-
-        al = strlen(t1);
-        bl = strlen(t2);
-        
-        if (al != bl) 
-            return al < bl ? -1 : 1;
-
-        if ((r =  strcmp(t1, t2)) != 0)
-            return r;
-    }
-}
-
-gint avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b) {
-    g_assert(a);
-    g_assert(b);
-
-    if (a == b)
-        return 0;
-    
-/*     gchar *t; */
-
-/*     g_message("comparing [%s]", t = avahi_record_to_string(a)); */
-/*     g_free(t); */
-
-/*     g_message("and [%s]", t = avahi_record_to_string(b)); */
-/*     g_free(t); */
-
-    if (a->key->class < b->key->class)
-        return -1;
-    else if (a->key->class > b->key->class)
-        return 1;
-
-    if (a->key->type < b->key->type)
-        return -1;
-    else if (a->key->type > b->key->type)
-        return 1;
-
-    switch (a->key->type) {
-
-        case AVAHI_DNS_TYPE_PTR:
-        case AVAHI_DNS_TYPE_CNAME:
-            return lexicographical_domain_cmp(a->data.ptr.name, b->data.ptr.name);
-
-        case AVAHI_DNS_TYPE_SRV: {
-            gint r;
-            if ((r = uint16_cmp(a->data.srv.priority, b->data.srv.priority)) == 0 &&
-                (r = uint16_cmp(a->data.srv.weight, b->data.srv.weight)) == 0 &&
-                (r = uint16_cmp(a->data.srv.port, b->data.srv.port)) == 0)
-                r = lexicographical_domain_cmp(a->data.srv.name, b->data.srv.name);
-            
-            return r;
-        }
-
-        case AVAHI_DNS_TYPE_HINFO: {
-            size_t al = strlen(a->data.hinfo.cpu), bl = strlen(b->data.hinfo.cpu);
-            gint r;
-
-            if (al != bl)
-                return al < bl ? -1 : 1;
-
-            if ((r = strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu)) != 0)
-                return r;
-
-            al = strlen(a->data.hinfo.os), bl = strlen(b->data.hinfo.os);
-
-            if (al != bl)
-                return al < bl ? -1 : 1;
-
-            if ((r = strcmp(a->data.hinfo.os, b->data.hinfo.os)) != 0)
-                return r;
-
-            return 0;
-
-        }
-
-        case AVAHI_DNS_TYPE_TXT: {
-
-            guint8 *ma, *mb;
-            guint asize, bsize;
-            gint r;
-
-            ma = g_new(guint8, asize = avahi_string_list_serialize(a->data.txt.string_list, NULL, 0));
-            mb = g_new(guint8, bsize = avahi_string_list_serialize(b->data.txt.string_list, NULL, 0));
-            avahi_string_list_serialize(a->data.txt.string_list, ma, asize);
-            avahi_string_list_serialize(a->data.txt.string_list, mb, bsize);
-
-            r = lexicographical_memcmp(ma, asize, mb, bsize);
-            g_free(ma);
-            g_free(mb);
-
-            return r;
-        }
-        
-        case AVAHI_DNS_TYPE_A:
-            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(AvahiIPv4Address));
-
-        case AVAHI_DNS_TYPE_AAAA:
-            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(AvahiIPv6Address));
-
-        default:
-            return lexicographical_memcmp(a->data.generic.data, a->data.generic.size,
-                                          b->data.generic.data, b->data.generic.size);
-    }
-    
-}
diff --git a/rr.h b/rr.h
deleted file mode 100644 (file)
index 6f1a8cb..0000000
--- a/rr.h
+++ /dev/null
@@ -1,117 +0,0 @@
-#ifndef foorrhfoo
-#define foorrhfoo
-
-#include <glib.h>
-
-#include "strlst.h"
-#include "address.h"
-
-enum {
-    AVAHI_DNS_TYPE_A = 0x01,
-    AVAHI_DNS_TYPE_NS = 0x02,
-    AVAHI_DNS_TYPE_CNAME = 0x05,
-    AVAHI_DNS_TYPE_SOA = 0x06,
-    AVAHI_DNS_TYPE_PTR = 0x0C,
-    AVAHI_DNS_TYPE_HINFO = 0x0D,
-    AVAHI_DNS_TYPE_MX = 0x0F,
-    AVAHI_DNS_TYPE_TXT = 0x10,
-    AVAHI_DNS_TYPE_AAAA = 0x1C,
-    AVAHI_DNS_TYPE_SRV = 0x21,
-    AVAHI_DNS_TYPE_ANY = 0xFF
-};
-
-enum {
-    AVAHI_DNS_CLASS_IN = 0x01,
-    AVAHI_DNS_CACHE_FLUSH = 0x8000,
-    AVAHI_DNS_UNICAST_RESPONSE = 0x8000
-};
-
-#define AVAHI_DEFAULT_TTL (120*60)
-
-typedef struct {
-    guint ref;
-    gchar *name;
-    guint16 class;
-    guint16 type;
-} AvahiKey;
-
-typedef struct  {
-    guint ref;
-    AvahiKey *key;
-    
-    guint32 ttl;
-
-    union {
-        struct {
-            gpointer data;
-            guint16 size;
-        } generic;
-
-        struct {
-            guint16 priority;
-            guint16 weight;
-            guint16 port;
-            gchar *name;
-        } srv;
-
-        struct {
-            gchar *name;
-        } ptr; /* and cname */
-
-        struct {
-            gchar *cpu;
-            gchar *os;
-        } hinfo;
-
-        struct {
-            AvahiStringList *string_list;
-        } txt;
-
-        struct {
-            AvahiIPv4Address address;
-        } a;
-
-        struct {
-            AvahiIPv6Address address;
-        } aaaa;
-
-    } data;
-    
-} AvahiRecord;
-
-AvahiKey *avahi_key_new(const gchar *name, guint16 class, guint16 type);
-AvahiKey *avahi_key_ref(AvahiKey *k);
-void avahi_key_unref(AvahiKey *k);
-
-gboolean avahi_key_equal(const AvahiKey *a, const AvahiKey *b);  /* Treat AVAHI_DNS_CLASS_ANY like any other type */
-gboolean avahi_key_pattern_match(const AvahiKey *pattern, const AvahiKey *k); /* If pattern.type is AVAHI_DNS_CLASS_ANY, k.type is ignored */
-
-gboolean avahi_key_is_pattern(const AvahiKey *k);
-
-guint avahi_key_hash(const AvahiKey *k);
-
-AvahiRecord *avahi_record_new(AvahiKey *k);
-AvahiRecord *avahi_record_new_full(const gchar *name, guint16 class, guint16 type);
-AvahiRecord *avahi_record_ref(AvahiRecord *r);
-void avahi_record_unref(AvahiRecord *r);
-
-const gchar *avahi_dns_class_to_string(guint16 class);
-const gchar *avahi_dns_type_to_string(guint16 type);
-
-gchar *avahi_key_to_string(const AvahiKey *k); /* g_free() the result! */
-gchar *avahi_record_to_string(const AvahiRecord *r);  /* g_free() the result! */
-
-gboolean avahi_record_equal_no_ttl(const AvahiRecord *a, const AvahiRecord *b);
-
-AvahiRecord *avahi_record_copy(AvahiRecord *r);
-
-/* returns a maximum estimate for the space that is needed to store
- * this key in a DNS packet */
-guint avahi_key_get_estimate_size(AvahiKey *k);
-
-/* ditto */
-guint avahi_record_get_estimate_size(AvahiRecord *r);
-
-gint avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b);
-
-#endif
diff --git a/server.c b/server.c
deleted file mode 100644 (file)
index b17b142..0000000
--- a/server.c
+++ /dev/null
@@ -1,1014 +0,0 @@
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <sys/utsname.h>
-#include <unistd.h>
-
-#include "server.h"
-#include "util.h"
-#include "iface.h"
-#include "socket.h"
-#include "subscribe.h"
-
-static void free_entry(AvahiServer*s, AvahiEntry *e) {
-    AvahiEntry *t;
-
-    g_assert(s);
-    g_assert(e);
-
-    avahi_goodbye_entry(s, e, TRUE);
-
-    /* Remove from linked list */
-    AVAHI_LLIST_REMOVE(AvahiEntry, entries, s->entries, e);
-
-    /* Remove from hash table indexed by name */
-    t = g_hash_table_lookup(s->entries_by_key, e->record->key);
-    AVAHI_LLIST_REMOVE(AvahiEntry, by_key, t, e);
-    if (t)
-        g_hash_table_replace(s->entries_by_key, t->record->key, t);
-    else
-        g_hash_table_remove(s->entries_by_key, e->record->key);
-
-    /* Remove from associated group */
-    if (e->group)
-        AVAHI_LLIST_REMOVE(AvahiEntry, by_group, e->group->entries, e);
-
-    avahi_record_unref(e->record);
-    g_free(e);
-}
-
-static void free_group(AvahiServer *s, AvahiEntryGroup *g) {
-    g_assert(s);
-    g_assert(g);
-
-    while (g->entries)
-        free_entry(s, g->entries);
-
-    AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, s->groups, g);
-    g_free(g);
-}
-
-static void cleanup_dead(AvahiServer *s) {
-    AvahiEntryGroup *g, *ng;
-    AvahiEntry *e, *ne;
-    g_assert(s);
-
-
-    if (s->need_group_cleanup) {
-        for (g = s->groups; g; g = ng) {
-            ng = g->groups_next;
-            
-            if (g->dead)
-                free_group(s, g);
-        }
-
-        s->need_group_cleanup = FALSE;
-    }
-
-    if (s->need_entry_cleanup) {
-        for (e = s->entries; e; e = ne) {
-            ne = e->entries_next;
-            
-            if (e->dead)
-                free_entry(s, e);
-        }
-
-        s->need_entry_cleanup = FALSE;
-    }
-}
-
-static void handle_query_key(AvahiServer *s, AvahiKey *k, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) {
-    AvahiEntry *e;
-    gchar *txt;
-    
-    g_assert(s);
-    g_assert(k);
-    g_assert(i);
-    g_assert(a);
-
-    g_message("Handling query: %s", txt = avahi_key_to_string(k));
-    g_free(txt);
-
-    avahi_packet_scheduler_incoming_query(i->scheduler, k);
-
-    if (k->type == AVAHI_DNS_TYPE_ANY) {
-
-        /* Handle ANY query */
-        
-        for (e = s->entries; e; e = e->entries_next)
-            if (!e->dead && avahi_key_pattern_match(k, e->record->key) && avahi_entry_registered(s, e, i))
-                avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE);
-    } else {
-
-        /* Handle all other queries */
-        
-        for (e = g_hash_table_lookup(s->entries_by_key, k); e; e = e->by_key_next)
-            if (!e->dead && avahi_entry_registered(s, e, i))
-                avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE);
-    }
-}
-
-static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
-    g_assert(s);
-    g_assert(e);
-
-    
-    if (e->group) {
-        AvahiEntry *k;
-        
-        for (k = e->group->entries; k; k = k->by_group_next) {
-            avahi_goodbye_entry(s, k, FALSE);
-            k->dead = TRUE;
-        }
-        
-        avahi_entry_group_change_state(e->group, AVAHI_ENTRY_GROUP_COLLISION);
-    } else {
-        avahi_goodbye_entry(s, e, FALSE);
-        e->dead = TRUE;
-    }
-
-    s->need_entry_cleanup = TRUE;
-}
-
-static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *i) {
-    AvahiEntry *e, *n;
-    gchar *t;
-    
-    g_assert(s);
-    g_assert(record);
-    g_assert(i);
-
-    t = avahi_record_to_string(record);
-
-/*     g_message("PROBE: [%s]", t); */
-    
-    for (e = g_hash_table_lookup(s->entries_by_key, record->key); e; e = n) {
-        n = e->by_key_next;
-
-        if (e->dead || avahi_record_equal_no_ttl(record, e->record))
-            continue;
-
-        if (avahi_entry_registering(s, e, i)) {
-            gint cmp;
-
-            if ((cmp = avahi_record_lexicographical_compare(record, e->record)) > 0) {
-                withdraw_entry(s, e);
-                g_message("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t);
-            } else if (cmp < 0)
-                g_message("Recieved conflicting probe [%s]. Local host won.", t);
-
-        }
-    }
-
-    g_free(t);
-}
-
-static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) {
-    guint n;
-    
-    g_assert(s);
-    g_assert(p);
-    g_assert(i);
-    g_assert(a);
-
-    /* Handle the questions */
-    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n --) {
-        AvahiKey *key;
-        gboolean unicast_response = FALSE;
-
-        if (!(key = avahi_dns_packet_consume_key(p, &unicast_response))) {
-            g_warning("Packet too short (1)");
-            return;
-        }
-
-        handle_query_key(s, key, i, a, port, legacy_unicast, unicast_response);
-        avahi_key_unref(key);
-    }
-
-    /* Known Answer Suppression */
-    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT); n > 0; n --) {
-        AvahiRecord *record;
-        gboolean unique = FALSE;
-
-        if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
-            g_warning("Packet too short (2)");
-            return;
-        }
-
-        avahi_packet_scheduler_incoming_known_answer(i->scheduler, record, a);
-        avahi_record_unref(record);
-    }
-
-    /* Probe record */
-    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT); n > 0; n --) {
-        AvahiRecord *record;
-        gboolean unique = FALSE;
-
-        if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
-            g_warning("Packet too short (3)");
-            return;
-        }
-
-        if (record->key->type != AVAHI_DNS_TYPE_ANY)
-            incoming_probe(s, record, i);
-        
-        avahi_record_unref(record);
-    }
-}
-
-static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, gboolean unique, const AvahiAddress *a) {
-    gboolean valid = TRUE;
-    AvahiEntry *e, *n;
-    gchar *t;
-    
-    g_assert(s);
-    g_assert(i);
-    g_assert(record);
-
-    t = avahi_record_to_string(record);
-
-/*     g_message("CHECKING FOR CONFLICT: [%s]", t); */
-
-    for (e = g_hash_table_lookup(s->entries_by_key, record->key); e; e = n) {
-        n = e->by_key_next;
-
-        if (e->dead)
-            continue;
-        
-        if (avahi_entry_registered(s, e, i)) {
-
-            gboolean equal = avahi_record_equal_no_ttl(record, e->record);
-                
-            /* Check whether there is a unique record conflict */
-            if (!equal && ((e->flags & AVAHI_ENTRY_UNIQUE) || unique)) {
-                gint cmp;
-                
-                /* The lexicographically later data wins. */
-                if ((cmp = avahi_record_lexicographical_compare(record, e->record)) > 0) {
-                    g_message("Recieved conflicting record [%s]. Local host lost. Withdrawing.", t);
-                    withdraw_entry(s, e);
-                } else if (cmp < 0) {
-                    /* Tell the other host that our entry is lexicographically later */
-
-                    g_message("Recieved conflicting record [%s]. Local host won. Refreshing.", t);
-
-                    valid = FALSE;
-                    avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
-                }
-                
-                /* Check wheter there is a TTL conflict */
-            } else if (equal && record->ttl <= e->record->ttl/2) {
-                /* Correct the TTL */
-                valid = FALSE;
-                avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
-                g_message("Recieved record with bad TTL [%s]. Refreshing.", t);
-            }
-            
-        } else if (avahi_entry_registering(s, e, i)) {
-
-            if (!avahi_record_equal_no_ttl(record, e->record) && ((e->flags & AVAHI_ENTRY_UNIQUE) || unique)) {
-
-                /* We are currently registering a matching record, but
-                 * someone else already claimed it, so let's
-                 * withdraw */
-                
-                g_message("Recieved conflicting record [%s] with local record to be. Withdrawing.", t);
-                withdraw_entry(s, e);
-            }
-        }
-    }
-
-    g_free(t);
-
-    return valid;
-}
-
-static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a) {
-    guint n;
-    
-    g_assert(s);
-    g_assert(p);
-    g_assert(i);
-    g_assert(a);
-    
-    for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) +
-             avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT); n > 0; n--) {
-        AvahiRecord *record;
-        gboolean cache_flush = FALSE;
-        gchar *txt;
-        
-        if (!(record = avahi_dns_packet_consume_record(p, &cache_flush))) {
-            g_warning("Packet too short (4)");
-            return;
-        }
-
-        if (record->key->type != AVAHI_DNS_TYPE_ANY) {
-
-            g_message("Handling response: %s", txt = avahi_record_to_string(record));
-            g_free(txt);
-            
-            if (handle_conflict(s, i, record, cache_flush, a)) {
-                avahi_cache_update(i->cache, record, cache_flush, a);
-                avahi_packet_scheduler_incoming_response(i->scheduler, record);
-            }
-        }
-            
-        avahi_record_unref(record);
-    }
-}
-
-static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr *sa, gint iface, gint ttl) {
-    AvahiInterface *i;
-    AvahiAddress a;
-    guint16 port;
-    
-    g_assert(s);
-    g_assert(p);
-    g_assert(sa);
-    g_assert(iface > 0);
-
-    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, sa->sa_family))) {
-        g_warning("Recieved packet from invalid interface.");
-        return;
-    }
-
-    g_message("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol);
-
-    if (sa->sa_family == AF_INET6) {
-        static const guint8 ipv4_in_ipv6[] = {
-            0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00,
-            0xFF, 0xFF, 0xFF, 0xFF };
-
-        /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
-
-        if (memcmp(((struct sockaddr_in6*) sa)->sin6_addr.s6_addr, ipv4_in_ipv6, sizeof(ipv4_in_ipv6)) == 0)
-            return;
-    }
-
-    if (avahi_dns_packet_check_valid(p) < 0) {
-        g_warning("Recieved invalid packet.");
-        return;
-    }
-
-    port = avahi_port_from_sockaddr(sa);
-    avahi_address_from_sockaddr(sa, &a);
-
-    if (avahi_dns_packet_is_query(p)) {
-        gboolean legacy_unicast = FALSE;
-
-        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT) == 0 ||
-            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT) != 0) {
-            g_warning("Invalid query packet.");
-            return;
-        }
-
-        if (port != AVAHI_MDNS_PORT) {
-            /* Legacy Unicast */
-
-            if ((avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) != 0 ||
-                 avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) != 0)) {
-                g_warning("Invalid legacy unicast query packet.");
-                return;
-            }
-        
-            legacy_unicast = TRUE;
-        }
-
-        handle_query(s, p, i, &a, port, legacy_unicast);
-        
-        g_message("Handled query");
-    } else {
-
-        if (port != AVAHI_MDNS_PORT) {
-            g_warning("Recieved repsonse with invalid source port %u on interface '%s.%i'", port, i->hardware->name, i->protocol);
-            return;
-        }
-
-        if (ttl != 255) {
-            g_warning("Recieved response with invalid TTL %u on interface '%s.%i'.", ttl, i->hardware->name, i->protocol);
-            if (!s->ignore_bad_ttl)
-                return;
-        }
-
-        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT) != 0 ||
-            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) == 0 ||
-            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) != 0) {
-            g_warning("Invalid response packet.");
-            return;
-        }
-
-        handle_response(s, p, i, &a);
-        g_message("Handled response");
-    }
-}
-
-static void work(AvahiServer *s) {
-    struct sockaddr_in6 sa6;
-    struct sockaddr_in sa;
-    AvahiDnsPacket *p;
-    gint iface = -1;
-    guint8 ttl;
-        
-    g_assert(s);
-
-    if (s->pollfd_ipv4.revents & G_IO_IN) {
-        if ((p = avahi_recv_dns_packet_ipv4(s->fd_ipv4, &sa, &iface, &ttl))) {
-            dispatch_packet(s, p, (struct sockaddr*) &sa, iface, ttl);
-            avahi_dns_packet_free(p);
-        }
-    }
-
-    if (s->pollfd_ipv6.revents & G_IO_IN) {
-        if ((p = avahi_recv_dns_packet_ipv6(s->fd_ipv6, &sa6, &iface, &ttl))) {
-            dispatch_packet(s, p, (struct sockaddr*) &sa6, iface, ttl);
-            avahi_dns_packet_free(p);
-        }
-    }
-}
-
-static gboolean prepare_func(GSource *source, gint *timeout) {
-    g_assert(source);
-    g_assert(timeout);
-    
-    *timeout = -1;
-    return FALSE;
-}
-
-static gboolean check_func(GSource *source) {
-    AvahiServer* s;
-    g_assert(source);
-
-    s = *((AvahiServer**) (((guint8*) source) + sizeof(GSource)));
-    g_assert(s);
-    
-    return (s->pollfd_ipv4.revents | s->pollfd_ipv6.revents) & (G_IO_IN | G_IO_HUP | G_IO_ERR);
-}
-
-static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
-    AvahiServer* s;
-    g_assert(source);
-
-    s = *((AvahiServer**) (((guint8*) source) + sizeof(GSource)));
-    g_assert(s);
-
-    work(s);
-    cleanup_dead(s);
-
-    return TRUE;
-}
-
-static void add_default_entries(AvahiServer *s) {
-    gint length = 0;
-    struct utsname utsname;
-    gchar *hinfo;
-    AvahiAddress a;
-    AvahiRecord *r;
-    
-    g_assert(s);
-    
-    /* Fill in HINFO rr */
-    r = avahi_record_new_full(s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_HINFO);
-    uname(&utsname);
-    r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine));
-    r->data.hinfo.os = g_strdup(g_strup(utsname.sysname));
-    avahi_server_add(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, r);
-    avahi_record_unref(r);
-
-    /* Add localhost entries */
-    avahi_address_parse("127.0.0.1", AF_INET, &a);
-    avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE|AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "localhost", &a);
-
-    avahi_address_parse("::1", AF_INET6, &a);
-    avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE|AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "ip6-localhost", &a);
-}
-
-AvahiServer *avahi_server_new(GMainContext *c) {
-    gchar *hn, *e;
-    AvahiServer *s;
-    
-    static GSourceFuncs source_funcs = {
-        prepare_func,
-        check_func,
-        dispatch_func,
-        NULL,
-        NULL,
-        NULL
-    };
-
-    s = g_new(AvahiServer, 1);
-
-    s->ignore_bad_ttl = FALSE;
-    s->need_entry_cleanup = s->need_group_cleanup = FALSE;
-    
-    s->fd_ipv4 = avahi_open_socket_ipv4();
-    s->fd_ipv6 = avahi_open_socket_ipv6();
-    
-    if (s->fd_ipv6 < 0 && s->fd_ipv4 < 0) {
-        g_critical("Failed to create IP sockets.\n");
-        g_free(s);
-        return NULL;
-    }
-
-    if (s->fd_ipv4 < 0)
-        g_message("Failed to create IPv4 socket, proceeding in IPv6 only mode");
-    else if (s->fd_ipv6 < 0)
-        g_message("Failed to create IPv6 socket, proceeding in IPv4 only mode");
-    
-    if (c)
-        g_main_context_ref(s->context = c);
-    else
-        s->context = g_main_context_default();
-    
-    AVAHI_LLIST_HEAD_INIT(AvahiEntry, s->entries);
-    s->entries_by_key = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
-    AVAHI_LLIST_HEAD_INIT(AvahiGroup, s->groups);
-
-    AVAHI_LLIST_HEAD_INIT(AvahiSubscription, s->subscriptions);
-    s->subscription_hashtable = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
-
-    /* Get host name */
-    hn = avahi_get_host_name();
-    hn[strcspn(hn, ".")] = 0;
-
-    s->hostname = g_strdup_printf("%s.local.", hn);
-    g_free(hn);
-
-    s->time_event_queue = avahi_time_event_queue_new(s->context, G_PRIORITY_DEFAULT+10); /* Slightly less priority than the FDs */
-    s->monitor = avahi_interface_monitor_new(s);
-    avahi_interface_monitor_sync(s->monitor);
-    add_default_entries(s);
-    
-    /* Prepare IO source registration */
-    s->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(AvahiServer*));
-    *((AvahiServer**) (((guint8*) s->source) + sizeof(GSource))) = s;
-
-    memset(&s->pollfd_ipv4, 0, sizeof(s->pollfd_ipv4));
-    s->pollfd_ipv4.fd = s->fd_ipv4;
-    s->pollfd_ipv4.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
-    g_source_add_poll(s->source, &s->pollfd_ipv4);
-    
-    memset(&s->pollfd_ipv6, 0, sizeof(s->pollfd_ipv6));
-    s->pollfd_ipv6.fd = s->fd_ipv6;
-    s->pollfd_ipv6.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
-    g_source_add_poll(s->source, &s->pollfd_ipv6);
-
-    g_source_attach(s->source, s->context);
-
-    return s;
-}
-
-void avahi_server_free(AvahiServer* s) {
-    g_assert(s);
-
-    while(s->entries)
-        free_entry(s, s->entries);
-
-    avahi_interface_monitor_free(s->monitor);
-
-    while (s->groups)
-        free_group(s, s->groups);
-
-    while (s->subscriptions)
-        avahi_subscription_free(s->subscriptions);
-    g_hash_table_destroy(s->subscription_hashtable);
-
-    g_hash_table_destroy(s->entries_by_key);
-
-    avahi_time_event_queue_free(s->time_event_queue);
-
-    if (s->fd_ipv4 >= 0)
-        close(s->fd_ipv4);
-    if (s->fd_ipv6 >= 0)
-        close(s->fd_ipv6);
-    
-    g_free(s->hostname);
-
-    g_source_destroy(s->source);
-    g_source_unref(s->source);
-    g_main_context_unref(s->context);
-
-    g_free(s);
-}
-
-void avahi_server_add(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    AvahiRecord *r) {
-    
-    AvahiEntry *e, *t;
-    g_assert(s);
-    g_assert(r);
-
-    g_assert(r->key->type != AVAHI_DNS_TYPE_ANY);
-
-    e = g_new(AvahiEntry, 1);
-    e->server = s;
-    e->record = avahi_record_ref(r);
-    e->group = g;
-    e->interface = interface;
-    e->protocol = protocol;
-    e->flags = flags;
-    e->dead = FALSE;
-
-    AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, e->announcements);
-
-    AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e);
-
-    /* Insert into hash table indexed by name */
-    t = g_hash_table_lookup(s->entries_by_key, e->record->key);
-    AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e);
-    g_hash_table_replace(s->entries_by_key, e->record->key, t);
-
-    /* Insert into group list */
-    if (g)
-        AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); 
-
-    avahi_announce_entry(s, e);
-}
-const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiEntryGroup *g, void **state) {
-    AvahiEntry **e = (AvahiEntry**) state;
-    g_assert(s);
-    g_assert(e);
-
-    if (!*e)
-        *e = g ? g->entries : s->entries;
-    
-    while (*e && (*e)->dead)
-        *e = g ? (*e)->by_group_next : (*e)->entries_next;
-        
-    if (!*e)
-        return NULL;
-
-    return avahi_record_ref((*e)->record);
-}
-
-void avahi_server_dump(AvahiServer *s, FILE *f) {
-    AvahiEntry *e;
-    g_assert(s);
-    g_assert(f);
-
-    fprintf(f, "\n;;; ZONE DUMP FOLLOWS ;;;\n");
-
-    for (e = s->entries; e; e = e->entries_next) {
-        gchar *t;
-
-        if (e->dead)
-            continue;
-        
-        t = avahi_record_to_string(e->record);
-        fprintf(f, "%s ; iface=%i proto=%i\n", t, e->interface, e->protocol);
-        g_free(t);
-    }
-
-    avahi_dump_caches(s->monitor, f);
-}
-
-void avahi_server_add_ptr(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    const gchar *dest) {
-
-    AvahiRecord *r;
-
-    g_assert(dest);
-
-    r = avahi_record_new_full(name ? name : s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR);
-    r->data.ptr.name = avahi_normalize_name(dest);
-    avahi_server_add(s, g, interface, protocol, flags, r);
-    avahi_record_unref(r);
-}
-
-void avahi_server_add_address(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    AvahiAddress *a) {
-
-    gchar *n = NULL;
-    g_assert(s);
-    g_assert(a);
-
-    name = name ? (n = avahi_normalize_name(name)) : s->hostname;
-    
-    if (a->family == AF_INET) {
-        gchar *reverse;
-        AvahiRecord  *r;
-
-        r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A);
-        r->data.a.address = a->data.ipv4;
-        avahi_server_add(s, g, interface, protocol, flags, r);
-        avahi_record_unref(r);
-        
-        reverse = avahi_reverse_lookup_name_ipv4(&a->data.ipv4);
-        g_assert(reverse);
-        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
-        g_free(reverse);
-        
-    } else {
-        gchar *reverse;
-        AvahiRecord *r;
-            
-        r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA);
-        r->data.aaaa.address = a->data.ipv6;
-        avahi_server_add(s, g, interface, protocol, flags, r);
-        avahi_record_unref(r);
-
-        reverse = avahi_reverse_lookup_name_ipv6_arpa(&a->data.ipv6);
-        g_assert(reverse);
-        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
-        g_free(reverse);
-    
-        reverse = avahi_reverse_lookup_name_ipv6_int(&a->data.ipv6);
-        g_assert(reverse);
-        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
-        g_free(reverse);
-    }
-    
-    g_free(n);
-}
-
-void avahi_server_add_text_strlst(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    AvahiStringList *strlst) {
-
-    AvahiRecord *r;
-    
-    g_assert(s);
-    
-    r = avahi_record_new_full(name ? name : s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT);
-    r->data.txt.string_list = strlst;
-    avahi_server_add(s, g, interface, protocol, flags, r);
-    avahi_record_unref(r);
-}
-
-void avahi_server_add_text_va(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    va_list va) {
-    
-    g_assert(s);
-
-    avahi_server_add_text_strlst(s, g, interface, protocol, flags, name, avahi_string_list_new_va(va));
-}
-
-void avahi_server_add_text(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    AvahiEntryFlags flags,
-    const gchar *name,
-    ...) {
-
-    va_list va;
-    
-    g_assert(s);
-
-    va_start(va, name);
-    avahi_server_add_text_va(s, g, interface, protocol, flags, name, va);
-    va_end(va);
-}
-
-static void escape_service_name(gchar *d, guint size, const gchar *s) {
-    g_assert(d);
-    g_assert(size);
-    g_assert(s);
-
-    while (*s && size >= 2) {
-        if (*s == '.' || *s == '\\') {
-            if (size < 3)
-                break;
-
-            *(d++) = '\\';
-            size--;
-        }
-            
-        *(d++) = *(s++);
-        size--;
-    }
-
-    g_assert(size > 0);
-    *(d++) = 0;
-}
-
-void avahi_server_add_service_strlst(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    const gchar *type,
-    const gchar *name,
-    const gchar *domain,
-    const gchar *host,
-    guint16 port,
-    AvahiStringList *strlst) {
-
-    gchar ptr_name[256], svc_name[256], ename[64], enum_ptr[256];
-    AvahiRecord *r;
-    
-    g_assert(s);
-    g_assert(type);
-    g_assert(name);
-
-    escape_service_name(ename, sizeof(ename), name);
-
-    if (domain) {
-        while (domain[0] == '.')
-            domain++;
-    } else
-        domain = "local";
-
-    if (!host)
-        host = s->hostname;
-
-    snprintf(ptr_name, sizeof(ptr_name), "%s.%s", type, domain);
-    snprintf(svc_name, sizeof(svc_name), "%s.%s.%s", ename, type, domain);
-    
-    avahi_server_add_ptr(s, g, interface, protocol, AVAHI_ENTRY_NULL, ptr_name, svc_name);
-
-    r = avahi_record_new_full(svc_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV);
-    r->data.srv.priority = 0;
-    r->data.srv.weight = 0;
-    r->data.srv.port = port;
-    r->data.srv.name = avahi_normalize_name(host);
-    avahi_server_add(s, g, interface, protocol, AVAHI_ENTRY_UNIQUE, r);
-    avahi_record_unref(r);
-
-    avahi_server_add_text_strlst(s, g, interface, protocol, AVAHI_ENTRY_UNIQUE, svc_name, strlst);
-
-    snprintf(enum_ptr, sizeof(enum_ptr), "_services._dns-sd._udp.%s", domain);
-    avahi_server_add_ptr(s, g, interface, protocol, AVAHI_ENTRY_NULL, enum_ptr, ptr_name);
-}
-
-void avahi_server_add_service_va(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    const gchar *type,
-    const gchar *name,
-    const gchar *domain,
-    const gchar *host,
-    guint16 port,
-    va_list va){
-
-    g_assert(s);
-    g_assert(type);
-    g_assert(name);
-
-    avahi_server_add_service(s, g, interface, protocol, type, name, domain, host, port, avahi_string_list_new_va(va));
-}
-
-void avahi_server_add_service(
-    AvahiServer *s,
-    AvahiEntryGroup *g,
-    gint interface,
-    guchar protocol,
-    const gchar *type,
-    const gchar *name,
-    const gchar *domain,
-    const gchar *host,
-    guint16 port,
-    ... ){
-
-    va_list va;
-    
-    g_assert(s);
-    g_assert(type);
-    g_assert(name);
-
-    va_start(va, port);
-    avahi_server_add_service_va(s, g, interface, protocol, type, name, domain, host, port, va);
-    va_end(va);
-}
-
-static void post_query_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
-    AvahiKey *k = userdata;
-
-    g_assert(m);
-    g_assert(i);
-    g_assert(k);
-
-    avahi_interface_post_query(i, k, FALSE);
-}
-
-void avahi_server_post_query(AvahiServer *s, gint interface, guchar protocol, AvahiKey *key) {
-    g_assert(s);
-    g_assert(key);
-
-    avahi_interface_monitor_walk(s->monitor, interface, protocol, post_query_callback, key);
-}
-
-struct tmpdata {
-    AvahiRecord *record;
-    gboolean flush_cache;
-};
-
-static void post_response_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
-    struct tmpdata *tmpdata = userdata;
-
-    g_assert(m);
-    g_assert(i);
-    g_assert(tmpdata);
-
-    avahi_interface_post_response(i, NULL, tmpdata->record, tmpdata->flush_cache, FALSE);
-}
-
-void avahi_server_post_response(AvahiServer *s, gint interface, guchar protocol, AvahiRecord *record, gboolean flush_cache) {
-    struct tmpdata tmpdata;
-    
-    g_assert(s);
-    g_assert(record);
-
-    tmpdata.record = record;
-    tmpdata.flush_cache = flush_cache;
-
-    avahi_interface_monitor_walk(s->monitor, interface, protocol, post_response_callback, &tmpdata);
-}
-
-void avahi_entry_group_change_state(AvahiEntryGroup *g, AvahiEntryGroupState state) {
-    g_assert(g);
-
-    g->state = state;
-    
-    if (g->callback) {
-        g->callback(g->server, g, state, g->userdata);
-        return;
-    }
-}
-
-AvahiEntryGroup *avahi_entry_group_new(AvahiServer *s, AvahiEntryGroupCallback callback, gpointer userdata) {
-    AvahiEntryGroup *g;
-    
-    g_assert(s);
-
-    g = g_new(AvahiEntryGroup, 1);
-    g->server = s;
-    g->callback = callback;
-    g->userdata = userdata;
-    g->dead = FALSE;
-    g->state = AVAHI_ENTRY_GROUP_UNCOMMITED;
-    g->n_probing = 0;
-    AVAHI_LLIST_HEAD_INIT(AvahiEntry, g->entries);
-
-    AVAHI_LLIST_PREPEND(AvahiEntryGroup, groups, s->groups, g);
-    return g;
-}
-
-void avahi_entry_group_free(AvahiEntryGroup *g) {
-    g_assert(g);
-    g_assert(g->server);
-
-    g->dead = TRUE;
-    g->server->need_group_cleanup = TRUE;
-}
-
-void avahi_entry_group_commit(AvahiEntryGroup *g) {
-    AvahiEntry *e;
-    
-    g_assert(g);
-    g_assert(!g->dead);
-
-    if (g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)
-        return;
-
-    avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING);
-    avahi_announce_group(g->server, g);
-    avahi_entry_group_check_probed(g, FALSE);
-}
-
-gboolean avahi_entry_commited(AvahiEntry *e) {
-    g_assert(e);
-    g_assert(!e->dead);
-
-    return !e->group ||
-        e->group->state == AVAHI_ENTRY_GROUP_REGISTERING ||
-        e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED;
-}
-
-AvahiEntryGroupState avahi_entry_group_get_state(AvahiEntryGroup *g) {
-    g_assert(g);
-    g_assert(!g->dead);
-
-    return g->state;
-}
diff --git a/server.h b/server.h
deleted file mode 100644 (file)
index 9f7ef51..0000000
--- a/server.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef fooAvahiserverhfoo
-#define fooAvahiserverhfoo
-
-#include "avahi.h"
-#include "iface.h"
-#include "prioq.h"
-#include "llist.h"
-#include "timeeventq.h"
-#include "announce.h"
-#include "subscribe.h"
-
-struct _AvahiEntry {
-    AvahiServer *server;
-    AvahiEntryGroup *group;
-
-    gboolean dead;
-    
-    AvahiEntryFlags flags;
-    AvahiRecord *record;
-    gint interface;
-    guchar protocol;
-
-    AVAHI_LLIST_FIELDS(AvahiEntry, entries);
-    AVAHI_LLIST_FIELDS(AvahiEntry, by_key);
-    AVAHI_LLIST_FIELDS(AvahiEntry, by_group);
-    
-    AVAHI_LLIST_HEAD(AvahiAnnouncement, announcements);
-};
-
-struct _AvahiEntryGroup {
-    AvahiServer *server;
-    gboolean dead;
-
-    AvahiEntryGroupState state;
-    gpointer userdata;
-    AvahiEntryGroupCallback callback;
-
-    guint n_probing;
-    
-    AVAHI_LLIST_FIELDS(AvahiEntryGroup, groups);
-    AVAHI_LLIST_HEAD(AvahiEntry, entries);
-};
-
-struct _AvahiServer {
-    GMainContext *context;
-    AvahiInterfaceMonitor *monitor;
-
-    AVAHI_LLIST_HEAD(AvahiEntry, entries);
-    GHashTable *entries_by_key;
-
-    AVAHI_LLIST_HEAD(AvahiEntryGroup, groups);
-    
-    AVAHI_LLIST_HEAD(AvahiSubscription, subscriptions);
-    GHashTable *subscription_hashtable;
-
-    gboolean need_entry_cleanup, need_group_cleanup;
-    
-    AvahiTimeEventQueue *time_event_queue;
-    
-    gchar *hostname;
-
-    gint fd_ipv4, fd_ipv6;
-
-    GPollFD pollfd_ipv4, pollfd_ipv6;
-    GSource *source;
-
-    gboolean ignore_bad_ttl;
-};
-
-gboolean avahi_server_entry_match_interface(AvahiEntry *e, AvahiInterface *i);
-
-void avahi_server_post_query(AvahiServer *s, gint interface, guchar protocol, AvahiKey *key);
-void avahi_server_post_response(AvahiServer *s, gint interface, guchar protocol, AvahiRecord *record, gboolean flush_cache);
-
-void avahi_entry_group_change_state(AvahiEntryGroup *g, AvahiEntryGroupState state);
-
-gboolean avahi_entry_commited(AvahiEntry *e);
-
-#endif
diff --git a/socket.c b/socket.c
deleted file mode 100644 (file)
index 1ef8131..0000000
--- a/socket.c
+++ /dev/null
@@ -1,488 +0,0 @@
-#include <inttypes.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-
-#include "dns.h"
-#include "util.h"
-#include "socket.h"
-
-static void mdns_mcast_group_ipv4(struct sockaddr_in *ret_sa) {
-    g_assert(ret_sa);
-
-    memset(ret_sa, 0, sizeof(struct sockaddr_in));
-    
-    ret_sa->sin_family = AF_INET;
-    ret_sa->sin_port = htons(AVAHI_MDNS_PORT);
-    inet_pton(AF_INET, "224.0.0.251", &ret_sa->sin_addr);
-}
-
-static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
-
-    g_assert(ret_sa);
-
-    memset(ret_sa, 0, sizeof(struct sockaddr_in6));
-    
-    ret_sa->sin6_family = AF_INET6;
-    ret_sa->sin6_port = htons(AVAHI_MDNS_PORT);
-    inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
-}
-
-int avahi_mdns_mcast_join_ipv4 (int index, int fd)
-{
-    struct ip_mreqn mreq; 
-    struct sockaddr_in sa;
-
-    mdns_mcast_group_ipv4 (&sa);
-    memset(&mreq, 0, sizeof(mreq));
-    mreq.imr_multiaddr = sa.sin_addr;
-    mreq.imr_ifindex = index;
-    if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
-        g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
-        return -1;
-    } 
-
-    return 0;
-}
-
-int avahi_mdns_mcast_join_ipv6 (int index, int fd)
-{
-    struct ipv6_mreq mreq6; 
-    struct sockaddr_in6 sa6;
-
-    mdns_mcast_group_ipv6 (&sa6);
-
-    memset(&mreq6, 0, sizeof(mreq6));
-    mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
-    mreq6.ipv6mr_interface = index;
-
-    if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
-        g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-int avahi_mdns_mcast_leave_ipv4 (int index, int fd)
-{
-    struct ip_mreqn mreq; 
-    struct sockaddr_in sa;
-    
-    mdns_mcast_group_ipv4 (&sa);
-    memset(&mreq, 0, sizeof(mreq));
-    mreq.imr_multiaddr = sa.sin_addr;
-    mreq.imr_ifindex = index;
-    if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
-        g_warning("IP_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-int avahi_mdns_mcast_leave_ipv6 (int index, int fd)
-{
-    struct ipv6_mreq mreq6; 
-    struct sockaddr_in6 sa6;
-
-    mdns_mcast_group_ipv6 (&sa6);
-
-    memset(&mreq6, 0, sizeof(mreq6));
-    mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
-    mreq6.ipv6mr_interface = index;
-
-    if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
-        g_warning("IPV6_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-gint avahi_open_socket_ipv4(void) {
-    struct sockaddr_in sa, local;
-    int fd = -1, ttl, yes;
-        
-    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-        g_warning("socket() failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    ttl = 255;
-    if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
-        g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    ttl = 255;
-    if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
-        g_warning("IP_TTL failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    yes = 1;
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
-        g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    yes = 1;
-    if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
-        g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    
-    memset(&local, 0, sizeof(local));
-    local.sin_family = AF_INET;
-    local.sin_port = htons(AVAHI_MDNS_PORT);
-    
-    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
-        g_warning("bind() failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    yes = 1;
-    if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
-        g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    yes = 1;
-    if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
-        g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    if (avahi_set_cloexec(fd) < 0) {
-        g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    if (avahi_set_nonblock(fd) < 0) {
-        g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    return fd;
-
-fail:
-    if (fd >= 0)
-        close(fd);
-
-    return -1;
-}
-
-gint avahi_open_socket_ipv6(void) {
-    struct sockaddr_in6 sa, local;
-    int fd = -1, ttl, yes;
-
-    mdns_mcast_group_ipv6(&sa);
-        
-    if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
-        g_warning("socket() failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    ttl = 255;
-    if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
-        g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    ttl = 255;
-    if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
-        g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    yes = 1;
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
-        g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    yes = 1;
-    if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
-        g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    yes = 1;
-    if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
-        g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    memset(&local, 0, sizeof(local));
-    local.sin6_family = AF_INET6;
-    local.sin6_port = htons(AVAHI_MDNS_PORT);
-    
-    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
-        g_warning("bind() failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    yes = 1;
-    if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
-        g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    yes = 1;
-    if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
-        g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    if (avahi_set_cloexec(fd) < 0) {
-        g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
-        goto fail;
-    }
-    
-    if (avahi_set_nonblock(fd) < 0) {
-        g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
-        goto fail;
-    }
-
-    return fd;
-
-fail:
-    if (fd >= 0)
-        close(fd);
-
-    return -1;
-}
-
-static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
-    g_assert(fd >= 0);
-    g_assert(msg);
-
-    for (;;) {
-    
-        if (sendmsg(fd, msg, flags) >= 0)
-            break;
-        
-        if (errno != EAGAIN) {
-            g_message("sendmsg() failed: %s\n", strerror(errno));
-            return -1;
-        }
-        
-        if (avahi_wait_for_write(fd) < 0)
-            return -1;
-    }
-
-    return 0;
-}
-
-gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p) {
-    struct sockaddr_in sa;
-    struct msghdr msg;
-    struct iovec io;
-    struct cmsghdr *cmsg;
-    struct in_pktinfo *pkti;
-    uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
-    int i, n;
-
-    g_assert(fd >= 0);
-    g_assert(p);
-    g_assert(avahi_dns_packet_check_valid(p) >= 0);
-
-    mdns_mcast_group_ipv4(&sa);
-
-    memset(&io, 0, sizeof(io));
-    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
-    io.iov_len = p->size;
-
-    memset(cmsg_data, 0, sizeof(cmsg_data));
-    cmsg = (struct cmsghdr*) cmsg_data;
-    cmsg->cmsg_len = sizeof(cmsg_data);
-    cmsg->cmsg_level = IPPROTO_IP;
-    cmsg->cmsg_type = IP_PKTINFO;
-
-    pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
-    pkti->ipi_ifindex = interface;
-    
-    memset(&msg, 0, sizeof(msg));
-    msg.msg_name = &sa;
-    msg.msg_namelen = sizeof(sa);
-    msg.msg_iov = &io;
-    msg.msg_iovlen = 1;
-    msg.msg_control = cmsg_data;
-    msg.msg_controllen = sizeof(cmsg_data);
-    msg.msg_flags = 0;
-
-    return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
-}
-
-gint avahi_send_dns_packet_ipv6(gint fd, gint interface, AvahiDnsPacket *p) {
-    struct sockaddr_in6 sa;
-    struct msghdr msg;
-    struct iovec io;
-    struct cmsghdr *cmsg;
-    struct in6_pktinfo *pkti;
-    uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
-    int i, n;
-
-    g_assert(fd >= 0);
-    g_assert(p);
-    g_assert(avahi_dns_packet_check_valid(p) >= 0);
-
-    mdns_mcast_group_ipv6(&sa);
-
-    memset(&io, 0, sizeof(io));
-    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
-    io.iov_len = p->size;
-
-    memset(cmsg_data, 0, sizeof(cmsg_data));
-    cmsg = (struct cmsghdr*) cmsg_data;
-    cmsg->cmsg_len = sizeof(cmsg_data);
-    cmsg->cmsg_level = IPPROTO_IPV6;
-    cmsg->cmsg_type = IPV6_PKTINFO;
-
-    pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
-    pkti->ipi6_ifindex = interface;
-    
-    memset(&msg, 0, sizeof(msg));
-    msg.msg_name = &sa;
-    msg.msg_namelen = sizeof(sa);
-    msg.msg_iov = &io;
-    msg.msg_iovlen = 1;
-    msg.msg_control = cmsg_data;
-    msg.msg_controllen = sizeof(cmsg_data);
-    msg.msg_flags = 0;
-
-    return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
-}
-
-AvahiDnsPacket* avahi_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
-    AvahiDnsPacket *p= NULL;
-    struct msghdr msg;
-    struct iovec io;
-    uint8_t aux[64];
-    ssize_t l;
-    struct cmsghdr *cmsg;
-    gboolean found_ttl = FALSE, found_iface = FALSE;
-
-    g_assert(fd >= 0);
-    g_assert(ret_sa);
-    g_assert(ret_iface);
-    g_assert(ret_ttl);
-
-    p = avahi_dns_packet_new(0);
-
-    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
-    io.iov_len = p->max_size;
-    
-    memset(&msg, 0, sizeof(msg));
-    msg.msg_name = ret_sa;
-    msg.msg_namelen = sizeof(struct sockaddr_in);
-    msg.msg_iov = &io;
-    msg.msg_iovlen = 1;
-    msg.msg_control = aux;
-    msg.msg_controllen = sizeof(aux);
-    msg.msg_flags = 0;
-    
-    if ((l = recvmsg(fd, &msg, 0)) < 0)
-        goto fail;
-
-    p->size = (size_t) l;
-    
-    *ret_ttl = 0;
-        
-    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
-        if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
-            *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
-            found_ttl = TRUE;
-        }
-            
-        if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
-            *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
-            found_iface = TRUE;
-        }
-    }
-
-    g_assert(found_iface);
-    g_assert(found_ttl);
-
-    return p;
-
-fail:
-    if (p)
-        avahi_dns_packet_free(p);
-
-    return NULL;
-}
-
-AvahiDnsPacket* avahi_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
-    AvahiDnsPacket *p = NULL;
-    struct msghdr msg;
-    struct iovec io;
-    uint8_t aux[64];
-    ssize_t l;
-    struct cmsghdr *cmsg;
-    gboolean found_ttl = FALSE, found_iface = FALSE;
-
-    g_assert(fd >= 0);
-    g_assert(ret_sa);
-    g_assert(ret_iface);
-    g_assert(ret_ttl);
-
-    p = avahi_dns_packet_new(0);
-
-    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
-    io.iov_len = p->max_size;
-    
-    memset(&msg, 0, sizeof(msg));
-    msg.msg_name = ret_sa;
-    msg.msg_namelen = sizeof(struct sockaddr_in6);
-    msg.msg_iov = &io;
-    msg.msg_iovlen = 1;
-    msg.msg_control = aux;
-    msg.msg_controllen = sizeof(aux);
-    msg.msg_flags = 0;
-    
-    if ((l = recvmsg(fd, &msg, 0)) < 0)
-        goto fail;
-
-    p->size = (size_t) l;
-    
-    *ret_ttl = 0;
-
-    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-        if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
-            *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
-            found_ttl = TRUE;
-        }
-            
-        if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
-            *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
-            found_iface = TRUE;
-        }
-    }
-
-    g_assert(found_iface);
-    g_assert(found_ttl);
-
-    return p;
-
-fail:
-    if (p)
-        avahi_dns_packet_free(p);
-
-    return NULL;
-}
-
diff --git a/socket.h b/socket.h
deleted file mode 100644 (file)
index 2baa122..0000000
--- a/socket.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef foosockethfoo
-#define foosockethfoo
-
-#include <netinet/in.h>
-
-#include "dns.h"
-
-#define AVAHI_MDNS_PORT 5353
-
-
-
-gint avahi_open_socket_ipv4(void);
-gint avahi_open_socket_ipv6(void);
-
-gint avahi_send_dns_packet_ipv4(gint fd, gint iface, AvahiDnsPacket *p);
-gint avahi_send_dns_packet_ipv6(gint fd, gint iface, AvahiDnsPacket *p);
-
-AvahiDnsPacket *avahi_recv_dns_packet_ipv4(gint fd, struct sockaddr_in*ret_sa, gint *ret_iface, guint8 *ret_ttl);
-AvahiDnsPacket *avahi_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6*ret_sa, gint *ret_iface, guint8 *ret_ttl);
-
-int avahi_mdns_mcast_join_ipv4(int index, int fd);
-int avahi_mdns_mcast_join_ipv6(int index, int fd);
-
-int avahi_mdns_mcast_leave_ipv4(int index, int fd);
-int avahi_mdns_mcast_leave_ipv6(int index, int fd);
-
-#endif
diff --git a/strlst-test.c b/strlst-test.c
deleted file mode 100644 (file)
index 5e28ce2..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <glib.h>
-#include <stdio.h>
-
-#include "strlst.h"
-
-int main(int argc, char *argv[]) {
-    gchar *t;
-    guint8 data[1024];
-    AvahiStringList *a = NULL, *b;
-    guint size, n;
-
-    a = avahi_string_list_add(a, "start");
-    a = avahi_string_list_add(a, "foo");
-    a = avahi_string_list_add(a, "bar");
-    a = avahi_string_list_add(a, "quux");
-    a = avahi_string_list_add_arbitrary(a, "null\0null", 9);
-    a = avahi_string_list_add(a, "end");
-
-    t = avahi_string_list_to_string(a);
-    printf("--%s--\n", t);
-    g_free(t);
-
-    size = avahi_string_list_serialize(a, data, sizeof(data));
-
-    printf("%u\n", size);
-
-    for (t = (gchar*) data, n = 0; n < size; n++, t++) {
-        if (*t <= 32)
-            printf("(%u)", *t);
-        else
-            printf("%c", *t);
-    }
-
-    printf("\n");
-    
-    b = avahi_string_list_parse(data, size);
-
-    g_assert(avahi_string_list_equal(a, b));
-    
-    t = avahi_string_list_to_string(b);
-    printf("--%s--\n", t);
-    g_free(t);
-
-    avahi_string_list_free(b);
-
-    b = avahi_string_list_copy(a);
-
-    g_assert(avahi_string_list_equal(a, b));
-
-    t = avahi_string_list_to_string(b);
-    printf("--%s--\n", t);
-    g_free(t);
-    
-    avahi_string_list_free(a);
-    avahi_string_list_free(b);
-    
-    return 0;
-}
diff --git a/strlst.c b/strlst.c
deleted file mode 100644 (file)
index f2d76e4..0000000
--- a/strlst.c
+++ /dev/null
@@ -1,218 +0,0 @@
-#include <string.h>
-#include <stdarg.h>
-
-#include "strlst.h"
-
-AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const guint8*text, guint size) {
-    AvahiStringList *n;
-
-    g_assert(text);
-
-    n = g_malloc(sizeof(AvahiStringList) + size);
-    n->next = l;
-    memcpy(n->text, text, n->size = size);
-    
-    return n;
-}
-
-AvahiStringList *avahi_string_list_add(AvahiStringList *l, const gchar *text) {
-    g_assert(text);
-
-    return avahi_string_list_add_arbitrary(l, (const guint8*) text, strlen(text));
-}
-
-AvahiStringList *avahi_string_list_parse(gconstpointer data, guint size) {
-    AvahiStringList *r = NULL;
-    const guint8 *c;
-    g_assert(data);
-
-    c = data;
-    for (;;) {
-        guint k;
-        
-        if (size < 1)
-            break;
-
-        k = *(c++);
-        r = avahi_string_list_add_arbitrary(r, c, k);
-        c += k;
-
-        size -= 1 + k;
-    }
-
-    return r;
-}
-
-void avahi_string_list_free(AvahiStringList *l) {
-    AvahiStringList *n;
-
-    while (l) {
-        n = l->next;
-        g_free(l);
-        l = n;
-    }
-}
-
-static AvahiStringList* string_list_reverse(AvahiStringList *l) {
-    AvahiStringList *r = NULL, *n;
-
-    while (l) {
-        n = l->next;
-        l->next = r;
-        r = l;
-        l = n;
-    }
-
-    return r;
-}
-
-gchar* avahi_string_list_to_string(AvahiStringList *l) {
-    AvahiStringList *n;
-    guint s = 0;
-    gchar *t, *e;
-
-    l = string_list_reverse(l);
-    
-    for (n = l; n; n = n->next) {
-        if (n != l)
-            s ++;
-
-        s += n->size+3;
-    }
-
-    t = e = g_new(gchar, s);
-
-    for (n = l; n; n = n->next) {
-        if (n != l)
-            *(e++) = ' ';
-
-        *(e++) = '"';
-        strncpy(e, n->text, n->size);
-        e[n->size] = 0;
-        e = strchr(e, 0);
-        *(e++) = '"';
-    }
-
-    l = string_list_reverse(l);
-
-    *e = 0;
-
-    return t;
-}
-
-guint avahi_string_list_serialize(AvahiStringList *l, gpointer data, guint size) {
-    guint used = 0;
-
-    if (data) {
-        guint8 *c;
-        AvahiStringList *n;
-    
-        g_assert(data);
-        
-        l = string_list_reverse(l);
-        c = data;
-        
-        for (n = l; n; n = n->next) {
-            guint k;
-            if (size < 1)
-                break;
-            
-            k = n->size;
-            if (k > 255)
-                k = 255;
-            
-            if (k > size-1)
-                k = size-1;
-            
-            *(c++) = k;
-            memcpy(c, n->text, k);
-            c += k;
-            
-            used += 1+ k;
-        }
-        
-        l = string_list_reverse(l);
-    } else {
-        AvahiStringList *n;
-
-        for (n = l; n; n = n->next) {
-            guint k;
-        
-            k = n->size;
-            if (k > 255)
-                k = 255;
-            
-            used += 1+k;
-        }
-    }
-
-    return used;
-}
-
-gboolean avahi_string_list_equal(AvahiStringList *a, AvahiStringList *b) {
-
-    for (;;) {
-        if (!a && !b)
-            return TRUE;
-
-        if (!a || !b)
-            return FALSE;
-
-        if (a->size != b->size)
-            return FALSE;
-
-        if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
-            return FALSE;
-
-        a = a->next;
-        b = b->next;
-    }
-}
-
-AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
-    va_list va;
-
-    va_start(va, r);
-    r = avahi_string_list_add_many_va(r, va);
-    va_end(va);
-    
-    return r;
-}
-
-AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
-    const gchar *txt;
-
-    while ((txt = va_arg(va, const gchar*)))
-        r = avahi_string_list_add(r, txt);
-
-    return r;
-}
-
-
-AvahiStringList *avahi_string_list_new(const gchar *txt, ...) {
-    va_list va;
-    AvahiStringList *r = NULL;
-
-    if (txt) {
-        r = avahi_string_list_add(r, txt);
-
-        va_start(va, txt);
-        r = avahi_string_list_add_many_va(r, va);
-        va_end(va);
-    }
-
-    return r;
-}
-
-AvahiStringList *avahi_string_list_new_va(va_list va) {
-    return avahi_string_list_add_many_va(NULL, va);
-}
-
-AvahiStringList *avahi_string_list_copy(AvahiStringList *l) {
-    AvahiStringList *r = NULL;
-
-    for (; l; l = l->next)
-        r = avahi_string_list_add_arbitrary(r, l->text, l->size);
-
-    return string_list_reverse(r);
-}
diff --git a/strlst.h b/strlst.h
deleted file mode 100644 (file)
index 22cdc88..0000000
--- a/strlst.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef footxtlisthfoo
-#define footxtlisthfoo
-
-#include <glib.h>
-
-typedef struct _AvahiStringList AvahiStringList;
-
-struct _AvahiStringList {
-    AvahiStringList *next;
-    guint size;
-    guint8 text[1];
-};
-
-AvahiStringList *avahi_string_list_new(const gchar *txt, ...);
-AvahiStringList *avahi_string_list_new_va(va_list va);
-
-void avahi_string_list_free(AvahiStringList *l);
-
-AvahiStringList *avahi_string_list_add(AvahiStringList *l, const gchar *text);
-AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const guint8 *text, guint size);
-AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...);
-AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va);
-
-gchar* avahi_string_list_to_string(AvahiStringList *l);
-
-guint avahi_string_list_serialize(AvahiStringList *l, gpointer data, guint size);
-AvahiStringList *avahi_string_list_parse(gconstpointer data, guint size);
-
-gboolean avahi_string_list_equal(AvahiStringList *a, AvahiStringList *b);
-
-AvahiStringList *avahi_string_list_copy(AvahiStringList *l);
-
-#endif
-
diff --git a/subscribe.c b/subscribe.c
deleted file mode 100644 (file)
index 902e966..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-#include "subscribe.h"
-#include "util.h"
-
-static void elapse(AvahiTimeEvent *e, void *userdata) {
-    AvahiSubscription *s = userdata;
-    GTimeVal tv;
-    gchar *t;
-    
-    g_assert(s);
-
-    avahi_server_post_query(s->server, s->interface, s->protocol, s->key);
-
-    if (s->n_query++ <= 8)
-        s->sec_delay *= 2;
-
-    g_message("%i. Continuous querying for %s", s->n_query, t = avahi_key_to_string(s->key));
-    g_free(t);
-    
-    avahi_elapse_time(&tv, s->sec_delay*1000, 0);
-    avahi_time_event_queue_update(s->server->time_event_queue, s->time_event, &tv);
-}
-
-struct cbdata {
-    AvahiSubscription *subscription;
-    AvahiInterface *interface;
-};
-
-static gpointer scan_cache_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) {
-    struct cbdata *cbdata = userdata;
-
-    g_assert(c);
-    g_assert(pattern);
-    g_assert(e);
-    g_assert(cbdata);
-
-    cbdata->subscription->callback(
-        cbdata->subscription,
-        e->record,
-        cbdata->interface->hardware->index,
-        cbdata->interface->protocol,
-        AVAHI_SUBSCRIPTION_NEW,
-        cbdata->subscription->userdata);
-
-    return NULL;
-}
-
-static void scan_interface_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
-    AvahiSubscription *s = userdata;
-    struct cbdata cbdata = { s, i };
-
-    g_assert(m);
-    g_assert(i);
-    g_assert(s);
-
-    avahi_cache_walk(i->cache, s->key, scan_cache_callback, &cbdata);
-}
-
-AvahiSubscription *avahi_subscription_new(AvahiServer *server, AvahiKey *key, gint interface, guchar protocol, AvahiSubscriptionCallback callback, gpointer userdata) {
-    AvahiSubscription *s, *t;
-    GTimeVal tv;
-
-    g_assert(server);
-    g_assert(key);
-    g_assert(callback);
-
-    g_assert(!avahi_key_is_pattern(key));
-    
-    s = g_new(AvahiSubscription, 1);
-    s->server = server;
-    s->key = avahi_key_ref(key);
-    s->interface = interface;
-    s->protocol = protocol;
-    s->callback = callback;
-    s->userdata = userdata;
-    s->n_query = 1;
-    s->sec_delay = 1;
-
-    avahi_server_post_query(s->server, s->interface, s->protocol, s->key);
-    
-    avahi_elapse_time(&tv, s->sec_delay*1000, 0);
-    s->time_event = avahi_time_event_queue_add(server->time_event_queue, &tv, elapse, s);
-
-    AVAHI_LLIST_PREPEND(AvahiSubscription, subscriptions, server->subscriptions, s);
-
-    /* Add the new entry to the subscription hash table */
-    t = g_hash_table_lookup(server->subscription_hashtable, key);
-    AVAHI_LLIST_PREPEND(AvahiSubscription, by_key, t, s);
-    g_hash_table_replace(server->subscription_hashtable, key, t);
-
-    /* Scan the caches */
-    avahi_interface_monitor_walk(s->server->monitor, s->interface, s->protocol, scan_interface_callback, s);
-    
-    return s;
-}
-
-void avahi_subscription_free(AvahiSubscription *s) {
-    AvahiSubscription *t;
-    
-    g_assert(s);
-
-    AVAHI_LLIST_REMOVE(AvahiSubscription, subscriptions, s->server->subscriptions, s);
-
-    t = g_hash_table_lookup(s->server->subscription_hashtable, s->key);
-    AVAHI_LLIST_REMOVE(AvahiSubscription, by_key, t, s);
-    if (t)
-        g_hash_table_replace(s->server->subscription_hashtable, t->key, t);
-    else
-        g_hash_table_remove(s->server->subscription_hashtable, s->key);
-    
-    avahi_time_event_queue_remove(s->server->time_event_queue, s->time_event);
-    avahi_key_unref(s->key);
-
-    
-    g_free(s);
-}
-
-void avahi_subscription_notify(AvahiServer *server, AvahiInterface *i, AvahiRecord *record, AvahiSubscriptionEvent event) {
-    AvahiSubscription *s;
-    AvahiKey *pattern;
-    
-    g_assert(server);
-    g_assert(record);
-
-    for (s = g_hash_table_lookup(server->subscription_hashtable, record->key); s; s = s->by_key_next)
-        if (avahi_interface_match(i, s->interface, s->protocol))
-            s->callback(s, record, i->hardware->index, i->protocol, event, s->userdata);
-}
-
-gboolean avahi_is_subscribed(AvahiServer *server, AvahiKey *k) {
-    g_assert(server);
-    g_assert(k);
-
-    return !!g_hash_table_lookup(server->subscription_hashtable, k);
-}
diff --git a/subscribe.h b/subscribe.h
deleted file mode 100644 (file)
index 2cb1528..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef foosubscribehfoo
-#define foosubscribehfoo
-
-#include "llist.h"
-#include "avahi.h"
-#include "subscribe.h"
-#include "timeeventq.h"
-#include "server.h"
-
-struct _AvahiSubscription {
-    AvahiServer *server;
-    AvahiKey *key;
-    gint interface;
-    guchar protocol;
-    gint n_query;
-    guint sec_delay;
-
-    AvahiTimeEvent *time_event;
-
-    AvahiSubscriptionCallback callback;
-    gpointer userdata;
-
-    AVAHI_LLIST_FIELDS(AvahiSubscription, subscriptions);
-    AVAHI_LLIST_FIELDS(AvahiSubscription, by_key);
-};
-
-void avahi_subscription_notify(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, AvahiSubscriptionEvent event);
-
-gboolean avahi_is_subscribed(AvahiServer *s, AvahiKey *k);
-
-#endif
diff --git a/timeeventq.c b/timeeventq.c
deleted file mode 100644 (file)
index fc84157..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-#include "timeeventq.h"
-#include "util.h"
-
-static gint compare(gconstpointer _a, gconstpointer _b) {
-    const AvahiTimeEvent *a = _a,  *b = _b;
-
-    return avahi_timeval_compare(&a->expiry, &b->expiry);
-}
-
-static gboolean prepare_func(GSource *source, gint *timeout) {
-    AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
-    AvahiTimeEvent *e;
-    GTimeVal now;
-
-    g_assert(source);
-    g_assert(timeout);
-
-    if (!q->prioq->root) {
-        *timeout = -1;
-        return FALSE;
-    }
-    
-    e = q->prioq->root->data;
-    g_assert(e);
-
-    g_source_get_current_time(source, &now);
-
-    if (avahi_timeval_compare(&now, &e->expiry) >= 0) {
-        *timeout = -1;
-        return TRUE;
-    }
-
-    *timeout = (gint) (avahi_timeval_diff(&e->expiry, &now)/1000);
-    
-    return FALSE;
-}
-
-static gboolean check_func(GSource *source) {
-    AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
-    AvahiTimeEvent *e;
-    GTimeVal now;
-
-    g_assert(source);
-
-    if (!q->prioq->root)
-        return FALSE;
-
-    e = q->prioq->root->data;
-    g_assert(e);
-
-    g_source_get_current_time(source, &now);
-    
-    return avahi_timeval_compare(&now, &e->expiry) >= 0;
-}
-
-static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
-    AvahiTimeEventQueue *q = (AvahiTimeEventQueue*) source;
-    GTimeVal now;
-
-    g_assert(source);
-
-    g_source_get_current_time(source, &now);
-
-    while (q->prioq->root) {
-        AvahiTimeEvent *e = q->prioq->root->data;
-
-        if (avahi_timeval_compare(&now, &e->expiry) < 0)
-            break;
-
-        g_assert(e->callback);
-        e->callback(e, e->userdata);
-    }
-
-    return TRUE;
-}
-
-AvahiTimeEventQueue* avahi_time_event_queue_new(GMainContext *context, gint priority) {
-    AvahiTimeEventQueue *q;
-
-    static GSourceFuncs source_funcs = {
-        prepare_func,
-        check_func,
-        dispatch_func,
-        NULL,
-        NULL,
-        NULL
-    };
-
-    q = (AvahiTimeEventQueue*) g_source_new(&source_funcs, sizeof(AvahiTimeEventQueue));
-    q->prioq = avahi_prio_queue_new(compare);
-
-    g_source_set_priority((GSource*) q, priority);
-    
-    g_source_attach(&q->source, context);
-    
-    return q;
-}
-
-void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
-    g_assert(q);
-
-    while (q->prioq->root)
-        avahi_time_event_queue_remove(q, q->prioq->root->data);
-    avahi_prio_queue_free(q->prioq);
-
-    g_source_destroy(&q->source);
-    g_source_unref(&q->source);
-}
-
-AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const GTimeVal *timeval, void (*callback)(AvahiTimeEvent *e, void *userdata), void *userdata) {
-    AvahiTimeEvent *e;
-    
-    g_assert(q);
-    g_assert(timeval);
-    g_assert(callback);
-    g_assert(userdata);
-
-    e = g_new(AvahiTimeEvent, 1);
-    e->queue = q;
-    e->expiry = *timeval;
-    e->callback = callback;
-    e->userdata = userdata;
-
-    e->node = avahi_prio_queue_put(q->prioq, e);
-    
-    return e;
-}
-
-void avahi_time_event_queue_remove(AvahiTimeEventQueue *q, AvahiTimeEvent *e) {
-    g_assert(q);
-    g_assert(e);
-    g_assert(e->queue == q);
-
-    avahi_prio_queue_remove(q->prioq, e->node);
-    g_free(e);
-}
-
-void avahi_time_event_queue_update(AvahiTimeEventQueue *q, AvahiTimeEvent *e, const GTimeVal *timeval) {
-    g_assert(q);
-    g_assert(e);
-    g_assert(e->queue == q);
-
-    e->expiry = *timeval;
-
-    avahi_prio_queue_shuffle(q->prioq, e->node);
-}
-
-AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q) {
-    g_assert(q);
-
-    return q->prioq->root ? q->prioq->root->data : NULL;
-}
-
-AvahiTimeEvent* avahi_time_event_next(AvahiTimeEvent *e) {
-    g_assert(e);
-
-    return e->node->next->data;
-}
-
-
diff --git a/timeeventq.h b/timeeventq.h
deleted file mode 100644 (file)
index 69ff860..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef footimeeventqhfoo
-#define footimeeventqhfoo
-
-typedef struct _AvahiTimeEventQueue AvahiTimeEventQueue;
-typedef struct _AvahiTimeEvent AvahiTimeEvent;
-
-#include "prioq.h"
-
-struct _AvahiTimeEvent {
-    AvahiTimeEventQueue *queue;
-    AvahiPrioQueueNode *node;
-    GTimeVal expiry;
-    void (*callback)(AvahiTimeEvent *e, void *userdata);
-    void *userdata;
-};
-
-struct _AvahiTimeEventQueue {
-    GSource source;
-    AvahiPrioQueue *prioq;
-};
-
-AvahiTimeEventQueue* avahi_time_event_queue_new(GMainContext *context, gint priority);
-void avahi_time_event_queue_free(AvahiTimeEventQueue *q);
-
-AvahiTimeEvent* avahi_time_event_queue_add(AvahiTimeEventQueue *q, const GTimeVal *timeval, void (*callback)(AvahiTimeEvent *e, void *userdata), void *userdata);
-void avahi_time_event_queue_remove(AvahiTimeEventQueue *q, AvahiTimeEvent *e);
-
-void avahi_time_event_queue_update(AvahiTimeEventQueue *q, AvahiTimeEvent *e, const GTimeVal *timeval);
-
-AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q);
-AvahiTimeEvent* avahi_time_event_next(AvahiTimeEvent *e);
-
-
-
-
-#endif
diff --git a/util.c b/util.c
deleted file mode 100644 (file)
index 270a48f..0000000
--- a/util.c
+++ /dev/null
@@ -1,214 +0,0 @@
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-
-#include "util.h"
-
-gchar *avahi_get_host_name(void) {
-#ifdef HOST_NAME_MAX
-    char t[HOST_NAME_MAX];
-#else
-    char t[256];
-#endif
-    gethostname(t, sizeof(t));
-    t[sizeof(t)-1] = 0;
-    return avahi_normalize_name(t);
-}
-
-gchar *avahi_normalize_name(const gchar *s) {
-    size_t l;
-    g_assert(s);
-
-    l = strlen(s);
-
-    if (!l)
-        return g_strdup(".");
-
-    if (s[l-1] == '.')
-        return g_strdup(s);
-    
-    return g_strdup_printf("%s.", s);
-}
-
-gint avahi_timeval_compare(const GTimeVal *a, const GTimeVal *b) {
-    g_assert(a);
-    g_assert(b);
-
-    if (a->tv_sec < b->tv_sec)
-        return -1;
-
-    if (a->tv_sec > b->tv_sec)
-        return 1;
-
-    if (a->tv_usec < b->tv_usec)
-        return -1;
-
-    if (a->tv_usec > b->tv_usec)
-        return 1;
-
-    return 0;
-}
-
-glong avahi_timeval_diff(const GTimeVal *a, const GTimeVal *b) {
-    g_assert(a);
-    g_assert(b);
-
-    if (avahi_timeval_compare(a, b) < 0)
-        return avahi_timeval_diff(b, a);
-
-    return ((glong) a->tv_sec - b->tv_sec)*1000000 + a->tv_usec - b->tv_usec;
-}
-
-
-gint avahi_set_cloexec(gint fd) {
-    gint n;
-
-    g_assert(fd >= 0);
-    
-    if ((n = fcntl(fd, F_GETFD)) < 0)
-        return -1;
-
-    if (n & FD_CLOEXEC)
-        return 0;
-
-    return fcntl(fd, F_SETFD, n|FD_CLOEXEC);
-}
-
-gint avahi_set_nonblock(gint fd) {
-    gint n;
-
-    g_assert(fd >= 0);
-
-    if ((n = fcntl(fd, F_GETFL)) < 0)
-        return -1;
-
-    if (n & O_NONBLOCK)
-        return 0;
-
-    return fcntl(fd, F_SETFL, n|O_NONBLOCK);
-}
-
-gint avahi_wait_for_write(gint fd) {
-    fd_set fds;
-    gint r;
-    
-    FD_ZERO(&fds);
-    FD_SET(fd, &fds);
-    
-    if ((r = select(fd+1, NULL, &fds, NULL, NULL)) < 0) {
-        g_message("select() failed: %s", strerror(errno));
-
-        return -1;
-    }
-    
-    g_assert(r > 0);
-
-    return 0;
-}
-
-GTimeVal *avahi_elapse_time(GTimeVal *tv, guint msec, guint jitter) {
-    g_assert(tv);
-
-    g_get_current_time(tv);
-
-    if (msec)
-        g_time_val_add(tv, msec*1000);
-
-    if (jitter)
-        g_time_val_add(tv, g_random_int_range(0, jitter) * 1000);
-        
-    return tv;
-}
-
-gint avahi_age(const GTimeVal *a) {
-    GTimeVal now;
-    
-    g_assert(a);
-
-    g_get_current_time(&now);
-
-    return avahi_timeval_diff(&now, a);
-}
-
-gboolean avahi_domain_cmp(const gchar *a, const gchar *b) {
-    int escaped_a = 0, escaped_b = 0;
-    g_assert(a);
-    g_assert(b);
-
-    for (;;) {
-        /* Check for escape characters "\" */
-        if ((escaped_a = *a == '\\'))
-            a ++;
-
-        if ((escaped_b = *b == '\\'))
-            b++;
-
-        /* Check for string end */
-        if (*a == 0 && *b == 0)
-            return 0;
-        
-        if (*a == 0 && !escaped_b && *b == '.' && *(b+1) == 0)
-            return 0;
-
-        if (!escaped_a && *a == '.' && *(a+1) == 0 && *b == 0)
-            return 0;
-
-        /* Compare characters */
-        if (escaped_a == escaped_b && *a != *b)
-            return *a < *b ? -1 : 1;
-
-        /* Next characters */
-        a++;
-        b++;
-        
-    }
-}
-
-gboolean avahi_domain_equal(const gchar *a, const gchar *b) {
-    return avahi_domain_cmp(a, b) == 0;
-}
-
-guint avahi_domain_hash(const gchar *p) {
-    char t[256];
-    strncpy(t, p, sizeof(t)-1);
-    t[sizeof(t)-1] = 0;
-
-    return g_int_hash(t);
-}
-
-void avahi_hexdump(gconstpointer p, guint size) {
-    const guint8 *c = p;
-    g_assert(p);
-
-    printf("Dumping %u bytes from %p:\n", size, p);
-    
-    while (size > 0) {
-        guint i;
-
-        for (i = 0; i < 16; i++) { 
-            if (i < size)
-                printf("%02x ", c[i]);
-            else
-                printf("   ");
-        }
-
-        for (i = 0; i < 16; i++) {
-            if (i < size)
-                printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
-            else
-                printf(" ");
-        }
-        
-        printf("\n");
-
-        c += 16;
-
-        if (size <= 16)
-            break;
-        
-        size -= 16;
-    }
-}
diff --git a/util.h b/util.h
deleted file mode 100644 (file)
index 7755ee2..0000000
--- a/util.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef fooutilhfoo
-#define fooutilhfoo
-
-#include <glib.h>
-
-gchar *avahi_normalize_name(const gchar *s); /* g_free() the result! */
-gchar *avahi_get_host_name(void); /* g_free() the result! */
-
-gint avahi_timeval_compare(const GTimeVal *a, const GTimeVal *b);
-glong avahi_timeval_diff(const GTimeVal *a, const GTimeVal *b);
-
-gint avahi_set_cloexec(gint fd);
-gint avahi_set_nonblock(gint fd);
-gint avahi_wait_for_write(gint fd);
-
-GTimeVal *avahi_elapse_time(GTimeVal *tv, guint msec, guint jitter);
-
-gint avahi_age(const GTimeVal *a);
-
-guint avahi_domain_hash(const gchar *p);
-gboolean avahi_domain_cmp(const gchar *a, const gchar *b);
-gboolean avahi_domain_equal(const gchar *a, const gchar *b);
-
-void avahi_hexdump(gconstpointer p, guint size);
-
-#endif