get rid of SOCKTYPE and FDTYPE
[oweals/gnunet.git] / src / util / op.c
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 <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
35 struct 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
66 struct 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  */
88 struct GNUNET_OP_Handle *
89 GNUNET_OP_create ()
90 {
91   return GNUNET_new (struct GNUNET_OP_Handle);
92 }
93
94
95 /**
96  * Destroy operations handle.
97  */
98 void
99 GNUNET_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  */
113 uint64_t
114 GNUNET_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  */
130 static struct OperationListItem *
131 op_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  */
160 int
161 GNUNET_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
169   if (NULL != op)
170   {
171     if (NULL != result_cb)
172       *result_cb = op->result_cb;
173     if (NULL != cls)
174       *cls = op->cls;
175     if (NULL != ctx)
176       *ctx = op->ctx;
177     return GNUNET_YES;
178   }
179   return GNUNET_NO;
180 }
181
182
183 /**
184  * Add a new operation.
185  *
186  * @param h
187  *        Operations handle.
188  * @param result_cb
189  *        Function to call with the result of the operation.
190  * @param cls
191  *        Closure for @a result_cb.
192  * @param ctx
193  *        User context.
194  *
195  * @return ID of the new operation.
196  */
197 uint64_t
198 GNUNET_OP_add (struct GNUNET_OP_Handle *h,
199                GNUNET_ResultCallback result_cb,
200                void *cls,
201                void *ctx)
202 {
203   struct OperationListItem *op;
204
205   op = GNUNET_new (struct OperationListItem);
206   op->op_id = GNUNET_OP_get_next_id (h);
207   op->result_cb = result_cb;
208   op->cls = cls;
209   op->ctx = ctx;
210   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
211                                     h->op_tail,
212                                     op);
213   LOG (GNUNET_ERROR_TYPE_DEBUG,
214        "%p Added operation #%" PRIu64 "\n",
215        h, op->op_id);
216   return op->op_id;
217 }
218
219
220 /**
221  * Remove an operation, and call its result callback (unless it was cancelled).
222  *
223  *
224  * @param h
225  *        Operations handle.
226  * @param op_id
227  *        Operation ID.
228  * @param result_code
229  *        Result of the operation.
230  * @param data
231  *        Data result of the operation.
232  * @param data_size
233  *        Size of @a data.
234  * @param[out] ctx
235  *        User context.
236  * @param cancel
237  *        Is the operation cancelled?
238  *        #GNUNET_NO  Not cancelled, result callback is called.
239  *        #GNUNET_YES Cancelled, result callback is not called.
240  *
241  * @return #GNUNET_YES if the operation was found and removed,
242  *         #GNUNET_NO  if the operation was not found.
243  */
244 static int
245 op_result (struct GNUNET_OP_Handle *h,
246            uint64_t op_id,
247            int64_t result_code,
248            const void *data,
249            uint16_t data_size,
250            void **ctx,
251            uint8_t cancel)
252 {
253   if (0 == op_id)
254     return GNUNET_NO;
255
256   struct OperationListItem *op = op_find (h, op_id);
257   if (NULL == op)
258   {
259     LOG (GNUNET_ERROR_TYPE_WARNING,
260          "Could not find operation #%" PRIu64 "\n", op_id);
261     return GNUNET_NO;
262   }
263
264   if (NULL != ctx)
265     *ctx = op->ctx;
266
267   GNUNET_CONTAINER_DLL_remove (h->op_head,
268                                h->op_tail,
269                                op);
270
271   if ((GNUNET_YES != cancel) &&
272       (NULL != op->result_cb))
273     op->result_cb (op->cls,
274                    result_code, data,
275                    data_size);
276   GNUNET_free (op);
277   return GNUNET_YES;
278 }
279
280
281 /**
282  * Call the result callback of an operation and remove it.
283  *
284  * @param h
285  *        Operations handle.
286  * @param op_id
287  *        Operation ID.
288  * @param result_code
289  *        Result of the operation.
290  * @param data
291  *        Data result of the operation.
292  * @param data_size
293  *        Size of @a data.
294  * @param[out] ctx
295  *        User context.
296  *
297  * @return #GNUNET_YES if the operation was found and removed,
298  *         #GNUNET_NO  if the operation was not found.
299  */
300 int
301 GNUNET_OP_result (struct GNUNET_OP_Handle *h,
302                   uint64_t op_id,
303                   int64_t result_code,
304                   const void *data,
305                   uint16_t data_size,
306                   void **ctx)
307 {
308   LOG (GNUNET_ERROR_TYPE_DEBUG,
309        "%p Received result for operation #%" PRIu64 ": %" PRId64 " (size: %u)\n",
310        h, op_id, result_code, data_size);
311   return op_result (h, op_id, result_code, data, data_size, ctx, GNUNET_NO);
312 }
313
314
315 /**
316  * Remove / cancel an operation.
317  *
318  * @param h
319  *        Operations handle.
320  * @param op_id
321  *        Operation ID.
322  *
323  * @return #GNUNET_YES if the operation was found and removed,
324  *         #GNUNET_NO  if the operation was not found.
325  */
326 int
327 GNUNET_OP_remove (struct GNUNET_OP_Handle *h,
328                   uint64_t op_id)
329 {
330   LOG (GNUNET_ERROR_TYPE_DEBUG,
331        "%p Cancelling operation #%" PRIu64  "\n",
332        h, op_id);
333   return op_result (h, op_id, 0, NULL, 0, NULL, GNUNET_YES);
334 }