Back to index

citadel  8.12
event_client.h
Go to the documentation of this file.
00001 /*
00002  *
00003  * Copyright (c) 1998-2012 by the citadel.org team
00004  *
00005  *  This program is open source software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 3 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #ifndef __EVENT_CLIENT_H__
00021 #define __EVENT_CLIENT_H__
00022 #define EV_COMPAT3 0
00023 #include "sysconfig.h"
00024 #include <ev.h>
00025 #include <sys/types.h>
00026 #include <sys/socket.h>
00027 #include <netdb.h>
00028 #include <arpa/nameser.h>
00029 #include <ares.h>
00030 #include <curl/curl.h>
00031 
00032 typedef struct AsyncIO AsyncIO;
00033 
00034 typedef enum _eNextState {
00035        eSendDNSQuery,
00036        eReadDNSReply,
00037 
00038        eDBQuery,
00039 
00040        eConnect,
00041        eSendReply,
00042        eSendMore,
00043        eSendFile,
00044 
00045        eReadMessage,
00046        eReadMore,
00047        eReadPayload,
00048        eReadFile,
00049 
00050        eTerminateConnection,
00051        eAbort
00052 }eNextState;
00053 
00054 typedef eNextState (*IO_CallBack)(AsyncIO *IO);
00055 typedef eReadState (*IO_LineReaderCallback)(AsyncIO *IO);
00056 typedef void (*ParseDNSAnswerCb)(AsyncIO*, unsigned char*, int);
00057 typedef void (*FreeDNSReply)(void *DNSData);
00058 
00059 
00060 typedef struct __ReadAsyncMsg {
00061        StrBuf *MsgBuf;
00062        size_t maxlen;              /* maximum message length */
00063 
00064        const char *terminator;     /* token signalling EOT */
00065        long tlen;
00066        int dodot;
00067 
00068        int flushing;
00069 /* if we read maxlen, read until nothing more arives and ignore this. */
00070 
00071        int crlf;            /* CRLF newlines instead of LF */
00072 } ReadAsyncMsg;
00073 
00074 
00075 typedef struct _DNSQueryParts {
00076        ParseDNSAnswerCb DNS_CB;
00077        IO_CallBack PostDNS;
00078 
00079        int DNSStatus;
00080        void *VParsedDNSReply;
00081        FreeDNSReply DNSReplyFree;
00082        void *Data;
00083 } DNSQueryParts;
00084 
00085 typedef struct _evcurl_request_data
00086 {
00087        CURL                 *chnd;
00088        struct curl_slist    *headers;
00089        char                  errdesc[CURL_ERROR_SIZE];
00090 
00091        int                   attached;
00092 
00093        char                 *PlainPostData;
00094        long                  PlainPostDataLen;
00095        StrBuf               *PostData;
00096 
00097        StrBuf               *ReplyData;
00098        long                  httpcode;
00099 } evcurl_request_data;
00100 
00101 /* DNS Related */
00102 typedef struct __evcares_data {
00103        ev_tstamp Start;
00104        ev_io recv_event,
00105               send_event;
00106        ev_timer timeout;           /* timeout while requesting ips */
00107        short int SourcePort;
00108 
00109        struct ares_options Options;
00110        ares_channel Channel;
00111        DNSQueryParts *Query;
00112 
00113        IO_CallBack Fail;      /* the dns lookup didn't work out. */
00114 } evcares_data;
00115 
00116 struct AsyncIO {
00117        long ID;
00118        ev_tstamp Now;
00119        ev_tstamp StartIO;
00120        ev_tstamp StartDB;
00121        eNextState NextState;
00122 
00123        /* connection related */
00124        ParsedURL *ConnectMe;
00125 
00126        /* read/send related... */
00127        StrBuf *IOBuf;
00128        IOBuffer SendBuf,
00129               RecvBuf;
00130 
00131        FDIOBuffer IOB;
00132        /* when sending from / reading into files, this is used. */
00133 
00134        /* our events... */
00135        ev_cleanup abort_by_shutdown, /* server wants to go down... */
00136               db_abort_by_shutdown; /* server wants to go down... */
00137        ev_timer conn_fail,           /* connection establishing timed out */
00138               rw_timeout;           /* timeout while sending data */
00139        ev_idle unwind_stack,         /* get c-ares out of the stack */
00140               db_unwind_stack,      /* wait for next db operation... */
00141               conn_fail_immediate;  /* unwind stack, but fail immediately. */
00142        ev_io recv_event,             /* receive data from the client */
00143               send_event,           /* send more data to the client */
00144               conn_event;           /* Connection successfully established */
00145 
00146        StrBuf *ErrMsg; /* if we fail to connect, or lookup, error goes here. */
00147 
00148        /* Citadel application callbacks... */
00149        IO_CallBack ReadDone, /* Theres new data to read... */
00150               SendDone,     /* we may send more data */
00151               Terminate,    /* shutting down... */
00152               DBTerminate,  /* shutting down... */
00153               Timeout,      /* Timeout handler;may also be conn. timeout */
00154               ConnFail,     /* What to do when one connection failed? */
00155               ShutdownAbort,/* we're going down. make your piece. */
00156               NextDBOperation; /* Perform Database IO */
00157 
00158        /* if we have linereaders, maybe we want to read more lines before
00159         * the real application logic is called? */
00160        IO_LineReaderCallback LineReader;
00161 
00162        evcares_data DNS;
00163 
00164        evcurl_request_data HttpReq;
00165 
00166        /* Saving / loading a message async from / to disk */
00167        ReadAsyncMsg *ReadMsg;
00168        struct CtdlMessage *AsyncMsg;
00169        struct recptypes *AsyncRcp;
00170 
00171        /* Context specific data; Hint: put AsyncIO in there */
00172        void *Data;        /* application specific data */
00173        void *CitContext;  /* Citadel Session context... */
00174 };
00175 
00176 typedef struct _IOAddHandler {
00177        AsyncIO *IO;
00178        IO_CallBack EvAttch;
00179 } IOAddHandler;
00180 
00181 
00182 
00183 extern int DebugEventLoop;
00184 extern int DebugCAres;
00185 
00186 #define EDBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (DebugEventLoop != 0))
00187 
00188 #define CCID ((CitContext*)IO->CitContext)->cs_pid
00189 
00190 #define EVQ_syslog(LEVEL, FORMAT, ...)                                \
00191        EDBGLOG (LEVEL) syslog(LEVEL, "IOQ " FORMAT, __VA_ARGS__)
00192 
00193 #define EVQM_syslog(LEVEL, FORMAT)               \
00194        EDBGLOG (LEVEL) syslog(LEVEL, "IO " FORMAT)
00195 
00196 #define EV_syslog(LEVEL, FORMAT, ...)                                 \
00197        EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID, __VA_ARGS__)
00198 
00199 #define EVM_syslog(LEVEL, FORMAT)                              \
00200        EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID)
00201 
00202 #define EVNC_syslog(LEVEL, FORMAT, ...)                               \
00203        EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld] " FORMAT, IO->ID, __VA_ARGS__)
00204 
00205 #define EVNCM_syslog(LEVEL, FORMAT) EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]" FORMAT, IO->ID)
00206 
00207 
00208 #define CDBGLOG() if (DebugCAres != 0)
00209 #define CEDBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (DebugCAres != 0))
00210 #define EV_DNS_LOG_START(a)                                           \
00211        CDBGLOG () {syslog(LOG_DEBUG, "IO[%ld]CC[%d] + Starting " #a " %s %p FD %d", IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \
00212                   EV_backtrace(IO);}
00213 
00214 #define EV_DNS_LOG_STOP(a)                                            \
00215        CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] - Stopping " #a " %s %p FD %d", IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \
00216                    EV_backtrace(IO);}
00217 
00218 #define EV_DNS_LOG_INIT(a)                                            \
00219        CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] * Init " #a " %s %p FD %d", IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \
00220                    EV_backtrace(IO);}
00221 
00222 #define EV_DNS_LOGT_START(a)                                                 \
00223        CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] + Starting " #a " %s %p", IO->ID, CCID, __FUNCTION__, &IO->a); \
00224                    EV_backtrace(IO);}
00225 
00226 #define EV_DNS_LOGT_STOP(a)                                           \
00227        CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] - Stopping " #a " %s %p", IO->ID, CCID, __FUNCTION__, &IO->a); \
00228                    EV_backtrace(IO); }
00229 
00230 #define EV_DNS_LOGT_INIT(a)                                           \
00231        CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] * Init " #a " %p", IO->ID, CCID, &IO->a); \
00232                    EV_backtrace(IO);}
00233 
00234 #define EV_DNS_syslog(LEVEL, FORMAT, ...)                      \
00235        CEDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID, __VA_ARGS__)
00236 
00237 #define EVM_DNS_syslog(LEVEL, FORMAT)                                 \
00238        CEDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID)
00239 
00240 void FreeAsyncIOContents(AsyncIO *IO);
00241 
00242 eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB);
00243 eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB);
00244 void StopDBWatchers(AsyncIO *IO);
00245 eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB);
00246 eNextState QueueCurlContext(AsyncIO *IO);
00247 
00248 eNextState EvConnectSock(AsyncIO *IO,
00249                       double conn_timeout,
00250                       double first_rw_timeout,
00251                       int ReadFirst);
00252 void IO_postdns_callback(struct ev_loop *loop, ev_idle *watcher, int revents);
00253 
00254 int QueueQuery(ns_type Type,
00255               const char *name,
00256               AsyncIO *IO,
00257               DNSQueryParts *QueryParts,
00258               IO_CallBack PostDNS);
00259 
00260 void QueueGetHostByName(AsyncIO *IO,
00261                      const char *Hostname,
00262                      DNSQueryParts *QueryParts,
00263                      IO_CallBack PostDNS);
00264 
00265 void QueryCbDone(AsyncIO *IO);
00266 
00267 void StopClient(AsyncIO *IO);
00268 
00269 void StopClientWatchers(AsyncIO *IO, int CloseFD);
00270 
00271 void SetNextTimeout(AsyncIO *IO, double timeout);
00272 
00273 #include <curl/curl.h>
00274 
00275 #define OPT(s, v) \
00276        do { \
00277               sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v));       \
00278               if (sta)  {                                      \
00279                      EVQ_syslog(LOG_ERR,                       \
00280                             "error setting option " #s         \
00281                             " on curl handle: %s",                    \
00282                             curl_easy_strerror(sta));          \
00283        } } while (0)
00284 
00285 void InitIOStruct(AsyncIO *IO,
00286                 void *Data,
00287                 eNextState NextState,
00288                 IO_LineReaderCallback LineReader,
00289                 IO_CallBack DNS_Fail,
00290                 IO_CallBack SendDone,
00291                 IO_CallBack ReadDone,
00292                 IO_CallBack Terminate,
00293                 IO_CallBack DBTerminate,
00294                 IO_CallBack ConnFail,
00295                 IO_CallBack Timeout,
00296                 IO_CallBack ShutdownAbort);
00297 
00298 int InitcURLIOStruct(AsyncIO *IO,
00299                    void *Data,
00300                    const char* Desc,
00301                    IO_CallBack SendDone,
00302                    IO_CallBack Terminate,
00303                    IO_CallBack DBTerminate,
00304                    IO_CallBack ShutdownAbort);
00305 
00306 void StopCurlWatchers(AsyncIO *IO);
00307 
00308 
00309 eNextState ReAttachIO(AsyncIO *IO,
00310                     void *pData,
00311                     int ReadFirst);
00312 
00313 void EV_backtrace(AsyncIO *IO);
00314 ev_tstamp ctdl_ev_now (void);
00315 
00316 #endif /* __EVENT_CLIENT_H__ */