]> git.meshlink.io Git - catta/commitdiff
assorted work:
authorLennart Poettering <lennart@poettering.net>
Tue, 12 Apr 2005 03:09:56 +0000 (03:09 +0000)
committerLennart Poettering <lennart@poettering.net>
Tue, 12 Apr 2005 03:09:56 +0000 (03:09 +0000)
* new rr implementation: resource data is stored in parsed form now.
* make TXT and SRV functions variadic
* many other things

git-svn-id: file:///home/lennart/svn/public/avahi/trunk@23 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

13 files changed:
Makefile
announce.c
dns.c
dns.h
flx.h
main.c
rr.c
rr.h
server.c
strlst-test.c [new file with mode: 0644]
strlst.c [new file with mode: 0644]
strlst.h [new file with mode: 0644]
todo

index 8f60172d364f005af7aa34d816d779b50830406f..58512868cf3f7d5b3edb1f0c3af39c72ad223b55 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,9 +2,9 @@
 CFLAGS=-g -O0 -Wall -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused
 LIBS=$(shell pkg-config --libs glib-2.0)
 
-all: flexmdns prioq-test
+all: strlst-test prioq-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
+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
@@ -14,7 +14,11 @@ prioq-test: prioq-test.o prioq.o
        $(CC) -o $@ $^ $(LIBS)
 
 
+strlst-test: strlst-test.o strlst.o
+       $(CC) -o $@ $^ $(LIBS)
+
+
 *.o: *.h
 
 clean:
-       rm -f *.o flexmdns prioq-test
+       rm -f *.o flexmdns prioq-test strlst-test
index 9229753d9051beb9a78153f0038ddab9740413c3..1671758d2fcab2ed844a919a297d0769434bb243 100644 (file)
@@ -116,13 +116,18 @@ void flx_announce_entry(flxServer *s, flxServerEntry *e) {
 
 static flxRecord *make_goodbye_record(flxRecord *r) {
     gchar *t;
+    flxRecord *g;
     
     g_assert(r);
 
     g_message("Preparing goodbye for record [%s]", t = flx_record_to_string(r));
     g_free(t);
 
-    return flx_record_new(r->key, r->data, r->size, 0);
+    g = flx_record_copy(r);
+    g_assert(g->ref == 1);
+    g->ttl = 0;
+
+    return g;
 }
     
 void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean goodbye) {
diff --git a/dns.c b/dns.c
index bed7344d81d4fe5341d84567d63f2052eb299825..776ead24bf9130ab92540287b69103ccf92e7865 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -1,3 +1,5 @@
+#include <netinet/in.h>
+
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -139,6 +141,25 @@ guint8 *flx_dns_packet_append_bytes(flxDnsPacket  *p, gconstpointer b, guint l)
     return d;
 }
 
+guint8* flx_dns_packet_append_string(flxDnsPacket *p, const gchar *s) {
+    guint8* d;
+    guint k;
+    
+    g_assert(p);
+    g_assert(s);
+
+    if ((k = strlen(s)) >= 255)
+        k = 255;
+    
+    if (!(d = flx_dns_packet_extend(p, k+1)))
+        return NULL;
+
+    *d = (guint8) k;
+    memcpy(d+1, s, k);
+
+    return d;
+}
+
 guint8 *flx_dns_packet_extend(flxDnsPacket *p, guint l) {
     guint8 *d;
     
@@ -310,10 +331,38 @@ gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l) {
     return 0;
 }
 
+gint flx_dns_packet_consume_string(flxDnsPacket *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 = FLX_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, FLX_DNS_PACKET_DATA(p)+p->rindex+1, l-1);
+    ret_string[l-1] = 0;
+
+    
+    p->rindex += 1+k;
+
+    return 0;
+    
+}
+
 gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p) {
     g_assert(p);
     
-    if (p->rindex >= p->size)
+    if (p->rindex > p->size)
         return NULL;
 
     return FLX_DNS_PACKET_DATA(p) + p->rindex;
@@ -330,65 +379,144 @@ gint flx_dns_packet_skip(flxDnsPacket *p, guint length) {
 }
 
 flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush) {
-    gchar name[257], buf[257+6];
+    gchar name[257], buf[257];
     guint16 type, class;
     guint32 ttl;
     guint16 rdlength;
     gconstpointer data;
+    flxRecord *r = NULL;
+    gconstpointer start;
 
     g_assert(p);
     g_assert(ret_cache_flush);
 
+    g_message("consume_record()");
+
     if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
         flx_dns_packet_consume_uint16(p, &type) < 0 ||
         flx_dns_packet_consume_uint16(p, &class) < 0 ||
         flx_dns_packet_consume_uint32(p, &ttl) < 0 ||
-        flx_dns_packet_consume_uint16(p, &rdlength) < 0)
-        return NULL;
+        flx_dns_packet_consume_uint16(p, &rdlength) < 0 ||
+        p->rindex + rdlength > p->size)
+        
+        goto fail;
+
+    g_message("name = %s, rdlength = %u", name, rdlength);
+    
+    start = flx_dns_packet_get_rptr(p);
 
+    r = flx_record_new_full(name, class, type);
+    
     switch (type) {
         case FLX_DNS_TYPE_PTR:
         case FLX_DNS_TYPE_CNAME:
+
+            g_message("ptr");
+            
             if (flx_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
-                return NULL;
+                goto fail;
+
+            r->data.ptr.name = g_strdup(buf);
+            break;
+
             
-            data = buf;
-            rdlength = strlen(buf);
+        case FLX_DNS_TYPE_SRV:
+
+            g_message("srv");
+            
+            if (flx_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 ||
+                flx_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 ||
+                flx_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 ||
+                flx_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
+                goto fail;
+            
+            r->data.srv.name = g_strdup(buf);
+            break;
+
+        case FLX_DNS_TYPE_HINFO:
+            
+            g_message("hinfo");
+
+            if (flx_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
+                goto fail;
+
+            r->data.hinfo.cpu = g_strdup(buf);
+
+            if (flx_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
+                goto fail;
+
+            r->data.hinfo.os = g_strdup(buf);
             break;
 
-        case FLX_DNS_TYPE_SRV: {
-            const guint8 *t = flx_dns_packet_get_rptr(p);
+        case FLX_DNS_TYPE_TXT:
+
+            g_message("txt");
 
-            if (flx_dns_packet_skip(p, 6) < 0)
-                return NULL;
+            if (rdlength > 0) {
+                r->data.txt.string_list = flx_string_list_parse(flx_dns_packet_get_rptr(p), rdlength);
+                
+                if (flx_dns_packet_skip(p, rdlength) < 0)
+                    goto fail;
+            }
             
-            memcpy(buf, t, 6);
+            break;
+
+        case FLX_DNS_TYPE_A:
+
+            g_message("A");
 
-            if (flx_dns_packet_consume_name(p, buf+6, sizeof(buf)-6) < 0)
-                return NULL;
 
-            data = buf;
-            rdlength = 6 + strlen(buf+6);
+            g_message("%p", flx_dns_packet_get_rptr(p));
+                
+            if (flx_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(flxIPv4Address)) < 0)
+                goto fail;
+
+            g_message("%p", flx_dns_packet_get_rptr(p));
+            
+            break;
+
+        case FLX_DNS_TYPE_AAAA:
+
+            g_message("aaaa");
+            
+            if (flx_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(flxIPv6Address)) < 0)
+                goto fail;
+            
             break;
-        }
             
         default:
 
+            g_message("generic");
+            
             if (rdlength > 0) {
 
-                if (!(data = flx_dns_packet_get_rptr(p)) ||
-                    flx_dns_packet_skip(p, rdlength) < 0)
-                    return NULL;
-            } else
-                data = NULL;
+                r->data.generic.data = g_memdup(flx_dns_packet_get_rptr(p), rdlength);
+                
+                if (flx_dns_packet_skip(p, rdlength) < 0)
+                    goto fail;
+            }
 
             break;
     }
 
+    g_message("%i == %u ?", (guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start, rdlength);
+    
+    /* Check if we read enough data */
+    if ((guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start != rdlength)
+        goto fail;
+    
     *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH);
     class &= ~ MDNS_CACHE_FLUSH;
 
-    return flx_record_new_full(name, class, type, data, rdlength, ttl);
+    r->ttl = ttl;
+
+    return r;
+
+fail:
+    if (r)
+        flx_record_unref(r);
+
+    return NULL;
 }
 
 flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) {
@@ -427,7 +555,7 @@ guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k) {
 }
 
 guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush) {
-    guint8 *t;
+    guint8 *t, *l, *start;
     guint size;
 
     g_assert(p);
@@ -438,47 +566,89 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac
     if (!(t = flx_dns_packet_append_name(p, r->key->name)) ||
         !flx_dns_packet_append_uint16(p, r->key->type) ||
         !flx_dns_packet_append_uint16(p, cache_flush ? (r->key->class | MDNS_CACHE_FLUSH) : (r->key->class &~ MDNS_CACHE_FLUSH)) ||
-        !flx_dns_packet_append_uint32(p, r->ttl))
+        !flx_dns_packet_append_uint32(p, r->ttl) ||
+        !(l = flx_dns_packet_append_uint16(p, 0)))
         goto fail;
 
+    start = flx_dns_packet_extend(p, 0);
+
     switch (r->key->type) {
         
         case FLX_DNS_TYPE_PTR:
-        case FLX_DNS_TYPE_CNAME: {
-            char ptr_name[257];
+        case FLX_DNS_TYPE_CNAME :
 
-            g_assert((size_t) r->size+1 <= sizeof(ptr_name));
-            memcpy(ptr_name, r->data, r->size);
-            ptr_name[r->size] = 0;
+            if (!(flx_dns_packet_append_name(p, r->data.ptr.name)))
+                goto fail;
             
-            if (!flx_dns_packet_append_uint16(p, strlen(ptr_name)+1) ||
-                !flx_dns_packet_append_name(p, ptr_name))
+            break;
+
+        case FLX_DNS_TYPE_SRV:
+
+            if (!flx_dns_packet_append_uint16(p, r->data.srv.priority) ||
+                !flx_dns_packet_append_uint16(p, r->data.srv.weight) ||
+                !flx_dns_packet_append_uint16(p, r->data.srv.port) ||
+                !flx_dns_packet_append_name(p, r->data.srv.name))
                 goto fail;
 
             break;
-        }
 
-        case FLX_DNS_TYPE_SRV: {
-            char name[257];
+        case FLX_DNS_TYPE_HINFO:
+            if (!flx_dns_packet_append_string(p, r->data.hinfo.cpu) ||
+                !flx_dns_packet_append_string(p, r->data.hinfo.os))
+                goto fail;
+
+            break;
+
+        case FLX_DNS_TYPE_TXT: {
+
+            guint8 *data;
+            guint size;
 
-            g_assert(r->size >= 6 && (size_t) r->size-6+1 <= sizeof(name));
-            memcpy(name, r->data+6, r->size-6);
-            name[r->size-6] = 0;
+            size = flx_string_list_serialize(r->data.txt.string_list, NULL, 0);
 
-            if (!flx_dns_packet_append_uint16(p, strlen(name+6)+1+6) ||
-                !flx_dns_packet_append_bytes(p, r->data, 6) ||
-                !flx_dns_packet_append_name(p, name))
+            g_message("appending string: %u %p", size, r->data.txt.string_list);
+
+            if (!(data = flx_dns_packet_extend(p, size)))
                 goto fail;
 
+            flx_string_list_serialize(r->data.txt.string_list, data, size);
             break;
         }
 
+
+        case FLX_DNS_TYPE_A:
+
+            if (!flx_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address)))
+                goto fail;
+            
+            break;
+
+        case FLX_DNS_TYPE_AAAA:
+            
+            if (!flx_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address)))
+                goto fail;
+            
+            break;
+            
         default:
-            if (!flx_dns_packet_append_uint16(p, r->size) ||
-                (r->size != 0 && !flx_dns_packet_append_bytes(p, r->data, r->size)))
+
+            if (r->data.generic.size &&
+                flx_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size))
                 goto fail;
+
+            break;
     }
 
+
+
+    
+    size = flx_dns_packet_extend(p, 0) - start;
+    g_assert(size <= 0xFFFF);
+
+    g_message("appended %u", size);
+
+    * (guint16*) l = g_htons((guint16) size);
+    
     return t;
 
 
diff --git a/dns.h b/dns.h
index c5d2fae3562f96fe230c73e1e57a6e06dd885535..38944d3d86aebd823b7afdad55afc9fcd0a66079 100644 (file)
--- a/dns.h
+++ b/dns.h
@@ -32,6 +32,7 @@ guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name
 guint8 *flx_dns_packet_append_bytes(flxDnsPacket  *p, gconstpointer, guint l);
 guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k);
 guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush);
+guint8* flx_dns_packet_append_string(flxDnsPacket *p, const gchar *s);
 
 gint flx_dns_packet_is_query(flxDnsPacket *p);
 gint flx_dns_packet_check_valid(flxDnsPacket *p);
@@ -42,6 +43,7 @@ gint flx_dns_packet_consume_name(flxDnsPacket *p, gchar *ret_name, guint l);
 gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l);
 flxKey* flx_dns_packet_consume_key(flxDnsPacket *p);
 flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush);
+gint flx_dns_packet_consume_string(flxDnsPacket *p, gchar *ret_string, guint l);
 
 gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p);
 
diff --git a/flx.h b/flx.h
index 1debd89e069522baec73722a103cd17ae675e5ab..8f8b0bac4c1ddcde36d486ea30862215d07dc90a 100644 (file)
--- a/flx.h
+++ b/flx.h
@@ -4,7 +4,6 @@
 #include <stdio.h>
 #include <glib.h>
 
-struct _flxServer;
 typedef struct _flxServer flxServer;
 
 #include "address.h"
@@ -23,18 +22,14 @@ void flx_server_add(
     gboolean unique,
     flxRecord *r);
 
-void flx_server_add_full(
+void flx_server_add_ptr(
     flxServer *s,
     gint id,
     gint interface,
     guchar protocol,
     gboolean unique,
     const gchar *name,
-    guint16 class,
-    guint16 type,
-    gconstpointer data,
-    guint size,
-    guint32 ttl);
+    const gchar *dest);
 
 void flx_server_add_address(
     flxServer *s,
@@ -52,7 +47,41 @@ void flx_server_add_text(
     guchar protocol,
     gboolean unique,
     const gchar *name,
-    const gchar *text);
+    ... /* text records, terminated by NULL */);
+
+void flx_server_add_text_va(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    va_list va);
+
+void flx_server_add_service(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    ...  /* text records, terminated by NULL */);
+
+void flx_server_add_service_va(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    va_list va);
+
 
 void flx_server_remove(flxServer *s, gint id);
 
diff --git a/main.c b/main.c
index d5278c741e05ec7b9e5a03dce0009f14943aa888..0479f14b56c3ffbe7d59aae5080a7d66c0564e29 100644 (file)
--- a/main.c
+++ b/main.c
@@ -56,7 +56,7 @@ int main(int argc, char *argv[]) {
 
     flx = flx_server_new(NULL);
 
-    flx_server_add_text(flx, 0, 0, AF_UNSPEC, FALSE, NULL, "hallo");
+    flx_server_add_text(flx, 0, 0, AF_UNSPEC, FALSE, NULL, "hallo", NULL);
 
 /*     k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_ANY); */
 /*     s = flx_subscription_new(flx, k, 0, AF_UNSPEC, subscription, NULL); */
diff --git a/rr.c b/rr.c
index 600e7219bb7b58116f378f8b300b06ca05e4261a..a1c5868ce0f980c694b04231b84bf4c9d6325905 100644 (file)
--- a/rr.c
+++ b/rr.c
@@ -45,31 +45,30 @@ void flx_key_unref(flxKey *k) {
     }
 }
 
-flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 ttl) {
+flxRecord *flx_record_new(flxKey *k) {
     flxRecord *r;
     
     g_assert(k);
-    g_assert(size == 0 || data);
     
     r = g_new(flxRecord, 1);
     r->ref = 1;
     r->key = flx_key_ref(k);
-    r->data = size > 0 ? g_memdup(data, size) : NULL;
-    r->size = size;
-    r->ttl = ttl;
+
+    memset(&r->data, 0, sizeof(r->data));
+
+    r->ttl = FLX_DEFAULT_TTL;
 
     return r;
 }
 
-flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type, gconstpointer data, guint16 size, guint32 ttl) {
+flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type) {
     flxRecord *r;
     flxKey *k;
 
     g_assert(name);
-    g_assert(size == 0 || data);
     
     k = flx_key_new(name, class, type);
-    r = flx_record_new(k, data, size, ttl);
+    r = flx_record_new(k);
     flx_key_unref(k);
 
     return r;
@@ -88,8 +87,35 @@ void flx_record_unref(flxRecord *r) {
     g_assert(r->ref >= 1);
 
     if ((--r->ref) <= 0) {
+        switch (r->key->type) {
+
+            case FLX_DNS_TYPE_SRV:
+                g_free(r->data.srv.name);
+                break;
+
+            case FLX_DNS_TYPE_PTR:
+            case FLX_DNS_TYPE_CNAME:
+                g_free(r->data.ptr.name);
+                break;
+
+            case FLX_DNS_TYPE_HINFO:
+                g_free(r->data.hinfo.cpu);
+                g_free(r->data.hinfo.os);
+                break;
+
+            case FLX_DNS_TYPE_TXT:
+                flx_string_list_free(r->data.txt.string_list);
+                break;
+
+            case FLX_DNS_TYPE_A:
+            case FLX_DNS_TYPE_AAAA:
+                break;
+            
+            default:
+                g_free(r->data.generic.data);
+        }
+        
         flx_key_unref(r->key);
-        g_free(r->data);
         g_free(r);
     }
 }
@@ -123,97 +149,56 @@ const gchar *flx_dns_type_to_string(guint16 type) {
 }
 
 
-gchar *flx_key_to_string(flxKey *k) {
+gchar *flx_key_to_string(const flxKey *k) {
     return g_strdup_printf("%s\t%s\t%s",
                            k->name,
                            flx_dns_class_to_string(k->class),
                            flx_dns_type_to_string(k->type));
 }
 
-gchar *flx_record_to_string(flxRecord *r) {
+gchar *flx_record_to_string(const flxRecord *r) {
     gchar *p, *s;
-    char t[257] = "<unparsable>";
+    char buf[257], *t, *d = NULL;
 
     switch (r->key->type) {
         case FLX_DNS_TYPE_A:
-            inet_ntop(AF_INET, r->data, t, sizeof(t));
+            inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf));
             break;
             
         case FLX_DNS_TYPE_AAAA:
-            inet_ntop(AF_INET6, r->data, t, sizeof(t));
+            inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf));
             break;
             
-        case FLX_DNS_TYPE_PTR: {
-            size_t l;
-        
-            l = r->size;
-            if (l > sizeof(t)-1)
-                l = sizeof(t)-1;
-            
-            memcpy(t, r->data, l);
-            t[l] = 0;
-            break;
-        }
-
-        case FLX_DNS_TYPE_TXT: {
+        case FLX_DNS_TYPE_PTR:
+        case FLX_DNS_TYPE_CNAME :
 
-            if (r->size == 0)
-                t[0] = 0;
-            else {
-                guchar l = ((guchar*) r->data)[0];
+            t = r->data.ptr.name;
+            break;
 
-                if ((size_t) l+1 <= r->size) {
-                    memcpy(t, r->data+1, ((guchar*) r->data)[0]);
-                    t[((guchar*) r->data)[0]] = 0;
-                }
-            }
+        case FLX_DNS_TYPE_TXT:
+            t = d = flx_string_list_to_string(r->data.txt.string_list);
             break;
-        }
 
-        case FLX_DNS_TYPE_HINFO: {
-            gchar *s2;
-            gchar hi1[256], hi2[256];
-            guchar len;
-
-            if ((size_t) (len = ((guchar*) r->data)[0]) + 2 <= r->size) {
-                guchar len2;
-                memcpy(hi1, (gchar*) r->data +1, len);
-                hi1[len] = 0;
-
-                if ((size_t) (len2 = ((guchar*) r->data)[len+1]) + len + 2 <= r->size) {
-                    memcpy(hi2, (gchar*) r->data+len+2, len2);
-                    hi2[len2] = 0;
-                    snprintf(t, sizeof(t), "'%s' '%s'", hi1, hi2);
-                }
-                
-            }
+        case FLX_DNS_TYPE_HINFO:
 
+            snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os);
             break;
-        }
 
-        case FLX_DNS_TYPE_SRV: {
-            char k[257];
-            size_t l;
+        case FLX_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);
 
-            l = r->size-6;
-            if (l > sizeof(k)-1)
-                l = sizeof(k)-1;
-            
-            memcpy(k, r->data+6, l);
-            k[l] = 0;
-            
-            snprintf(t, sizeof(t), "%u %u %u %s",
-                     ntohs(((guint16*) r->data)[0]),
-                     ntohs(((guint16*) r->data)[1]),
-                     ntohs(((guint16*) r->data)[2]),
-                     k);
             break;
-        }
     }
 
     p = flx_key_to_string(r->key);
-    s = g_strdup_printf("%s %s ; ttl=%u", p, t, r->ttl);
+    s = g_strdup_printf("%s %s ; ttl=%u", p, t ? t : "<unparsable>", r->ttl);
     g_free(p);
+    g_free(d);
     
     return s;
 }
@@ -255,12 +240,108 @@ guint flx_key_hash(const flxKey *k) {
     return g_str_hash(k->name) + k->type + k->class;
 }
 
+static gboolean rdata_equal(const flxRecord *a, const flxRecord *b) {
+    gchar *t;
+    g_assert(a);
+    g_assert(b);
+    g_assert(a->key->type == b->key->type);
+
+    t = flx_record_to_string(a);
+    g_message("comparing %s", t);
+    g_free(t);
+
+    t = flx_record_to_string(b);
+    g_message("and %s", t);
+    g_free(t);
+
+    
+    switch (a->key->type) {
+        case FLX_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 &&
+                !strcmp(a->data.srv.name, b->data.srv.name);
+
+        case FLX_DNS_TYPE_PTR:
+        case FLX_DNS_TYPE_CNAME:
+            return !strcmp(a->data.ptr.name, b->data.ptr.name);
+
+        case FLX_DNS_TYPE_HINFO:
+            return
+                !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) &&
+                !strcmp(a->data.hinfo.os, b->data.hinfo.os);
+
+        case FLX_DNS_TYPE_TXT:
+            return flx_string_list_equal(a->data.txt.string_list, b->data.txt.string_list);
+
+        case FLX_DNS_TYPE_A:
+            return memcmp(&a->data.a.address, &b->data.a.address, sizeof(flxIPv4Address)) == 0;
+
+        case FLX_DNS_TYPE_AAAA:
+            return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(flxIPv6Address)) == 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 flx_record_equal_no_ttl(const flxRecord *a, const flxRecord *b) {
     g_assert(a);
     g_assert(b);
 
-    return flx_key_equal(a->key, b->key) &&
-/*        a->ttl == b->ttl && */
-        a->size == b->size &&
-        (a->size == 0 || memcmp(a->data, b->data, a->size) == 0);
+    return
+        flx_key_equal(a->key, b->key) &&
+        rdata_equal(a, b);
+}
+
+
+flxRecord *flx_record_copy(flxRecord *r) {
+    flxRecord *copy;
+
+    copy = g_new(flxRecord, 1);
+    copy->ref = 1;
+    copy->key = flx_key_ref(r->key);
+    copy->ttl = r->ttl;
+
+    switch (r->key->type) {
+        case FLX_DNS_TYPE_PTR:
+        case FLX_DNS_TYPE_CNAME:
+            copy->data.ptr.name = g_strdup(r->data.ptr.name);
+            break;
+
+        case FLX_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 FLX_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 FLX_DNS_TYPE_TXT:
+            copy->data.txt.string_list = flx_string_list_copy(r->data.txt.string_list);
+            break;
+
+        case FLX_DNS_TYPE_A:
+            copy->data.a.address = r->data.a.address;
+            break;
+
+        case FLX_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;
 }
diff --git a/rr.h b/rr.h
index 65abb1d1e609e081ffd36e011b04162c58b488b7..1ba6d958533abed0051669e74a852a57c3658e33 100644 (file)
--- a/rr.h
+++ b/rr.h
@@ -3,6 +3,9 @@
 
 #include <glib.h>
 
+#include "strlst.h"
+#include "address.h"
+
 enum {
     FLX_DNS_TYPE_A = 0x01,
     FLX_DNS_TYPE_NS = 0x02,
@@ -34,9 +37,44 @@ typedef struct  {
     guint ref;
     flxKey *key;
     
-    gpointer data;
-    guint16 size;
     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 {
+            flxStringList *string_list;
+        } txt;
+
+        struct {
+            flxIPv4Address address;
+        } a;
+
+        struct {
+            flxIPv6Address address;
+        } aaaa;
+
+    } data;
+    
 } flxRecord;
 
 flxKey *flx_key_new(const gchar *name, guint16 class, guint16 type);
@@ -50,17 +88,19 @@ gboolean flx_key_is_pattern(const flxKey *k);
 
 guint flx_key_hash(const flxKey *k);
 
-flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 ttl);
-flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type, gconstpointer data, guint16 size, guint32 ttl);
+flxRecord *flx_record_new(flxKey *k);
+flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type);
 flxRecord *flx_record_ref(flxRecord *r);
 void flx_record_unref(flxRecord *r);
 
 const gchar *flx_dns_class_to_string(guint16 class);
 const gchar *flx_dns_type_to_string(guint16 type);
 
-gchar *flx_key_to_string(flxKey *k); /* g_free() the result! */
-gchar *flx_record_to_string(flxRecord *r);  /* g_free() the result! */
+gchar *flx_key_to_string(const flxKey *k); /* g_free() the result! */
+gchar *flx_record_to_string(const flxRecord *r);  /* g_free() the result! */
 
 gboolean flx_record_equal_no_ttl(const flxRecord *a, const flxRecord *b);
 
+flxRecord *flx_record_copy(flxRecord *r);
+
 #endif
index 04c7d10821bc8a0c4712f68b716715f5eef879cc..fcf42487d9a85dfb9aef65c2306a345636e53e3b 100644 (file)
--- a/server.c
+++ b/server.c
@@ -92,19 +92,20 @@ static void handle_response(flxServer *s, flxDnsPacket *p, flxInterface *i, cons
         gchar *txt;
         
         if (!(record = flx_dns_packet_consume_record(p, &cache_flush))) {
-            g_warning("Packet too short");
+            g_warning("Packet too short (3)");
             return;
         }
 
-        if (record->key->type != FLX_DNS_TYPE_ANY) {
-            g_message("Handling response: %s", txt = flx_record_to_string(record));
-            g_free(txt);
-            
-            flx_cache_update(i->cache, record, cache_flush, a);
-            
-            flx_packet_scheduler_incoming_response(i->scheduler, record);
-            flx_record_unref(record);
-        }
+        if (record->key->type == FLX_DNS_TYPE_ANY)
+            continue;
+        
+        g_message("Handling response: %s", txt = flx_record_to_string(record));
+        g_free(txt);
+        
+        flx_cache_update(i->cache, record, cache_flush, a);
+        
+        flx_packet_scheduler_incoming_response(i->scheduler, record);
+        flx_record_unref(record);
     }
 }
 
@@ -232,20 +233,17 @@ static void add_default_entries(flxServer *s) {
     struct utsname utsname;
     gchar *hinfo;
     flxAddress a;
+    flxRecord *r;
     
     g_assert(s);
     
     /* Fill in HINFO rr */
+    r = flx_record_new_full(s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO);
     uname(&utsname);
-    hinfo = g_strdup_printf("%c%s%c%s%n",
-                            strlen(utsname.machine), g_strup(utsname.machine),
-                            strlen(utsname.sysname), g_strup(utsname.sysname),
-                            &length);
-    
-    flx_server_add_full(s, 0, 0, AF_UNSPEC, TRUE,
-                        s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO, hinfo, length, FLX_DEFAULT_TTL);
-
-    g_free(hinfo);
+    r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine));
+    r->data.hinfo.os = g_strdup(g_strup(utsname.sysname));
+    flx_server_add(s, 0, 0, AF_UNSPEC, TRUE, r);
+    flx_record_unref(r);
 
     /* Add localhost entries */
     flx_address_parse("127.0.0.1", AF_INET, &a);
@@ -402,30 +400,6 @@ void flx_server_add(
 
     flx_announce_entry(s, e);
 }
-
-void flx_server_add_full(
-    flxServer *s,
-    gint id,
-    gint interface,
-    guchar protocol,
-    gboolean unique,
-    const gchar *name,
-    guint16 class,
-    guint16 type,
-    gconstpointer data,
-    guint size,
-    guint32 ttl) {
-    
-    flxRecord *r;
-    g_assert(s);
-    g_assert(data);
-    g_assert(size);
-
-    r = flx_record_new_full(name ? name : s->hostname, class, type, data, size, ttl);
-    flx_server_add(s, id, interface, protocol, unique, r);
-    flx_record_unref(r);
-}
-
 const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) {
     flxServerEntry **e = (flxServerEntry**) state;
     g_assert(s);
@@ -504,6 +478,26 @@ void flx_server_dump(flxServer *s, FILE *f) {
     flx_dump_caches(s->monitor, f);
 }
 
+void flx_server_add_ptr(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    const gchar *dest) {
+
+    flxRecord *r;
+
+    g_assert(dest);
+
+    r = flx_record_new_full(name ? name : s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR);
+    r->data.ptr.name = flx_normalize_name(dest);
+    flx_server_add(s, id, interface, protocol, unique, r);
+    flx_record_unref(r);
+
+}
+
 void flx_server_add_address(
     flxServer *s,
     gint id,
@@ -513,41 +507,68 @@ void flx_server_add_address(
     const gchar *name,
     flxAddress *a) {
 
-    gchar *n;
+    gchar *n = NULL;
     g_assert(s);
     g_assert(a);
 
-    n = name ? flx_normalize_name(name) : s->hostname;
+    name = name ? (n = flx_normalize_name(name)) : s->hostname;
     
     if (a->family == AF_INET) {
-        gchar *r;
-        
-        flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A, &a->data.ipv4, sizeof(a->data.ipv4), FLX_DEFAULT_TTL);
+        gchar *reverse;
+        flxRecord  *r;
 
-        r = flx_reverse_lookup_name_ipv4(&a->data.ipv4);
-        g_assert(r);
-        flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
-        g_free(r);
+        r = flx_record_new_full(name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A);
+        r->data.a.address = a->data.ipv4;
+        flx_server_add(s, id, interface, protocol, unique, r);
+        flx_record_unref(r);
+        
+        reverse = flx_reverse_lookup_name_ipv4(&a->data.ipv4);
+        g_assert(reverse);
+        flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name);
+        g_free(reverse);
         
     } else {
-        gchar *r;
+        gchar *reverse;
+        flxRecord *r;
             
-        flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA, &a->data.ipv6, sizeof(a->data.ipv6), FLX_DEFAULT_TTL);
-
-        r = flx_reverse_lookup_name_ipv6_arpa(&a->data.ipv6);
-        g_assert(r);
-        flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
-        g_free(r);
+        r = flx_record_new_full(name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA);
+        r->data.aaaa.address = a->data.ipv6;
+        flx_server_add(s, id, interface, protocol, unique, r);
+        flx_record_unref(r);
+
+        reverse = flx_reverse_lookup_name_ipv6_arpa(&a->data.ipv6);
+        g_assert(reverse);
+        flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name);
+        g_free(reverse);
     
-        r = flx_reverse_lookup_name_ipv6_int(&a->data.ipv6);
-        g_assert(r);
-        flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
-        g_free(r);
+        reverse = flx_reverse_lookup_name_ipv6_int(&a->data.ipv6);
+        g_assert(reverse);
+        flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name);
+        g_free(reverse);
     }
     
     g_free(n);
 }
 
+void flx_server_add_text_va(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    va_list va) {
+
+    flxRecord *r;
+    
+    g_assert(s);
+    
+    r = flx_record_new_full(name ? name : s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT);
+    r->data.txt.string_list = flx_string_list_new_va(va);
+    flx_server_add(s, id, interface, protocol, unique, r);
+    flx_record_unref(r);
+}
+
 void flx_server_add_text(
     flxServer *s,
     gint id,
@@ -555,22 +576,110 @@ void flx_server_add_text(
     guchar protocol,
     gboolean unique,
     const gchar *name,
-    const gchar *text) {
+    ...) {
+
+    va_list va;
     
-    gchar buf[256];
-    guint l;
+    g_assert(s);
+
+    va_start(va, name);
+    flx_server_add_text_va(s, id, interface, protocol, unique, 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 flx_server_add_service_va(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    const gchar *type,
+    const gchar *name,
+    const gchar *domain,
+    const gchar *host,
+    guint16 port,
+    va_list va) {
+
+    gchar ptr_name[256], svc_name[256], ename[64], enum_ptr[256];
+    flxRecord *r;
     
     g_assert(s);
-    g_assert(text);
+    g_assert(type);
+    g_assert(name);
 
-    if ((l = strlen(text)) > 255)
-        buf[0] = 255;
-    else
-        buf[0] = (gchar) l;
+    escape_service_name(ename, sizeof(ename), name);
+
+    if (domain) {
+        while (domain[0] == '.')
+            domain++;
+    } else
+        domain = "local";
 
-    memcpy(buf+1, text, l);
+    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);
+    
+    flx_server_add_ptr(s, id, interface, protocol, FALSE, ptr_name, svc_name);
+
+    r = flx_record_new_full(svc_name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_SRV);
+    r->data.srv.priority = 0;
+    r->data.srv.weight = 0;
+    r->data.srv.port = port;
+    r->data.srv.name = flx_normalize_name(host);
+    flx_server_add(s, id, interface, protocol, TRUE, r);
+    flx_record_unref(r);
+
+    flx_server_add_text_va(s, id, interface, protocol, FALSE, svc_name, va);
+
+    snprintf(enum_ptr, sizeof(enum_ptr), "_services._dns-sd._udp.%s", domain);
+    flx_server_add_ptr(s, id, interface, protocol, FALSE, enum_ptr, ptr_name);
+}
+
+void flx_server_add_service(
+    flxServer *s,
+    gint id,
+    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);
 
-    flx_server_add_full(s, id, interface, protocol, unique, name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT, buf, l+1, FLX_DEFAULT_TTL);
+    va_start(va, port);
+    flx_server_add_service_va(s, id, interface, protocol, type, name, domain, host, port, va);
+    va_end(va);
 }
 
 static void post_query_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
diff --git a/strlst-test.c b/strlst-test.c
new file mode 100644 (file)
index 0000000..c4cef31
--- /dev/null
@@ -0,0 +1,46 @@
+#include <glib.h>
+#include <stdio.h>
+
+#include "strlst.h"
+
+int main(int argc, char *argv[]) {
+    gchar *t;
+    guint8 data[1024];
+    flxStringList *a = NULL, *b;
+    guint size, n;
+
+    a = flx_string_list_add(a, "foo");
+    a = flx_string_list_add(a, "bar");
+    a = flx_string_list_add(a, "baz");
+
+    t = flx_string_list_to_string(a);
+    printf("--%s--\n", t);
+    g_free(t);
+
+    size = flx_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 = flx_string_list_parse(data, size);
+
+    g_assert(flx_string_list_equal(a, b));
+    
+    t = flx_string_list_to_string(b);
+    printf("--%s--\n", t);
+    g_free(t);
+
+
+    flx_string_list_free(a);
+    flx_string_list_free(b);
+    
+    return 0;
+}
diff --git a/strlst.c b/strlst.c
new file mode 100644 (file)
index 0000000..8993f3a
--- /dev/null
+++ b/strlst.c
@@ -0,0 +1,215 @@
+#include <string.h>
+#include <stdarg.h>
+
+#include "strlst.h"
+
+static flxStringList *string_list_add_internal(flxStringList *l, const gchar *text, guint size) {
+    flxStringList *n;
+
+    g_assert(text);
+
+    n = g_malloc(sizeof(flxStringList) + size);
+    n->next = l;
+    strncpy(n->text, text, size);
+    n->text[size] = 0;
+    
+    return n;
+}
+
+flxStringList *flx_string_list_add(flxStringList *l, const gchar *text) {
+    g_assert(text);
+
+    return string_list_add_internal(l, text, strlen(text));
+}
+
+flxStringList *flx_string_list_parse(gconstpointer data, guint size) {
+    flxStringList *r = NULL;
+    const guint8 *c;
+    g_assert(data);
+
+    c = data;
+    for (;;) {
+        guint k;
+        
+        if (size < 1)
+            break;
+
+        k = *(c++);
+        r = string_list_add_internal(r, (const gchar*) c, k);
+        c += k;
+
+        size -= 1 + k;
+    }
+
+    return r;
+}
+
+void flx_string_list_free(flxStringList *l) {
+    flxStringList *n;
+
+    while (l) {
+        n = l->next;
+        g_free(l);
+        l = n;
+    }
+}
+
+
+static flxStringList* string_list_reverse(flxStringList *l) {
+    flxStringList *r = NULL, *n;
+
+    while (l) {
+        n = l->next;
+        l->next = r;
+        r = l;
+        l = n;
+    }
+
+    return r;
+}
+
+gchar* flx_string_list_to_string(flxStringList *l) {
+    flxStringList *n;
+    guint s = 0;
+    gchar *t, *e;
+
+    l = string_list_reverse(l);
+    
+    for (n = l; n; n = n->next) {
+        if (n != l)
+            s ++;
+
+        s += strlen(n->text)+2;
+    }
+
+    t = e = g_new(gchar, s+1);
+
+    for (n = l; n; n = n->next) {
+        if (n != l)
+            *(e++) = ' ';
+
+        *(e++) = '"';
+        strcpy(e, n->text);
+        e += strlen(n->text);
+        *(e++) = '"';
+    }
+
+    l = string_list_reverse(l);
+
+    *e = 0;
+
+    return t;
+}
+
+guint flx_string_list_serialize(flxStringList *l, gpointer data, guint size) {
+    guint used = 0;
+
+    if (data) {
+        guint8 *c;
+        flxStringList *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 = strlen(n->text);
+            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 {
+        flxStringList *n;
+
+        for (n = l; n; n = n->next) {
+            guint k;
+        
+            k = strlen(n->text);
+            if (k > 255)
+                k = 255;
+            
+            used += 1+k;
+        }
+    }
+
+    return used;
+}
+
+gboolean flx_string_list_equal(flxStringList *a, flxStringList *b) {
+
+    for (;;) {
+        if (!a && !b)
+            return TRUE;
+
+        if (!a || !b)
+            return FALSE;
+
+        if (strcmp(a->text, b->text) != 0)
+            return FALSE;
+
+        a = a->next;
+        b = b->next;
+    }
+}
+
+flxStringList *flx_string_list_add_many(flxStringList *r, ...) {
+    va_list va;
+
+    va_start(va, r);
+    r = flx_string_list_add_many_va(r, va);
+    va_end(va);
+    
+    return r;
+}
+
+flxStringList *flx_string_list_add_many_va(flxStringList *r, va_list va) {
+    const gchar *txt;
+
+    while ((txt = va_arg(va, const gchar*)))
+        r = flx_string_list_add(r, txt);
+
+    return r;
+}
+
+flxStringList *flx_string_list_new(const gchar *txt, ...) {
+    va_list va;
+    flxStringList *r = NULL;
+
+    if (txt) {
+        r = flx_string_list_add(r, txt);
+
+        va_start(va, txt);
+        r = flx_string_list_add_many_va(r, va);
+        va_end(va);
+    }
+
+    return r;
+}
+
+flxStringList *flx_string_list_new_va(va_list va) {
+    return flx_string_list_add_many_va(NULL, va);
+}
+
+flxStringList *flx_string_list_copy(flxStringList *l) {
+    flxStringList *r;
+
+    for (; l; l = l->next)
+        r = flx_string_list_add(l, l->text);
+
+    return string_list_reverse(r);
+}
diff --git a/strlst.h b/strlst.h
new file mode 100644 (file)
index 0000000..94fb563
--- /dev/null
+++ b/strlst.h
@@ -0,0 +1,32 @@
+#ifndef footxtlisthfoo
+#define footxtlisthfoo
+
+#include <glib.h>
+
+typedef struct _flxStringList flxStringList;
+
+struct _flxStringList {
+    flxStringList *next;
+    gchar text[1];
+};
+
+flxStringList *flx_string_list_new(const gchar *txt, ...);
+flxStringList *flx_string_list_new_va(va_list va);
+
+void flx_string_list_free(flxStringList *l);
+
+flxStringList *flx_string_list_add(flxStringList *l, const gchar *text);
+flxStringList *flx_string_list_add_many(flxStringList *r, ...);
+flxStringList *flx_string_list_add_many_va(flxStringList *r, va_list va);
+
+gchar* flx_string_list_to_string(flxStringList *l);
+
+guint flx_string_list_serialize(flxStringList *l, gpointer data, guint size);
+flxStringList *flx_string_list_parse(gconstpointer data, guint size);
+
+gboolean flx_string_list_equal(flxStringList *a, flxStringList *b);
+
+flxStringList *flx_string_list_copy(flxStringList *l);
+
+#endif
+
diff --git a/todo b/todo
index 786a0ec4fad555f4419594fe89b8e7680a50aaed..8f315422526353b22c6637352ded96c661685293 100644 (file)
--- a/todo
+++ b/todo
@@ -12,8 +12,6 @@ todo:
 * add SRV and TXT records referenced from PTR records automatically to packet
 * add A and AAAA records referenced from SRV records automatically to packet
 
-* make flx_server_add_text() and flx_server_add_service() variadic functions
-
 * name compression
 
 * respect escaping in name serialization
@@ -24,3 +22,5 @@ done:
 * FLX_DNS_TYPE_ANY support
 * Known-Answer suppression client part
 * Known-Answer suppression server part
+* make flx_server_add_text() and flx_server_add_service() variadic functions
+