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