aboutsummaryrefslogtreecommitdiff
path: root/src/lib/util/op.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/op.c')
-rw-r--r--src/lib/util/op.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/src/lib/util/op.c b/src/lib/util/op.c
new file mode 100644
index 000000000..a8fc3de4a
--- /dev/null
+++ b/src/lib/util/op.c
@@ -0,0 +1,335 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file
23 * Asynchronous operations; register callbacks for operations and call them when a response arrives.
24 *
25 * @author Gabor X Toth
26 */
27
28#include "platform.h"
29#include <inttypes.h>
30
31
32#include "gnunet_util_lib.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "util-op", __VA_ARGS__)
35
36struct OperationListItem
37{
38 struct OperationListItem *prev;
39 struct OperationListItem *next;
40
41 /**
42 * Operation ID.
43 */
44 uint64_t op_id;
45
46 /**
47 * Continuation to invoke with the result of an operation.
48 */
49 GNUNET_ResultCallback result_cb;
50
51 /**
52 * Closure for @a result_cb.
53 */
54 void *cls;
55
56 /**
57 * User context.
58 */
59 void *ctx;
60};
61
62
63/**
64 * Operations handle.
65 */
66
67struct GNUNET_OP_Handle
68{
69 /**
70 * First operation in the linked list.
71 */
72 struct OperationListItem *op_head;
73
74 /**
75 * Last operation in the linked list.
76 */
77 struct OperationListItem *op_tail;
78
79 /**
80 * Last operation ID used.
81 */
82 uint64_t last_op_id;
83};
84
85
86/**
87 * Create new operations handle.
88 */
89struct GNUNET_OP_Handle *
90GNUNET_OP_create ()
91{
92 return GNUNET_new (struct GNUNET_OP_Handle);
93}
94
95
96/**
97 * Destroy operations handle.
98 */
99void
100GNUNET_OP_destroy (struct GNUNET_OP_Handle *h)
101{
102 GNUNET_free (h);
103}
104
105
106/**
107 * Get a unique operation ID to distinguish between asynchronous requests.
108 *
109 * @param h
110 * Operations handle.
111 *
112 * @return Operation ID to use.
113 */
114uint64_t
115GNUNET_OP_get_next_id (struct GNUNET_OP_Handle *h)
116{
117 return ++h->last_op_id;
118}
119
120
121/**
122 * Find operation by ID.
123 *
124 * @param h
125 * Operations handle.
126 * @param op_id
127 * Operation ID to look up.
128 *
129 * @return Operation, or NULL if not found.
130 */
131static struct OperationListItem *
132op_find (struct GNUNET_OP_Handle *h,
133 uint64_t op_id)
134{
135 struct OperationListItem *op;
136
137 for (op = h->op_head; NULL != op; op = op->next)
138 if (op->op_id == op_id)
139 return op;
140 return NULL;
141}
142
143
144/**
145 * Find operation by ID.
146 *
147 * @param h
148 * Operations handle.
149 * @param op_id
150 * Operation ID to look up.
151 * @param[out] result_cb
152 * If an operation was found, its result callback is returned here.
153 * @param[out] cls
154 * If an operation was found, its closure is returned here.
155 * @param[out] ctx
156 * If an operation was found, its user context is returned here.
157 *
158 * @return #GNUNET_YES if an operation was found,
159 * #GNUNET_NO if not found.
160 */
161int
162GNUNET_OP_get (struct GNUNET_OP_Handle *h,
163 uint64_t op_id,
164 GNUNET_ResultCallback *result_cb,
165 void **cls,
166 void **ctx)
167{
168 struct OperationListItem *op = op_find (h, op_id);
169
170 if (NULL != op)
171 {
172 if (NULL != result_cb)
173 *result_cb = op->result_cb;
174 if (NULL != cls)
175 *cls = op->cls;
176 if (NULL != ctx)
177 *ctx = op->ctx;
178 return GNUNET_YES;
179 }
180 return GNUNET_NO;
181}
182
183
184/**
185 * Add a new operation.
186 *
187 * @param h
188 * Operations handle.
189 * @param result_cb
190 * Function to call with the result of the operation.
191 * @param cls
192 * Closure for @a result_cb.
193 * @param ctx
194 * User context.
195 *
196 * @return ID of the new operation.
197 */
198uint64_t
199GNUNET_OP_add (struct GNUNET_OP_Handle *h,
200 GNUNET_ResultCallback result_cb,
201 void *cls,
202 void *ctx)
203{
204 struct OperationListItem *op;
205
206 op = GNUNET_new (struct OperationListItem);
207 op->op_id = GNUNET_OP_get_next_id (h);
208 op->result_cb = result_cb;
209 op->cls = cls;
210 op->ctx = ctx;
211 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
212 h->op_tail,
213 op);
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
215 "%p Added operation #%" PRIu64 "\n",
216 h, op->op_id);
217 return op->op_id;
218}
219
220
221/**
222 * Remove an operation, and call its result callback (unless it was cancelled).
223 *
224 *
225 * @param h
226 * Operations handle.
227 * @param op_id
228 * Operation ID.
229 * @param result_code
230 * Result of the operation.
231 * @param data
232 * Data result of the operation.
233 * @param data_size
234 * Size of @a data.
235 * @param[out] ctx
236 * User context.
237 * @param cancel
238 * Is the operation cancelled?
239 * #GNUNET_NO Not cancelled, result callback is called.
240 * #GNUNET_YES Cancelled, result callback is not called.
241 *
242 * @return #GNUNET_YES if the operation was found and removed,
243 * #GNUNET_NO if the operation was not found.
244 */
245static int
246op_result (struct GNUNET_OP_Handle *h,
247 uint64_t op_id,
248 int64_t result_code,
249 const void *data,
250 uint16_t data_size,
251 void **ctx,
252 uint8_t cancel)
253{
254 if (0 == op_id)
255 return GNUNET_NO;
256
257 struct OperationListItem *op = op_find (h, op_id);
258 if (NULL == op)
259 {
260 LOG (GNUNET_ERROR_TYPE_WARNING,
261 "Could not find operation #%" PRIu64 "\n", op_id);
262 return GNUNET_NO;
263 }
264
265 if (NULL != ctx)
266 *ctx = op->ctx;
267
268 GNUNET_CONTAINER_DLL_remove (h->op_head,
269 h->op_tail,
270 op);
271
272 if ((GNUNET_YES != cancel) &&
273 (NULL != op->result_cb))
274 op->result_cb (op->cls,
275 result_code, data,
276 data_size);
277 GNUNET_free (op);
278 return GNUNET_YES;
279}
280
281
282/**
283 * Call the result callback of an operation and remove it.
284 *
285 * @param h
286 * Operations handle.
287 * @param op_id
288 * Operation ID.
289 * @param result_code
290 * Result of the operation.
291 * @param data
292 * Data result of the operation.
293 * @param data_size
294 * Size of @a data.
295 * @param[out] ctx
296 * User context.
297 *
298 * @return #GNUNET_YES if the operation was found and removed,
299 * #GNUNET_NO if the operation was not found.
300 */
301int
302GNUNET_OP_result (struct GNUNET_OP_Handle *h,
303 uint64_t op_id,
304 int64_t result_code,
305 const void *data,
306 uint16_t data_size,
307 void **ctx)
308{
309 LOG (GNUNET_ERROR_TYPE_DEBUG,
310 "%p Received result for operation #%" PRIu64 ": %" PRId64 " (size: %u)\n",
311 h, op_id, result_code, data_size);
312 return op_result (h, op_id, result_code, data, data_size, ctx, GNUNET_NO);
313}
314
315
316/**
317 * Remove / cancel an operation.
318 *
319 * @param h
320 * Operations handle.
321 * @param op_id
322 * Operation ID.
323 *
324 * @return #GNUNET_YES if the operation was found and removed,
325 * #GNUNET_NO if the operation was not found.
326 */
327int
328GNUNET_OP_remove (struct GNUNET_OP_Handle *h,
329 uint64_t op_id)
330{
331 LOG (GNUNET_ERROR_TYPE_DEBUG,
332 "%p Cancelling operation #%" PRIu64 "\n",
333 h, op_id);
334 return op_result (h, op_id, 0, NULL, 0, NULL, GNUNET_YES);
335}