aboutsummaryrefslogtreecommitdiff
path: root/src/setu/setu_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/setu/setu_api.c')
-rw-r--r--src/setu/setu_api.c872
1 files changed, 872 insertions, 0 deletions
diff --git a/src/setu/setu_api.c b/src/setu/setu_api.c
new file mode 100644
index 000000000..48260de55
--- /dev/null
+++ b/src/setu/setu_api.c
@@ -0,0 +1,872 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2016, 2020 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 * @file set/setu_api.c
22 * @brief api for the set union service
23 * @author Florian Dold
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_setu_service.h"
30#include "setu.h"
31
32
33#define LOG(kind, ...) GNUNET_log_from (kind, "set-api", __VA_ARGS__)
34
35/**
36 * Opaque handle to a set.
37 */
38struct GNUNET_SETU_Handle
39{
40 /**
41 * Message queue for @e client.
42 */
43 struct GNUNET_MQ_Handle *mq;
44
45 /**
46 * Linked list of operations on the set.
47 */
48 struct GNUNET_SETU_OperationHandle *ops_head;
49
50 /**
51 * Linked list of operations on the set.
52 */
53 struct GNUNET_SETU_OperationHandle *ops_tail;
54
55 /**
56 * Should the set be destroyed once all operations are gone?
57 * #GNUNET_SYSERR if #GNUNET_SETU_destroy() must raise this flag,
58 * #GNUNET_YES if #GNUNET_SETU_destroy() did raise this flag.
59 */
60 int destroy_requested;
61
62 /**
63 * Has the set become invalid (e.g. service died)?
64 */
65 int invalid;
66
67};
68
69
70/**
71 * Handle for a set operation request from another peer.
72 */
73struct GNUNET_SETU_Request
74{
75 /**
76 * Id of the request, used to identify the request when
77 * accepting/rejecting it.
78 */
79 uint32_t accept_id;
80
81 /**
82 * Has the request been accepted already?
83 * #GNUNET_YES/#GNUNET_NO
84 */
85 int accepted;
86};
87
88
89/**
90 * Handle to an operation. Only known to the service after committing
91 * the handle with a set.
92 */
93struct GNUNET_SETU_OperationHandle
94{
95 /**
96 * Function to be called when we have a result,
97 * or an error.
98 */
99 GNUNET_SETU_ResultIterator result_cb;
100
101 /**
102 * Closure for @e result_cb.
103 */
104 void *result_cls;
105
106 /**
107 * Local set used for the operation,
108 * NULL if no set has been provided by conclude yet.
109 */
110 struct GNUNET_SETU_Handle *set;
111
112 /**
113 * Message sent to the server on calling conclude,
114 * NULL if conclude has been called.
115 */
116 struct GNUNET_MQ_Envelope *conclude_mqm;
117
118 /**
119 * Address of the request if in the conclude message,
120 * used to patch the request id into the message when the set is known.
121 */
122 uint32_t *request_id_addr;
123
124 /**
125 * Handles are kept in a linked list.
126 */
127 struct GNUNET_SETU_OperationHandle *prev;
128
129 /**
130 * Handles are kept in a linked list.
131 */
132 struct GNUNET_SETU_OperationHandle *next;
133
134 /**
135 * Request ID to identify the operation within the set.
136 */
137 uint32_t request_id;
138};
139
140
141/**
142 * Opaque handle to a listen operation.
143 */
144struct GNUNET_SETU_ListenHandle
145{
146 /**
147 * Message queue for the client.
148 */
149 struct GNUNET_MQ_Handle*mq;
150
151 /**
152 * Configuration handle for the listener, stored
153 * here to be able to reconnect transparently on
154 * connection failure.
155 */
156 const struct GNUNET_CONFIGURATION_Handle *cfg;
157
158 /**
159 * Function to call on a new incoming request,
160 * or on error.
161 */
162 GNUNET_SETU_ListenCallback listen_cb;
163
164 /**
165 * Closure for @e listen_cb.
166 */
167 void *listen_cls;
168
169 /**
170 * Application ID we listen for.
171 */
172 struct GNUNET_HashCode app_id;
173
174 /**
175 * Time to wait until we try to reconnect on failure.
176 */
177 struct GNUNET_TIME_Relative reconnect_backoff;
178
179 /**
180 * Task for reconnecting when the listener fails.
181 */
182 struct GNUNET_SCHEDULER_Task *reconnect_task;
183
184};
185
186
187/**
188 * Check that the given @a msg is well-formed.
189 *
190 * @param cls closure
191 * @param msg message to check
192 * @return #GNUNET_OK if message is well-formed
193 */
194static int
195check_result (void *cls,
196 const struct GNUNET_SETU_ResultMessage *msg)
197{
198 /* minimum size was already checked, everything else is OK! */
199 return GNUNET_OK;
200}
201
202
203/**
204 * Handle result message for a set operation.
205 *
206 * @param cls the set
207 * @param mh the message
208 */
209static void
210handle_result (void *cls,
211 const struct GNUNET_SETU_ResultMessage *msg)
212{
213 struct GNUNET_SETU_Handle *set = cls;
214 struct GNUNET_SETU_OperationHandle *oh;
215 struct GNUNET_SETU_Element e;
216 enum GNUNET_SETU_Status result_status;
217 int destroy_set;
218
219 GNUNET_assert (NULL != set->mq);
220 result_status = (enum GNUNET_SETU_Status) ntohs (msg->result_status);
221 LOG (GNUNET_ERROR_TYPE_DEBUG,
222 "Got result message with status %d\n",
223 result_status);
224 oh = GNUNET_MQ_assoc_get (set->mq,
225 ntohl (msg->request_id));
226 if (NULL == oh)
227 {
228 /* 'oh' can be NULL if we canceled the operation, but the service
229 did not get the cancel message yet. */
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Ignoring result from canceled operation\n");
232 return;
233 }
234
235 switch (result_status)
236 {
237 case GNUNET_SETU_STATUS_ADD_LOCAL:
238 LOG (GNUNET_ERROR_TYPE_DEBUG,
239 "Treating result as element\n");
240 e.data = &msg[1];
241 e.size = ntohs (msg->header.size)
242 - sizeof(struct GNUNET_SETU_ResultMessage);
243 e.element_type = ntohs (msg->element_type);
244 if (NULL != oh->result_cb)
245 oh->result_cb (oh->result_cls,
246 &e,
247 GNUNET_ntohll (msg->current_size),
248 result_status);
249 return;
250 case GNUNET_SETU_STATUS_FAILURE:
251 case GNUNET_SETU_STATUS_DONE:
252 LOG (GNUNET_ERROR_TYPE_DEBUG,
253 "Treating result as final status\n");
254 GNUNET_MQ_assoc_remove (set->mq,
255 ntohl (msg->request_id));
256 GNUNET_CONTAINER_DLL_remove (set->ops_head,
257 set->ops_tail,
258 oh);
259 /* Need to do this calculation _before_ the result callback,
260 as IF the application still has a valid set handle, it
261 may trigger destruction of the set during the callback. */
262 destroy_set = (GNUNET_YES == set->destroy_requested) &&
263 (NULL == set->ops_head);
264 if (NULL != oh->result_cb)
265 {
266 oh->result_cb (oh->result_cls,
267 NULL,
268 GNUNET_ntohll (msg->current_size),
269 result_status);
270 }
271 else
272 {
273 LOG (GNUNET_ERROR_TYPE_DEBUG,
274 "No callback for final status\n");
275 }
276 if (destroy_set)
277 GNUNET_SETU_destroy (set);
278 GNUNET_free (oh);
279 return;
280 }
281}
282
283
284/**
285 * Destroy the given set operation.
286 *
287 * @param oh set operation to destroy
288 */
289static void
290set_operation_destroy (struct GNUNET_SETU_OperationHandle *oh)
291{
292 struct GNUNET_SETU_Handle *set = oh->set;
293 struct GNUNET_SETU_OperationHandle *h_assoc;
294
295 if (NULL != oh->conclude_mqm)
296 GNUNET_MQ_discard (oh->conclude_mqm);
297 /* is the operation already commited? */
298 if (NULL != set)
299 {
300 GNUNET_CONTAINER_DLL_remove (set->ops_head,
301 set->ops_tail,
302 oh);
303 h_assoc = GNUNET_MQ_assoc_remove (set->mq,
304 oh->request_id);
305 GNUNET_assert ((NULL == h_assoc) ||
306 (h_assoc == oh));
307 }
308 GNUNET_free (oh);
309}
310
311
312/**
313 * Cancel the given set operation. We need to send an explicit cancel
314 * message, as all operations one one set communicate using one
315 * handle.
316 *
317 * @param oh set operation to cancel
318 */
319void
320GNUNET_SETU_operation_cancel (struct GNUNET_SETU_OperationHandle *oh)
321{
322 struct GNUNET_SETU_Handle *set = oh->set;
323 struct GNUNET_SETU_CancelMessage *m;
324 struct GNUNET_MQ_Envelope *mqm;
325
326 LOG (GNUNET_ERROR_TYPE_DEBUG,
327 "Cancelling SET operation\n");
328 if (NULL != set)
329 {
330 mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SETU_CANCEL);
331 m->request_id = htonl (oh->request_id);
332 GNUNET_MQ_send (set->mq, mqm);
333 }
334 set_operation_destroy (oh);
335 if ((NULL != set) &&
336 (GNUNET_YES == set->destroy_requested) &&
337 (NULL == set->ops_head))
338 {
339 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 "Destroying set after operation cancel\n");
341 GNUNET_SETU_destroy (set);
342 }
343}
344
345
346/**
347 * We encountered an error communicating with the set service while
348 * performing a set operation. Report to the application.
349 *
350 * @param cls the `struct GNUNET_SETU_Handle`
351 * @param error error code
352 */
353static void
354handle_client_set_error (void *cls,
355 enum GNUNET_MQ_Error error)
356{
357 struct GNUNET_SETU_Handle *set = cls;
358
359 LOG (GNUNET_ERROR_TYPE_ERROR,
360 "Handling client set error %d\n",
361 error);
362 while (NULL != set->ops_head)
363 {
364 if ((NULL != set->ops_head->result_cb) &&
365 (GNUNET_NO == set->destroy_requested))
366 set->ops_head->result_cb (set->ops_head->result_cls,
367 NULL,
368 0,
369 GNUNET_SETU_STATUS_FAILURE);
370 set_operation_destroy (set->ops_head);
371 }
372 set->invalid = GNUNET_YES;
373}
374
375
376/**
377 * Create an empty set, supporting the specified operation.
378 *
379 * @param cfg configuration to use for connecting to the
380 * set service
381 * @return a handle to the set
382 */
383struct GNUNET_SETU_Handle *
384GNUNET_SETU_create (const struct GNUNET_CONFIGURATION_Handle *cfg)
385{
386 struct GNUNET_SETU_Handle *set = GNUNET_new (struct GNUNET_SETU_Handle);
387 struct GNUNET_MQ_MessageHandler mq_handlers[] = {
388 GNUNET_MQ_hd_var_size (result,
389 GNUNET_MESSAGE_TYPE_SETU_RESULT,
390 struct GNUNET_SETU_ResultMessage,
391 set),
392 GNUNET_MQ_handler_end ()
393 };
394 struct GNUNET_MQ_Envelope *mqm;
395 struct GNUNET_SETU_CreateMessage *create_msg;
396
397 set->mq = GNUNET_CLIENT_connect (cfg,
398 "setu",
399 mq_handlers,
400 &handle_client_set_error,
401 set);
402 if (NULL == set->mq)
403 {
404 GNUNET_free (set);
405 return NULL;
406 }
407 mqm = GNUNET_MQ_msg (create_msg,
408 GNUNET_MESSAGE_TYPE_SETU_CREATE);
409 GNUNET_MQ_send (set->mq,
410 mqm);
411 return set;
412}
413
414
415/**
416 * Add an element to the given set. After the element has been added
417 * (in the sense of being transmitted to the set service), @a cont
418 * will be called. Multiple calls to GNUNET_SETU_add_element() can be
419 * queued.
420 *
421 * @param set set to add element to
422 * @param element element to add to the set
423 * @param cb continuation called after the element has been added
424 * @param cb_cls closure for @a cb
425 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
426 * set is invalid (e.g. the set service crashed)
427 */
428int
429GNUNET_SETU_add_element (struct GNUNET_SETU_Handle *set,
430 const struct GNUNET_SETU_Element *element,
431 GNUNET_SCHEDULER_TaskCallback cb,
432 void *cb_cls)
433{
434 struct GNUNET_MQ_Envelope *mqm;
435 struct GNUNET_SETU_ElementMessage *msg;
436
437 LOG (GNUNET_ERROR_TYPE_DEBUG,
438 "adding element of type %u to set %p\n",
439 (unsigned int) element->element_type,
440 set);
441 GNUNET_assert (NULL != set);
442 if (GNUNET_YES == set->invalid)
443 {
444 if (NULL != cb)
445 cb (cb_cls);
446 return GNUNET_SYSERR;
447 }
448 mqm = GNUNET_MQ_msg_extra (msg,
449 element->size,
450 GNUNET_MESSAGE_TYPE_SETU_ADD);
451 msg->element_type = htons (element->element_type);
452 GNUNET_memcpy (&msg[1],
453 element->data,
454 element->size);
455 GNUNET_MQ_notify_sent (mqm,
456 cb,
457 cb_cls);
458 GNUNET_MQ_send (set->mq,
459 mqm);
460 return GNUNET_OK;
461}
462
463
464/**
465 * Destroy the set handle if no operations are left, mark the set
466 * for destruction otherwise.
467 *
468 * @param set set handle to destroy
469 */
470void
471GNUNET_SETU_destroy (struct GNUNET_SETU_Handle *set)
472{
473 /* destroying set while iterator is active is currently
474 not supported; we should expand the API to allow
475 clients to explicitly cancel the iteration! */
476 GNUNET_assert (NULL != set);
477 if ((NULL != set->ops_head) ||
478 (GNUNET_SYSERR == set->destroy_requested))
479 {
480 LOG (GNUNET_ERROR_TYPE_DEBUG,
481 "Set operations are pending, delaying set destruction\n");
482 set->destroy_requested = GNUNET_YES;
483 return;
484 }
485 LOG (GNUNET_ERROR_TYPE_DEBUG,
486 "Really destroying set\n");
487 if (NULL != set->mq)
488 {
489 GNUNET_MQ_destroy (set->mq);
490 set->mq = NULL;
491 }
492 GNUNET_free (set);
493}
494
495
496/**
497 * Prepare a set operation to be evaluated with another peer.
498 * The evaluation will not start until the client provides
499 * a local set with #GNUNET_SETU_commit().
500 *
501 * @param other_peer peer with the other set
502 * @param app_id hash for the application using the set
503 * @param context_msg additional information for the request
504 * @param result_cb called on error or success
505 * @param result_cls closure for @e result_cb
506 * @return a handle to cancel the operation
507 */
508struct GNUNET_SETU_OperationHandle *
509GNUNET_SETU_prepare (const struct GNUNET_PeerIdentity *other_peer,
510 const struct GNUNET_HashCode *app_id,
511 const struct GNUNET_MessageHeader *context_msg,
512 const struct GNUNET_SETU_Option options[],
513 GNUNET_SETU_ResultIterator result_cb,
514 void *result_cls)
515{
516 struct GNUNET_MQ_Envelope *mqm;
517 struct GNUNET_SETU_OperationHandle *oh;
518 struct GNUNET_SETU_EvaluateMessage *msg;
519
520 LOG (GNUNET_ERROR_TYPE_DEBUG,
521 "Client prepares set union operation\n");
522 oh = GNUNET_new (struct GNUNET_SETU_OperationHandle);
523 oh->result_cb = result_cb;
524 oh->result_cls = result_cls;
525 mqm = GNUNET_MQ_msg_nested_mh (msg,
526 GNUNET_MESSAGE_TYPE_SETU_EVALUATE,
527 context_msg);
528 msg->app_id = *app_id;
529 msg->target_peer = *other_peer;
530 for (const struct GNUNET_SETU_Option *opt = options; opt->type != 0; opt++)
531 {
532 switch (opt->type)
533 {
534 case GNUNET_SETU_OPTION_BYZANTINE:
535 msg->byzantine = GNUNET_YES;
536 msg->byzantine_lower_bound = opt->v.num;
537 break;
538 case GNUNET_SETU_OPTION_FORCE_FULL:
539 msg->force_full = GNUNET_YES;
540 break;
541 case GNUNET_SETU_OPTION_FORCE_DELTA:
542 msg->force_delta = GNUNET_YES;
543 break;
544 default:
545 LOG (GNUNET_ERROR_TYPE_ERROR,
546 "Option with type %d not recognized\n",
547 (int) opt->type);
548 }
549 }
550 oh->conclude_mqm = mqm;
551 oh->request_id_addr = &msg->request_id;
552 return oh;
553}
554
555
556/**
557 * Connect to the set service in order to listen for requests.
558 *
559 * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect
560 */
561static void
562listen_connect (void *cls);
563
564
565/**
566 * Check validity of request message for a listen operation
567 *
568 * @param cls the listen handle
569 * @param msg the message
570 * @return #GNUNET_OK if the message is well-formed
571 */
572static int
573check_request (void *cls,
574 const struct GNUNET_SETU_RequestMessage *msg)
575{
576 const struct GNUNET_MessageHeader *context_msg;
577
578 if (ntohs (msg->header.size) == sizeof(*msg))
579 return GNUNET_OK; /* no context message is OK */
580 context_msg = GNUNET_MQ_extract_nested_mh (msg);
581 if (NULL == context_msg)
582 {
583 /* malformed context message is NOT ok */
584 GNUNET_break_op (0);
585 return GNUNET_SYSERR;
586 }
587 return GNUNET_OK;
588}
589
590
591/**
592 * Handle request message for a listen operation
593 *
594 * @param cls the listen handle
595 * @param msg the message
596 */
597static void
598handle_request (void *cls,
599 const struct GNUNET_SETU_RequestMessage *msg)
600{
601 struct GNUNET_SETU_ListenHandle *lh = cls;
602 struct GNUNET_SETU_Request req;
603 const struct GNUNET_MessageHeader *context_msg;
604 struct GNUNET_MQ_Envelope *mqm;
605 struct GNUNET_SETU_RejectMessage *rmsg;
606
607 LOG (GNUNET_ERROR_TYPE_DEBUG,
608 "Processing incoming operation request with id %u\n",
609 ntohl (msg->accept_id));
610 /* we got another valid request => reset the backoff */
611 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
612 req.accept_id = ntohl (msg->accept_id);
613 req.accepted = GNUNET_NO;
614 context_msg = GNUNET_MQ_extract_nested_mh (msg);
615 /* calling #GNUNET_SETU_accept() in the listen cb will set req->accepted */
616 lh->listen_cb (lh->listen_cls,
617 &msg->peer_id,
618 context_msg,
619 &req);
620 if (GNUNET_YES == req.accepted)
621 return; /* the accept-case is handled in #GNUNET_SETU_accept() */
622 LOG (GNUNET_ERROR_TYPE_DEBUG,
623 "Rejected request %u\n",
624 ntohl (msg->accept_id));
625 mqm = GNUNET_MQ_msg (rmsg,
626 GNUNET_MESSAGE_TYPE_SETU_REJECT);
627 rmsg->accept_reject_id = msg->accept_id;
628 GNUNET_MQ_send (lh->mq,
629 mqm);
630}
631
632
633/**
634 * Our connection with the set service encountered an error,
635 * re-initialize with exponential back-off.
636 *
637 * @param cls the `struct GNUNET_SETU_ListenHandle *`
638 * @param error reason for the disconnect
639 */
640static void
641handle_client_listener_error (void *cls,
642 enum GNUNET_MQ_Error error)
643{
644 struct GNUNET_SETU_ListenHandle *lh = cls;
645
646 LOG (GNUNET_ERROR_TYPE_DEBUG,
647 "Listener broke down (%d), re-connecting\n",
648 (int) error);
649 GNUNET_MQ_destroy (lh->mq);
650 lh->mq = NULL;
651 lh->reconnect_task = GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff,
652 &listen_connect,
653 lh);
654 lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
655}
656
657
658/**
659 * Connect to the set service in order to listen for requests.
660 *
661 * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect
662 */
663static void
664listen_connect (void *cls)
665{
666 struct GNUNET_SETU_ListenHandle *lh = cls;
667 struct GNUNET_MQ_MessageHandler mq_handlers[] = {
668 GNUNET_MQ_hd_var_size (request,
669 GNUNET_MESSAGE_TYPE_SETU_REQUEST,
670 struct GNUNET_SETU_RequestMessage,
671 lh),
672 GNUNET_MQ_handler_end ()
673 };
674 struct GNUNET_MQ_Envelope *mqm;
675 struct GNUNET_SETU_ListenMessage *msg;
676
677 lh->reconnect_task = NULL;
678 GNUNET_assert (NULL == lh->mq);
679 lh->mq = GNUNET_CLIENT_connect (lh->cfg,
680 "setu",
681 mq_handlers,
682 &handle_client_listener_error,
683 lh);
684 if (NULL == lh->mq)
685 return;
686 mqm = GNUNET_MQ_msg (msg,
687 GNUNET_MESSAGE_TYPE_SETU_LISTEN);
688 msg->app_id = lh->app_id;
689 GNUNET_MQ_send (lh->mq,
690 mqm);
691}
692
693
694/**
695 * Wait for set operation requests for the given application id
696 *
697 * @param cfg configuration to use for connecting to
698 * the set service, needs to be valid for the lifetime of the listen handle
699 * @param app_id id of the application that handles set operation requests
700 * @param listen_cb called for each incoming request matching the operation
701 * and application id
702 * @param listen_cls handle for @a listen_cb
703 * @return a handle that can be used to cancel the listen operation
704 */
705struct GNUNET_SETU_ListenHandle *
706GNUNET_SETU_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
707 const struct GNUNET_HashCode *app_id,
708 GNUNET_SETU_ListenCallback listen_cb,
709 void *listen_cls)
710{
711 struct GNUNET_SETU_ListenHandle *lh;
712
713 LOG (GNUNET_ERROR_TYPE_DEBUG,
714 "Starting listener for app %s\n",
715 GNUNET_h2s (app_id));
716 lh = GNUNET_new (struct GNUNET_SETU_ListenHandle);
717 lh->listen_cb = listen_cb;
718 lh->listen_cls = listen_cls;
719 lh->cfg = cfg;
720 lh->app_id = *app_id;
721 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
722 listen_connect (lh);
723 if (NULL == lh->mq)
724 {
725 GNUNET_free (lh);
726 return NULL;
727 }
728 return lh;
729}
730
731
732/**
733 * Cancel the given listen operation.
734 *
735 * @param lh handle for the listen operation
736 */
737void
738GNUNET_SETU_listen_cancel (struct GNUNET_SETU_ListenHandle *lh)
739{
740 LOG (GNUNET_ERROR_TYPE_DEBUG,
741 "Canceling listener %s\n",
742 GNUNET_h2s (&lh->app_id));
743 if (NULL != lh->mq)
744 {
745 GNUNET_MQ_destroy (lh->mq);
746 lh->mq = NULL;
747 }
748 if (NULL != lh->reconnect_task)
749 {
750 GNUNET_SCHEDULER_cancel (lh->reconnect_task);
751 lh->reconnect_task = NULL;
752 }
753 GNUNET_free (lh);
754}
755
756
757/**
758 * Accept a request we got via #GNUNET_SETU_listen. Must be called during
759 * #GNUNET_SETU_listen, as the 'struct GNUNET_SETU_Request' becomes invalid
760 * afterwards.
761 * Call #GNUNET_SETU_commit to provide the local set to use for the operation,
762 * and to begin the exchange with the remote peer.
763 *
764 * @param request request to accept
765 * @param result_mode specified how results will be returned,
766 * see `enum GNUNET_SETU_ResultMode`.
767 * @param result_cb callback for the results
768 * @param result_cls closure for @a result_cb
769 * @return a handle to cancel the operation
770 */
771struct GNUNET_SETU_OperationHandle *
772GNUNET_SETU_accept (struct GNUNET_SETU_Request *request,
773 const struct GNUNET_SETU_Option options[],
774 GNUNET_SETU_ResultIterator result_cb,
775 void *result_cls)
776{
777 struct GNUNET_MQ_Envelope *mqm;
778 struct GNUNET_SETU_OperationHandle *oh;
779 struct GNUNET_SETU_AcceptMessage *msg;
780
781 GNUNET_assert (GNUNET_NO == request->accepted);
782 LOG (GNUNET_ERROR_TYPE_DEBUG,
783 "Client accepts set union operation with id %u\n",
784 request->accept_id);
785 request->accepted = GNUNET_YES;
786 mqm = GNUNET_MQ_msg (msg,
787 GNUNET_MESSAGE_TYPE_SETU_ACCEPT);
788 msg->accept_reject_id = htonl (request->accept_id);
789 oh = GNUNET_new (struct GNUNET_SETU_OperationHandle);
790 oh->result_cb = result_cb;
791 oh->result_cls = result_cls;
792 oh->conclude_mqm = mqm;
793 oh->request_id_addr = &msg->request_id;
794 return oh;
795}
796
797
798/**
799 * Commit a set to be used with a set operation.
800 * This function is called once we have fully constructed
801 * the set that we want to use for the operation. At this
802 * time, the P2P protocol can then begin to exchange the
803 * set information and call the result callback with the
804 * result information.
805 *
806 * @param oh handle to the set operation
807 * @param set the set to use for the operation
808 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
809 * set is invalid (e.g. the set service crashed)
810 */
811int
812GNUNET_SETU_commit (struct GNUNET_SETU_OperationHandle *oh,
813 struct GNUNET_SETU_Handle *set)
814{
815 if (NULL != oh->set)
816 {
817 /* Some other set was already committed for this
818 * operation, there is a logic bug in the client of this API */
819 GNUNET_break (0);
820 return GNUNET_OK;
821 }
822 GNUNET_assert (NULL != set);
823 if (GNUNET_YES == set->invalid)
824 return GNUNET_SYSERR;
825 LOG (GNUNET_ERROR_TYPE_DEBUG,
826 "Client commits to SET\n");
827 GNUNET_assert (NULL != oh->conclude_mqm);
828 oh->set = set;
829 GNUNET_CONTAINER_DLL_insert (set->ops_head,
830 set->ops_tail,
831 oh);
832 oh->request_id = GNUNET_MQ_assoc_add (set->mq,
833 oh);
834 *oh->request_id_addr = htonl (oh->request_id);
835 GNUNET_MQ_send (set->mq,
836 oh->conclude_mqm);
837 oh->conclude_mqm = NULL;
838 oh->request_id_addr = NULL;
839 return GNUNET_OK;
840}
841
842
843/**
844 * Hash a set element.
845 *
846 * @param element the element that should be hashed
847 * @param[out] ret_hash a pointer to where the hash of @a element
848 * should be stored
849 */
850void
851GNUNET_SETU_element_hash (const struct GNUNET_SETU_Element *element,
852 struct GNUNET_HashCode *ret_hash)
853{
854 struct GNUNET_HashContext *ctx = GNUNET_CRYPTO_hash_context_start ();
855
856 /* It's not guaranteed that the element data is always after the element header,
857 so we need to hash the chunks separately. */
858 GNUNET_CRYPTO_hash_context_read (ctx,
859 &element->size,
860 sizeof(uint16_t));
861 GNUNET_CRYPTO_hash_context_read (ctx,
862 &element->element_type,
863 sizeof(uint16_t));
864 GNUNET_CRYPTO_hash_context_read (ctx,
865 element->data,
866 element->size);
867 GNUNET_CRYPTO_hash_context_finish (ctx,
868 ret_hash);
869}
870
871
872/* end of setu_api.c */