2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
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.
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.
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/>.
21 * Asynchronous operations; register callbacks for operations and call them when a response arrives.
23 * @author Gabor X Toth
29 #include "gnunet_util_lib.h"
31 #define LOG(kind,...) GNUNET_log_from (kind, "util-op", __VA_ARGS__)
33 struct OperationListItem
35 struct OperationListItem *prev;
36 struct OperationListItem *next;
44 * Continuation to invoke with the result of an operation.
46 GNUNET_ResultCallback result_cb;
49 * Closure for @a result_cb.
64 struct GNUNET_OP_Handle
67 * First operation in the linked list.
69 struct OperationListItem *op_head;
72 * Last operation in the linked list.
74 struct OperationListItem *op_tail;
77 * Last operation ID used.
84 * Create new operations handle.
86 struct GNUNET_OP_Handle *
89 return GNUNET_new (struct GNUNET_OP_Handle);
94 * Destroy operations handle.
97 GNUNET_OP_destroy (struct GNUNET_OP_Handle *h)
104 * Get a unique operation ID to distinguish between asynchronous requests.
109 * @return Operation ID to use.
112 GNUNET_OP_get_next_id (struct GNUNET_OP_Handle *h)
114 return ++h->last_op_id;
119 * Find operation by ID.
124 * Operation ID to look up.
126 * @return Operation, or NULL if not found.
128 static struct OperationListItem *
129 op_find (struct GNUNET_OP_Handle *h,
132 struct OperationListItem *op;
134 for (op = h->op_head; NULL != op; op = op->next)
135 if (op->op_id == op_id)
142 * Find operation by ID.
147 * Operation ID to look up.
148 * @param[out] result_cb
149 * If an operation was found, its result callback is returned here.
151 * If an operation was found, its closure is returned here.
153 * If an operation was found, its user context is returned here.
155 * @return #GNUNET_YES if an operation was found,
156 * #GNUNET_NO if not found.
159 GNUNET_OP_get (struct GNUNET_OP_Handle *h,
161 GNUNET_ResultCallback *result_cb,
165 struct OperationListItem *op = op_find (h, op_id);
168 if (NULL != result_cb)
169 *result_cb = op->result_cb;
181 * Add a new operation.
186 * Function to call with the result of the operation.
188 * Closure for @a result_cb.
192 * @return ID of the new operation.
195 GNUNET_OP_add (struct GNUNET_OP_Handle *h,
196 GNUNET_ResultCallback result_cb,
200 struct OperationListItem *op;
202 op = GNUNET_new (struct OperationListItem);
203 op->op_id = GNUNET_OP_get_next_id (h);
204 op->result_cb = result_cb;
207 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
210 LOG (GNUNET_ERROR_TYPE_DEBUG,
211 "%p Added operation #%" PRIu64 "\n",
218 * Remove an operation, and call its result callback (unless it was cancelled).
226 * Result of the operation.
228 * Data result of the operation.
234 * Is the operation cancelled?
235 * #GNUNET_NO Not cancelled, result callback is called.
236 * #GNUNET_YES Cancelled, result callback is not called.
238 * @return #GNUNET_YES if the operation was found and removed,
239 * #GNUNET_NO if the operation was not found.
242 op_result (struct GNUNET_OP_Handle *h,
253 struct OperationListItem *op = op_find (h, op_id);
256 LOG (GNUNET_ERROR_TYPE_WARNING,
257 "Could not find operation #%" PRIu64 "\n", op_id);
264 GNUNET_CONTAINER_DLL_remove (h->op_head,
268 if ( (GNUNET_YES != cancel) &&
269 (NULL != op->result_cb) )
270 op->result_cb (op->cls,
279 * Call the result callback of an operation and remove it.
286 * Result of the operation.
288 * Data result of the operation.
294 * @return #GNUNET_YES if the operation was found and removed,
295 * #GNUNET_NO if the operation was not found.
298 GNUNET_OP_result (struct GNUNET_OP_Handle *h,
305 LOG (GNUNET_ERROR_TYPE_DEBUG,
306 "%p Received result for operation #%" PRIu64 ": %" PRId64 " (size: %u)\n",
307 h, op_id, result_code, data_size);
308 return op_result (h, op_id, result_code, data, data_size, ctx, GNUNET_NO);
313 * Remove / cancel an operation.
320 * @return #GNUNET_YES if the operation was found and removed,
321 * #GNUNET_NO if the operation was not found.
324 GNUNET_OP_remove (struct GNUNET_OP_Handle *h,
327 LOG (GNUNET_ERROR_TYPE_DEBUG,
328 "%p Cancelling operation #%" PRIu64 "\n",
330 return op_result (h, op_id, 0, NULL, 0, NULL, GNUNET_YES);