e0cd0bec0f30a6e0974c2cce93076fcf2de761f1
[sfrench/samba-autobuild/.git] / lib / tevent / tevent_req.c
1 /*
2    Unix SMB/CIFS implementation.
3    Infrastructure for async requests
4    Copyright (C) Volker Lendecke 2008
5    Copyright (C) Stefan Metzmacher 2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "replace.h"
22 #include "tevent.h"
23 #include "tevent_internal.h"
24 #include "tevent_util.h"
25
26 /**
27  * @brief Print an tevent_req structure in debug messages
28  * @param[in] mem_ctx   The memory context for the result
29  * @param[in] req       The request to be printed
30  * @retval              Text representation of req
31  *
32  */
33
34 char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
35 {
36         return talloc_asprintf(mem_ctx,
37                                "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
38                                " state[%s (%p)] timer[%p]",
39                                req, req->internal.location,
40                                req->internal.state,
41                                (unsigned long long)req->internal.error,
42                                (unsigned long long)req->internal.error,
43                                talloc_get_name(req->private_state),
44                                req->private_state,
45                                req->internal.timer
46                                );
47 }
48
49 /**
50  * @brief Create an async request
51  * @param[in] mem_ctx   The memory context for the result
52  * @param[in] ev        The event context this async request will be driven by
53  * @retval              A new async request
54  *
55  * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
56  */
57
58 struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
59                                     void *pstate,
60                                     size_t state_size,
61                                     const char *type,
62                                     const char *location)
63 {
64         struct tevent_req *req;
65         void **ppstate = (void **)pstate;
66         void *state;
67
68         req = talloc_zero(mem_ctx, struct tevent_req);
69         if (req == NULL) {
70                 return NULL;
71         }
72         req->internal.private_type      = type;
73         req->internal.location          = location;
74         req->internal.state             = TEVENT_REQ_IN_PROGRESS;
75
76         state = talloc_size(req, state_size);
77         if (state == NULL) {
78                 talloc_free(req);
79                 return NULL;
80         }
81         talloc_set_name_const(state, type);
82
83         req->private_state = state;
84
85         *ppstate = state;
86         return req;
87 }
88
89 static void tevent_req_finish(struct tevent_req *req, enum tevent_req_state state)
90 {
91         req->internal.state = state;
92         if (req->async.fn != NULL) {
93                 req->async.fn(req);
94         }
95 }
96
97 /**
98  * @brief An async request has successfully finished
99  * @param[in] req       The finished request
100  *
101  * async_req_done is to be used by implementors of async requests. When a
102  * request is successfully finished, this function calls the user's completion
103  * function.
104  */
105
106 void tevent_req_done(struct tevent_req *req)
107 {
108         tevent_req_finish(req, TEVENT_REQ_DONE);
109 }
110
111 /**
112  * @brief An async request has seen an error
113  * @param[in] req       The request with an error
114  * @param[in] error     The error code
115  *
116  * tevent_req_done is to be used by implementors of async requests. When a
117  * request can not successfully completed, the implementation should call this
118  * function with the appropriate status code.
119  *
120  * If error is 0 the function returns false and does nothing more.
121  *
122  * Call pattern would be
123  * \code
124  * int error = first_function();
125  * if (tevent_req_error(req, error)) {
126  *      return;
127  * }
128  *
129  * error = second_function();
130  * if (tevent_req_error(req, error)) {
131  *      return;
132  * }
133  *
134  * tevent_req_done(req);
135  * return;
136  * \endcode
137  */
138
139 bool tevent_req_error(struct tevent_req *req, uint64_t error)
140 {
141         if (error == 0) {
142                 return false;
143         }
144
145         req->internal.error = error;
146         tevent_req_finish(req, TEVENT_REQ_USER_ERROR);
147         return true;
148 }
149
150 /**
151  * @brief Helper function for nomem check
152  * @param[in] p         The pointer to be checked
153  * @param[in] req       The request being processed
154  *
155  * Convenience helper to easily check alloc failure within a callback
156  * implementing the next step of an async request.
157  *
158  * Call pattern would be
159  * \code
160  * p = talloc(mem_ctx, bla);
161  * if (tevent_req_nomem(p, req)) {
162  *      return;
163  * }
164  * \endcode
165  */
166
167 bool tevent_req_nomem(const void *p, struct tevent_req *req)
168 {
169         if (p != NULL) {
170                 return false;
171         }
172         tevent_req_finish(req, TEVENT_REQ_NO_MEMORY);
173         return true;
174 }
175
176 /**
177  * @brief Timed event callback
178  * @param[in] ev        Event context
179  * @param[in] te        The timed event
180  * @param[in] now       zero time
181  * @param[in] priv      The async request to be finished
182  */
183 static void tevent_req_trigger(struct tevent_context *ev,
184                                struct tevent_timer *te,
185                                struct timeval zero,
186                                void *private_data)
187 {
188         struct tevent_req *req = talloc_get_type(private_data,
189                                  struct tevent_req);
190
191         talloc_free(req->internal.trigger);
192         req->internal.trigger = NULL;
193
194         tevent_req_finish(req, req->internal.state);
195 }
196
197 /**
198  * @brief Finish a request before the caller had the change to set the callback
199  * @param[in] req       The finished request
200  * @param[in] ev        The tevent_context for the timed event
201  * @retval              On success req will be returned,
202  *                      on failure req will be destroyed
203  *
204  * An implementation of an async request might find that it can either finish
205  * the request without waiting for an external event, or it can't even start
206  * the engine. To present the illusion of a callback to the user of the API,
207  * the implementation can call this helper function which triggers an
208  * immediate timed event. This way the caller can use the same calling
209  * conventions, independent of whether the request was actually deferred.
210  */
211
212 struct tevent_req *tevent_req_post(struct tevent_req *req,
213                                    struct tevent_context *ev)
214 {
215         req->internal.trigger = tevent_add_timer(ev, req, ev_timeval_zero(),
216                                                  tevent_req_trigger, req);
217         if (!req->internal.trigger) {
218                 talloc_free(req);
219                 return NULL;
220         }
221
222         return req;
223 }
224
225 bool tevent_req_is_in_progress(struct tevent_req *req)
226 {
227         if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
228                 return true;
229         }
230
231         return false;
232 }
233
234 bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
235                         uint64_t *error)
236 {
237         if (req->internal.state == TEVENT_REQ_DONE) {
238                 return false;
239         }
240         if (req->internal.state == TEVENT_REQ_USER_ERROR) {
241                 *error = req->internal.error;
242         }
243         *state = req->internal.state;
244         return true;
245 }
246
247 static void tevent_req_timedout(struct tevent_context *ev,
248                                struct tevent_timer *te,
249                                struct timeval now,
250                                void *private_data)
251 {
252         struct tevent_req *req = talloc_get_type(private_data,
253                                  struct tevent_req);
254
255         talloc_free(req->internal.timer);
256         req->internal.timer = NULL;
257
258         tevent_req_finish(req, TEVENT_REQ_TIMED_OUT);
259 }
260
261 bool tevent_req_set_timeout(struct tevent_req *req,
262                             struct tevent_context *ev,
263                             struct timeval endtime)
264 {
265         talloc_free(req->internal.timer);
266
267         req->internal.timer = tevent_add_timer(ev, req, endtime,
268                                                tevent_req_timedout,
269                                                req);
270         if (tevent_req_nomem(req->internal.timer, req)) {
271                 return false;
272         }
273
274         return true;
275 }
276