aboutsummaryrefslogtreecommitdiff
path: root/src/service/setu/setu_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/setu/setu_api.c')
-rw-r--r--src/service/setu/setu_api.c911
1 files changed, 911 insertions, 0 deletions
diff --git a/src/service/setu/setu_api.c b/src/service/setu/setu_api.c
new file mode 100644
index 000000000..7fa144590
--- /dev/null
+++ b/src/service/setu/setu_api.c
@@ -0,0 +1,911 @@
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
496struct GNUNET_SETU_OperationHandle *
497GNUNET_SETU_prepare (const struct GNUNET_PeerIdentity *other_peer,
498 const struct GNUNET_HashCode *app_id,
499 const struct GNUNET_MessageHeader *context_msg,
500 const struct GNUNET_SETU_Option options[],
501 GNUNET_SETU_ResultIterator result_cb,
502 void *result_cls)
503{
504 struct GNUNET_MQ_Envelope *mqm;
505 struct GNUNET_SETU_OperationHandle *oh;
506 struct GNUNET_SETU_EvaluateMessage *msg;
507
508 LOG (GNUNET_ERROR_TYPE_DEBUG,
509 "Client prepares set union operation\n");
510 oh = GNUNET_new (struct GNUNET_SETU_OperationHandle);
511 oh->result_cb = result_cb;
512 oh->result_cls = result_cls;
513 mqm = GNUNET_MQ_msg_nested_mh (msg,
514 GNUNET_MESSAGE_TYPE_SETU_EVALUATE,
515 context_msg);
516 msg->app_id = *app_id;
517 msg->target_peer = *other_peer;
518
519 /* Set default values */
520 msg->byzantine_upper_bond = UINT64_MAX;
521 msg->bandwidth_latency_tradeoff = 0;
522 msg->ibf_bucket_number_factor = 2;
523 msg->ibf_number_of_buckets_per_element = 3;
524
525
526 for (const struct GNUNET_SETU_Option *opt = options; opt->type != 0; opt++)
527 {
528 switch (opt->type)
529 {
530 case GNUNET_SETU_OPTION_BYZANTINE:
531 msg->byzantine = GNUNET_YES;
532 msg->byzantine_lower_bound = htonl (opt->v.num);
533 break;
534 case GNUNET_SETU_OPTION_CUSTOM_BYZANTINE_UPPER_BOUND:
535 msg->byzantine_upper_bond = htonl (opt->v.num);
536 break;
537 case GNUNET_SETU_OPTION_CUSTOM_BANDWIDTH_LATENCY_TRADEOFF:
538 msg->bandwidth_latency_tradeoff = htonl (opt->v.num);
539 break;
540 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKET_NUMBER_FACTOR:
541 msg->ibf_bucket_number_factor = htonl (opt->v.num);
542 break;
543 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKETS_PER_ELEMENT:
544 msg->ibf_number_of_buckets_per_element = htonl (opt->v.num);
545 break;
546 case GNUNET_SETU_OPTION_FORCE_FULL:
547 msg->force_full = GNUNET_YES;
548 break;
549 case GNUNET_SETU_OPTION_FORCE_DELTA:
550 msg->force_delta = GNUNET_YES;
551 break;
552 case GNUNET_SETU_OPTION_SYMMETRIC:
553 msg->symmetric = GNUNET_YES;
554 break;
555 default:
556 LOG (GNUNET_ERROR_TYPE_ERROR,
557 "Option with type %d not recognized\n",
558 (int) opt->type);
559 }
560 }
561 oh->conclude_mqm = mqm;
562 oh->request_id_addr = &msg->request_id;
563 return oh;
564}
565
566
567/**
568 * Connect to the set service in order to listen for requests.
569 *
570 * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect
571 */
572static void
573listen_connect (void *cls);
574
575
576/**
577 * Check validity of request message for a listen operation
578 *
579 * @param cls the listen handle
580 * @param msg the message
581 * @return #GNUNET_OK if the message is well-formed
582 */
583static int
584check_request (void *cls,
585 const struct GNUNET_SETU_RequestMessage *msg)
586{
587 const struct GNUNET_MessageHeader *context_msg;
588
589 if (ntohs (msg->header.size) == sizeof(*msg))
590 return GNUNET_OK; /* no context message is OK */
591 context_msg = GNUNET_MQ_extract_nested_mh (msg);
592 if (NULL == context_msg)
593 {
594 /* malformed context message is NOT ok */
595 GNUNET_break_op (0);
596 return GNUNET_SYSERR;
597 }
598 return GNUNET_OK;
599}
600
601
602/**
603 * Handle request message for a listen operation
604 *
605 * @param cls the listen handle
606 * @param msg the message
607 */
608static void
609handle_request (void *cls,
610 const struct GNUNET_SETU_RequestMessage *msg)
611{
612 struct GNUNET_SETU_ListenHandle *lh = cls;
613 struct GNUNET_SETU_Request req;
614 const struct GNUNET_MessageHeader *context_msg;
615 struct GNUNET_MQ_Envelope *mqm;
616 struct GNUNET_SETU_RejectMessage *rmsg;
617
618 LOG (GNUNET_ERROR_TYPE_DEBUG,
619 "Processing incoming operation request with id %u\n",
620 ntohl (msg->accept_id));
621 /* we got another valid request => reset the backoff */
622 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
623 req.accept_id = ntohl (msg->accept_id);
624 req.accepted = GNUNET_NO;
625 context_msg = GNUNET_MQ_extract_nested_mh (msg);
626 /* calling #GNUNET_SETU_accept() in the listen cb will set req->accepted */
627 lh->listen_cb (lh->listen_cls,
628 &msg->peer_id,
629 context_msg,
630 &req);
631 if (GNUNET_YES == req.accepted)
632 return; /* the accept-case is handled in #GNUNET_SETU_accept() */
633 LOG (GNUNET_ERROR_TYPE_DEBUG,
634 "Rejected request %u\n",
635 ntohl (msg->accept_id));
636 mqm = GNUNET_MQ_msg (rmsg,
637 GNUNET_MESSAGE_TYPE_SETU_REJECT);
638 rmsg->accept_reject_id = msg->accept_id;
639 GNUNET_MQ_send (lh->mq,
640 mqm);
641}
642
643
644/**
645 * Our connection with the set service encountered an error,
646 * re-initialize with exponential back-off.
647 *
648 * @param cls the `struct GNUNET_SETU_ListenHandle *`
649 * @param error reason for the disconnect
650 */
651static void
652handle_client_listener_error (void *cls,
653 enum GNUNET_MQ_Error error)
654{
655 struct GNUNET_SETU_ListenHandle *lh = cls;
656
657 LOG (GNUNET_ERROR_TYPE_DEBUG,
658 "Listener broke down (%d), re-connecting\n",
659 (int) error);
660 GNUNET_MQ_destroy (lh->mq);
661 lh->mq = NULL;
662 lh->reconnect_task = GNUNET_SCHEDULER_add_delayed (lh->reconnect_backoff,
663 &listen_connect,
664 lh);
665 lh->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (lh->reconnect_backoff);
666}
667
668
669/**
670 * Connect to the set service in order to listen for requests.
671 *
672 * @param cls the `struct GNUNET_SETU_ListenHandle *` to connect
673 */
674static void
675listen_connect (void *cls)
676{
677 struct GNUNET_SETU_ListenHandle *lh = cls;
678 struct GNUNET_MQ_MessageHandler mq_handlers[] = {
679 GNUNET_MQ_hd_var_size (request,
680 GNUNET_MESSAGE_TYPE_SETU_REQUEST,
681 struct GNUNET_SETU_RequestMessage,
682 lh),
683 GNUNET_MQ_handler_end ()
684 };
685 struct GNUNET_MQ_Envelope *mqm;
686 struct GNUNET_SETU_ListenMessage *msg;
687
688 lh->reconnect_task = NULL;
689 GNUNET_assert (NULL == lh->mq);
690 lh->mq = GNUNET_CLIENT_connect (lh->cfg,
691 "setu",
692 mq_handlers,
693 &handle_client_listener_error,
694 lh);
695 if (NULL == lh->mq)
696 return;
697 mqm = GNUNET_MQ_msg (msg,
698 GNUNET_MESSAGE_TYPE_SETU_LISTEN);
699 msg->app_id = lh->app_id;
700 GNUNET_MQ_send (lh->mq,
701 mqm);
702}
703
704
705/**
706 * Wait for set operation requests for the given application id
707 *
708 * @param cfg configuration to use for connecting to
709 * the set service, needs to be valid for the lifetime of the listen handle
710 * @param app_id id of the application that handles set operation requests
711 * @param listen_cb called for each incoming request matching the operation
712 * and application id
713 * @param listen_cls handle for @a listen_cb
714 * @return a handle that can be used to cancel the listen operation
715 */
716struct GNUNET_SETU_ListenHandle *
717GNUNET_SETU_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
718 const struct GNUNET_HashCode *app_id,
719 GNUNET_SETU_ListenCallback listen_cb,
720 void *listen_cls)
721{
722 struct GNUNET_SETU_ListenHandle *lh;
723
724 LOG (GNUNET_ERROR_TYPE_DEBUG,
725 "Starting listener for app %s\n",
726 GNUNET_h2s (app_id));
727 lh = GNUNET_new (struct GNUNET_SETU_ListenHandle);
728 lh->listen_cb = listen_cb;
729 lh->listen_cls = listen_cls;
730 lh->cfg = cfg;
731 lh->app_id = *app_id;
732 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
733 listen_connect (lh);
734 if (NULL == lh->mq)
735 {
736 GNUNET_free (lh);
737 return NULL;
738 }
739 return lh;
740}
741
742
743/**
744 * Cancel the given listen operation.
745 *
746 * @param lh handle for the listen operation
747 */
748void
749GNUNET_SETU_listen_cancel (struct GNUNET_SETU_ListenHandle *lh)
750{
751 LOG (GNUNET_ERROR_TYPE_DEBUG,
752 "Canceling listener %s\n",
753 GNUNET_h2s (&lh->app_id));
754 if (NULL != lh->mq)
755 {
756 GNUNET_MQ_destroy (lh->mq);
757 lh->mq = NULL;
758 }
759 if (NULL != lh->reconnect_task)
760 {
761 GNUNET_SCHEDULER_cancel (lh->reconnect_task);
762 lh->reconnect_task = NULL;
763 }
764 GNUNET_free (lh);
765}
766
767
768struct GNUNET_SETU_OperationHandle *
769GNUNET_SETU_accept (struct GNUNET_SETU_Request *request,
770 const struct GNUNET_SETU_Option options[],
771 GNUNET_SETU_ResultIterator result_cb,
772 void *result_cls)
773{
774 struct GNUNET_MQ_Envelope *mqm;
775 struct GNUNET_SETU_OperationHandle *oh;
776 struct GNUNET_SETU_AcceptMessage *msg;
777
778 GNUNET_assert (GNUNET_NO == request->accepted);
779 LOG (GNUNET_ERROR_TYPE_DEBUG,
780 "Client accepts set union operation with id %u\n",
781 request->accept_id);
782 request->accepted = GNUNET_YES;
783 mqm = GNUNET_MQ_msg (msg,
784 GNUNET_MESSAGE_TYPE_SETU_ACCEPT);
785 msg->accept_reject_id = htonl (request->accept_id);
786
787 /* Set default values */
788 msg->byzantine_upper_bond = UINT64_MAX;
789 msg->bandwidth_latency_tradeoff = 0;
790 msg->ibf_bucket_number_factor = 2;
791 msg->ibf_number_of_buckets_per_element = 3;
792
793 for (const struct GNUNET_SETU_Option *opt = options; opt->type != 0; opt++)
794 {
795 switch (opt->type)
796 {
797 case GNUNET_SETU_OPTION_BYZANTINE:
798 msg->byzantine = GNUNET_YES;
799 msg->byzantine_lower_bound = htonl (opt->v.num);
800 break;
801 case GNUNET_SETU_OPTION_CUSTOM_BYZANTINE_UPPER_BOUND:
802 msg->byzantine_upper_bond = htonl (opt->v.num);
803 break;
804 case GNUNET_SETU_OPTION_CUSTOM_BANDWIDTH_LATENCY_TRADEOFF:
805 msg->bandwidth_latency_tradeoff = htonl (opt->v.num);
806 break;
807 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKET_NUMBER_FACTOR:
808 msg->ibf_bucket_number_factor = htonl (opt->v.num);
809 break;
810 case GNUNET_SETU_OPTION_CUSTOM_IBF_BUCKETS_PER_ELEMENT:
811 msg->ibf_number_of_buckets_per_element = htonl (opt->v.num);
812 break;
813 case GNUNET_SETU_OPTION_FORCE_FULL:
814 msg->force_full = GNUNET_YES;
815 break;
816 case GNUNET_SETU_OPTION_FORCE_DELTA:
817 msg->force_delta = GNUNET_YES;
818 break;
819 case GNUNET_SETU_OPTION_SYMMETRIC:
820 msg->symmetric = GNUNET_YES;
821 break;
822 default:
823 LOG (GNUNET_ERROR_TYPE_ERROR,
824 "Option with type %d not recognized\n",
825 (int) opt->type);
826 }
827 }
828 oh = GNUNET_new (struct GNUNET_SETU_OperationHandle);
829 oh->result_cb = result_cb;
830 oh->result_cls = result_cls;
831 oh->conclude_mqm = mqm;
832 oh->request_id_addr = &msg->request_id;
833 return oh;
834}
835
836
837/**
838 * Commit a set to be used with a set operation.
839 * This function is called once we have fully constructed
840 * the set that we want to use for the operation. At this
841 * time, the P2P protocol can then begin to exchange the
842 * set information and call the result callback with the
843 * result information.
844 *
845 * @param oh handle to the set operation
846 * @param set the set to use for the operation
847 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
848 * set is invalid (e.g. the set service crashed)
849 */
850int
851GNUNET_SETU_commit (struct GNUNET_SETU_OperationHandle *oh,
852 struct GNUNET_SETU_Handle *set)
853{
854 if (NULL != oh->set)
855 {
856 /* Some other set was already committed for this
857 * operation, there is a logic bug in the client of this API */
858 GNUNET_break (0);
859 return GNUNET_OK;
860 }
861 GNUNET_assert (NULL != set);
862 if (GNUNET_YES == set->invalid)
863 return GNUNET_SYSERR;
864 LOG (GNUNET_ERROR_TYPE_DEBUG,
865 "Client commits to SET\n");
866 GNUNET_assert (NULL != oh->conclude_mqm);
867 oh->set = set;
868 GNUNET_CONTAINER_DLL_insert (set->ops_head,
869 set->ops_tail,
870 oh);
871 oh->request_id = GNUNET_MQ_assoc_add (set->mq,
872 oh);
873 *oh->request_id_addr = htonl (oh->request_id);
874 GNUNET_MQ_send (set->mq,
875 oh->conclude_mqm);
876 oh->conclude_mqm = NULL;
877 oh->request_id_addr = NULL;
878 return GNUNET_OK;
879}
880
881
882/**
883 * Hash a set element.
884 *
885 * @param element the element that should be hashed
886 * @param[out] ret_hash a pointer to where the hash of @a element
887 * should be stored
888 */
889void
890GNUNET_SETU_element_hash (const struct GNUNET_SETU_Element *element,
891 struct GNUNET_HashCode *ret_hash)
892{
893 struct GNUNET_HashContext *ctx = GNUNET_CRYPTO_hash_context_start ();
894
895 /* It's not guaranteed that the element data is always after the element header,
896 so we need to hash the chunks separately. */
897 GNUNET_CRYPTO_hash_context_read (ctx,
898 &element->size,
899 sizeof(uint16_t));
900 GNUNET_CRYPTO_hash_context_read (ctx,
901 &element->element_type,
902 sizeof(uint16_t));
903 GNUNET_CRYPTO_hash_context_read (ctx,
904 element->data,
905 element->size);
906 GNUNET_CRYPTO_hash_context_finish (ctx,
907 ret_hash);
908}
909
910
911/* end of setu_api.c */