+#include "ctdl_module.h"
+
+
+ConstStr IOStates[] = {
+ {HKEY("DB Queue")},
+ {HKEY("DB Q Next")},
+ {HKEY("DB Attach")},
+ {HKEY("DB Next")},
+ {HKEY("DB Stop")},
+ {HKEY("DB Exit")},
+ {HKEY("DB Terminate")},
+ {HKEY("IO Queue")},
+ {HKEY("IO Attach")},
+ {HKEY("IO Connect Socket")},
+ {HKEY("IO Abort")},
+ {HKEY("IO Timeout")},
+ {HKEY("IO ConnFail")},
+ {HKEY("IO ConnFail Now")},
+ {HKEY("IO Conn Now")},
+ {HKEY("IO Conn Wait")},
+ {HKEY("Curl Q")},
+ {HKEY("Curl Start")},
+ {HKEY("Curl Shotdown")},
+ {HKEY("Curl More IO")},
+ {HKEY("Curl Got IO")},
+ {HKEY("Curl Got Data")},
+ {HKEY("Curl Got Status")},
+ {HKEY("C-Ares Start")},
+ {HKEY("C-Ares IO Done")},
+ {HKEY("C-Ares Finished")},
+ {HKEY("C-Ares exit")},
+ {HKEY("Killing")},
+ {HKEY("Exit")}
+};
+
+void SetEVState(AsyncIO *IO, eIOState State)
+{
+
+ CitContext* CCC = IO->CitContext;
+ if (CCC != NULL)
+ memcpy(CCC->lastcmdname, IOStates[State].Key, IOStates[State].len + 1);
+
+}
+
+
+static void IO_Timeout_callback(struct ev_loop *loop, ev_timer *watcher, int revents);
+static void IO_abort_shutdown_callback(struct ev_loop *loop,
+ ev_cleanup *watcher,
+ int revents);
+
+
+/*------------------------------------------------------------------------------
+ * Server DB IO
+ *----------------------------------------------------------------------------*/
+extern int evdb_count;
+extern pthread_mutex_t DBEventQueueMutex;
+extern pthread_mutex_t DBEventExitQueueMutex;
+extern HashList *DBInboundEventQueue;
+extern struct ev_loop *event_db;
+extern ev_async DBAddJob;
+extern ev_async DBExitEventLoop;
+
+eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB)
+{
+ IOAddHandler *h;
+ int i;
+
+ SetEVState(IO, eDBQ);
+ h = (IOAddHandler*)malloc(sizeof(IOAddHandler));
+ h->IO = IO;
+ h->EvAttch = CB;
+ ev_cleanup_init(&IO->db_abort_by_shutdown,
+ IO_abort_shutdown_callback);
+ IO->db_abort_by_shutdown.data = IO;
+
+ pthread_mutex_lock(&DBEventQueueMutex);
+ if (DBInboundEventQueue == NULL)
+ {
+ /* shutting down... */
+ free(h);
+ EVM_syslog(LOG_DEBUG, "DBEVENT Q exiting.\n");
+ pthread_mutex_unlock(&DBEventQueueMutex);
+ return eAbort;
+ }
+ EVM_syslog(LOG_DEBUG, "DBEVENT Q\n");
+ i = ++evdb_count ;
+ Put(DBInboundEventQueue, IKEY(i), h, NULL);
+ pthread_mutex_unlock(&DBEventQueueMutex);
+
+ pthread_mutex_lock(&DBEventExitQueueMutex);
+ if (event_db == NULL)
+ {
+ pthread_mutex_unlock(&DBEventExitQueueMutex);
+ return eAbort;
+ }
+ ev_async_send (event_db, &DBAddJob);
+ pthread_mutex_unlock(&DBEventExitQueueMutex);
+
+ EVM_syslog(LOG_DEBUG, "DBEVENT Q Done.\n");
+ return eDBQuery;
+}
+
+void StopDBWatchers(AsyncIO *IO)
+{
+ SetEVState(IO, eDBStop);
+ ev_cleanup_stop(event_db, &IO->db_abort_by_shutdown);
+ ev_idle_stop(event_db, &IO->db_unwind_stack);
+}
+
+void ShutDownDBCLient(AsyncIO *IO)
+{
+ CitContext *Ctx =IO->CitContext;
+ become_session(Ctx);
+
+ SetEVState(IO, eDBTerm);
+ EVM_syslog(LOG_DEBUG, "DBEVENT Terminating.\n");
+ StopDBWatchers(IO);
+
+ assert(IO->DBTerminate);
+ IO->DBTerminate(IO);
+}
+
+void
+DB_PerformNext(struct ev_loop *loop, ev_idle *watcher, int revents)
+{
+ AsyncIO *IO = watcher->data;
+
+ SetEVState(IO, eDBNext);
+ IO->Now = ev_now(event_db);
+ EV_syslog(LOG_DEBUG, "%s()", __FUNCTION__);
+ become_session(IO->CitContext);
+
+ ev_idle_stop(event_db, &IO->db_unwind_stack);
+
+ assert(IO->NextDBOperation);
+ switch (IO->NextDBOperation(IO))
+ {
+ case eDBQuery:
+ break;
+ case eSendDNSQuery:
+ case eReadDNSReply:
+ case eConnect:
+ case eSendReply:
+ case eSendMore:
+ case eSendFile:
+ case eReadMessage:
+ case eReadMore:
+ case eReadPayload:
+ case eReadFile:
+ ev_cleanup_stop(loop, &IO->db_abort_by_shutdown);
+ break;
+ case eTerminateConnection:
+ case eAbort:
+ ev_idle_stop(event_db, &IO->db_unwind_stack);
+ ev_cleanup_stop(loop, &IO->db_abort_by_shutdown);
+ ShutDownDBCLient(IO);
+ }
+}