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.c937
1 files changed, 0 insertions, 937 deletions
diff --git a/src/setu/setu_api.c b/src/setu/setu_api.c
deleted file mode 100644
index faa57aaba..000000000
--- a/src/setu/setu_api.c
+++ /dev/null
@@ -1,937 +0,0 @@
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 * @author Elias Summermatter
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_setu_service.h"
31#include "setu.h"
32
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "set-api", __VA_ARGS__)
35
36/**
37 * Opaque handle to a set.
38 */
39struct GNUNET_SETU_Handle
40{
41 /**
42 * Message queue for @e client.
43 */
44 struct GNUNET_MQ_Handle *mq;
45
46 /**
47 * Linked list of operations on the set.
48 */
49 struct GNUNET_SETU_OperationHandle *ops_head;
50
51 /**
52 * Linked list of operations on the set.
53 */
54 struct GNUNET_SETU_OperationHandle *ops_tail;
55
56 /**
57 * Should the set be destroyed once all operations are gone?
58 * #GNUNET_SYSERR if #GNUNET_SETU_destroy() must raise this flag,
59 * #GNUNET_YES if #GNUNET_SETU_destroy() did raise this flag.
60 */
61 int destroy_requested;
62
63 /**
64 * Has the set become invalid (e.g. service died)?
65 */
66 int invalid;
67
68};
69
70
71/**
72 * Handle for a set operation request from another peer.
73 */
74struct GNUNET_SETU_Request
75{
76 /**
77 * Id of the request, used to identify the request when
78 * accepting/rejecting it.
79 */
80 uint32_t accept_id;
81
82 /**
83 * Has the request been accepted already?
84 * #GNUNET_YES/#GNUNET_NO
85 */
86 int accepted;
87};
88
89
90/**
91 * Handle to an operation. Only known to the service after committing
92 * the handle with a set.
93 */
94struct GNUNET_SETU_OperationHandle
95{
96 /**
97 * Function to be called when we have a result,
98 * or an error.
99 */
100 GNUNET_SETU_ResultIterator result_cb;
101
102 /**
103 * Closure for @e result_cb.
104 */
105 void *result_cls;
106
107 /**
108 * Local set used for the operation,
109 * NULL if no set has been provided by conclude yet.
110 */
111 struct GNUNET_SETU_Handle *set;
112
113 /**
114 * Message sent to the server on calling conclude,
115 * NULL if conclude has been called.
116 */
117 struct GNUNET_MQ_Envelope *conclude_mqm;
118
119 /**
120 * Address of the request if in the conclude message,
121 * used to patch the request id into the message when the set is known.
122 */
123 uint32_t *request_id_addr;
124
125 /**
126 * Handles are kept in a linked list.
127 */
128 struct GNUNET_SETU_OperationHandle *prev;
129
130 /**
131 * Handles are kept in a linked list.
132 */
133 struct GNUNET_SETU_OperationHandle *next;
134
135 /**
136 * Request ID to identify the operation within the set.
137 */
138 uint32_t request_id;
139};
140
141
142/**
143 * Opaque handle to a listen operation.
144 */
145struct GNUNET_SETU_ListenHandle
146{
147 /**
148 * Message queue for the client.
149 */
150 struct GNUNET_MQ_Handle*mq;
151
152 /**
153 * Configuration handle for the listener, stored
154 * here to be able to reconnect transparently on
155 * connection failure.
156 */
157 const struct GNUNET_CONFIGURATION_Handle *cfg;
158
159 /**
160 * Function to call on a new incoming request,
161 * or on error.
162 */
163 GNUNET_SETU_ListenCallback listen_cb;
164
165 /**
166 * Closure for @e listen_cb.
167 */
168 void *listen_cls;
169
170 /**
171 * Application ID we listen for.
172 */
173 struct GNUNET_HashCode app_id;
174
175 /**
176 * Time to wait until we try to reconnect on failure.
177 */
178 struct GNUNET_TIME_Relative reconnect_backoff;
179
180 /**
181 * Task for reconnecting when the listener fails.
182 */
183 struct GNUNET_SCHEDULER_Task *reconnect_task;
184
185};
186
187
188/**
189 * Check that the given @a msg is well-formed.
190 *
191 * @param cls closure
192 * @param msg message to check
193 * @return #GNUNET_OK if message is well-formed
194 */
195static int
196check_result (void *cls,
197 const struct GNUNET_SETU_ResultMessage *msg)
198{
199 /* minimum size was already checked, everything else is OK! */
200 return GNUNET_OK;
201}
202
203
204/**
205 * Handle result message for a set operation.
206 *
207 * @param cls the set
208 * @param mh the message
209 */
210static void
211handle_result (void *cls,
212 const struct GNUNET_SETU_ResultMessage *msg)
213{
214 struct GNUNET_SETU_Handle *set = cls;
215 struct GNUNET_SETU_OperationHandle *oh;
216 struct GNUNET_SETU_Element e;
217 enum GNUNET_SETU_Status result_status;
218 int destroy_set;
219
220 GNUNET_assert (NULL != set->mq);
221 result_status = (enum GNUNET_SETU_Status) ntohs (msg->result_status);
222 LOG (GNUNET_ERROR_TYPE_DEBUG,
223 "Got result message with status %d\n",
224 result_status);
225 oh = GNUNET_MQ_assoc_get (set->mq,
226 ntohl (msg->request_id));
227 if (NULL == oh)
228 {
229 /* 'oh' can be NULL if we canceled the operation, but the service
230 did not get the cancel message yet. */
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232 "Ignoring result from canceled operation\n");
233 return;
234 }
235
236 switch (result_status)
237 {
238 case GNUNET_SETU_STATUS_ADD_LOCAL:
239 case GNUNET_SETU_STATUS_ADD_REMOTE:
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 committed? */
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
531 /* Set default values */
532 msg->byzantine_upper_bond = UINT64_MAX;
533 msg->bandwidth_latency_tradeoff = 0;
534 msg->ibf_bucket_number_factor = 2;
535 msg->ibf_number_of_buckets_per_element = 3;
536
537
538 for (const struct GNUNET_SETU_Option *opt = options; opt->type != 0; opt++)
539 {
540 switch (opt->type)
541 {
542 case GNUNET_SETU_OPTION_BYZANTINE:
543 msg->byzantine = GNUNET_YES;
544 msg->byzantine_lower_bound = htonl (opt->v.num);
545 break;
546 case GNUNET_SETU_OPTION_CUSTOM_BYZANTINE_UPPER_BOUND:
547 msg->byzantine_upper_bond = htonl (opt->v.num);
548 break;
549 case GNUNET_SETU_OPTION_CUSTOM_BANDWIDTH_LATENCY_TRADEOFF:
550 msg->bandwidth_latency_tradeoff = htonl (opt->v.num);
551 break;
552 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKET_NUMBER_FACTOR:
553 msg->ibf_bucket_number_factor = htonl (opt->v.num);
554 break;
555 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKETS_PER_ELEMENT:
556 msg->ibf_number_of_buckets_per_element = htonl (opt->v.num);
557 break;
558 case GNUNET_SETU_OPTION_FORCE_FULL:
559 msg->force_full = GNUNET_YES;
560 break;
561 case GNUNET_SETU_OPTION_FORCE_DELTA:
562 msg->force_delta = GNUNET_YES;
563 break;
564 case GNUNET_SETU_OPTION_SYMMETRIC:
565 msg->symmetric = GNUNET_YES;
566 break;
567 default:
568 LOG (GNUNET_ERROR_TYPE_ERROR,
569 "Option with type %d not recognized\n",
570 (int) opt->type);
571 }
572 }
573 oh->conclude_mqm = mqm;
574 oh->request_id_addr = &msg->request_id;
575 return oh;
576}
577
578
579/**
580 * Connect to the set service in order to listen for requests.
581 *
582 * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect
583 */
584static void
585listen_connect (void *cls);
586
587
588/**
589 * Check validity of request message for a listen operation
590 *
591 * @param cls the listen handle
592 * @param msg the message
593 * @return #GNUNET_OK if the message is well-formed
594 */
595static int
596check_request (void *cls,
597 const struct GNUNET_SETU_RequestMessage *msg)
598{
599 const struct GNUNET_MessageHeader *context_msg;
600
601 if (ntohs (msg->header.size) == sizeof(*msg))
602 return GNUNET_OK; /* no context message is OK */
603 context_msg = GNUNET_MQ_extract_nested_mh (msg);
604 if (NULL == context_msg)
605 {
606 /* malformed context message is NOT ok */
607 GNUNET_break_op (0);
608 return GNUNET_SYSERR;
609 }
610 return GNUNET_OK;
611}
612
613
614/**
615 * Handle request message for a listen operation
616 *
617 * @param cls the listen handle
618 * @param msg the message
619 */
620static void
621handle_request (void *cls,
622 const struct GNUNET_SETU_RequestMessage *msg)
623{
624 struct GNUNET_SETU_ListenHandle *lh = cls;
625 struct GNUNET_SETU_Request req;
626 const struct GNUNET_MessageHeader *context_msg;
627 struct GNUNET_MQ_Envelope *mqm;
628 struct GNUNET_SETU_RejectMessage *rmsg;
629
630 LOG (GNUNET_ERROR_TYPE_DEBUG,
631 "Processing incoming operation request with id %u\n",
632 ntohl (msg->accept_id));
633 /* we got another valid request => reset the backoff */
634 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
635 req.accept_id = ntohl (msg->accept_id);
636 req.accepted = GNUNET_NO;
637 context_msg = GNUNET_MQ_extract_nested_mh (msg);
638 /* calling #GNUNET_SETU_accept() in the listen cb will set req->accepted */
639 lh->listen_cb (lh->listen_cls,
640 &msg->peer_id,
641 context_msg,
642 &req);
643 if (GNUNET_YES == req.accepted)
644 return; /* the accept-case is handled in #GNUNET_SETU_accept() */
645 LOG (GNUNET_ERROR_TYPE_DEBUG,
646 "Rejected request %u\n",
647 ntohl (msg->accept_id));
648 mqm = GNUNET_MQ_msg (rmsg,
649 GNUNET_MESSAGE_TYPE_SETU_REJECT);
650 rmsg->accept_reject_id = msg->accept_id;
651 GNUNET_MQ_send (lh->mq,
652 mqm);
653}
654
655
656/**
657 * Our connection with the set service encountered an error,
658 * re-initialize with exponential back-off.
659 *
660 * @param cls the `struct GNUNET_SETU_ListenHandle *`
661 * @param error reason for the disconnect
662 */
663static void
664handle_client_listener_error (void *cls,
665 enum GNUNET_MQ_Error error)
666{
667 struct GNUNET_SETU_ListenHandle *lh = cls;
668
669 LOG (GNUNET_ERROR_TYPE_DEBUG,
670 "Listener broke down (%d), re-connecting\n",
671 (int) error);
672 GNUNET_MQ_destroy (lh->mq);
673 lh->mq = NULL;
674 lh->reconnect_task = GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff,
675 &listen_connect,
676 lh);
677 lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
678}
679
680
681/**
682 * Connect to the set service in order to listen for requests.
683 *
684 * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect
685 */
686static void
687listen_connect (void *cls)
688{
689 struct GNUNET_SETU_ListenHandle *lh = cls;
690 struct GNUNET_MQ_MessageHandler mq_handlers[] = {
691 GNUNET_MQ_hd_var_size (request,
692 GNUNET_MESSAGE_TYPE_SETU_REQUEST,
693 struct GNUNET_SETU_RequestMessage,
694 lh),
695 GNUNET_MQ_handler_end ()
696 };
697 struct GNUNET_MQ_Envelope *mqm;
698 struct GNUNET_SETU_ListenMessage *msg;
699
700 lh->reconnect_task = NULL;
701 GNUNET_assert (NULL == lh->mq);
702 lh->mq = GNUNET_CLIENT_connect (lh->cfg,
703 "setu",
704 mq_handlers,
705 &handle_client_listener_error,
706 lh);
707 if (NULL == lh->mq)
708 return;
709 mqm = GNUNET_MQ_msg (msg,
710 GNUNET_MESSAGE_TYPE_SETU_LISTEN);
711 msg->app_id = lh->app_id;
712 GNUNET_MQ_send (lh->mq,
713 mqm);
714}
715
716
717/**
718 * Wait for set operation requests for the given application id
719 *
720 * @param cfg configuration to use for connecting to
721 * the set service, needs to be valid for the lifetime of the listen handle
722 * @param app_id id of the application that handles set operation requests
723 * @param listen_cb called for each incoming request matching the operation
724 * and application id
725 * @param listen_cls handle for @a listen_cb
726 * @return a handle that can be used to cancel the listen operation
727 */
728struct GNUNET_SETU_ListenHandle *
729GNUNET_SETU_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
730 const struct GNUNET_HashCode *app_id,
731 GNUNET_SETU_ListenCallback listen_cb,
732 void *listen_cls)
733{
734 struct GNUNET_SETU_ListenHandle *lh;
735
736 LOG (GNUNET_ERROR_TYPE_DEBUG,
737 "Starting listener for app %s\n",
738 GNUNET_h2s (app_id));
739 lh = GNUNET_new (struct GNUNET_SETU_ListenHandle);
740 lh->listen_cb = listen_cb;
741 lh->listen_cls = listen_cls;
742 lh->cfg = cfg;
743 lh->app_id = *app_id;
744 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
745 listen_connect (lh);
746 if (NULL == lh->mq)
747 {
748 GNUNET_free (lh);
749 return NULL;
750 }
751 return lh;
752}
753
754
755/**
756 * Cancel the given listen operation.
757 *
758 * @param lh handle for the listen operation
759 */
760void
761GNUNET_SETU_listen_cancel (struct GNUNET_SETU_ListenHandle *lh)
762{
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Canceling listener %s\n",
765 GNUNET_h2s (&lh->app_id));
766 if (NULL != lh->mq)
767 {
768 GNUNET_MQ_destroy (lh->mq);
769 lh->mq = NULL;
770 }
771 if (NULL != lh->reconnect_task)
772 {
773 GNUNET_SCHEDULER_cancel (lh->reconnect_task);
774 lh->reconnect_task = NULL;
775 }
776 GNUNET_free (lh);
777}
778
779
780/**
781 * Accept a request we got via #GNUNET_SETU_listen. Must be called during
782 * #GNUNET_SETU_listen, as the 'struct GNUNET_SETU_Request' becomes invalid
783 * afterwards.
784 * Call #GNUNET_SETU_commit to provide the local set to use for the operation,
785 * and to begin the exchange with the remote peer.
786 *
787 * @param request request to accept
788 * @param result_mode specified how results will be returned,
789 * see `enum GNUNET_SETU_ResultMode`.
790 * @param result_cb callback for the results
791 * @param result_cls closure for @a result_cb
792 * @return a handle to cancel the operation
793 */
794struct GNUNET_SETU_OperationHandle *
795GNUNET_SETU_accept (struct GNUNET_SETU_Request *request,
796 const struct GNUNET_SETU_Option options[],
797 GNUNET_SETU_ResultIterator result_cb,
798 void *result_cls)
799{
800 struct GNUNET_MQ_Envelope *mqm;
801 struct GNUNET_SETU_OperationHandle *oh;
802 struct GNUNET_SETU_AcceptMessage *msg;
803
804 GNUNET_assert (GNUNET_NO == request->accepted);
805 LOG (GNUNET_ERROR_TYPE_DEBUG,
806 "Client accepts set union operation with id %u\n",
807 request->accept_id);
808 request->accepted = GNUNET_YES;
809 mqm = GNUNET_MQ_msg (msg,
810 GNUNET_MESSAGE_TYPE_SETU_ACCEPT);
811 msg->accept_reject_id = htonl (request->accept_id);
812
813 /* Set default values */
814 msg->byzantine_upper_bond = UINT64_MAX;
815 msg->bandwidth_latency_tradeoff = 0;
816 msg->ibf_bucket_number_factor = 2;
817 msg->ibf_number_of_buckets_per_element = 3;
818
819 for (const struct GNUNET_SETU_Option *opt = options; opt->type != 0; opt++)
820 {
821 switch (opt->type)
822 {
823 case GNUNET_SETU_OPTION_BYZANTINE:
824 msg->byzantine = GNUNET_YES;
825 msg->byzantine_lower_bound = htonl (opt->v.num);
826 break;
827 case GNUNET_SETU_OPTION_CUSTOM_BYZANTINE_UPPER_BOUND:
828 msg->byzantine_upper_bond = htonl (opt->v.num);
829 break;
830 case GNUNET_SETU_OPTION_CUSTOM_BANDWIDTH_LATENCY_TRADEOFF:
831 msg->bandwidth_latency_tradeoff = htonl (opt->v.num);
832 break;
833 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKET_NUMBER_FACTOR:
834 msg->ibf_bucket_number_factor = htonl (opt->v.num);
835 break;
836 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKETS_PER_ELEMENT:
837 msg->ibf_number_of_buckets_per_element = htonl (opt->v.num);
838 break;
839 case GNUNET_SETU_OPTION_FORCE_FULL:
840 msg->force_full = GNUNET_YES;
841 break;
842 case GNUNET_SETU_OPTION_FORCE_DELTA:
843 msg->force_delta = GNUNET_YES;
844 break;
845 case GNUNET_SETU_OPTION_SYMMETRIC:
846 msg->symmetric = GNUNET_YES;
847 break;
848 default:
849 LOG (GNUNET_ERROR_TYPE_ERROR,
850 "Option with type %d not recognized\n",
851 (int) opt->type);
852 }
853 }
854 oh = GNUNET_new (struct GNUNET_SETU_OperationHandle);
855 oh->result_cb = result_cb;
856 oh->result_cls = result_cls;
857 oh->conclude_mqm = mqm;
858 oh->request_id_addr = &msg->request_id;
859 return oh;
860}
861
862
863/**
864 * Commit a set to be used with a set operation.
865 * This function is called once we have fully constructed
866 * the set that we want to use for the operation. At this
867 * time, the P2P protocol can then begin to exchange the
868 * set information and call the result callback with the
869 * result information.
870 *
871 * @param oh handle to the set operation
872 * @param set the set to use for the operation
873 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
874 * set is invalid (e.g. the set service crashed)
875 */
876int
877GNUNET_SETU_commit (struct GNUNET_SETU_OperationHandle *oh,
878 struct GNUNET_SETU_Handle *set)
879{
880 if (NULL != oh->set)
881 {
882 /* Some other set was already committed for this
883 * operation, there is a logic bug in the client of this API */
884 GNUNET_break (0);
885 return GNUNET_OK;
886 }
887 GNUNET_assert (NULL != set);
888 if (GNUNET_YES == set->invalid)
889 return GNUNET_SYSERR;
890 LOG (GNUNET_ERROR_TYPE_DEBUG,
891 "Client commits to SET\n");
892 GNUNET_assert (NULL != oh->conclude_mqm);
893 oh->set = set;
894 GNUNET_CONTAINER_DLL_insert (set->ops_head,
895 set->ops_tail,
896 oh);
897 oh->request_id = GNUNET_MQ_assoc_add (set->mq,
898 oh);
899 *oh->request_id_addr = htonl (oh->request_id);
900 GNUNET_MQ_send (set->mq,
901 oh->conclude_mqm);
902 oh->conclude_mqm = NULL;
903 oh->request_id_addr = NULL;
904 return GNUNET_OK;
905}
906
907
908/**
909 * Hash a set element.
910 *
911 * @param element the element that should be hashed
912 * @param[out] ret_hash a pointer to where the hash of @a element
913 * should be stored
914 */
915void
916GNUNET_SETU_element_hash (const struct GNUNET_SETU_Element *element,
917 struct GNUNET_HashCode *ret_hash)
918{
919 struct GNUNET_HashContext *ctx = GNUNET_CRYPTO_hash_context_start ();
920
921 /* It's not guaranteed that the element data is always after the element header,
922 so we need to hash the chunks separately. */
923 GNUNET_CRYPTO_hash_context_read (ctx,
924 &element->size,
925 sizeof(uint16_t));
926 GNUNET_CRYPTO_hash_context_read (ctx,
927 &element->element_type,
928 sizeof(uint16_t));
929 GNUNET_CRYPTO_hash_context_read (ctx,
930 element->data,
931 element->size);
932 GNUNET_CRYPTO_hash_context_finish (ctx,
933 ret_hash);
934}
935
936
937/* end of setu_api.c */