+ 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;
+}
+
+
+guint flx_key_get_estimate_size(flxKey *k) {
+ g_assert(k);
+
+ return strlen(k->name)+1+4;
+}
+
+guint flx_record_get_estimate_size(flxRecord *r) {
+ guint n;
+ g_assert(r);
+
+ n = flx_key_get_estimate_size(r->key) + 4 + 2;
+
+ switch (r->key->type) {
+ case FLX_DNS_TYPE_PTR:
+ case FLX_DNS_TYPE_CNAME:
+ n += strlen(r->data.ptr.name) + 1;
+ break;
+
+ case FLX_DNS_TYPE_SRV:
+ n += 6 + strlen(r->data.srv.name) + 1;
+ break;
+
+ case FLX_DNS_TYPE_HINFO:
+ n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1;
+ break;
+
+ case FLX_DNS_TYPE_TXT:
+ n += flx_string_list_serialize(r->data.txt.string_list, NULL, 0);
+ break;
+
+ case FLX_DNS_TYPE_A:
+ n += sizeof(flxIPv4Address);
+ break;
+
+ case FLX_DNS_TYPE_AAAA:
+ n += sizeof(flxIPv6Address);
+ 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;
+
+ flx_unescape_label(t1, sizeof(t1), &a);
+ flx_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 flx_record_lexicographical_compare(flxRecord *a, flxRecord *b) {
+ g_assert(a);
+ g_assert(b);
+
+/* gchar *t; */
+
+/* g_message("comparing [%s]", t = flx_record_to_string(a)); */
+/* g_free(t); */
+
+/* g_message("and [%s]", t = flx_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 FLX_DNS_TYPE_PTR:
+ case FLX_DNS_TYPE_CNAME:
+ return lexicographical_domain_cmp(a->data.ptr.name, b->data.ptr.name);
+
+ case FLX_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 FLX_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 FLX_DNS_TYPE_TXT: {
+
+ guint8 *ma, *mb;
+ guint asize, bsize;
+ gint r;
+
+ ma = g_new(guint8, asize = flx_string_list_serialize(a->data.txt.string_list, NULL, 0));
+ mb = g_new(guint8, bsize = flx_string_list_serialize(b->data.txt.string_list, NULL, 0));
+ flx_string_list_serialize(a->data.txt.string_list, ma, asize);
+ flx_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 FLX_DNS_TYPE_A:
+ return memcmp(&a->data.a.address, &b->data.a.address, sizeof(flxIPv4Address));
+
+ case FLX_DNS_TYPE_AAAA:
+ return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(flxIPv6Address));
+
+ default:
+ return lexicographical_memcmp(a->data.generic.data, a->data.generic.size,
+ b->data.generic.data, b->data.generic.size);
+ }
+