rename InitEventIO to EvConnectSock, since this suits better what this function does...
[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 /* DNS Related */
82 typedef struct __evcares_data {
83         ev_io recv_event, 
84                 send_event;
85         ev_timer timeout;           /* timeout while requesting ips */
86 #ifdef DEBUG_CARES
87         short int SourcePort;
88 #endif
89         struct ares_options Options;
90         ares_channel Channel;
91         DNSQueryParts *Query;
92         
93         IO_CallBack Fail;      /* the dns lookup didn't work out. */
94 } evcares_data;
95
96 struct AsyncIO {
97         long ID;
98         eNextState NextState;
99
100         /* connection related */
101         ParsedURL *ConnectMe;
102         
103         /* read/send related... */
104         StrBuf *IOBuf;
105         IOBuffer SendBuf, 
106                 RecvBuf;
107
108         FDIOBuffer IOB; /* when sending from / reading into files, this is used. */
109
110         /* our events... */
111         ev_cleanup abort_by_shutdown, /* server wants to go down... */
112                 db_abort_by_shutdown; /* server wants to go down... */
113         ev_timer conn_fail,           /* connection establishing timed out */
114                 rw_timeout;           /* timeout while sending data */
115         ev_idle unwind_stack,         /* get c-ares out of the stack */
116                 db_unwind_stack,      /* wait for next db operation... */
117                 conn_fail_immediate;  /* unwind stack, but fail immediately. */
118         ev_io recv_event,             /* receive data from the client */
119                 send_event,           /* send more data to the client */
120                 conn_event;           /* Connection successfully established */
121
122         StrBuf *ErrMsg; /* if we fail to connect, or lookup, error goes here. */
123
124         /* Citadel application callbacks... */
125         IO_CallBack ReadDone, /* Theres new data to read... */
126                 SendDone,     /* we may send more data */
127                 Terminate,    /* shutting down... */
128                 Timeout,      /* Timeout handler; may also be connection timeout */
129                 ConnFail,     /* What to do when one connection failed? */
130                 ShutdownAbort,/* we're going down. make your piece. */ 
131                 NextDBOperation; /* Perform Database IO */
132
133         IO_LineReaderCallback LineReader; /* if we have linereaders, maybe we want to read more lines before the real application logic is called? */
134
135         evcares_data DNS;
136
137         evcurl_request_data HttpReq;
138
139         /* Saving / loading a message async from / to disk */
140         ReadAsyncMsg *ReadMsg;
141         struct CtdlMessage *AsyncMsg;
142         struct recptypes *AsyncRcp;
143
144         /* Custom data; its expected to contain  AsyncIO so we can save malloc()s... */
145         void *Data;        /* application specific data */
146         void *CitContext;  /* Citadel Session context... */
147 };
148
149 typedef struct _IOAddHandler {
150         AsyncIO *IO;
151         IO_CallBack EvAttch;
152 }IOAddHandler; 
153
154 #define CCID ((CitContext*)IO->CitContext)->cs_pid
155 #define EV_syslog(LEVEL, FORMAT, ...) syslog(LEVEL, "IO[%ld]CC[%d]" FORMAT, IO->ID, CCID, __VA_ARGS__)
156 #define EVM_syslog(LEVEL, FORMAT) syslog(LEVEL, "IO[%ld]CC[%d]" FORMAT, IO->ID, CCID)
157
158 #define EVNC_syslog(LEVEL, FORMAT, ...) syslog(LEVEL, "IO[%ld]" FORMAT, IO->ID, __VA_ARGS__)
159 #define EVNCM_syslog(LEVEL, FORMAT) syslog(LEVEL, "IO[%ld]" FORMAT, IO->ID)
160
161 void FreeAsyncIOContents(AsyncIO *IO);
162
163 eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB);
164 eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB);
165 eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB);
166 eNextState QueueCurlContext(AsyncIO *IO);
167
168 eNextState EvConnectSock(AsyncIO *IO, 
169                          void *pData, 
170                          double conn_timeout, 
171                          double first_rw_timeout,
172                          int ReadFirst);
173 void IO_postdns_callback(struct ev_loop *loop, ev_idle *watcher, int revents);
174
175 int QueueQuery(ns_type Type, const char *name, AsyncIO *IO, DNSQueryParts *QueryParts, IO_CallBack PostDNS);
176 void QueueGetHostByName(AsyncIO *IO, const char *Hostname, DNSQueryParts *QueryParts, IO_CallBack PostDNS);
177
178 void QueryCbDone(AsyncIO *IO);
179
180 void StopClient(AsyncIO *IO);
181
182 void StopClientWatchers(AsyncIO *IO);
183
184 void SetNextTimeout(AsyncIO *IO, double timeout);
185
186 void InitC_ares_dns(AsyncIO *IO);
187
188 #include <curl/curl.h>
189
190 #define OPT(s, v) \
191         do { \
192                 sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v)); \
193                 if (sta)  {                                             \
194                         syslog(LOG_ERR, "error setting option " #s " on curl handle: %s", curl_easy_strerror(sta)); \
195         } } while (0)
196
197 int evcurl_init(AsyncIO *IO,
198                 void *CustomData,
199                 const char* Desc,
200                 IO_CallBack CallBack,
201                 IO_CallBack Terminate, 
202                 IO_CallBack ShutdownAbort);
203
204 eNextState ReAttachIO(AsyncIO *IO, 
205                       void *pData, 
206                       int ReadFirst);
207
208 #endif /* __EVENT_CLIENT_H__ */