-CFLAGS=-g -O0 -Wall -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused
+#CC=gcc
+CFLAGS=-g -O0 -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused
LIBS=$(shell pkg-config --libs glib-2.0)
all: flexmdns prioq-test
if (a->family != b->family)
return -1;
- return memcmp(a->data, b->data, flx_address_get_size(a));
+ return memcmp(a->data.data, b->data.data, flx_address_get_size(a));
}
gchar *flx_address_snprint(char *s, guint length, const flxAddress *a) {
g_assert(s);
g_assert(length);
g_assert(a);
- return (gchar*) inet_ntop(a->family, a->data, s, length);
+ return (gchar*) inet_ntop(a->family, a->data.data, s, length);
}
gchar* flx_reverse_lookup_name_ipv4(const flxIPv4Address *a) {
g_assert(ret_addr);
g_assert(s);
- if (inet_pton(family, s, ret_addr->data) < 0)
+ if (inet_pton(family, s, ret_addr->data.data) < 0)
return NULL;
ret_addr->family = family;
ret_addr->family = sa->sa_family;
if (sa->sa_family == AF_INET)
- memcpy(&ret_addr->ipv4, &((struct sockaddr_in*) sa)->sin_addr, sizeof(ret_addr->ipv4));
+ memcpy(&ret_addr->data.ipv4, &((struct sockaddr_in*) sa)->sin_addr, sizeof(ret_addr->data.ipv4));
else
- memcpy(&ret_addr->ipv6, &((struct sockaddr_in6*) sa)->sin6_addr, sizeof(ret_addr->ipv6));
+ memcpy(&ret_addr->data.ipv6, &((struct sockaddr_in6*) sa)->sin6_addr, sizeof(ret_addr->data.ipv6));
return ret_addr;
}
flxIPv6Address ipv6;
flxIPv4Address ipv4;
guint8 data[0];
- };
+ } data;
} flxAddress;
guint flx_address_get_size(const flxAddress *a);
if (remove_from_hash_table) {
flxCacheEntry *t;
- t = g_hash_table_lookup(c->hash_table, &e->record->key);
+ t = g_hash_table_lookup(c->hash_table, e->record->key);
FLX_LLIST_REMOVE(flxCacheEntry, by_name, t, e);
if (t)
- g_hash_table_replace(c->hash_table, &t->record->key, t);
+ g_hash_table_replace(c->hash_table, t->record->key, t);
else
- g_hash_table_remove(c->hash_table, &e->record->key);
+ g_hash_table_remove(c->hash_table, e->record->key);
}
flx_record_unref(e->record);
+
+ if (e->time_event)
+ flx_time_event_queue_remove(c->server->time_event_queue, e->time_event);
+
g_free(e);
}
-flxCache *flx_cache_new(flxServer *server, flxInterface *iface) {
+flxCache *flx_cache_new(flxServer *server, flxInterface *iface, guchar protocol) {
flxCache *c;
g_assert(server);
c = g_new(flxCache, 1);
c->server = server;
c->interface = iface;
+ c->protocol = protocol;
c->hash_table = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
return c;
return NULL;
}
+static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent);
+
+static void elapse_func(flxTimeEvent *t, void *userdata) {
+ flxCacheEntry *e = userdata;
+
+ g_assert(t);
+ g_assert(e);
+
+ if (e->state == FLX_CACHE_FINAL) {
+ remove_entry(e->cache, e, TRUE);
+ g_message("Removing entry from cache due to expiration");
+ } else {
+ guint percent = 0;
+
+ switch (e->state) {
+ case FLX_CACHE_VALID:
+ e->state = FLX_CACHE_EXPIRY1;
+ percent = 85;
+ break;
+
+ case FLX_CACHE_EXPIRY1:
+ e->state = FLX_CACHE_EXPIRY2;
+ percent = 90;
+ break;
+ case FLX_CACHE_EXPIRY2:
+ e->state = FLX_CACHE_EXPIRY3;
+ percent = 95;
+ break;
+
+ case FLX_CACHE_EXPIRY3:
+ e->state = FLX_CACHE_FINAL;
+ percent = 100;
+ break;
+
+ default:
+ ;
+ }
+
+ g_assert(percent > 0);
+
+ g_message("Requesting cache entry update at %i%%.", percent);
+
+ /* Request a cache update */
+ flx_interface_post_query(e->cache->interface, e->cache->protocol, e->record->key);
+
+ /* Check again later */
+ next_expiry(e->cache, e, percent);
+ }
+}
+
+static void next_expiry(flxCache *c, flxCacheEntry *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);
+
+ if (e->time_event)
+ flx_time_event_queue_update(c->server->time_event_queue, e->time_event, &e->expiry);
+ else
+ e->time_event = flx_time_event_queue_add(c->server->time_event_queue, &e->expiry, elapse_func, e);
+}
+
flxCacheEntry *flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddress *a) {
flxCacheEntry *e, *t;
+ gchar *txt;
g_assert(c);
- g_assert(r);
+ g_assert(r && r->ref >= 1);
+
+ g_message("cache update: %s", (txt = flx_record_to_string(r)));
+ g_free(txt);
if ((t = e = flx_cache_lookup_key(c, r->key))) {
+/* g_message("found prev cache entry"); */
+
if (unique) {
- flxCacheEntry *n;
/* Drop all entries but the first which we replace */
-
while (e->by_name_next)
remove_entry(c, e->by_name_next, TRUE);
- g_free(e->record->data);
- e->record->data = g_memdup(r->data, r->size);
- e->record->size = r->size;
- e->record->ttl = r->ttl;
-
} else {
/* Look for exactly the same entry */
-
- for (; e; e = e->by_name_next) {
- if (e->record->size == r->size &&
- !memcmp(e->record->data, r->data, r->size)) {
-
- /* We found it, so let's update the TTL */
- e->record->ttl = r->ttl;
+ for (; e; e = e->by_name_next)
+ if (flx_record_equal(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_name_prev == NULL)
+ g_hash_table_replace(c->hash_table, r->key, e);
+
+ /* Update the record */
+ flx_record_unref(e->record);
+ e->record = flx_record_ref(r);
- if (!e) {
+
+ } else {
/* No entry found, therefore we create a new one */
+
+/* g_message("couldn't find matching cache entry"); */
e = g_new(flxCacheEntry, 1);
- e->node = NULL;
-
+ e->cache = c;
+ e->time_event = NULL;
e->record = flx_record_ref(r);
FLX_LLIST_PREPEND(flxCacheEntry, by_name, t, e);
- g_hash_table_replace(c->hash_table, e->record->key, e);
+ g_hash_table_replace(c->hash_table, e->record->key, t);
}
e->origin = *a;
-
g_get_current_time(&e->timestamp);
- e->expiry = e->timestamp;
- g_time_val_add(&e->expiry, e->record->ttl * 1000000);
-
+ next_expiry(c, e, 80);
e->state = FLX_CACHE_VALID;
return e;
#include "prioq.h"
#include "server.h"
#include "llist.h"
+#include "timeeventq.h"
typedef enum {
FLX_CACHE_VALID,
FLX_CACHE_EXPIRY1,
FLX_CACHE_EXPIRY2,
- FLX_CACHE_EXPIRY3
-
+ FLX_CACHE_EXPIRY3,
+ FLX_CACHE_FINAL
} flxCacheEntryState;
typedef struct flxCacheEntry flxCacheEntry;
struct flxCacheEntry {
+ flxCache *cache;
flxRecord *record;
GTimeVal timestamp;
GTimeVal expiry;
flxAddress origin;
flxCacheEntryState state;
+ flxTimeEvent *time_event;
FLX_LLIST_FIELDS(flxCacheEntry, by_name);
-
- flxPrioQueueNode *node;
};
flxServer *server;
flxInterface *interface;
+ guchar protocol;
GHashTable *hash_table;
};
-flxCache *flx_cache_new(flxServer *server, flxInterface *interface);
+flxCache *flx_cache_new(flxServer *server, flxInterface *interface, guchar protocol);
void flx_cache_free(flxCache *c);
flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k);
}
flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush) {
- gchar name[256];
+ gchar name[257], buf[257+6];
guint16 type, class;
guint32 ttl;
guint16 rdlength;
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 ||
- !(data = flx_dns_packet_get_rptr(p)) ||
- flx_dns_packet_skip(p, rdlength) < 0)
+ flx_dns_packet_consume_uint16(p, &rdlength) < 0)
return NULL;
+ switch (type) {
+ case FLX_DNS_TYPE_PTR:
+ case FLX_DNS_TYPE_CNAME:
+ if (flx_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
+ return NULL;
+
+ data = buf;
+ rdlength = strlen(buf);
+ break;
+
+ case FLX_DNS_TYPE_SRV: {
+ const guint8 *t = flx_dns_packet_get_rptr(p);
+
+ if (flx_dns_packet_skip(p, 6) < 0)
+ return NULL;
+
+ memcpy(buf, t, 6);
+
+ if (flx_dns_packet_consume_name(p, buf+6, sizeof(buf)-6) < 0)
+ return NULL;
+
+ data = buf;
+ rdlength = 6 + strlen(buf+6);
+ break;
+ }
+
+ default:
+ if (!(data = flx_dns_packet_get_rptr(p)) ||
+ flx_dns_packet_skip(p, rdlength) < 0)
+ return NULL;
+
+ break;
+ }
+
*ret_cache_flush = !!(class & MDNS_CACHE_FLUSH);
class &= ~ MDNS_CACHE_FLUSH;
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_uint16(p, r->size) ||
- !flx_dns_packet_append_bytes(p, r->data, r->size))
+ !flx_dns_packet_append_uint32(p, r->ttl))
return NULL;
+ switch (r->key->type) {
+
+ case FLX_DNS_TYPE_PTR:
+ case FLX_DNS_TYPE_CNAME: {
+ char ptr_name[257];
+
+ 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_uint16(p, strlen(ptr_name)) ||
+ !flx_dns_packet_append_name(p, ptr_name))
+ return NULL;
+
+ break;
+ }
+
+ case FLX_DNS_TYPE_SRV: {
+ char name[257];
+
+ 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;
+
+ if (!flx_dns_packet_append_uint16(p, strlen(name+6)) ||
+ !flx_dns_packet_append_bytes(p, r->data, 6) ||
+ !flx_dns_packet_append_name(p, name))
+ return NULL;
+
+ break;
+ }
+
+ default:
+ if (!flx_dns_packet_append_uint16(p, r->size) ||
+ !flx_dns_packet_append_bytes(p, r->data, r->size))
+ return NULL;
+ }
+
return t;
}
void flx_server_remove(flxServer *s, gint id);
-void flx_server_send_query(flxServer *s, gint interface, guchar protocol, flxKey *k);
+void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey *k);
const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state);
FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i);
g_hash_table_insert(m->hash_table, &i->index, i);
i->mtu = 1500;
- i->ipv4_cache = flx_cache_new(m->server, i);
- i->ipv6_cache = flx_cache_new(m->server, i);
+ i->ipv4_cache = flx_cache_new(m->server, i, AF_INET);
+ i->ipv6_cache = flx_cache_new(m->server, i, AF_INET6);
i->ipv4_scheduler = flx_packet_scheduler_new(m->server, i, AF_INET);
i->ipv6_scheduler = flx_packet_scheduler_new(m->server, i, AF_INET6);
(raddr.family == AF_INET && RTA_PAYLOAD(a) != 4))
return;
- memcpy(raddr.data, RTA_DATA(a), RTA_PAYLOAD(a));
+ memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a));
raddr_valid = 1;
break;
flxServer *flx = data;
flxKey *k;
- flx_server_dump(flx, stdout);
-
+ /* k = flx_key_new("cocaine.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); */
+/* flx_server_post_query(flx, 0, AF_UNSPEC, k); */
+/* flx_key_unref(k); */
- k = flx_key_new("cocaine.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A);
- flx_server_send_query(flx, 0, AF_UNSPEC, k);
+ k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A);
+ flx_server_post_query(flx, 0, AF_INET, k);
flx_key_unref(k);
return FALSE;
}
+static gboolean dump_timeout(gpointer data) {
+ flxServer *flx = data;
+ flx_server_dump(flx, stdout);
+ return TRUE;
+}
+
int main(int argc, char *argv[]) {
flxServer *flx;
gchar *r;
loop = g_main_loop_new(NULL, FALSE);
- /*g_timeout_add(1000*5, quit_timeout, loop);*/
+ g_timeout_add(1000*60, quit_timeout, loop);
g_timeout_add(1000, send_timeout, flx);
+ g_timeout_add(1000*10, dump_timeout, flx);
g_main_loop_run(loop);
return;
}
- p = flx_dns_packet_new_query(s->interface->mtu - 200);
+ p = flx_dns_packet_new_query(s->interface->mtu - 48);
d = packet_add_query_job(s, p, qj);
g_assert(d);
n = 1;
k->class = class;
k->type = type;
+/* g_message("%p %% ref=1", k); */
+
return k;
}
g_assert(k->ref >= 1);
k->ref++;
+
+/* g_message("%p ++ ref=%i", k, k->ref); */
+
return 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);
const gchar *flx_dns_type_to_string(guint16 type) {
switch (type) {
+ case FLX_DNS_TYPE_CNAME:
+ return "CNAME";
case FLX_DNS_TYPE_A:
return "A";
case FLX_DNS_TYPE_AAAA:
return "HINFO";
case FLX_DNS_TYPE_TXT:
return "TXT";
+ case FLX_DNS_TYPE_SRV:
+ return "SRV";
default:
return NULL;
}
gchar *flx_record_to_string(flxRecord *r) {
gchar *p, *s;
- char t[256] = "<unparsable>";
-
- if (r->key->type == FLX_DNS_TYPE_A)
- inet_ntop(AF_INET, r->data, t, sizeof(t));
- else if (r->key->type == FLX_DNS_TYPE_AAAA)
- inet_ntop(AF_INET6, r->data, t, sizeof(t));
- else if (r->key->type == FLX_DNS_TYPE_PTR || r->key->type == FLX_DNS_TYPE_TXT) {
- size_t l;
-
- l = r->size;
- if (l > sizeof(t)-1)
- l = sizeof(t)-1;
-
- memcpy(t, r->data, l);
- t[l] = 0;
- } else if (r->key->type == FLX_DNS_TYPE_HINFO) {
- char *s2;
+ char t[257] = "<unparsable>";
+
+ switch (r->key->type) {
+ case FLX_DNS_TYPE_A:
+ inet_ntop(AF_INET, r->data, t, sizeof(t));
+ break;
+
+ case FLX_DNS_TYPE_AAAA:
+ inet_ntop(AF_INET6, r->data, t, sizeof(t));
+ break;
+
+ case FLX_DNS_TYPE_PTR:
+ case FLX_DNS_TYPE_TXT: {
+ size_t l;
- if ((s2 = memchr(r->data, 0, r->size))) {
- s2++;
- if (memchr(s2, 0, r->size - ((char*) s2 - (char*) r->data)))
- snprintf(t, sizeof(t), "'%s' '%s'", (char*) r->data, s2);
+ 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_HINFO: {
+ char *s2;
+
+ if ((s2 = memchr(r->data, 0, r->size))) {
+ s2++;
+ if (memchr(s2, 0, r->size - ((char*) s2 - (char*) r->data)))
+ snprintf(t, sizeof(t), "'%s' '%s'", (char*) r->data, s2);
+ }
+
+ break;
+ }
+
+ case FLX_DNS_TYPE_SRV: {
+ char k[257];
+ size_t l;
+
+ 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);
}
}
p = flx_key_to_string(r->key);
- s = g_strdup_printf("%s %s", p, t);
+ s = g_strdup_printf("%s %s ; ttl=%u", p, t, r->ttl);
g_free(p);
return s;
gboolean flx_key_equal(const flxKey *a, const flxKey *b) {
g_assert(a);
g_assert(b);
+
+/* g_message("equal: %p %p", a, b); */
return strcmp(a->name, b->name) == 0 && a->type == b->type && a->class == b->class;
}
FLX_DNS_TYPE_MX = 0x0F,
FLX_DNS_TYPE_TXT = 0x10,
FLX_DNS_TYPE_AAAA = 0x1C,
+ FLX_DNS_TYPE_SRV = 0x21
};
enum {
FLX_DNS_CLASS_IN = 0x01
};
-#define FLX_DEFAULT_TTL (120*60)
+#define FLX_DEFAULT_TTL 10 /*(120*60)*/
typedef struct {
guint ref;
static void handle_query_key(flxServer *s, flxKey *k, flxInterface *i, const flxAddress *a) {
flxEntry *e;
+ gchar *txt;
g_assert(s);
g_assert(k);
g_assert(i);
g_assert(a);
+ g_message("Handling query: %s", txt = flx_key_to_string(k));
+ g_free(txt);
+
for (e = g_hash_table_lookup(s->rrset_by_name, k); e; e = e->by_name_next) {
if ((e->interface <= 0 || e->interface == i->index) &&
g_assert(i);
g_assert(a);
- for (n = flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT); n > 0; n--) {
+ for (n = flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT) +
+ flx_dns_packet_get_field(p, DNS_FIELD_ARCOUNT); n > 0; n--) {
flxRecord *record;
gboolean cache_flush = FALSE;
+ gchar *txt;
if (!(record = flx_dns_packet_consume_record(p, &cache_flush))) {
g_warning("Packet too short");
return;
}
+ g_message("Handling response: %s", txt = flx_record_to_string(record));
+ g_free(txt);
+
flx_cache_update(a->family == AF_INET ? i->ipv4_cache : i->ipv6_cache, record, cache_flush, a);
flx_packet_scheduler_drop_response(a->family == AF_INET ? i->ipv4_scheduler : i->ipv6_scheduler, record);
flx_record_unref(record);
flx_address_from_sockaddr(sa, &a);
-
if (flx_dns_packet_is_query(p)) {
if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) == 0 ||
} else {
if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) != 0 ||
flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT) == 0 ||
- flx_dns_packet_get_field(p, DNS_FIELD_NSCOUNT) != 0 ||
- flx_dns_packet_get_field(p, DNS_FIELD_ARCOUNT) != 0) {
+ flx_dns_packet_get_field(p, DNS_FIELD_NSCOUNT) != 0) {
g_warning("Invalid response packet.");
return;
}
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->ipv4, sizeof(a->ipv4), FLX_DEFAULT_TTL);
+ 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);
- r = flx_reverse_lookup_name_ipv4(&a->ipv4);
+ 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);
} else {
gchar *r;
- flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA, &a->ipv6, sizeof(a->ipv6), FLX_DEFAULT_TTL);
+ 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->ipv6);
+ 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_reverse_lookup_name_ipv6_int(&a->ipv6);
+ 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);
flx_server_add_full(s, id, interface, protocol, unique, name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT, text, strlen(text), FLX_DEFAULT_TTL);
}
-void flx_server_send_query(flxServer *s, gint interface, guchar protocol, flxKey *k) {
+void flx_server_post_query(flxServer *s, gint interface, guchar protocol, flxKey *k) {
g_assert(s);
g_assert(k);
*ret_ttl = 0;
- g_message("pre");
-
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);
*ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
found_iface = TRUE;
}
-
- g_message("-- %u -- %u\n", cmsg->cmsg_level, cmsg->cmsg_type);
}
- g_message("post");
-
-
g_assert(found_iface);
g_assert(found_ttl);