ea68053d295bdd9cce9d9607f411824dfb344d6f
[citadel.git] / citadel / event_client.h
1 #ifndef __EVENT_CLIENT_H__
2 #define __EVENT_CLIENT_H__
3 #define EV_COMPAT3 0
4 #include "sysconfig.h"
5 #include <ev.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netdb.h>
9 #include <arpa/nameser.h>
10 #include <ares.h>
11 #include <curl/curl.h>
12
13 typedef struct AsyncIO AsyncIO;
14
15 typedef enum _eNextState {
16         eSendDNSQuery,
17         eReadDNSReply,
18
19         eDBQuery,
20
21         eConnect,
22         eSendReply, 
23         eSendMore,
24         eSendFile,
25
26         eReadMessage, 
27         eReadMore,
28         eReadPayload,
29         eReadFile,
30
31         eTerminateConnection,
32         eAbort
33 }eNextState;
34
35 typedef eNextState (*IO_CallBack)(AsyncIO *IO);
36 typedef eReadState (*IO_LineReaderCallback)(AsyncIO *IO);
37 typedef void (*ParseDNSAnswerCb)(AsyncIO*, unsigned char*, int);
38 typedef void (*FreeDNSReply)(void *DNSData);
39
40
41 typedef struct __ReadAsyncMsg {
42         StrBuf *MsgBuf;
43         size_t maxlen;          /* maximum message length */
44
45         const char *terminator; /* token signalling EOT */
46         long tlen;
47         int dodot;
48
49         int flushing;           /* if we read maxlen, read until nothing more arives and ignore this. */
50
51         int crlf;               /* CRLF newlines instead of LF */
52 } ReadAsyncMsg;
53
54
55 typedef struct _DNSQueryParts {
56         ParseDNSAnswerCb DNS_CB;
57         IO_CallBack PostDNS;
58
59         int DNSStatus;
60         void *VParsedDNSReply;
61         FreeDNSReply DNSReplyFree;
62         void *Data;
63 } DNSQueryParts;
64
65 typedef struct _evcurl_request_data 
66 {
67         CURL              *chnd;
68         struct curl_slist *headers;
69         char               errdesc[CURL_ERROR_SIZE];
70
71         int                attached;
72
73         char              *PlainPostData;
74         long               PlainPostDataLen;
75         StrBuf            *PostData;
76
77         StrBuf            *ReplyData;
78         long               httpcode;
79 } evcurl_request_data;
80
81 struct AsyncIO {
82         long ID;
83         eNextState NextState;
84
85         /* connection related */
86         ParsedURL *ConnectMe;
87         
88         /* read/send related... */
89         StrBuf *IOBuf;
90         IOBuffer SendBuf, 
91                 RecvBuf;
92
93         FDIOBuffer IOB; /* when sending from / reading into files, this is used. */
94
95         /* our events... */
96         ev_cleanup abort_by_shutdown, /* server wants to go down... */
97                 db_abort_by_shutdown; /* server wants to go down... */
98         ev_timer conn_fail,           /* connection establishing timed out */
99                 rw_timeout;           /* timeout while sending data */
100         ev_idle unwind_stack,         /* get c-ares out of the stack */
101                 db_unwind_stack,      /* wait for next db operation... */
102                 conn_fail_immediate;  /* unwind stack, but fail immediately. */
103         ev_io recv_event,             /* receive data from the client */
104                 send_event,           /* send more data to the client */
105                 conn_event;           /* Connection successfully established */
106
107         StrBuf *ErrMsg; /* if we fail to connect, or lookup, error goes here. */
108
109         /* Citadel application callbacks... */
110         IO_CallBack ReadDone, /* Theres new data to read... */
111                 SendDone,     /* we may send more data */
112                 Terminate,    /* shutting down... */
113                 Timeout,      /* Timeout handler; may also be connection timeout */
114                 ConnFail,     /* What to do when one connection failed? */
115                 DNSFail,      /* the dns lookup didn't work out. */
116                 ShutdownAbort,/* we're going down. make your piece. */ 
117                 NextDBOperation; /* Perform Database IO */
118
119         IO_LineReaderCallback LineReader; /* if we have linereaders, maybe we want to read more lines before the real application logic is called? */
120
121         /* DNS Related */
122         ev_io dns_recv_event, 
123                 dns_send_event;
124         ev_timer dns_timeout;           /* timeout while requesting ips */
125 #ifdef DEBUG_CARES
126         short int DnsSourcePort;
127 #endif
128         struct ares_options DNSOptions;
129         ares_channel DNSChannel;
130         DNSQueryParts *DNSQuery;
131         
132         evcurl_request_data HttpReq;
133
134         /* Saving / loading a message async from / to disk */
135         ReadAsyncMsg *ReadMsg;
136         struct CtdlMessage *AsyncMsg;
137         struct recptypes *AsyncRcp;
138
139         /* Custom data; its expected to contain  AsyncIO so we can save malloc()s... */
140         void *Data;        /* application specific data */
141         void *CitContext;  /* Citadel Session context... */
142 };
143
144 typedef struct _IOAddHandler {
145         AsyncIO *IO;
146         IO_CallBack EvAttch;
147 }IOAddHandler; 
148
149 #define CCID ((CitContext*)IO->CitContext)->cs_pid
150 #define EV_syslog(LEVEL, FORMAT, ...) syslog(LEVEL, "IO[%ld]CC[%d]" FORMAT, IO->ID, CCID, __VA_ARGS__)
151 #define EVM_syslog(LEVEL, FORMAT) syslog(LEVEL, "IO[%ld]CC[%d]" FORMAT, IO->ID, CCID)
152
153 #define EVNC_syslog(LEVEL, FORMAT, ...) syslog(LEVEL, "IO[%ld]" FORMAT, IO->ID, __VA_ARGS__)
154 #define EVNCM_syslog(LEVEL, FORMAT) syslog(LEVEL, "IO[%ld]" FORMAT, IO->ID)
155
156 void FreeAsyncIOContents(AsyncIO *IO);
157
158 eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB);
159 eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB);
160 eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB);
161 eNextState QueueCurlContext(AsyncIO *IO);
162 int ShutDownEventQueue(void);
163
164 eNextState InitEventIO(AsyncIO *IO, 
165                        void *pData, 
166                        double conn_timeout, 
167                        double first_rw_timeout,
168                        int ReadFirst);
169 void IO_postdns_callback(struct ev_loop *loop, ev_idle *watcher, int revents);
170
171 int QueueQuery(ns_type Type, const char *name, AsyncIO *IO, DNSQueryParts *QueryParts, IO_CallBack PostDNS);
172 void QueueGetHostByName(AsyncIO *IO, const char *Hostname, DNSQueryParts *QueryParts, IO_CallBack PostDNS);
173
174 void QueryCbDone(AsyncIO *IO);
175
176 void StopClient(AsyncIO *IO);
177
178 void StopClientWatchers(AsyncIO *IO);
179
180 void SetNextTimeout(AsyncIO *IO, double timeout);
181
182 void InitC_ares_dns(AsyncIO *IO);
183
184 #include <curl/curl.h>
185
186 #define OPT(s, v) \
187         do { \
188                 sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v)); \
189                 if (sta)  {                                             \
190                         syslog(LOG_ERR, "error setting option " #s " on curl handle: %s", curl_easy_strerror(sta)); \
191         } } while (0)
192
193 int evcurl_init(AsyncIO *IO,
194                 void *CustomData,
195                 const char* Desc,
196                 IO_CallBack CallBack,
197                 IO_CallBack Terminate, 
198                 IO_CallBack ShutdownAbort);
199
200 eNextState ReAttachIO(AsyncIO *IO, 
201                       void *pData, 
202                       int ReadFirst);
203
204 #endif /* __EVENT_CLIENT_H__ */