Event-client: add waiting for the server greeting to our error status (preventive..)
[citadel.git] / citadel / event_client.c
index 87da6c2169d5f5359d956c8d5d6aefcc01ed5df0..7b409fcf4a49404e85607402f5947faa046d642f 100644 (file)
 #include "ctdl_module.h"
 
 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)
-{
-       AsyncIO *IO = watcher->data;
-       EV_syslog(LOG_DEBUG, "EVENT Q: %s\n", __FUNCTION__);
-
-       assert(IO->ShutdownAbort);
-       IO->ShutdownAbort(IO);
-}
+                                      int revents);
 
 
 /*------------------------------------------------------------------------------
@@ -90,6 +82,7 @@ static void IO_abort_shutdown_callback(struct ev_loop *loop,
  *----------------------------------------------------------------------------*/
 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;
@@ -106,26 +99,47 @@ eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB)
        ev_cleanup_init(&IO->db_abort_by_shutdown,
                        IO_abort_shutdown_callback);
        IO->db_abort_by_shutdown.data = IO;
-       ev_cleanup_start(event_db, &IO->db_abort_by_shutdown);
 
        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)
+{
+       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);
 
        EVM_syslog(LOG_DEBUG, "DBEVENT Terminating.\n");
-       ev_cleanup_stop(event_db, &IO->db_abort_by_shutdown);
+       StopDBWatchers(IO);
 
        assert(IO->DBTerminate);
        IO->DBTerminate(IO);
@@ -135,7 +149,8 @@ void
 DB_PerformNext(struct ev_loop *loop, ev_idle *watcher, int revents)
 {
        AsyncIO *IO = watcher->data;
-       EV_syslog(LOG_DEBUG, "%s() - event type: %d", __FUNCTION__ , IO->NextDBOperation(IO) );
+       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);
@@ -180,11 +195,23 @@ eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB)
  *----------------------------------------------------------------------------*/
 extern int evbase_count;
 extern pthread_mutex_t EventQueueMutex;
+extern pthread_mutex_t EventExitQueueMutex; 
 extern HashList *InboundEventQueue;
 extern struct ev_loop *event_base;
 extern ev_async AddJob;
 extern ev_async ExitEventLoop;
 
+static void IO_abort_shutdown_callback(struct ev_loop *loop,
+                                      ev_cleanup *watcher,
+                                      int revents)
+{
+       AsyncIO *IO = watcher->data;
+       EV_syslog(LOG_DEBUG, "EVENT Q: %s\n", __FUNCTION__);
+       IO->Now = ev_now(event_base);
+       assert(IO->ShutdownAbort);
+       IO->ShutdownAbort(IO);
+}
+
 
 eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB)
 {
@@ -197,15 +224,28 @@ eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB)
        ev_cleanup_init(&IO->abort_by_shutdown,
                        IO_abort_shutdown_callback);
        IO->abort_by_shutdown.data = IO;
-       ev_cleanup_start(event_base, &IO->abort_by_shutdown);
 
        pthread_mutex_lock(&EventQueueMutex);
+       if (InboundEventQueue == NULL)
+       {
+               free(h);
+               /* shutting down... */
+               EVM_syslog(LOG_DEBUG, "EVENT Q exiting.\n");
+               pthread_mutex_unlock(&EventQueueMutex);
+               return eAbort;
+       }
        EVM_syslog(LOG_DEBUG, "EVENT Q\n");
        i = ++evbase_count;
        Put(InboundEventQueue, IKEY(i), h, NULL);
        pthread_mutex_unlock(&EventQueueMutex);
 
+       pthread_mutex_lock(&EventExitQueueMutex);
+       if (event_base == NULL) {
+               pthread_mutex_unlock(&EventExitQueueMutex);
+               return eAbort;
+       }
        ev_async_send (event_base, &AddJob);
+       pthread_mutex_unlock(&EventExitQueueMutex);
        EVM_syslog(LOG_DEBUG, "EVENT Q Done.\n");
        return eSendReply;
 }
@@ -222,12 +262,28 @@ eNextState QueueCurlContext(AsyncIO *IO)
        h->EvAttch = evcurl_handle_start;
 
        pthread_mutex_lock(&EventQueueMutex);
+       if (InboundEventQueue == NULL)
+       {
+               /* shutting down... */
+               free(h);
+               EVM_syslog(LOG_DEBUG, "EVENT Q exiting.\n");
+               pthread_mutex_unlock(&EventQueueMutex);
+               return eAbort;
+       }
+
        EVM_syslog(LOG_DEBUG, "EVENT Q\n");
        i = ++evbase_count;
        Put(InboundEventQueue, IKEY(i), h, NULL);
        pthread_mutex_unlock(&EventQueueMutex);
 
+       pthread_mutex_lock(&EventExitQueueMutex);
+       if (event_base == NULL) {
+               pthread_mutex_unlock(&EventExitQueueMutex);
+               return eAbort;
+       }
        ev_async_send (event_base, &AddJob);
+       pthread_mutex_unlock(&EventExitQueueMutex);
+
        EVM_syslog(LOG_DEBUG, "EVENT Q Done.\n");
        return eSendReply;
 }
@@ -258,6 +314,25 @@ void StopClientWatchers(AsyncIO *IO)
        ev_timer_stop (event_base, &IO->rw_timeout);
        ev_timer_stop(event_base, &IO->conn_fail);
        ev_idle_stop(event_base, &IO->unwind_stack);
+       ev_cleanup_stop(event_base, &IO->abort_by_shutdown);
+
+       ev_io_stop(event_base, &IO->conn_event);
+       ev_io_stop(event_base, &IO->send_event);
+       ev_io_stop(event_base, &IO->recv_event);
+
+       if (IO->SendBuf.fd != 0) {
+               close(IO->SendBuf.fd);
+       }
+       IO->SendBuf.fd = 0;
+       IO->RecvBuf.fd = 0;
+}
+
+void StopCurlWatchers(AsyncIO *IO)
+{
+       ev_timer_stop (event_base, &IO->rw_timeout);
+       ev_timer_stop(event_base, &IO->conn_fail);
+       ev_idle_stop(event_base, &IO->unwind_stack);
+       ev_cleanup_stop(event_base, &IO->abort_by_shutdown);
 
        ev_io_stop(event_base, &IO->conn_event);
        ev_io_stop(event_base, &IO->send_event);
@@ -277,7 +352,6 @@ void ShutDownCLient(AsyncIO *IO)
 
        EVM_syslog(LOG_DEBUG, "EVENT Terminating \n");
 
-       ev_cleanup_stop(event_base, &IO->abort_by_shutdown);
        StopClientWatchers(IO);
 
        if (IO->DNS.Channel != NULL) {
@@ -388,6 +462,7 @@ IO_send_callback(struct ev_loop *loop, ev_io *watcher, int revents)
        AsyncIO *IO = watcher->data;
        const char *errmsg = NULL;
 
+       IO->Now = ev_now(event_base);
        become_session(IO->CitContext);
 #ifdef BIGBAD_IODBG
        {
@@ -520,6 +595,7 @@ set_start_callback(struct ev_loop *loop, AsyncIO *IO, int revents)
        case eReadMore:
        case eReadMessage:
        case eReadFile:
+               StrBufAppendBufPlain(IO->ErrMsg, HKEY("[while waiting for greeting]"), 0);
                ev_io_start(event_base, &IO->recv_event);
                break;
        case eSendReply:
@@ -545,6 +621,7 @@ IO_Timeout_callback(struct ev_loop *loop, ev_timer *watcher, int revents)
 {
        AsyncIO *IO = watcher->data;
 
+       IO->Now = ev_now(event_base);
        ev_timer_stop (event_base, &IO->rw_timeout);
        become_session(IO->CitContext);
 
@@ -572,6 +649,7 @@ IO_connfail_callback(struct ev_loop *loop, ev_timer *watcher, int revents)
 {
        AsyncIO *IO = watcher->data;
 
+       IO->Now = ev_now(event_base);
        ev_timer_stop (event_base, &IO->conn_fail);
 
        if (IO->SendBuf.fd != 0)
@@ -603,6 +681,7 @@ IO_connfailimmediate_callback(struct ev_loop *loop,
 {
        AsyncIO *IO = watcher->data;
 
+       IO->Now = ev_now(event_base);
        ev_idle_stop (event_base, &IO->conn_fail_immediate);
 
        if (IO->SendBuf.fd != 0)
@@ -628,6 +707,9 @@ IO_connestd_callback(struct ev_loop *loop, ev_io *watcher, int revents)
 {
        AsyncIO *IO = watcher->data;
 
+       IO->Now = ev_now(event_base);
+       EVM_syslog(LOG_DEBUG, "connect() succeeded.\n");
+
        ev_io_stop(loop, &IO->conn_event);
        ev_timer_stop (event_base, &IO->conn_fail);
        set_start_callback(loop, IO, revents);
@@ -639,6 +721,7 @@ IO_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents)
        ssize_t nbytes;
        AsyncIO *IO = watcher->data;
 
+       IO->Now = ev_now(event_base);
        switch (IO->NextState) {
        case eReadFile:
                nbytes = FileRecvChunked(&IO->IOB, &errmsg);
@@ -711,6 +794,7 @@ void
 IO_postdns_callback(struct ev_loop *loop, ev_idle *watcher, int revents)
 {
        AsyncIO *IO = watcher->data;
+       IO->Now = ev_now(event_base);
        EV_syslog(LOG_DEBUG, "event: %s\n", __FUNCTION__);
        become_session(IO->CitContext);
        assert(IO->DNS.Query->PostDNS);
@@ -768,7 +852,7 @@ eNextState EvConnectSock(AsyncIO *IO,
        }
        fdflags = fcntl(IO->SendBuf.fd, F_GETFL);
        if (fdflags < 0) {
-               EV_syslog(LOG_DEBUG,
+               EV_syslog(LOG_ERR,
                          "EVENT: unable to get socket flags! %s \n",
                          strerror(errno));
                StrBufPrintf(IO->ErrMsg,
@@ -781,7 +865,7 @@ eNextState EvConnectSock(AsyncIO *IO,
        fdflags = fdflags | O_NONBLOCK;
        if (fcntl(IO->SendBuf.fd, F_SETFL, fdflags) < 0) {
                EV_syslog(
-                       LOG_DEBUG,
+                       LOG_ERR,
                        "EVENT: unable to set socket nonblocking flags! %s \n",
                        strerror(errno));
                StrBufPrintf(IO->ErrMsg,
@@ -965,6 +1049,7 @@ int InitcURLIOStruct(AsyncIO *IO,
 
 }
 
+extern int DebugEventLoopBacktrace;
 void EV_backtrace(AsyncIO *IO)
 {
 #ifdef HAVE_BACKTRACE
@@ -972,14 +1057,17 @@ void EV_backtrace(AsyncIO *IO)
        size_t size, i;
        char **strings;
 
-
+       if ((IO == NULL) || (DebugEventLoopBacktrace == 0))
+               return;
        size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
        strings = backtrace_symbols(stack_frames, size);
        for (i = 0; i < size; i++) {
-               if (strings != NULL)
+               if (strings != NULL) {
                        EV_syslog(LOG_ALERT, " BT %s\n", strings[i]);
-               else
+               }
+               else {
                        EV_syslog(LOG_ALERT, " BT %p\n", stack_frames[i]);
+               }
        }
        free(strings);
 #endif