+
+ 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();
+
+ FLX_LLIST_HEAD_INIT(flxEntry, s->entries);
+ s->entries_by_key = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
+ FLX_LLIST_HEAD_INIT(flxGroup, s->groups);
+
+ FLX_LLIST_HEAD_INIT(flxSubscription, s->subscriptions);
+ s->subscription_hashtable = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
+
+ /* Get host name */
+ hn = flx_get_host_name();
+ hn[strcspn(hn, ".")] = 0;
+
+ s->hostname = g_strdup_printf("%s.local.", hn);
+ g_free(hn);
+
+ s->time_event_queue = flx_time_event_queue_new(s->context, G_PRIORITY_DEFAULT+10); /* Slightly less priority than the FDs */
+ s->monitor = flx_interface_monitor_new(s);
+ flx_interface_monitor_sync(s->monitor);
+ add_default_entries(s);
+
+ /* Prepare IO source registration */
+ s->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(flxServer*));
+ *((flxServer**) (((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 flx_server_free(flxServer* s) {
+ g_assert(s);
+
+ while(s->entries)
+ free_entry(s, s->entries);
+
+ flx_interface_monitor_free(s->monitor);
+
+ while (s->groups)
+ free_group(s, s->groups);
+
+ while (s->subscriptions)
+ flx_subscription_free(s->subscriptions);
+ g_hash_table_destroy(s->subscription_hashtable);
+
+ g_hash_table_destroy(s->entries_by_key);
+
+ flx_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 flx_server_add(
+ flxServer *s,
+ flxEntryGroup *g,
+ gint interface,
+ guchar protocol,
+ flxEntryFlags flags,
+ flxRecord *r) {
+
+ flxEntry *e, *t;
+ g_assert(s);
+ g_assert(r);
+
+ g_assert(r->key->type != FLX_DNS_TYPE_ANY);
+
+ e = g_new(flxEntry, 1);
+ e->server = s;
+ e->record = flx_record_ref(r);
+ e->group = g;
+ e->interface = interface;
+ e->protocol = protocol;
+ e->flags = flags;
+ e->dead = FALSE;
+
+ FLX_LLIST_HEAD_INIT(flxAnnouncement, e->announcements);
+
+ FLX_LLIST_PREPEND(flxEntry, entries, s->entries, e);
+
+ /* Insert into hash table indexed by name */
+ t = g_hash_table_lookup(s->entries_by_key, e->record->key);
+ FLX_LLIST_PREPEND(flxEntry, by_key, t, e);
+ g_hash_table_replace(s->entries_by_key, e->record->key, t);
+
+ /* Insert into group list */
+ if (g)
+ FLX_LLIST_PREPEND(flxEntry, by_group, g->entries, e);
+
+ flx_announce_entry(s, e);
+}
+const flxRecord *flx_server_iterate(flxServer *s, flxEntryGroup *g, void **state) {
+ flxEntry **e = (flxEntry**) 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 flx_record_ref((*e)->record);