Updated the copyright declaration in several modules, removing any language which...
[citadel.git] / citadel / event_client.h
1 /*
2  *
3  * Copyright (c) 1998-2012 by the citadel.org team
4  *
5  *  This program is open source software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License, version 3.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  */
13
14 #ifndef __EVENT_CLIENT_H__
15 #define __EVENT_CLIENT_H__
16 #define EV_COMPAT3 0
17 #include "sysconfig.h"
18 #include <ev.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netdb.h>
22 #include <arpa/nameser.h>
23 #include <ares.h>
24 #include <curl/curl.h>
25
26 typedef struct AsyncIO AsyncIO;
27
28 typedef enum _eNextState {
29         eSendDNSQuery,
30         eReadDNSReply,
31
32         eDBQuery,
33
34         eConnect,
35         eSendReply,
36         eSendMore,
37         eSendFile,
38
39         eReadMessage,
40         eReadMore,
41         eReadPayload,
42         eReadFile,
43
44         eTerminateConnection,
45         eAbort
46 }eNextState;
47
48 typedef eNextState (*IO_CallBack)(AsyncIO *IO);
49 typedef eReadState (*IO_LineReaderCallback)(AsyncIO *IO);
50 typedef void (*ParseDNSAnswerCb)(AsyncIO*, unsigned char*, int);
51 typedef void (*FreeDNSReply)(void *DNSData);
52
53
54 typedef struct __ReadAsyncMsg {
55         StrBuf *MsgBuf;
56         size_t maxlen;          /* maximum message length */
57
58         const char *terminator; /* token signalling EOT */
59         long tlen;
60         int dodot;
61
62         int flushing;
63 /* if we read maxlen, read until nothing more arives and ignore this. */
64
65         int crlf;               /* CRLF newlines instead of LF */
66 } ReadAsyncMsg;
67
68
69 typedef struct _DNSQueryParts {
70         ParseDNSAnswerCb DNS_CB;
71         IO_CallBack PostDNS;
72
73         int DNSStatus;
74         void *VParsedDNSReply;
75         FreeDNSReply DNSReplyFree;
76         void *Data;
77 } DNSQueryParts;
78
79 typedef struct _evcurl_request_data
80 {
81         CURL                    *chnd;
82         struct curl_slist       *headers;
83         char                     errdesc[CURL_ERROR_SIZE];
84
85         int                      attached;
86
87         char                    *PlainPostData;
88         long                     PlainPostDataLen;
89         StrBuf                  *PostData;
90
91         StrBuf                  *ReplyData;
92         long                     httpcode;
93 } evcurl_request_data;
94
95 /* DNS Related */
96 typedef struct __evcares_data {
97         ev_tstamp Start;
98         ev_io recv_event,
99                 send_event;
100         ev_timer timeout;           /* timeout while requesting ips */
101         short int SourcePort;
102
103         struct ares_options Options;
104         ares_channel Channel;
105         DNSQueryParts *Query;
106
107         IO_CallBack Fail;      /* the dns lookup didn't work out. */
108 } evcares_data;
109
110 struct AsyncIO {
111         long ID;
112         ev_tstamp Now;
113         ev_tstamp StartIO;
114         ev_tstamp StartDB;
115         eNextState NextState;
116
117         /* connection related */
118         ParsedURL *ConnectMe;
119
120         /* read/send related... */
121         StrBuf *IOBuf;
122         IOBuffer SendBuf,
123                 RecvBuf;
124
125         FDIOBuffer IOB;
126         /* when sending from / reading into files, this is used. */
127
128         /* our events... */
129         ev_cleanup abort_by_shutdown, /* server wants to go down... */
130                 db_abort_by_shutdown; /* server wants to go down... */
131         ev_timer conn_fail,           /* connection establishing timed out */
132                 rw_timeout;           /* timeout while sending data */
133         ev_idle unwind_stack,         /* get c-ares out of the stack */
134                 db_unwind_stack,      /* wait for next db operation... */
135                 conn_fail_immediate;  /* unwind stack, but fail immediately. */
136         ev_io recv_event,             /* receive data from the client */
137                 send_event,           /* send more data to the client */
138                 conn_event;           /* Connection successfully established */
139
140         StrBuf *ErrMsg; /* if we fail to connect, or lookup, error goes here. */
141
142         /* Citadel application callbacks... */
143         IO_CallBack ReadDone, /* Theres new data to read... */
144                 SendDone,     /* we may send more data */
145                 Terminate,    /* shutting down... */
146                 DBTerminate,  /* shutting down... */
147                 Timeout,      /* Timeout handler;may also be conn. timeout */
148                 ConnFail,     /* What to do when one connection failed? */
149                 ShutdownAbort,/* we're going down. make your piece. */
150                 NextDBOperation; /* Perform Database IO */
151
152         /* if we have linereaders, maybe we want to read more lines before
153          * the real application logic is called? */
154         IO_LineReaderCallback LineReader;
155
156         evcares_data DNS;
157
158         evcurl_request_data HttpReq;
159
160         /* Saving / loading a message async from / to disk */
161         ReadAsyncMsg *ReadMsg;
162         struct CtdlMessage *AsyncMsg;
163         struct recptypes *AsyncRcp;
164
165         /* Context specific data; Hint: put AsyncIO in there */
166         void *Data;        /* application specific data */
167         void *CitContext;  /* Citadel Session context... */
168 };
169
170 typedef struct _IOAddHandler {
171         AsyncIO *IO;
172         IO_CallBack EvAttch;
173 } IOAddHandler;
174
175
176
177 extern int DebugEventLoop;
178 extern int DebugCAres;
179
180 #define EDBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (DebugEventLoop != 0))
181
182 #define CCID ((CitContext*)IO->CitContext)->cs_pid
183
184 #define EVQ_syslog(LEVEL, FORMAT, ...)                                  \
185         EDBGLOG (LEVEL) syslog(LEVEL, "IOQ " FORMAT, __VA_ARGS__)
186
187 #define EVQM_syslog(LEVEL, FORMAT)                      \
188         EDBGLOG (LEVEL) syslog(LEVEL, "IO " FORMAT)
189
190 #define EV_syslog(LEVEL, FORMAT, ...)                                   \
191         EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID, __VA_ARGS__)
192
193 #define EVM_syslog(LEVEL, FORMAT)                                       \
194         EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID)
195
196 #define EVNC_syslog(LEVEL, FORMAT, ...)                                 \
197         EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld] " FORMAT, IO->ID, __VA_ARGS__)
198
199 #define EVNCM_syslog(LEVEL, FORMAT) EDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]" FORMAT, IO->ID)
200
201
202 #define CDBGLOG() if (DebugCAres != 0)
203 #define CEDBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (DebugCAres != 0))
204 #define EV_DNS_LOG_START(a)                                                     \
205         CDBGLOG () {syslog(LOG_DEBUG, "IO[%ld]CC[%d] + Starting " #a " %s %p FD %d", IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \
206                     EV_backtrace(IO);}
207
208 #define EV_DNS_LOG_STOP(a)                                                      \
209         CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] - Stopping " #a " %s %p FD %d", IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \
210                      EV_backtrace(IO);}
211
212 #define EV_DNS_LOG_INIT(a)                                                      \
213         CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] * Init " #a " %s %p FD %d", IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \
214                      EV_backtrace(IO);}
215
216 #define EV_DNS_LOGT_START(a)                                                    \
217         CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] + Starting " #a " %s %p", IO->ID, CCID, __FUNCTION__, &IO->a); \
218                      EV_backtrace(IO);}
219
220 #define EV_DNS_LOGT_STOP(a)                                                     \
221         CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] - Stopping " #a " %s %p", IO->ID, CCID, __FUNCTION__, &IO->a); \
222                      EV_backtrace(IO); }
223
224 #define EV_DNS_LOGT_INIT(a)                                                     \
225         CDBGLOG () { syslog(LOG_DEBUG, "IO[%ld]CC[%d] * Init " #a " %p", IO->ID, CCID, &IO->a); \
226                      EV_backtrace(IO);}
227
228 #define EV_DNS_syslog(LEVEL, FORMAT, ...)                               \
229         CEDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID, __VA_ARGS__)
230
231 #define EVM_DNS_syslog(LEVEL, FORMAT)                                   \
232         CEDBGLOG (LEVEL) syslog(LEVEL, "IO[%ld]CC[%d] " FORMAT, IO->ID, CCID)
233
234 void FreeAsyncIOContents(AsyncIO *IO);
235
236 eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB);
237 eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB);
238 void StopDBWatchers(AsyncIO *IO);
239 eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB);
240 eNextState QueueCurlContext(AsyncIO *IO);
241
242 eNextState EvConnectSock(AsyncIO *IO,
243                          double conn_timeout,
244                          double first_rw_timeout,
245                          int ReadFirst);
246 void IO_postdns_callback(struct ev_loop *loop, ev_idle *watcher, int revents);
247
248 int QueueQuery(ns_type Type,
249                const char *name,
250                AsyncIO *IO,
251                DNSQueryParts *QueryParts,
252                IO_CallBack PostDNS);
253
254 void QueueGetHostByName(AsyncIO *IO,
255                         const char *Hostname,
256                         DNSQueryParts *QueryParts,
257                         IO_CallBack PostDNS);
258
259 void QueryCbDone(AsyncIO *IO);
260
261 void StopClient(AsyncIO *IO);
262
263 void StopClientWatchers(AsyncIO *IO, int CloseFD);
264
265 void SetNextTimeout(AsyncIO *IO, double timeout);
266
267 #include <curl/curl.h>
268
269 #define OPT(s, v) \
270         do { \
271                 sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v));       \
272                 if (sta)  {                                             \
273                         EVQ_syslog(LOG_ERR,                             \
274                                "error setting option " #s               \
275                                " on curl handle: %s",                   \
276                                curl_easy_strerror(sta));                \
277         } } while (0)
278
279 void InitIOStruct(AsyncIO *IO,
280                   void *Data,
281                   eNextState NextState,
282                   IO_LineReaderCallback LineReader,
283                   IO_CallBack DNS_Fail,
284                   IO_CallBack SendDone,
285                   IO_CallBack ReadDone,
286                   IO_CallBack Terminate,
287                   IO_CallBack DBTerminate,
288                   IO_CallBack ConnFail,
289                   IO_CallBack Timeout,
290                   IO_CallBack ShutdownAbort);
291
292 int InitcURLIOStruct(AsyncIO *IO,
293                      void *Data,
294                      const char* Desc,
295                      IO_CallBack SendDone,
296                      IO_CallBack Terminate,
297                      IO_CallBack DBTerminate,
298                      IO_CallBack ShutdownAbort);
299
300 void StopCurlWatchers(AsyncIO *IO);
301
302
303 eNextState ReAttachIO(AsyncIO *IO,
304                       void *pData,
305                       int ReadFirst);
306
307 void EV_backtrace(AsyncIO *IO);
308 ev_tstamp ctdl_ev_now (void);
309
310 #endif /* __EVENT_CLIENT_H__ */