+rb_dlink_list auth_providers;
+
+static rb_dlink_list free_pids;
+static uint32_t allocated_pids;
+static struct ev_entry *timeout_ev;
+
+/* Set a provider's raw status */
+static inline void
+set_provider_status(struct auth_client *auth, uint32_t provider, provider_status_t status)
+{
+ auth->data[provider].status = status;
+}
+
+/* Set the provider as running */
+static inline void
+set_provider_running(struct auth_client *auth, uint32_t provider)
+{
+ auth->providers_active++;
+ set_provider_status(auth, provider, PROVIDER_STATUS_RUNNING);
+}
+
+/* Provider is no longer operating on this auth client */
+static inline void
+set_provider_done(struct auth_client *auth, uint32_t provider)
+{
+ set_provider_status(auth, provider, PROVIDER_STATUS_DONE);
+ auth->providers_active--;
+}
+
+/* Initalise all providers */
+void
+init_providers(void)
+{
+ auth_clients = rb_dictionary_create("pending auth clients", rb_uint32cmp);
+ timeout_ev = rb_event_addish("provider_timeout_event", provider_timeout_event, NULL, 1);
+
+ /* FIXME must be started before rdns/ident to receive completion notification from them */
+ load_provider(&dnsbl_provider);
+ load_provider(&opm_provider);
+
+ /* FIXME must be started after dnsbl/opm in case of early completion notifications */
+ load_provider(&rdns_provider);
+ load_provider(&ident_provider);
+}
+
+/* Terminate all providers */
+void
+destroy_providers(void)
+{
+ rb_dlink_node *ptr, *nptr;
+ rb_dictionary_iter iter;
+ struct auth_client *auth;
+
+ /* Cancel outstanding connections */
+ RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
+ {
+ auth_client_ref(auth);
+
+ /* TBD - is this the right thing? */
+ reject_client(auth, UINT32_MAX, "destroy",
+ "Authentication system is down... try reconnecting in a few seconds");
+
+ auth_client_unref(auth);
+ }
+
+ RB_DLINK_FOREACH_SAFE(ptr, nptr, auth_providers.head)
+ {
+ struct auth_provider *provider = ptr->data;
+
+ if(provider->destroy)
+ provider->destroy();
+
+ rb_dlinkDelete(ptr, &auth_providers);
+ }
+
+ rb_dictionary_destroy(auth_clients, NULL, NULL);
+ rb_event_delete(timeout_ev);
+}