async_sock: Map ASYNC_REQ_TIMEOUT to ETIMEDOUT instead of ETIME
[ira/wip.git] / lib / async_req / async_req.c
1 /*
2    Unix SMB/CIFS implementation.
3    Infrastructure for async requests
4    Copyright (C) Volker Lendecke 2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "lib/tevent/tevent.h"
22 #include "lib/talloc/talloc.h"
23 #include "lib/util/dlinklist.h"
24 #include "lib/async_req/async_req.h"
25
26 #ifndef TALLOC_FREE
27 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
28 #endif
29
30 /**
31  * @brief Print an async_req structure
32  * @param[in] mem_ctx   The memory context for the result
33  * @param[in] req       The request to be printed
34  * @retval              Text representation of req
35  *
36  * This is a default print function for async requests. Implementations should
37  * override this with more specific information.
38  *
39  * This function should not be used by async API users, this is non-static
40  * only to allow implementations to easily provide default information in
41  * their specific functions.
42  */
43
44 char *async_req_print(TALLOC_CTX *mem_ctx, struct async_req *req)
45 {
46         return talloc_asprintf(mem_ctx, "async_req: state=%d, error=%d, "
47                                "priv=%s", req->state, (int)req->error,
48                                talloc_get_name(req->private_data));
49 }
50
51 /**
52  * @brief Create an async request
53  * @param[in] mem_ctx   The memory context for the result
54  * @param[in] ev        The event context this async request will be driven by
55  * @retval              A new async request
56  *
57  * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
58  */
59
60 struct async_req *async_req_new(TALLOC_CTX *mem_ctx)
61 {
62         struct async_req *result;
63
64         result = talloc_zero(mem_ctx, struct async_req);
65         if (result == NULL) {
66                 return NULL;
67         }
68         result->state = ASYNC_REQ_IN_PROGRESS;
69         result->print = async_req_print;
70         return result;
71 }
72
73 static void async_req_finish(struct async_req *req, enum async_req_state state)
74 {
75         req->state = state;
76         if (req->async.fn != NULL) {
77                 req->async.fn(req);
78         }
79 }
80
81 /**
82  * @brief An async request has successfully finished
83  * @param[in] req       The finished request
84  *
85  * async_req_done is to be used by implementors of async requests. When a
86  * request is successfully finished, this function calls the user's completion
87  * function.
88  */
89
90 void async_req_done(struct async_req *req)
91 {
92         async_req_finish(req, ASYNC_REQ_DONE);
93 }
94
95 /**
96  * @brief An async request has seen an error
97  * @param[in] req       The request with an error
98  * @param[in] error     The error code
99  *
100  * async_req_done is to be used by implementors of async requests. When a
101  * request can not successfully completed, the implementation should call this
102  * function with the appropriate status code.
103  */
104
105 void async_req_error(struct async_req *req, uint64_t error)
106 {
107         req->error = error;
108         async_req_finish(req, ASYNC_REQ_USER_ERROR);
109 }
110
111 /**
112  * @brief Timed event callback
113  * @param[in] ev        Event context
114  * @param[in] te        The timed event
115  * @param[in] now       zero time
116  * @param[in] priv      The async request to be finished
117  */
118
119 static void async_trigger(struct tevent_context *ev, struct tevent_timer *te,
120                           struct timeval now, void *priv)
121 {
122         struct async_req *req = talloc_get_type_abort(priv, struct async_req);
123
124         TALLOC_FREE(te);
125         if (req->error == 0) {
126                 async_req_done(req);
127         }
128         else {
129                 async_req_error(req, req->error);
130         }
131 }
132
133 /**
134  * @brief Helper function for nomem check
135  * @param[in] p         The pointer to be checked
136  * @param[in] req       The request being processed
137  *
138  * Convenience helper to easily check alloc failure within a callback
139  * implementing the next step of an async request.
140  *
141  * Call pattern would be
142  * \code
143  * p = talloc(mem_ctx, bla);
144  * if (async_req_ntnomem(p, req)) {
145  *      return;
146  * }
147  * \endcode
148  */
149
150 bool async_req_nomem(const void *p, struct async_req *req)
151 {
152         if (p != NULL) {
153                 return false;
154         }
155         async_req_finish(req, ASYNC_REQ_NO_MEMORY);
156         return true;
157 }
158
159 /**
160  * @brief Finish a request before it started processing
161  * @param[in] req       The finished request
162  * @param[in] status    The success code
163  *
164  * An implementation of an async request might find that it can either finish
165  * the request without waiting for an external event, or it can't even start
166  * the engine. To present the illusion of a callback to the user of the API,
167  * the implementation can call this helper function which triggers an
168  * immediate timed event. This way the caller can use the same calling
169  * conventions, independent of whether the request was actually deferred.
170  */
171
172 bool async_post_error(struct async_req *req, struct tevent_context *ev,
173                       uint64_t error)
174 {
175         req->error = error;
176
177         if (tevent_add_timer(ev, req, timeval_zero(),
178                             async_trigger, req) == NULL) {
179                 return false;
180         }
181         return true;
182 }
183
184 bool async_req_is_error(struct async_req *req, enum async_req_state *state,
185                         uint64_t *error)
186 {
187         if (req->state == ASYNC_REQ_DONE) {
188                 return false;
189         }
190         if (req->state == ASYNC_REQ_USER_ERROR) {
191                 *error = req->error;
192         }
193         *state = req->state;
194         return true;
195 }
196
197 static void async_req_timedout(struct tevent_context *ev,
198                                struct tevent_timer *te,
199                                struct timeval now,
200                                void *priv)
201 {
202         struct async_req *req = talloc_get_type_abort(priv, struct async_req);
203         TALLOC_FREE(te);
204         async_req_finish(req, ASYNC_REQ_TIMED_OUT);
205 }
206
207 bool async_req_set_timeout(struct async_req *req, struct tevent_context *ev,
208                            struct timeval to)
209 {
210         return (tevent_add_timer(
211                         ev, req, timeval_current_ofs(to.tv_sec, to.tv_usec),
212                         async_req_timedout, req)
213                 != NULL);
214 }
215
216 struct async_req *async_wait_send(TALLOC_CTX *mem_ctx,
217                                   struct tevent_context *ev,
218                                   struct timeval to)
219 {
220         struct async_req *result;
221
222         result = async_req_new(mem_ctx);
223         if (result == NULL) {
224                 return result;
225         }
226         if (!async_req_set_timeout(result, ev, to)) {
227                 TALLOC_FREE(result);
228                 return NULL;
229         }
230         return result;
231 }
232
233 bool async_wait_recv(struct async_req *req)
234 {
235         return true;
236 }
237
238 struct async_queue_entry {
239         struct async_queue_entry *prev, *next;
240         struct async_req_queue *queue;
241         struct async_req *req;
242         void (*trigger)(struct async_req *req);
243 };
244
245 struct async_req_queue {
246         struct async_queue_entry *queue;
247 };
248
249 struct async_req_queue *async_req_queue_init(TALLOC_CTX *mem_ctx)
250 {
251         return talloc_zero(mem_ctx, struct async_req_queue);
252 }
253
254 static int async_queue_entry_destructor(struct async_queue_entry *e)
255 {
256         struct async_req_queue *queue = e->queue;
257
258         DLIST_REMOVE(queue->queue, e);
259
260         if (queue->queue != NULL) {
261                 queue->queue->trigger(queue->queue->req);
262         }
263
264         return 0;
265 }
266
267 static void async_req_immediate_trigger(struct tevent_context *ev,
268                                         struct tevent_timer *te,
269                                         struct timeval now,
270                                         void *priv)
271 {
272         struct async_queue_entry *e = talloc_get_type_abort(
273                 priv, struct async_queue_entry);
274
275         TALLOC_FREE(te);
276         e->trigger(e->req);
277 }
278
279 bool async_req_enqueue(struct async_req_queue *queue, struct tevent_context *ev,
280                        struct async_req *req,
281                        void (*trigger)(struct async_req *req))
282 {
283         struct async_queue_entry *e;
284         bool busy;
285
286         busy = (queue->queue != NULL);
287
288         e = talloc(req, struct async_queue_entry);
289         if (e == NULL) {
290                 return false;
291         }
292
293         e->req = req;
294         e->trigger = trigger;
295         e->queue = queue;
296
297         DLIST_ADD_END(queue->queue, e, struct async_queue_entry *);
298         talloc_set_destructor(e, async_queue_entry_destructor);
299
300         if (!busy) {
301                 struct tevent_timer *te;
302
303                 te = tevent_add_timer(ev, e, timeval_zero(),
304                                      async_req_immediate_trigger,
305                                      e);
306                 if (te == NULL) {
307                         TALLOC_FREE(e);
308                         return false;
309                 }
310         }
311
312         return true;
313 }
314
315 bool _async_req_setup(TALLOC_CTX *mem_ctx, struct async_req **preq,
316                       void *pstate, size_t state_size, const char *typename)
317 {
318         struct async_req *req;
319         void **ppstate = (void **)pstate;
320         void *state;
321
322         req = async_req_new(mem_ctx);
323         if (req == NULL) {
324                 return false;
325         }
326         state = talloc_size(req, state_size);
327         if (state == NULL) {
328                 TALLOC_FREE(req);
329                 return false;
330         }
331         talloc_set_name_const(state, typename);
332         req->private_data = state;
333
334         *preq = req;
335         *ppstate = state;
336
337         return true;
338 }