Back to index

citadel  8.12
Functions | Variables
event_client.c File Reference
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <errno.h>
#include <sys/types.h>
#include <syslog.h>
#include <time.h>
#include <sys/wait.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <libcitadel.h>
#include "citadel.h"
#include "server.h"
#include "citserver.h"
#include "support.h"
#include "config.h"
#include "control.h"
#include "user_ops.h"
#include "database.h"
#include "msgbase.h"
#include "internet_addressing.h"
#include "genstamp.h"
#include "domain.h"
#include "clientsocket.h"
#include "locate_host.h"
#include "citadel_dirs.h"
#include "event_client.h"
#include "ctdl_module.h"

Go to the source code of this file.

Functions

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)
eNextState QueueDBOperation (AsyncIO *IO, IO_CallBack CB)
void StopDBWatchers (AsyncIO *IO)
void ShutDownDBCLient (AsyncIO *IO)
void DB_PerformNext (struct ev_loop *loop, ev_idle *watcher, int revents)
eNextState NextDBOperation (AsyncIO *IO, IO_CallBack CB)
eNextState QueueEventContext (AsyncIO *IO, IO_CallBack CB)
eNextState evcurl_handle_start (AsyncIO *IO)
eNextState QueueCurlContext (AsyncIO *IO)
void DestructCAres (AsyncIO *IO)
void FreeAsyncIOContents (AsyncIO *IO)
void StopClientWatchers (AsyncIO *IO, int CloseFD)
void StopCurlWatchers (AsyncIO *IO)
void ShutDownCLient (AsyncIO *IO)
void PostInbound (AsyncIO *IO)
eReadState HandleInbound (AsyncIO *IO)
static void IO_send_callback (struct ev_loop *loop, ev_io *watcher, int revents)
static void set_start_callback (struct ev_loop *loop, AsyncIO *IO, int revents)
static void IO_connfail_callback (struct ev_loop *loop, ev_timer *watcher, int revents)
static void IO_connfailimmediate_callback (struct ev_loop *loop, ev_idle *watcher, int revents)
static void IO_connestd_callback (struct ev_loop *loop, ev_io *watcher, int revents)
static void IO_recv_callback (struct ev_loop *loop, ev_io *watcher, int revents)
void IO_postdns_callback (struct ev_loop *loop, ev_idle *watcher, int revents)
eNextState EvConnectSock (AsyncIO *IO, double conn_timeout, double first_rw_timeout, int ReadFirst)
void SetNextTimeout (AsyncIO *IO, double timeout)
eNextState ReAttachIO (AsyncIO *IO, void *pData, int ReadFirst)
void InitIOStruct (AsyncIO *IO, void *Data, eNextState NextState, IO_LineReaderCallback LineReader, IO_CallBack DNS_Fail, IO_CallBack SendDone, IO_CallBack ReadDone, IO_CallBack Terminate, IO_CallBack DBTerminate, IO_CallBack ConnFail, IO_CallBack Timeout, IO_CallBack ShutdownAbort)
int evcurl_init (AsyncIO *IO)
int InitcURLIOStruct (AsyncIO *IO, void *Data, const char *Desc, IO_CallBack SendDone, IO_CallBack Terminate, IO_CallBack DBTerminate, IO_CallBack ShutdownAbort)
void EV_backtrace (AsyncIO *IO)
ev_tstamp ctdl_ev_now (void)

Variables

int evdb_count
pthread_mutex_t DBEventQueueMutex
pthread_mutex_t DBEventExitQueueMutex
HashList * DBInboundEventQueue
struct ev_loop * event_db
ev_async DBAddJob
ev_async DBExitEventLoop
int evbase_count
pthread_mutex_t EventQueueMutex
pthread_mutex_t EventExitQueueMutex
HashList * InboundEventQueue
struct ev_loop * event_base
ev_async AddJob
ev_async ExitEventLoop
int DebugEventLoopBacktrace

Function Documentation

ev_tstamp ctdl_ev_now ( void  )

Definition at line 1116 of file event_client.c.

{
       return ev_now(event_base);
}
void DB_PerformNext ( struct ev_loop *  loop,
ev_idle *  watcher,
int  revents 
)

Definition at line 149 of file event_client.c.

{
       AsyncIO *IO = watcher->data;
       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);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void DestructCAres ( AsyncIO IO)

Definition at line 306 of file serv_c-ares-dns.c.

{
       EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);

       EV_DNS_LOG_STOP(DNS.recv_event);
       ev_io_stop(event_base, &IO->DNS.recv_event);

       EV_DNS_LOG_STOP(DNS.send_event);
       ev_io_stop(event_base, &IO->DNS.send_event);

       EV_DNS_LOGT_STOP(DNS.timeout);
       ev_timer_stop (event_base, &IO->DNS.timeout);

       EV_DNS_LOGT_STOP(unwind_stack);
       ev_idle_stop(event_base, &IO->unwind_stack);
       ares_destroy_options(&IO->DNS.Options);
}

Here is the caller graph for this function:

void EV_backtrace ( AsyncIO IO)

Definition at line 1092 of file event_client.c.

{
#ifdef HAVE_BACKTRACE
       void *stack_frames[50];
       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) {
                     EV_syslog(LOG_ALERT, " BT %s\n", strings[i]);
              }
              else {
                     EV_syslog(LOG_ALERT, " BT %p\n", stack_frames[i]);
              }
       }
       free(strings);
#endif
}
eNextState EvConnectSock ( AsyncIO IO,
double  conn_timeout,
double  first_rw_timeout,
int  ReadFirst 
)

Definition at line 858 of file event_client.c.

{
       struct sockaddr_in egress_sin;
       int fdflags;
       int rc = -1;

       become_session(IO->CitContext);

       if (ReadFirst) {
              IO->NextState = eReadMessage;
       }
       else {
              IO->NextState = eSendReply;
       }

       IO->SendBuf.fd = IO->RecvBuf.fd =
              socket(
                     (IO->ConnectMe->IPv6)?PF_INET6:PF_INET,
                     SOCK_STREAM,
                     IPPROTO_TCP);

       if (IO->SendBuf.fd < 0) {
              EV_syslog(LOG_ERR,
                       "EVENT: socket() failed: %s\n",
                       strerror(errno));

              StrBufPrintf(IO->ErrMsg,
                          "Failed to create socket: %s",
                          strerror(errno));
              IO->SendBuf.fd = IO->RecvBuf.fd = 0;
              return eAbort;
       }
       fdflags = fcntl(IO->SendBuf.fd, F_GETFL);
       if (fdflags < 0) {
              EV_syslog(LOG_ERR,
                       "EVENT: unable to get socket flags! %s \n",
                       strerror(errno));
              StrBufPrintf(IO->ErrMsg,
                          "Failed to get socket flags: %s",
                          strerror(errno));
              close(IO->SendBuf.fd);
              IO->SendBuf.fd = IO->RecvBuf.fd = 0;
              return eAbort;
       }
       fdflags = fdflags | O_NONBLOCK;
       if (fcntl(IO->SendBuf.fd, F_SETFL, fdflags) < 0) {
              EV_syslog(
                     LOG_ERR,
                     "EVENT: unable to set socket nonblocking flags! %s \n",
                     strerror(errno));
              StrBufPrintf(IO->ErrMsg,
                          "Failed to set socket flags: %s",
                          strerror(errno));
              close(IO->SendBuf.fd);
              IO->SendBuf.fd = IO->RecvBuf.fd = 0;
              return eAbort;
       }
/* TODO: maye we could use offsetof() to calc the position of data...
 * http://doc.dvgu.ru/devel/ev.html#associating_custom_data_with_a_watcher
 */
       ev_io_init(&IO->recv_event, IO_recv_callback, IO->RecvBuf.fd, EV_READ);
       IO->recv_event.data = IO;
       ev_io_init(&IO->send_event, IO_send_callback, IO->SendBuf.fd, EV_WRITE);
       IO->send_event.data = IO;

       ev_timer_init(&IO->conn_fail, IO_connfail_callback, conn_timeout, 0);
       IO->conn_fail.data = IO;
       ev_timer_init(&IO->rw_timeout, IO_Timeout_callback, first_rw_timeout,0);
       IO->rw_timeout.data = IO;




       /* for debugging you may bypass it like this:
        * IO->Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        * ((struct sockaddr_in)IO->ConnectMe->Addr).sin_addr.s_addr =
        *   inet_addr("127.0.0.1");
        */
       if (IO->ConnectMe->IPv6) {
              rc = connect(IO->SendBuf.fd,
                          &IO->ConnectMe->Addr,
                          sizeof(struct sockaddr_in6));
       }
       else {
              /* If citserver is bound to a specific IP address on the host, make
               * sure we use that address for outbound connections.
               */
       
              memset(&egress_sin, 0, sizeof(egress_sin));
              egress_sin.sin_family = AF_INET;
              if (!IsEmptyStr(config.c_ip_addr)) {
                     egress_sin.sin_addr.s_addr = inet_addr(config.c_ip_addr);
                     if (egress_sin.sin_addr.s_addr == !INADDR_ANY) {
                            egress_sin.sin_addr.s_addr = INADDR_ANY;
                     }

                     /* If this bind fails, no problem; we can still use INADDR_ANY */
                     bind(IO->SendBuf.fd, (struct sockaddr *)&egress_sin, sizeof(egress_sin));
              }
              rc = connect(IO->SendBuf.fd,
                          (struct sockaddr_in *)&IO->ConnectMe->Addr,
                          sizeof(struct sockaddr_in));
       }

       if (rc >= 0){
              EVM_syslog(LOG_DEBUG, "connect() immediate success.\n");
              set_start_callback(event_base, IO, 0);
              return IO->NextState;
       }
       else if (errno == EINPROGRESS) {
              EVM_syslog(LOG_DEBUG, "connect() have to wait now.\n");

              ev_io_init(&IO->conn_event,
                        IO_connestd_callback,
                        IO->SendBuf.fd,
                        EV_READ|EV_WRITE);

              IO->conn_event.data = IO;

              ev_io_start(event_base, &IO->conn_event);
              ev_timer_start(event_base, &IO->conn_fail);
              return IO->NextState;
       }
       else {
              ev_idle_init(&IO->conn_fail_immediate,
                          IO_connfailimmediate_callback);
              IO->conn_fail_immediate.data = IO;
              ev_idle_start(event_base, &IO->conn_fail_immediate);

              EV_syslog(LOG_ERR, "connect() failed: %s\n", strerror(errno));
              StrBufPrintf(IO->ErrMsg,
                          "Failed to connect: %s",
                          strerror(errno));
              return IO->NextState;
       }
       return IO->NextState;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 520 of file serv_eventclient.c.

{
       CURLMcode msta;
       CURLcode sta;
       CURL *chnd;

       chnd = IO->HttpReq.chnd;
       EVCURL_syslog(LOG_DEBUG,
                "EVCURL: Loading URL: %s\n", IO->ConnectMe->PlainUrl);
       OPT(URL, IO->ConnectMe->PlainUrl);
       if (StrLength(IO->ConnectMe->CurlCreds))
       {
              OPT(HTTPAUTH, (long)CURLAUTH_BASIC);
              OPT(USERPWD, ChrPtr(IO->ConnectMe->CurlCreds));
       }
       if (StrLength(IO->HttpReq.PostData) > 0)
       {
              OPT(POSTFIELDS, ChrPtr(IO->HttpReq.PostData));
              OPT(POSTFIELDSIZE, StrLength(IO->HttpReq.PostData));

       }
       else if ((IO->HttpReq.PlainPostDataLen != 0) &&
               (IO->HttpReq.PlainPostData != NULL))
       {
              OPT(POSTFIELDS, IO->HttpReq.PlainPostData);
              OPT(POSTFIELDSIZE, IO->HttpReq.PlainPostDataLen);
       }
       OPT(HTTPHEADER, IO->HttpReq.headers);

       IO->NextState = eConnect;
       EVCURLM_syslog(LOG_DEBUG, "EVCURL: attaching to curl multi handle\n");
       msta = curl_multi_add_handle(global.mhnd, IO->HttpReq.chnd);
       if (msta)
       {
              EVCURL_syslog(LOG_ERR,
                       "EVCURL: error attaching to curl multi handle: %s\n",
                       curl_multi_strerror(msta));
       }

       IO->HttpReq.attached = 1;
       ev_async_send (event_base, &WakeupCurl);

       ev_cleanup_init(&IO->abort_by_shutdown,
                     IOcurl_abort_shutdown_callback);

       ev_cleanup_start(event_base, &IO->abort_by_shutdown);

       return eReadMessage;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int evcurl_init ( AsyncIO IO)

Definition at line 431 of file serv_eventclient.c.

{
       CURLcode sta;
       CURL *chnd;

       EVCURLM_syslog(LOG_DEBUG, "EVCURL: evcurl_init called ms\n");
       IO->HttpReq.attached = 0;
       chnd = IO->HttpReq.chnd = curl_easy_init();
       if (!chnd)
       {
              EVCURLM_syslog(LOG_ERR, "EVCURL: error initializing curl handle\n");
              return 0;
       }

#if DEBUG
       OPT(VERBOSE, (long)1);
#endif
       OPT(NOPROGRESS, 1L);

       OPT(NOSIGNAL, 1L);
       OPT(FAILONERROR, (long)1);
       OPT(ENCODING, "");
       OPT(FOLLOWLOCATION, (long)0);
       OPT(MAXREDIRS, (long)0);
       OPT(USERAGENT, CITADEL);

       OPT(TIMEOUT, (long)1800);
       OPT(LOW_SPEED_LIMIT, (long)64);
       OPT(LOW_SPEED_TIME, (long)600);
       OPT(CONNECTTIMEOUT, (long)600);
       OPT(PRIVATE, (void *)IO);

       OPT(FORBID_REUSE, 1);
       OPT(WRITEFUNCTION, &gotdata);
       OPT(WRITEDATA, (void *)IO);
       OPT(ERRORBUFFER, IO->HttpReq.errdesc);

       if ((!IsEmptyStr(config.c_ip_addr))
              && (strcmp(config.c_ip_addr, "*"))
              && (strcmp(config.c_ip_addr, "::"))
              && (strcmp(config.c_ip_addr, "0.0.0.0"))
              )
       {
              OPT(INTERFACE, config.c_ip_addr);
       }

#ifdef CURLOPT_HTTP_CONTENT_DECODING
       OPT(HTTP_CONTENT_DECODING, 1);
       OPT(ENCODING, "");
#endif

       IO->HttpReq.headers = curl_slist_append(IO->HttpReq.headers,
                                          "Connection: close");

       return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void FreeAsyncIOContents ( AsyncIO IO)

Definition at line 292 of file event_client.c.

{
       CitContext *Ctx = IO->CitContext;

       FreeStrBuf(&IO->IOBuf);
       FreeStrBuf(&IO->SendBuf.Buf);
       FreeStrBuf(&IO->RecvBuf.Buf);

       DestructCAres(IO);

       FreeURL(&IO->ConnectMe);
       FreeStrBuf(&IO->HttpReq.ReplyData);

       if (Ctx) {
              Ctx->state = CON_IDLE;
              Ctx->kill_me = 1;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

eReadState HandleInbound ( AsyncIO IO)

read new from socket...

done for now...

WHUT? todo: shut down!

Definition at line 400 of file event_client.c.

{
       const char *Err = NULL;
       eReadState Finished = eBufferNotEmpty;

       become_session(IO->CitContext);

       while ((Finished == eBufferNotEmpty) &&
              ((IO->NextState == eReadMessage)||
              (IO->NextState == eReadMore)||
              (IO->NextState == eReadFile)||
              (IO->NextState == eReadPayload)))
       {
              /* Reading lines...
               * lex line reply in callback,
               * or do it ourselves.
               * i.e. as nnn-blabla means continue reading in SMTP
               */
              if ((IO->NextState == eReadFile) &&
                  (Finished == eBufferNotEmpty))
              {
                     Finished = WriteIOBAlreadyRead(&IO->IOB, &Err);
                     if (Finished == eReadSuccess)
                     {
                            IO->NextState = eSendReply;
                     }
              }
              else if (IO->LineReader)
                     Finished = IO->LineReader(IO);
              else
                     Finished = StrBufChunkSipLine(IO->IOBuf,
                                                &IO->RecvBuf);

              switch (Finished) {
              case eMustReadMore: 
                     break;
              case eBufferNotEmpty: /* shouldn't happen... */
              case eReadSuccess: 
                     break;
              case eReadFail: 

                     break;
              }

              if (Finished != eMustReadMore) {
                     assert(IO->ReadDone);
                     ev_io_stop(event_base, &IO->recv_event);
                     IO->NextState = IO->ReadDone(IO);
                     Finished = StrBufCheckBuffer(&IO->RecvBuf);
              }
       }

       PostInbound(IO);

       return Finished;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int InitcURLIOStruct ( AsyncIO IO,
void *  Data,
const char *  Desc,
IO_CallBack  SendDone,
IO_CallBack  Terminate,
IO_CallBack  DBTerminate,
IO_CallBack  ShutdownAbort 
)

Definition at line 1066 of file event_client.c.

{
       IO->Data          = Data;

       IO->CitContext    = CloneContext(CC);
       ((CitContext *)IO->CitContext)->session_specific_data = (char*) Data;

       IO->SendDone      = SendDone;
       IO->Terminate     = Terminate;
       IO->DBTerminate   = DBTerminate;
       IO->ShutdownAbort = ShutdownAbort;

       strcpy(IO->HttpReq.errdesc, Desc);


       return  evcurl_init(IO);

}

Here is the call graph for this function:

Here is the caller graph for this function:

void InitIOStruct ( AsyncIO IO,
void *  Data,
eNextState  NextState,
IO_LineReaderCallback  LineReader,
IO_CallBack  DNS_Fail,
IO_CallBack  SendDone,
IO_CallBack  ReadDone,
IO_CallBack  Terminate,
IO_CallBack  DBTerminate,
IO_CallBack  ConnFail,
IO_CallBack  Timeout,
IO_CallBack  ShutdownAbort 
)

Definition at line 1024 of file event_client.c.

{
       IO->Data          = Data;

       IO->CitContext    = CloneContext(CC);
       ((CitContext *)IO->CitContext)->session_specific_data = (char*) Data;

       IO->NextState     = NextState;

       IO->SendDone      = SendDone;
       IO->ReadDone      = ReadDone;
       IO->Terminate     = Terminate;
       IO->DBTerminate   = DBTerminate;
       IO->LineReader    = LineReader;
       IO->ConnFail      = ConnFail;
       IO->Timeout       = Timeout;
       IO->ShutdownAbort = ShutdownAbort;

       IO->DNS.Fail      = DNS_Fail;

       IO->SendBuf.Buf   = NewStrBufPlain(NULL, 1024);
       IO->RecvBuf.Buf   = NewStrBufPlain(NULL, 1024);
       IO->IOBuf         = NewStrBuf();
       EV_syslog(LOG_DEBUG,
                "EVENT: Session lives at %p IO at %p \n",
                Data, IO);

}

Here is the call graph for this function:

Here is the caller graph for this function:

static void IO_abort_shutdown_callback ( struct ev_loop *  loop,
ev_cleanup *  watcher,
int  revents 
) [static]

Definition at line 204 of file event_client.c.

{
       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);
}

Here is the caller graph for this function:

static void IO_connestd_callback ( struct ev_loop *  loop,
ev_io *  watcher,
int  revents 
) [static]

Definition at line 718 of file event_client.c.

{
        AsyncIO *IO = watcher->data;
        int             so_err = 0;
        socklen_t       lon = sizeof(so_err);
        int             err;

        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);

        err = getsockopt(IO->SendBuf.fd,
                         SOL_SOCKET,
                         SO_ERROR,
                         (void*)&so_err,
                         &lon);

        if ((err == 0) && (so_err != 0))
        {
                EV_syslog(LOG_DEBUG, "connect() failed [%d][%s]\n",
                          so_err,
                          strerror(so_err));
                IO_connfail_callback(loop, &IO->conn_fail, revents);

        }
        else
        {
                EVM_syslog(LOG_DEBUG, "connect() succeeded\n");
                set_start_callback(loop, IO, revents);
        }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void IO_connfail_callback ( struct ev_loop *  loop,
ev_timer *  watcher,
int  revents 
) [static]

Definition at line 660 of file event_client.c.

{
       AsyncIO *IO = watcher->data;

       IO->Now = ev_now(event_base);
       ev_timer_stop (event_base, &IO->conn_fail);

       if (IO->SendBuf.fd != 0)
       {
              ev_io_stop(loop, &IO->conn_event);
              ev_io_stop(event_base, &IO->send_event);
              ev_io_stop(event_base, &IO->recv_event);
              ev_timer_stop (event_base, &IO->rw_timeout);
              close(IO->SendBuf.fd);
              IO->SendBuf.fd = IO->RecvBuf.fd = 0;
       }
       become_session(IO->CitContext);

       assert(IO->ConnFail);
       switch (IO->ConnFail(IO))
       {
       case eAbort:
              ShutDownCLient(IO);
       default:
              break;

       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void IO_connfailimmediate_callback ( struct ev_loop *  loop,
ev_idle *  watcher,
int  revents 
) [static]

Definition at line 690 of file event_client.c.

{
       AsyncIO *IO = watcher->data;

       IO->Now = ev_now(event_base);
       ev_idle_stop (event_base, &IO->conn_fail_immediate);

       if (IO->SendBuf.fd != 0)
       {
              close(IO->SendBuf.fd);
              IO->SendBuf.fd = IO->RecvBuf.fd = 0;
       }
       become_session(IO->CitContext);

       assert(IO->ConnFail);
       switch (IO->ConnFail(IO))
       {
       case eAbort:
              ShutDownCLient(IO);
       default:
              break;

       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void IO_postdns_callback ( struct ev_loop *  loop,
ev_idle *  watcher,
int  revents 
)

Definition at line 834 of file event_client.c.

{
       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);
       switch (IO->DNS.Query->PostDNS(IO))
       {
       case eAbort:
              assert(IO->DNS.Fail);
              switch (IO->DNS.Fail(IO)) {
              case eAbort:
                     ShutDownCLient(IO);
              default:
                     break;
              }
       default:
              break;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void IO_recv_callback ( struct ev_loop *  loop,
ev_io *  watcher,
int  revents 
) [static]

Definition at line 753 of file event_client.c.

{
       const char *errmsg;
       ssize_t nbytes;
       AsyncIO *IO = watcher->data;

       IO->Now = ev_now(event_base);
       switch (IO->NextState) {
       case eReadFile:
              nbytes = FileRecvChunked(&IO->IOB, &errmsg);
              if (nbytes < 0)
                     StrBufPlain(IO->ErrMsg, errmsg, -1);
              else
              {
                     if (IO->IOB.ChunkSendRemain == 0)
                     {
                            IO->NextState = eSendReply;
                            assert(IO->ReadDone);
                            ev_io_stop(event_base, &IO->recv_event);
                            PostInbound(IO);
                            return;
                     }
                     else
                            return;
              }
              break;
       default:
              nbytes = StrBuf_read_one_chunk_callback(IO->RecvBuf.fd,
                                                 0,
                                                 &IO->RecvBuf);
              break;
       }

#ifdef BIGBAD_IODBG
       {
              long nbytes;
              int rv = 0;
              char fn [SIZ];
              FILE *fd;
              const char *pch = ChrPtr(IO->RecvBuf.Buf);
              const char *pchh = IO->RecvBuf.ReadWritePointer;

              if (pchh == NULL)
                     pchh = pch;

              nbytes = StrLength(IO->RecvBuf.Buf) - (pchh - pch);
              snprintf(fn, SIZ, "/tmp/foolog_ev_%s.%d",
                      ((CitContext*)(IO->CitContext))->ServiceName,
                      IO->SendBuf.fd);

              fd = fopen(fn, "a+");
              fprintf(fd, "Read: BufSize: %ld BufContent: [",
                     nbytes);
              rv = fwrite(pchh, nbytes, 1, fd);
              if (!rv) printf("failed to write debug to %s!\n", fn);
              fprintf(fd, "]\n");
              fclose(fd);
       }
#endif
       if (nbytes > 0) {
              HandleInbound(IO);
       } else if (nbytes == 0) {
              SetNextTimeout(IO, 0.0);
              return;
       } else if (nbytes == -1) {
              if (errno != EAGAIN) {
                     // FD is gone. kick it. 
                     StopClientWatchers(IO, 1);
                     EV_syslog(LOG_DEBUG,
                              "EVENT: Socket Invalid! [%d] [%s] [%d]\n",
                              errno, strerror(errno), IO->SendBuf.fd);
                     StrBufPrintf(IO->ErrMsg,
                                 "Socket Invalid! [%s]",
                                 strerror(errno));
                     SetNextTimeout(IO, 0.0);
              }
              return;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void IO_send_callback ( struct ev_loop *  loop,
ev_io *  watcher,
int  revents 
) [static]

Definition at line 459 of file event_client.c.

{
       int rc;
       AsyncIO *IO = watcher->data;
       const char *errmsg = NULL;

       IO->Now = ev_now(event_base);
       become_session(IO->CitContext);
#ifdef BIGBAD_IODBG
       {
              int rv = 0;
              char fn [SIZ];
              FILE *fd;
              const char *pch = ChrPtr(IO->SendBuf.Buf);
              const char *pchh = IO->SendBuf.ReadWritePointer;
              long nbytes;

              if (pchh == NULL)
                     pchh = pch;

              nbytes = StrLength(IO->SendBuf.Buf) - (pchh - pch);
              snprintf(fn, SIZ, "/tmp/foolog_ev_%s.%d",
                      ((CitContext*)(IO->CitContext))->ServiceName,
                      IO->SendBuf.fd);

              fd = fopen(fn, "a+");
              fprintf(fd, "Send: BufSize: %ld BufContent: [",
                     nbytes);
              rv = fwrite(pchh, nbytes, 1, fd);
              if (!rv) printf("failed to write debug to %s!\n", fn);
              fprintf(fd, "]\n");
#endif
              switch (IO->NextState) {
              case eSendFile:
                     rc = FileSendChunked(&IO->IOB, &errmsg);
                     if (rc < 0)
                            StrBufPlain(IO->ErrMsg, errmsg, -1);
                     break;
              default:
                     rc = StrBuf_write_one_chunk_callback(IO->SendBuf.fd,
                                                      0,
                                                      &IO->SendBuf);
              }

#ifdef BIGBAD_IODBG
              fprintf(fd, "Sent: BufSize: %d bytes.\n", rc);
              fclose(fd);
       }
#endif
       if (rc == 0)
       {
              ev_io_stop(event_base, &IO->send_event);
              switch (IO->NextState) {
              case eSendMore:
                     assert(IO->SendDone);
                     IO->NextState = IO->SendDone(IO);

                     if ((IO->NextState == eTerminateConnection) ||
                         (IO->NextState == eAbort) )
                            ShutDownCLient(IO);
                     else {
                            ev_io_start(event_base, &IO->send_event);
                     }
                     break;
              case eSendFile:
                     if (IO->IOB.ChunkSendRemain > 0) {
                            ev_io_start(event_base, &IO->recv_event);
                            SetNextTimeout(IO, 100.0);

                     } else {
                            assert(IO->ReadDone);
                            IO->NextState = IO->ReadDone(IO);
                            switch(IO->NextState) {
                            case eSendDNSQuery:
                            case eReadDNSReply:
                            case eDBQuery:
                            case eConnect:
                                   break;
                            case eSendReply:
                            case eSendMore:
                            case eSendFile:
                                   ev_io_start(event_base,
                                              &IO->send_event);
                                   break;
                            case eReadMessage:
                            case eReadMore:
                            case eReadPayload:
                            case eReadFile:
                                   break;
                            case eTerminateConnection:
                            case eAbort:
                                   break;
                            }
                     }
                     break;
              case eSendReply:
                  if (StrBufCheckBuffer(&IO->SendBuf) != eReadSuccess)
                     break;
                  IO->NextState = eReadMore;
              case eReadMore:
              case eReadMessage:
              case eReadPayload:
              case eReadFile:
                     if (StrBufCheckBuffer(&IO->RecvBuf) == eBufferNotEmpty)
                     {
                            HandleInbound(IO);
                     }
                     else {
                            ev_io_start(event_base, &IO->recv_event);
                     }

                     break;
              case eDBQuery:
                     /*
                      * we now live in another queue,
                      * so we have to unregister.
                      */
                     ev_cleanup_stop(loop, &IO->abort_by_shutdown);
                     break;
              case eSendDNSQuery:
              case eReadDNSReply:
              case eConnect:
              case eTerminateConnection:
              case eAbort:
                     break;
              }
       }
       else if (rc < 0) {
              if (errno != EAGAIN) {
                     StopClientWatchers(IO, 1);
                     EV_syslog(LOG_DEBUG,
                              "EVENT: Socket Invalid! [%d] [%s] [%d]\n",
                              errno, strerror(errno), IO->SendBuf.fd);
                     StrBufPrintf(IO->ErrMsg,
                                 "Socket Invalid! [%s]",
                                 strerror(errno));
                     SetNextTimeout(IO, 0.0);
              }
       }
       /* else : must write more. */
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void IO_Timeout_callback ( struct ev_loop *  loop,
ev_timer *  watcher,
int  revents 
) [static]

Definition at line 632 of file event_client.c.

{
       AsyncIO *IO = watcher->data;

       IO->Now = ev_now(event_base);
       ev_timer_stop (event_base, &IO->rw_timeout);
       become_session(IO->CitContext);

       if (IO->SendBuf.fd != 0)
       {
              ev_io_stop(event_base, &IO->send_event);
              ev_io_stop(event_base, &IO->recv_event);
              ev_timer_stop (event_base, &IO->rw_timeout);
              close(IO->SendBuf.fd);
              IO->SendBuf.fd = IO->RecvBuf.fd = 0;
       }

       assert(IO->Timeout);
       switch (IO->Timeout(IO))
       {
       case eAbort:
              ShutDownCLient(IO);
       default:
              break;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 183 of file event_client.c.

{
       IO->NextDBOperation = CB;
       ev_idle_init(&IO->db_unwind_stack,
                   DB_PerformNext);
       IO->db_unwind_stack.data = IO;
       ev_idle_start(event_db, &IO->db_unwind_stack);
       return eDBQuery;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void PostInbound ( AsyncIO IO)

Definition at line 369 of file event_client.c.

{
       switch (IO->NextState) {
       case eSendFile:
              ev_io_start(event_base, &IO->send_event);
              break;
       case eSendReply:
       case eSendMore:
              assert(IO->SendDone);
              IO->NextState = IO->SendDone(IO);
              ev_io_start(event_base, &IO->send_event);
              break;
       case eReadPayload:
       case eReadMore:
       case eReadFile:
              ev_io_start(event_base, &IO->recv_event);
              break;
       case eTerminateConnection:
              ShutDownCLient(IO);
              break;
       case eAbort:
              ShutDownCLient(IO);
              break;
       case eSendDNSQuery:
       case eReadDNSReply:
       case eDBQuery:
       case eConnect:
       case eReadMessage:
              break;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 255 of file event_client.c.

{
       IOAddHandler *h;
       int i;

       h = (IOAddHandler*)malloc(sizeof(IOAddHandler));
       h->IO = 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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 91 of file event_client.c.

{
       IOAddHandler *h;
       int i;

       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 216 of file event_client.c.

{
       IOAddHandler *h;
       int i;

       h = (IOAddHandler*)malloc(sizeof(IOAddHandler));
       h->IO = IO;
       h->EvAttch = CB;
       ev_cleanup_init(&IO->abort_by_shutdown,
                     IO_abort_shutdown_callback);
       IO->abort_by_shutdown.data = IO;

       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

eNextState ReAttachIO ( AsyncIO IO,
void *  pData,
int  ReadFirst 
)

Definition at line 1006 of file event_client.c.

{
       IO->Data = pData;
       become_session(IO->CitContext);
       ev_cleanup_start(event_base, &IO->abort_by_shutdown);
       if (ReadFirst) {
              IO->NextState = eReadMessage;
       }
       else {
              IO->NextState = eSendReply;
       }
       set_start_callback(event_base, IO, 0);

       return IO->NextState;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void set_start_callback ( struct ev_loop *  loop,
AsyncIO IO,
int  revents 
) [static]

TODO: WHUT?

Definition at line 601 of file event_client.c.

{
       ev_timer_stop(event_base, &IO->conn_fail);
       ev_timer_start(event_base, &IO->rw_timeout);

       switch(IO->NextState) {
       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:
       case eSendMore:
       case eReadPayload:
       case eSendFile:
              become_session(IO->CitContext);
              IO_send_callback(loop, &IO->send_event, revents);
              break;
       case eDBQuery:
       case eSendDNSQuery:
       case eReadDNSReply:
       case eConnect:
       case eTerminateConnection:
       case eAbort:
              break;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void SetNextTimeout ( AsyncIO IO,
double  timeout 
)

Definition at line 999 of file event_client.c.

{
       IO->rw_timeout.repeat = timeout;
       ev_timer_again (event_base,  &IO->rw_timeout);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void ShutDownCLient ( AsyncIO IO)

Definition at line 348 of file event_client.c.

{
       CitContext *Ctx =IO->CitContext;
       become_session(Ctx);

       EVM_syslog(LOG_DEBUG, "EVENT Terminating \n");

       StopClientWatchers(IO, 1);

       if (IO->DNS.Channel != NULL) {
              ares_destroy(IO->DNS.Channel);
              EV_DNS_LOG_STOP(DNS.recv_event);
              EV_DNS_LOG_STOP(DNS.send_event);
              ev_io_stop(event_base, &IO->DNS.recv_event);
              ev_io_stop(event_base, &IO->DNS.send_event);
              IO->DNS.Channel = NULL;
       }
       assert(IO->Terminate);
       IO->Terminate(IO);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void ShutDownDBCLient ( AsyncIO IO)

Definition at line 136 of file event_client.c.

{
       CitContext *Ctx =IO->CitContext;
       become_session(Ctx);

       EVM_syslog(LOG_DEBUG, "DBEVENT Terminating.\n");
       StopDBWatchers(IO);

       assert(IO->DBTerminate);
       IO->DBTerminate(IO);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void StopClientWatchers ( AsyncIO IO,
int  CloseFD 
)

Definition at line 312 of file event_client.c.

{
       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 (CloseFD && (IO->SendBuf.fd > 0)) {
              close(IO->SendBuf.fd);
              IO->SendBuf.fd = -1;
              IO->RecvBuf.fd = -1;
       }
}

Here is the caller graph for this function:

void StopCurlWatchers ( AsyncIO IO)

Definition at line 330 of file event_client.c.

{
       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;
}

Here is the caller graph for this function:

void StopDBWatchers ( AsyncIO IO)

Definition at line 130 of file event_client.c.

{
       ev_cleanup_stop(event_db, &IO->db_abort_by_shutdown);
       ev_idle_stop(event_db, &IO->db_unwind_stack);
}

Here is the caller graph for this function:


Variable Documentation

ev_async AddJob

Definition at line 597 of file serv_eventclient.c.

ev_async DBAddJob

Definition at line 723 of file serv_eventclient.c.

pthread_mutex_t DBEventExitQueueMutex

Definition at line 718 of file serv_eventclient.c.

pthread_mutex_t DBEventQueueMutex

Definition at line 717 of file serv_eventclient.c.

ev_async DBExitEventLoop

Definition at line 724 of file serv_eventclient.c.

Definition at line 720 of file serv_eventclient.c.

Definition at line 64 of file serv_eventclient.c.

Definition at line 590 of file serv_eventclient.c.

Definition at line 716 of file serv_eventclient.c.

struct ev_loop* event_base

Definition at line 62 of file serv_eventclient.c.

struct ev_loop* event_db

Definition at line 715 of file serv_eventclient.c.

pthread_mutex_t EventExitQueueMutex

Definition at line 592 of file serv_eventclient.c.

pthread_mutex_t EventQueueMutex

Definition at line 591 of file serv_eventclient.c.

ev_async ExitEventLoop

Definition at line 598 of file serv_eventclient.c.

HashList* InboundEventQueue

Definition at line 594 of file serv_eventclient.c.