}
}
-static void handle_query_key(flxServer *s, flxKey *k, flxInterface *i, const flxAddress *a) {
+static void handle_query_key(flxServer *s, flxKey *k, flxInterface *i, const flxAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) {
flxEntry *e;
gchar *txt;
g_assert(s);
g_assert(e);
- e->dead = TRUE;
- s->need_entry_cleanup = TRUE;
-
- flx_goodbye_entry(s, e, FALSE);
- if (e->group)
- flx_entry_group_run_callback(e->group, FLX_ENTRY_GROUP_COLLISION);
+ if (e->group) {
+ flxEntry *k;
+
+ for (k = e->group->entries; k; k = k->by_group_next) {
+ flx_goodbye_entry(s, k, FALSE);
+ k->dead = TRUE;
+ }
+
+ flx_entry_group_change_state(e->group, FLX_ENTRY_GROUP_COLLISION);
+ } else {
+ flx_goodbye_entry(s, e, FALSE);
+ e->dead = TRUE;
+ }
+
+ s->need_entry_cleanup = TRUE;
}
static void incoming_probe(flxServer *s, flxRecord *record, flxInterface *i) {
t = flx_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 || !flx_record_equal_no_ttl(record, e->record))
+
+ if (e->dead || flx_record_equal_no_ttl(record, e->record))
continue;
if (flx_entry_registering(s, e, i)) {
-
- if (flx_record_lexicographical_compare(record, e->record) > 0) {
+ gint cmp;
+
+ if ((cmp = flx_record_lexicographical_compare(record, e->record)) > 0) {
withdraw_entry(s, e);
g_message("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t);
- } else
+ } else if (cmp < 0)
g_message("Recieved conflicting probe [%s]. Local host won.", t);
+
}
}
g_free(t);
}
-static void handle_query(flxServer *s, flxDnsPacket *p, flxInterface *i, const flxAddress *a) {
+static void handle_query(flxServer *s, flxDnsPacket *p, flxInterface *i, const flxAddress *a, guint16 port, gboolean legacy_unicast) {
guint n;
g_assert(s);
/* Handle the questions */
for (n = flx_dns_packet_get_field(p, FLX_DNS_FIELD_QDCOUNT); n > 0; n --) {
flxKey *key;
+ gboolean unicast_response = FALSE;
- if (!(key = flx_dns_packet_consume_key(p))) {
+ if (!(key = flx_dns_packet_consume_key(p, &unicast_response))) {
g_warning("Packet too short (1)");
return;
}
- handle_query_key(s, key, i, a);
+ handle_query_key(s, key, i, a, port, legacy_unicast, unicast_response);
flx_key_unref(key);
}
- /* Known Answer Suppresion */
+ /* Known Answer Suppression */
for (n = flx_dns_packet_get_field(p, FLX_DNS_FIELD_ANCOUNT); n > 0; n --) {
flxRecord *record;
gboolean unique = FALSE;
}
}
-static gboolean handle_conflict(flxServer *s, flxInterface *i, flxRecord *record, const flxAddress *a) {
+static gboolean handle_conflict(flxServer *s, flxInterface *i, flxRecord *record, gboolean unique, const flxAddress *a) {
gboolean valid = TRUE;
flxEntry *e, *n;
gchar *t;
t = flx_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;
gboolean equal = flx_record_equal_no_ttl(record, e->record);
/* Check whether there is a unique record conflict */
- if (!equal && (e->flags & FLX_ENTRY_UNIQUE)) {
+ if (!equal && ((e->flags & FLX_ENTRY_UNIQUE) || unique)) {
+ gint cmp;
/* The lexicographically later data wins. */
- if (flx_record_lexicographical_compare(record, e->record) > 0) {
- withdraw_entry(s, e);
+ if ((cmp = flx_record_lexicographical_compare(record, e->record)) > 0) {
g_message("Recieved conflicting record [%s]. Local host lost. Withdrawing.", t);
- } else {
+ 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;
flx_interface_post_response(i, a, e->record, e->flags & FLX_ENTRY_UNIQUE, TRUE);
- g_message("Recieved conflicting record [%s]. Local host won. Refreshing.", t);
}
/* Check wheter there is a TTL conflict */
flx_interface_post_response(i, a, e->record, e->flags & FLX_ENTRY_UNIQUE, TRUE);
g_message("Recieved record with bad TTL [%s]. Refreshing.", t);
}
+
+ } else if (flx_entry_registering(s, e, i)) {
+
+ if (!flx_record_equal_no_ttl(record, e->record) && ((e->flags & FLX_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_message("Handling response: %s", txt = flx_record_to_string(record));
g_free(txt);
- if (handle_conflict(s, i, record, a)) {
+ if (handle_conflict(s, i, record, cache_flush, a)) {
flx_cache_update(i->cache, record, cache_flush, a);
flx_packet_scheduler_incoming_response(i->scheduler, record);
}
static void dispatch_packet(flxServer *s, flxDnsPacket *p, struct sockaddr *sa, gint iface, gint ttl) {
flxInterface *i;
flxAddress a;
+ guint16 port;
g_assert(s);
g_assert(p);
g_assert(sa);
g_assert(iface > 0);
- g_message("new packet recieved.");
-
if (!(i = flx_interface_monitor_get_interface(s->monitor, iface, sa->sa_family))) {
g_warning("Recieved packet from invalid interface.");
return;
}
- if (ttl != 255) {
- g_warning("Recieved packet with invalid TTL on interface '%s.%i'.", i->hardware->name, i->protocol);
- if (!s->ignore_bad_ttl)
- return;
- }
+ g_message("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol);
if (sa->sa_family == AF_INET6) {
- static const unsigned char ipv4_in_ipv6[] = {
+ static const guint8 ipv4_in_ipv6[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF };
- if (memcmp(((struct sockaddr_in6*) sa)->sin6_addr.s6_addr, ipv4_in_ipv6, sizeof(ipv4_in_ipv6)) == 0) {
+ /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
- /* 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 (flx_dns_packet_check_valid(p) < 0) {
return;
}
+ port = flx_port_from_sockaddr(sa);
flx_address_from_sockaddr(sa, &a);
if (flx_dns_packet_is_query(p)) {
+ gboolean legacy_unicast = FALSE;
if (flx_dns_packet_get_field(p, FLX_DNS_FIELD_QDCOUNT) == 0 ||
flx_dns_packet_get_field(p, FLX_DNS_FIELD_ARCOUNT) != 0) {
g_warning("Invalid query packet.");
return;
}
-
- handle_query(s, p, i, &a);
+
+ if (port != FLX_MDNS_PORT) {
+ /* Legacy Unicast */
+
+ if ((flx_dns_packet_get_field(p, FLX_DNS_FIELD_ANCOUNT) != 0 ||
+ flx_dns_packet_get_field(p, FLX_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 != FLX_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 (flx_dns_packet_get_field(p, FLX_DNS_FIELD_QDCOUNT) != 0 ||
flx_dns_packet_get_field(p, FLX_DNS_FIELD_ANCOUNT) == 0 ||
flx_dns_packet_get_field(p, FLX_DNS_FIELD_NSCOUNT) != 0) {
uname(&utsname);
r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine));
r->data.hinfo.os = g_strdup(g_strup(utsname.sysname));
- flx_server_add(s, NULL, 0, AF_UNSPEC, FLX_ENTRY_UNIQUE | FLX_ENTRY_NOANNOUNCE | FLX_ENTRY_NOPROBE, r);
+ flx_server_add(s, NULL, 0, AF_UNSPEC, FLX_ENTRY_UNIQUE, r);
flx_record_unref(r);
/* Add localhost entries */
s->need_entry_cleanup = s->need_group_cleanup = FALSE;
s->fd_ipv4 = flx_open_socket_ipv4();
- s->fd_ipv6 = -1 /*flx_open_socket_ipv6() */;
+ s->fd_ipv6 = flx_open_socket_ipv6();
if (s->fd_ipv6 < 0 && s->fd_ipv4 < 0) {
g_critical("Failed to create IP sockets.\n");
g_free(n);
}
-void flx_server_add_text_va(
+void flx_server_add_text_strlst(
flxServer *s,
flxEntryGroup *g,
gint interface,
guchar protocol,
flxEntryFlags flags,
const gchar *name,
- va_list va) {
+ flxStringList *strlst) {
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);
+ r->data.txt.string_list = strlst;
flx_server_add(s, g, interface, protocol, flags, r);
flx_record_unref(r);
}
+void flx_server_add_text_va(
+ flxServer *s,
+ flxEntryGroup *g,
+ gint interface,
+ guchar protocol,
+ flxEntryFlags flags,
+ const gchar *name,
+ va_list va) {
+
+ g_assert(s);
+
+ flx_server_add_text_strlst(s, g, interface, protocol, flags, name, flx_string_list_new_va(va));
+}
+
void flx_server_add_text(
flxServer *s,
flxEntryGroup *g,
*(d++) = 0;
}
-
-void flx_server_add_service_va(
+void flx_server_add_service_strlst(
flxServer *s,
flxEntryGroup *g,
gint interface,
const gchar *domain,
const gchar *host,
guint16 port,
- va_list va) {
+ flxStringList *strlst) {
gchar ptr_name[256], svc_name[256], ename[64], enum_ptr[256];
flxRecord *r;
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, g, interface, protocol, FALSE, ptr_name, svc_name);
+ flx_server_add_ptr(s, g, interface, protocol, FLX_ENTRY_NULL, 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, g, interface, protocol, TRUE, r);
+ flx_server_add(s, g, interface, protocol, FLX_ENTRY_UNIQUE, r);
flx_record_unref(r);
- flx_server_add_text_va(s, g, interface, protocol, FALSE, svc_name, va);
+ flx_server_add_text_strlst(s, g, interface, protocol, FLX_ENTRY_UNIQUE, svc_name, strlst);
snprintf(enum_ptr, sizeof(enum_ptr), "_services._dns-sd._udp.%s", domain);
- flx_server_add_ptr(s, g, interface, protocol, FALSE, enum_ptr, ptr_name);
+ flx_server_add_ptr(s, g, interface, protocol, FLX_ENTRY_NULL, enum_ptr, ptr_name);
+}
+
+void flx_server_add_service_va(
+ flxServer *s,
+ flxEntryGroup *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);
+
+ flx_server_add_service(s, g, interface, protocol, type, name, domain, host, port, flx_string_list_new_va(va));
}
void flx_server_add_service(
flx_interface_monitor_walk(s->monitor, interface, protocol, post_response_callback, &tmpdata);
}
-void flx_entry_group_run_callback(flxEntryGroup *g, flxEntryGroupStatus status) {
+void flx_entry_group_change_state(flxEntryGroup *g, flxEntryGroupState state) {
g_assert(g);
+ g->state = state;
+
if (g->callback) {
- g->callback(g->server, g, status, g->userdata);
+ g->callback(g->server, g, state, g->userdata);
return;
}
-
- if (status == FLX_ENTRY_GROUP_COLLISION)
- flx_entry_group_free(g);
-
- /* Ignore the rest */
}
flxEntryGroup *flx_entry_group_new(flxServer *s, flxEntryGroupCallback callback, gpointer userdata) {
g->callback = callback;
g->userdata = userdata;
g->dead = FALSE;
- g->status = FLX_ENTRY_GROUP_UNCOMMITED;
+ g->state = FLX_ENTRY_GROUP_UNCOMMITED;
g->n_probing = 0;
FLX_LLIST_HEAD_INIT(flxEntry, g->entries);
g_assert(g);
g_assert(!g->dead);
- if (g->status != FLX_ENTRY_GROUP_UNCOMMITED)
+ if (g->state != FLX_ENTRY_GROUP_UNCOMMITED)
return;
- flx_entry_group_run_callback(g, g->status = FLX_ENTRY_GROUP_REGISTERING);
+ flx_entry_group_change_state(g, FLX_ENTRY_GROUP_REGISTERING);
flx_announce_group(g->server, g);
flx_entry_group_check_probed(g, FALSE);
}
g_assert(!e->dead);
return !e->group ||
- e->group->status == FLX_ENTRY_GROUP_REGISTERING ||
- e->group->status == FLX_ENTRY_GROUP_ESTABLISHED;
+ e->group->state == FLX_ENTRY_GROUP_REGISTERING ||
+ e->group->state == FLX_ENTRY_GROUP_ESTABLISHED;
}
-flxEntryGroupStatus flx_entry_group_get_status(flxEntryGroup *g) {
+flxEntryGroupState flx_entry_group_get_state(flxEntryGroup *g) {
g_assert(g);
g_assert(!g->dead);
- return g->status;
+ return g->state;
}