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