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