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