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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
23 * Asynchronous operations; register callbacks for operations and call them when a response arrives.
25 * @author Gabor X Toth
31 #include "gnunet_util_lib.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "util-op", __VA_ARGS__)
35 struct OperationListItem
37 struct OperationListItem *prev;
38 struct OperationListItem *next;
46 * Continuation to invoke with the result of an operation.
48 GNUNET_ResultCallback result_cb;
51 * Closure for @a result_cb.
66 struct GNUNET_OP_Handle
69 * First operation in the linked list.
71 struct OperationListItem *op_head;
74 * Last operation in the linked list.
76 struct OperationListItem *op_tail;
79 * Last operation ID used.
86 * Create new operations handle.
88 struct GNUNET_OP_Handle *
91 return GNUNET_new (struct GNUNET_OP_Handle);
96 * Destroy operations handle.
99 GNUNET_OP_destroy (struct GNUNET_OP_Handle *h)
106 * Get a unique operation ID to distinguish between asynchronous requests.
111 * @return Operation ID to use.
114 GNUNET_OP_get_next_id (struct GNUNET_OP_Handle *h)
116 return ++h->last_op_id;
121 * Find operation by ID.
126 * Operation ID to look up.
128 * @return Operation, or NULL if not found.
130 static struct OperationListItem *
131 op_find (struct GNUNET_OP_Handle *h,
134 struct OperationListItem *op;
136 for (op = h->op_head; NULL != op; op = op->next)
137 if (op->op_id == op_id)
144 * Find operation by ID.
149 * Operation ID to look up.
150 * @param[out] result_cb
151 * If an operation was found, its result callback is returned here.
153 * If an operation was found, its closure is returned here.
155 * If an operation was found, its user context is returned here.
157 * @return #GNUNET_YES if an operation was found,
158 * #GNUNET_NO if not found.
161 GNUNET_OP_get (struct GNUNET_OP_Handle *h,
163 GNUNET_ResultCallback *result_cb,
167 struct OperationListItem *op = op_find (h, op_id);
170 if (NULL != result_cb)
171 *result_cb = op->result_cb;
183 * Add a new operation.
188 * Function to call with the result of the operation.
190 * Closure for @a result_cb.
194 * @return ID of the new operation.
197 GNUNET_OP_add (struct GNUNET_OP_Handle *h,
198 GNUNET_ResultCallback result_cb,
202 struct OperationListItem *op;
204 op = GNUNET_new (struct OperationListItem);
205 op->op_id = GNUNET_OP_get_next_id (h);
206 op->result_cb = result_cb;
209 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
212 LOG (GNUNET_ERROR_TYPE_DEBUG,
213 "%p Added operation #%" PRIu64 "\n",
220 * Remove an operation, and call its result callback (unless it was cancelled).
228 * Result of the operation.
230 * Data result of the operation.
236 * Is the operation cancelled?
237 * #GNUNET_NO Not cancelled, result callback is called.
238 * #GNUNET_YES Cancelled, result callback is not called.
240 * @return #GNUNET_YES if the operation was found and removed,
241 * #GNUNET_NO if the operation was not found.
244 op_result (struct GNUNET_OP_Handle *h,
255 struct OperationListItem *op = op_find (h, op_id);
258 LOG (GNUNET_ERROR_TYPE_WARNING,
259 "Could not find operation #%" PRIu64 "\n", op_id);
266 GNUNET_CONTAINER_DLL_remove (h->op_head,
270 if ( (GNUNET_YES != cancel) &&
271 (NULL != op->result_cb) )
272 op->result_cb (op->cls,
281 * Call the result callback of an operation and remove it.
288 * Result of the operation.
290 * Data result of the operation.
296 * @return #GNUNET_YES if the operation was found and removed,
297 * #GNUNET_NO if the operation was not found.
300 GNUNET_OP_result (struct GNUNET_OP_Handle *h,
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);
315 * Remove / cancel an operation.
322 * @return #GNUNET_YES if the operation was found and removed,
323 * #GNUNET_NO if the operation was not found.
326 GNUNET_OP_remove (struct GNUNET_OP_Handle *h,
329 LOG (GNUNET_ERROR_TYPE_DEBUG,
330 "%p Cancelling operation #%" PRIu64 "\n",
332 return op_result (h, op_id, 0, NULL, 0, NULL, GNUNET_YES);