2 This file is part of GNUnet.
3 Copyright (C) 2009-2014 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file core/core_api.c
22 * @brief core service; this is the main API for encrypted P2P
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_core_service.h"
32 #define LOG(kind,...) GNUNET_log_from (kind, "core-api",__VA_ARGS__)
36 * Handle for a transmission request.
38 struct GNUNET_CORE_TransmitHandle
42 * Corresponding peer record.
44 struct PeerRecord *peer;
47 * Corresponding SEND_REQUEST message. Only non-NULL
48 * while SEND_REQUEST message is pending.
50 struct ControlMessage *cm;
53 * Function that will be called to get the actual request
54 * (once we are ready to transmit this request to the core).
55 * The function will be called with a NULL buffer to signal
58 GNUNET_CONNECTION_TransmitReadyNotify get_message;
61 * Closure for @e get_message.
63 void *get_message_cls;
66 * Deadline for the transmission (the request does not get cancelled
67 * at this time, this is merely how soon the application wants this out).
69 struct GNUNET_TIME_Absolute deadline;
72 * When did this request get queued?
74 struct GNUNET_TIME_Absolute request_time;
77 * How important is this message?
79 enum GNUNET_CORE_Priority priority;
87 * Size of this request.
92 * Send message request ID for this request.
100 * Information we track for each peer.
106 * We generally do NOT keep peer records in a DLL; this
107 * DLL is only used IF this peer's 'pending_head' message
108 * is ready for transmission.
110 struct PeerRecord *prev;
113 * We generally do NOT keep peer records in a DLL; this
114 * DLL is only used IF this peer's 'pending_head' message
115 * is ready for transmission.
117 struct PeerRecord *next;
120 * Corresponding core handle.
122 struct GNUNET_CORE_Handle *ch;
125 * Pending request, if any. 'th->peer' is set to NULL if the
126 * request is not active.
128 struct GNUNET_CORE_TransmitHandle th;
131 * Peer the record is about.
133 struct GNUNET_PeerIdentity peer;
136 * ID of task to run #run_request_next_transmission().
138 struct GNUNET_SCHEDULER_Task *ntr_task;
141 * SendMessageRequest ID generator for this peer.
149 * Type of function called upon completion.
152 * @param success #GNUNET_OK on success (which for request_connect
153 * ONLY means that we transmitted the connect request to CORE,
154 * it does not mean that we are actually now connected!);
155 * #GNUNET_NO on timeout,
156 * #GNUNET_SYSERR if core was shut down
159 (*GNUNET_CORE_ControlContinuation) (void *cls,
164 * Entry in a doubly-linked list of control messages to be transmitted
165 * to the core service. Control messages include traffic allocation,
166 * connection requests and of course our initial 'init' request.
168 * The actual message is allocated at the end of this struct.
170 struct ControlMessage
173 * This is a doubly-linked list.
175 struct ControlMessage *next;
178 * This is a doubly-linked list.
180 struct ControlMessage *prev;
183 * Function to run after transmission failed/succeeded.
185 GNUNET_CORE_ControlContinuation cont;
188 * Closure for @e cont.
193 * Transmit handle (if one is associated with this ControlMessage), or NULL.
195 struct GNUNET_CORE_TransmitHandle *th;
201 * Context for the core service connection.
203 struct GNUNET_CORE_Handle
207 * Configuration we're using.
209 const struct GNUNET_CONFIGURATION_Handle *cfg;
212 * Closure for the various callbacks.
217 * Function to call once we've handshaked with the core service.
219 GNUNET_CORE_StartupCallback init;
222 * Function to call whenever we're notified about a peer connecting.
224 GNUNET_CORE_ConnectEventHandler connects;
227 * Function to call whenever we're notified about a peer disconnecting.
229 GNUNET_CORE_DisconnectEventHandler disconnects;
232 * Function to call whenever we receive an inbound message.
234 GNUNET_CORE_MessageCallback inbound_notify;
237 * Function to call whenever we receive an outbound message.
239 GNUNET_CORE_MessageCallback outbound_notify;
242 * Function handlers for messages of particular type.
244 const struct GNUNET_CORE_MessageHandler *handlers;
247 * Our connection to the service.
249 struct GNUNET_CLIENT_Connection *client;
252 * Handle for our current transmission request.
254 struct GNUNET_CLIENT_TransmitHandle *cth;
257 * Head of doubly-linked list of pending requests.
259 struct ControlMessage *control_pending_head;
262 * Tail of doubly-linked list of pending requests.
264 struct ControlMessage *control_pending_tail;
267 * Head of doubly-linked list of peers that are core-approved
268 * to send their next message.
270 struct PeerRecord *ready_peer_head;
273 * Tail of doubly-linked list of peers that are core-approved
274 * to send their next message.
276 struct PeerRecord *ready_peer_tail;
279 * Hash map listing all of the peers that we are currently
282 struct GNUNET_CONTAINER_MultiPeerMap *peers;
285 * Identity of this peer.
287 struct GNUNET_PeerIdentity me;
290 * ID of reconnect task (if any).
292 struct GNUNET_SCHEDULER_Task * reconnect_task;
295 * Current delay we use for re-trying to connect to core.
297 struct GNUNET_TIME_Relative retry_backoff;
300 * Number of entries in the handlers array.
305 * For inbound notifications without a specific handler, do
306 * we expect to only receive headers?
308 int inbound_hdr_only;
311 * For outbound notifications without a specific handler, do
312 * we expect to only receive headers?
314 int outbound_hdr_only;
317 * Are we currently disconnected and hence unable to forward
326 * Our current client connection went down. Clean it up
327 * and try to reconnect!
329 * @param h our handle to the core service
332 reconnect (struct GNUNET_CORE_Handle *h);
336 * Task schedule to try to re-connect to core.
338 * @param cls the `struct GNUNET_CORE_Handle`
339 * @param tc task context
342 reconnect_task (void *cls,
343 const struct GNUNET_SCHEDULER_TaskContext *tc)
345 struct GNUNET_CORE_Handle *h = cls;
347 h->reconnect_task = NULL;
348 LOG (GNUNET_ERROR_TYPE_DEBUG,
349 "Connecting to CORE service after delay\n");
355 * Notify clients about disconnect and free
356 * the entry for connected peer.
358 * @param cls the `struct GNUNET_CORE_Handle *`
359 * @param key the peer identity (not used)
360 * @param value the `struct PeerRecord` to free.
361 * @return #GNUNET_YES (continue)
364 disconnect_and_free_peer_entry (void *cls,
365 const struct GNUNET_PeerIdentity *key,
368 struct GNUNET_CORE_Handle *h = cls;
369 struct GNUNET_CORE_TransmitHandle *th;
370 struct PeerRecord *pr = value;
372 if (NULL != pr->ntr_task)
374 GNUNET_SCHEDULER_cancel (pr->ntr_task);
377 if ( (NULL != pr->prev) ||
378 (NULL != pr->next) ||
379 (h->ready_peer_head == pr) )
380 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
383 if (NULL != h->disconnects)
384 h->disconnects (h->cls,
386 /* all requests should have been cancelled, clean up anyway, just in case */
388 if (NULL != th->peer)
395 /* done with 'voluntary' cleanups, now on to normal freeing */
396 GNUNET_assert (GNUNET_YES ==
397 GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr));
398 GNUNET_assert (pr->ch == h);
399 GNUNET_assert (NULL == pr->ntr_task);
406 * Close down any existing connection to the CORE service and
407 * try re-establishing it later.
409 * @param h our handle
412 reconnect_later (struct GNUNET_CORE_Handle *h)
414 struct ControlMessage *cm;
415 struct PeerRecord *pr;
417 GNUNET_assert (NULL == h->reconnect_task);
420 GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth);
423 if (NULL != h->client)
425 GNUNET_CLIENT_disconnect (h->client);
428 h->currently_down = GNUNET_YES;
429 GNUNET_assert (h->reconnect_task == NULL);
431 GNUNET_SCHEDULER_add_delayed (h->retry_backoff,
433 while (NULL != (cm = h->control_pending_head))
435 GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
436 h->control_pending_tail,
440 if (NULL != cm->cont)
441 cm->cont (cm->cont_cls, GNUNET_NO);
444 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
445 &disconnect_and_free_peer_entry, h);
446 while (NULL != (pr = h->ready_peer_head))
447 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
450 GNUNET_assert (NULL == h->control_pending_head);
451 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
456 * Check the list of pending requests, send the next
459 * @param h core handle
460 * @param ignore_currently_down transmit message even if not initialized?
463 trigger_next_request (struct GNUNET_CORE_Handle *h,
464 int ignore_currently_down);
468 * Send a control message to the peer asking for transmission
469 * of the message in the given peer record.
471 * @param pr peer to request transmission to
474 request_next_transmission (struct PeerRecord *pr)
476 struct GNUNET_CORE_Handle *h = pr->ch;
477 struct ControlMessage *cm;
478 struct SendMessageRequest *smr;
479 struct GNUNET_CORE_TransmitHandle *th;
482 if (NULL == th->peer)
484 trigger_next_request (h, GNUNET_NO);
488 return; /* already done */
489 GNUNET_assert (NULL == pr->prev);
490 GNUNET_assert (NULL == pr->next);
491 cm = GNUNET_malloc (sizeof (struct ControlMessage) +
492 sizeof (struct SendMessageRequest));
495 smr = (struct SendMessageRequest *) &cm[1];
496 smr->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
497 smr->header.size = htons (sizeof (struct SendMessageRequest));
498 smr->priority = htonl ((uint32_t) th->priority);
499 smr->deadline = GNUNET_TIME_absolute_hton (th->deadline);
500 smr->peer = pr->peer;
501 smr->reserved = htonl (0);
502 smr->size = htons (th->msize);
503 smr->smr_id = htons (th->smr_id = pr->smr_id_gen++);
504 GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
505 h->control_pending_tail, cm);
506 LOG (GNUNET_ERROR_TYPE_DEBUG,
507 "Adding SEND REQUEST for peer `%s' to message queue\n",
508 GNUNET_i2s (&pr->peer));
509 trigger_next_request (h, GNUNET_NO);
514 * Transmit the next message to the core service.
516 * @param cls closure with the `struct GNUNET_CORE_Handle`
517 * @param size number of bytes available in @a buf
518 * @param buf where the callee should write the message
519 * @return number of bytes written to @a buf
522 transmit_message (void *cls,
526 struct GNUNET_CORE_Handle *h = cls;
527 struct ControlMessage *cm;
528 struct GNUNET_CORE_TransmitHandle *th;
529 struct GNUNET_TIME_Relative delay;
530 struct GNUNET_TIME_Relative overdue;
531 struct PeerRecord *pr;
532 struct SendMessage *sm;
533 const struct GNUNET_MessageHeader *hdr;
537 GNUNET_assert (h->reconnect_task == NULL);
541 LOG (GNUNET_ERROR_TYPE_DEBUG,
542 "Transmission failed, initiating reconnect\n");
546 /* first check for control messages */
547 if (NULL != (cm = h->control_pending_head))
549 hdr = (const struct GNUNET_MessageHeader *) &cm[1];
550 msize = ntohs (hdr->size);
553 trigger_next_request (h, GNUNET_NO);
556 LOG (GNUNET_ERROR_TYPE_DEBUG,
557 "Transmitting control message with %u bytes of type %u to core.\n",
558 (unsigned int) msize,
559 (unsigned int) ntohs (hdr->type));
560 memcpy (buf, hdr, msize);
561 GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
562 h->control_pending_tail, cm);
565 if (NULL != cm->cont)
566 cm->cont (cm->cont_cls, GNUNET_OK);
568 trigger_next_request (h, GNUNET_NO);
571 /* now check for 'ready' P2P messages */
572 if (NULL == (pr = h->ready_peer_head))
574 GNUNET_assert (NULL != pr->th.peer);
576 if (size < th->msize + sizeof (struct SendMessage))
578 trigger_next_request (h, GNUNET_NO);
581 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
585 LOG (GNUNET_ERROR_TYPE_DEBUG,
586 "Transmitting SEND request to `%s' with %u bytes.\n",
587 GNUNET_i2s (&pr->peer),
588 (unsigned int) th->msize);
589 sm = (struct SendMessage *) buf;
590 sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND);
591 sm->priority = htonl ((uint32_t) th->priority);
592 sm->deadline = GNUNET_TIME_absolute_hton (th->deadline);
594 sm->cork = htonl ((uint32_t) th->cork);
595 sm->reserved = htonl (0);
597 th->get_message (th->get_message_cls,
598 size - sizeof (struct SendMessage),
600 delay = GNUNET_TIME_absolute_get_duration (th->request_time);
601 overdue = GNUNET_TIME_absolute_get_duration (th->deadline);
602 if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
603 LOG (GNUNET_ERROR_TYPE_WARNING,
604 "Transmitting overdue %u bytes to `%s' at priority %u with %s delay%s\n",
606 GNUNET_i2s (&pr->peer),
607 (unsigned int) th->priority,
608 GNUNET_STRINGS_relative_time_to_string (delay,
610 (th->cork) ? " (corked)" : "");
612 LOG (GNUNET_ERROR_TYPE_DEBUG,
613 "Transmitting %u bytes to `%s' at priority %u with %s delay%s\n",
615 GNUNET_i2s (&pr->peer),
616 (unsigned int) th->priority,
617 GNUNET_STRINGS_relative_time_to_string (delay,
619 (th->cork) ? " (corked)" : "");
621 (GNUNET_CORE_PRIO_BACKGROUND == th->priority) )
623 /* client decided to send nothing; as the priority was
624 BACKGROUND, we can just not send anything to core.
625 For higher-priority messages, we must give an
626 empty message to CORE so that it knows that this
627 message is no longer pending. */
628 LOG (GNUNET_ERROR_TYPE_DEBUG,
629 "Size of clients message to peer %s is 0!\n",
630 GNUNET_i2s (&pr->peer));
631 request_next_transmission (pr);
634 LOG (GNUNET_ERROR_TYPE_DEBUG,
635 "Produced SEND message to core with %u bytes payload\n",
637 if (ret + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
640 request_next_transmission (pr);
643 ret += sizeof (struct SendMessage);
644 sm->header.size = htons (ret);
645 GNUNET_assert (ret <= size);
646 request_next_transmission (pr);
652 * Check the list of pending requests, send the next one to the core.
654 * @param h core handle
655 * @param ignore_currently_down transmit message even if not initialized?
658 trigger_next_request (struct GNUNET_CORE_Handle *h,
659 int ignore_currently_down)
663 if ( (GNUNET_YES == h->currently_down) &&
664 (GNUNET_NO == ignore_currently_down) )
666 LOG (GNUNET_ERROR_TYPE_DEBUG,
667 "Core connection down, not processing queue\n");
672 LOG (GNUNET_ERROR_TYPE_DEBUG,
673 "Request pending, not processing queue\n");
676 if (NULL != h->control_pending_head)
678 ntohs (((struct GNUNET_MessageHeader *) &h->
679 control_pending_head[1])->size);
680 else if (h->ready_peer_head != NULL)
682 h->ready_peer_head->th.msize + sizeof (struct SendMessage);
685 LOG (GNUNET_ERROR_TYPE_DEBUG,
686 "Request queue empty, not processing queue\n");
687 return; /* no pending message */
690 GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
691 GNUNET_TIME_UNIT_FOREVER_REL,
693 &transmit_message, h);
698 * Handler for notification messages received from the core.
700 * @param cls our `struct GNUNET_CORE_Handle`
701 * @param msg the message received from the core service
704 main_notify_handler (void *cls,
705 const struct GNUNET_MessageHeader *msg)
707 struct GNUNET_CORE_Handle *h = cls;
708 const struct InitReplyMessage *m;
709 const struct ConnectNotifyMessage *cnm;
710 const struct DisconnectNotifyMessage *dnm;
711 const struct NotifyTrafficMessage *ntm;
712 const struct GNUNET_MessageHeader *em;
713 const struct SendMessageReady *smr;
714 const struct GNUNET_CORE_MessageHandler *mh;
715 GNUNET_CORE_StartupCallback init;
716 struct PeerRecord *pr;
717 struct GNUNET_CORE_TransmitHandle *th;
725 LOG (GNUNET_ERROR_TYPE_INFO,
726 _("Client was disconnected from core service, trying to reconnect.\n"));
730 msize = ntohs (msg->size);
731 LOG (GNUNET_ERROR_TYPE_DEBUG,
732 "Processing message of type %u and size %u from core service\n",
733 ntohs (msg->type), msize);
734 switch (ntohs (msg->type))
736 case GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY:
737 if (ntohs (msg->size) != sizeof (struct InitReplyMessage))
743 m = (const struct InitReplyMessage *) msg;
744 GNUNET_break (0 == ntohl (m->reserved));
745 /* start our message processing loop */
746 if (GNUNET_YES == h->currently_down)
748 h->currently_down = GNUNET_NO;
749 trigger_next_request (h, GNUNET_NO);
751 h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
752 h->me = m->my_identity;
753 if (NULL != (init = h->init))
755 /* mark so we don't call init on reconnect */
757 LOG (GNUNET_ERROR_TYPE_DEBUG,
758 "Connected to core service of peer `%s'.\n",
759 GNUNET_i2s (&h->me));
760 init (h->cls, &h->me);
764 LOG (GNUNET_ERROR_TYPE_DEBUG,
765 "Successfully reconnected to core service.\n");
767 /* fake 'connect to self' */
768 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &h->me);
769 GNUNET_assert (NULL == pr);
770 pr = GNUNET_new (struct PeerRecord);
773 GNUNET_assert (GNUNET_YES ==
774 GNUNET_CONTAINER_multipeermap_put (h->peers,
776 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
777 if (NULL != h->connects)
778 h->connects (h->cls, &pr->peer);
780 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT:
781 if (msize < sizeof (struct ConnectNotifyMessage))
787 cnm = (const struct ConnectNotifyMessage *) msg;
789 sizeof (struct ConnectNotifyMessage))
795 LOG (GNUNET_ERROR_TYPE_DEBUG,
796 "Received notification about connection from `%s'.\n",
797 GNUNET_i2s (&cnm->peer));
798 if (0 == memcmp (&h->me,
800 sizeof (struct GNUNET_PeerIdentity)))
802 /* connect to self!? */
806 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer);
813 pr = GNUNET_new (struct PeerRecord);
814 pr->peer = cnm->peer;
816 GNUNET_assert (GNUNET_YES ==
817 GNUNET_CONTAINER_multipeermap_put (h->peers,
819 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
820 if (NULL != h->connects)
821 h->connects (h->cls, &pr->peer);
823 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT:
824 if (msize != sizeof (struct DisconnectNotifyMessage))
830 dnm = (const struct DisconnectNotifyMessage *) msg;
831 if (0 == memcmp (&h->me,
833 sizeof (struct GNUNET_PeerIdentity)))
835 /* connection to self!? */
839 GNUNET_break (0 == ntohl (dnm->reserved));
840 LOG (GNUNET_ERROR_TYPE_DEBUG,
841 "Received notification about disconnect from `%s'.\n",
842 GNUNET_i2s (&dnm->peer));
843 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer);
850 trigger = ((pr->prev != NULL) || (pr->next != NULL) ||
851 (h->ready_peer_head == pr));
852 disconnect_and_free_peer_entry (h, &dnm->peer, pr);
854 trigger_next_request (h, GNUNET_NO);
856 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND:
857 if (msize < sizeof (struct NotifyTrafficMessage))
863 ntm = (const struct NotifyTrafficMessage *) msg;
865 sizeof (struct NotifyTrafficMessage) +
866 sizeof (struct GNUNET_MessageHeader)) )
872 em = (const struct GNUNET_MessageHeader *) &ntm[1];
873 LOG (GNUNET_ERROR_TYPE_DEBUG,
874 "Received message of type %u and size %u from peer `%s'\n",
875 ntohs (em->type), ntohs (em->size), GNUNET_i2s (&ntm->peer));
876 if ((GNUNET_NO == h->inbound_hdr_only) &&
878 ntohs (em->size) + sizeof (struct NotifyTrafficMessage)))
884 et = ntohs (em->type);
885 for (hpos = 0; hpos < h->hcnt; hpos++)
887 mh = &h->handlers[hpos];
890 if ((mh->expected_size != ntohs (em->size)) && (mh->expected_size != 0))
892 LOG (GNUNET_ERROR_TYPE_ERROR,
893 "Unexpected message size %u for message of type %u from peer `%s'\n",
894 htons (em->size), mh->type, GNUNET_i2s (&ntm->peer));
898 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer);
906 h->handlers[hpos].callback (h->cls, &ntm->peer, em))
908 /* error in processing, do not process other messages! */
912 if (NULL != h->inbound_notify)
913 h->inbound_notify (h->cls, &ntm->peer, em);
915 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND:
916 if (msize < sizeof (struct NotifyTrafficMessage))
922 ntm = (const struct NotifyTrafficMessage *) msg;
924 sizeof (struct NotifyTrafficMessage) +
925 sizeof (struct GNUNET_MessageHeader)) )
931 em = (const struct GNUNET_MessageHeader *) &ntm[1];
932 LOG (GNUNET_ERROR_TYPE_DEBUG,
933 "Received notification about transmission to `%s'.\n",
934 GNUNET_i2s (&ntm->peer));
935 if ((GNUNET_NO == h->outbound_hdr_only) &&
937 ntohs (em->size) + sizeof (struct NotifyTrafficMessage)))
943 if (NULL == h->outbound_notify)
948 h->outbound_notify (h->cls, &ntm->peer, em);
950 case GNUNET_MESSAGE_TYPE_CORE_SEND_READY:
951 if (msize != sizeof (struct SendMessageReady))
957 smr = (const struct SendMessageReady *) msg;
958 pr = GNUNET_CONTAINER_multipeermap_get (h->peers,
966 LOG (GNUNET_ERROR_TYPE_DEBUG,
967 "Received notification about transmission readiness to `%s'.\n",
968 GNUNET_i2s (&smr->peer));
969 if (NULL == pr->th.peer)
971 /* request must have been cancelled between the original request
972 * and the response from core, ignore core's readiness */
977 if (ntohs (smr->smr_id) != th->smr_id)
979 /* READY message is for expired or cancelled message,
980 * ignore! (we should have already sent another request) */
983 if ( (NULL != pr->prev) ||
984 (NULL != pr->next) ||
985 (h->ready_peer_head == pr) )
987 /* we should not already be on the ready list... */
992 GNUNET_CONTAINER_DLL_insert (h->ready_peer_head,
995 trigger_next_request (h, GNUNET_NO);
1001 GNUNET_CLIENT_receive (h->client,
1002 &main_notify_handler, h,
1003 GNUNET_TIME_UNIT_FOREVER_REL);
1008 * Task executed once we are done transmitting the INIT message.
1009 * Starts our 'receive' loop.
1011 * @param cls the 'struct GNUNET_CORE_Handle'
1012 * @param success were we successful
1015 init_done_task (void *cls, int success)
1017 struct GNUNET_CORE_Handle *h = cls;
1019 if (GNUNET_SYSERR == success)
1020 return; /* shutdown */
1021 if (GNUNET_NO == success)
1023 LOG (GNUNET_ERROR_TYPE_DEBUG,
1024 "Failed to exchange INIT with core, retrying\n");
1025 if (h->reconnect_task == NULL)
1026 reconnect_later (h);
1029 GNUNET_CLIENT_receive (h->client,
1030 &main_notify_handler, h,
1031 GNUNET_TIME_UNIT_FOREVER_REL);
1036 * Our current client connection went down. Clean it up
1037 * and try to reconnect!
1039 * @param h our handle to the core service
1042 reconnect (struct GNUNET_CORE_Handle *h)
1044 struct ControlMessage *cm;
1045 struct InitMessage *init;
1051 GNUNET_assert (NULL == h->client);
1052 GNUNET_assert (GNUNET_YES == h->currently_down);
1053 GNUNET_assert (NULL != h->cfg);
1054 h->client = GNUNET_CLIENT_connect ("core", h->cfg);
1055 if (NULL == h->client)
1057 reconnect_later (h);
1060 msize = h->hcnt * sizeof (uint16_t) + sizeof (struct InitMessage);
1061 cm = GNUNET_malloc (sizeof (struct ControlMessage) + msize);
1062 cm->cont = &init_done_task;
1064 init = (struct InitMessage *) &cm[1];
1065 init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT);
1066 init->header.size = htons (msize);
1068 if (NULL != h->inbound_notify)
1070 if (h->inbound_hdr_only)
1071 opt |= GNUNET_CORE_OPTION_SEND_HDR_INBOUND;
1073 opt |= GNUNET_CORE_OPTION_SEND_FULL_INBOUND;
1075 if (NULL != h->outbound_notify)
1077 if (h->outbound_hdr_only)
1078 opt |= GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND;
1080 opt |= GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND;
1082 LOG (GNUNET_ERROR_TYPE_INFO,
1083 "(Re)connecting to CORE service, monitoring messages of type %u\n",
1086 init->options = htonl (opt);
1087 ts = (uint16_t *) & init[1];
1088 for (hpos = 0; hpos < h->hcnt; hpos++)
1089 ts[hpos] = htons (h->handlers[hpos].type);
1090 GNUNET_CONTAINER_DLL_insert (h->control_pending_head,
1091 h->control_pending_tail,
1093 trigger_next_request (h, GNUNET_YES);
1099 * Connect to the core service. Note that the connection may
1100 * complete (or fail) asynchronously.
1102 * @param cfg configuration to use
1103 * @param cls closure for the various callbacks that follow (including handlers in the handlers array)
1104 * @param init callback to call once we have successfully
1105 * connected to the core service
1106 * @param connects function to call on peer connect, can be NULL
1107 * @param disconnects function to call on peer disconnect / timeout, can be NULL
1108 * @param inbound_notify function to call for all inbound messages, can be NULL
1109 * @param inbound_hdr_only set to #GNUNET_YES if inbound_notify will only read the
1110 * GNUNET_MessageHeader and hence we do not need to give it the full message;
1111 * can be used to improve efficiency, ignored if @a inbound_notify is NULLL
1112 * @param outbound_notify function to call for all outbound messages, can be NULL
1113 * @param outbound_hdr_only set to #GNUNET_YES if outbound_notify will only read the
1114 * GNUNET_MessageHeader and hence we do not need to give it the full message
1115 * can be used to improve efficiency, ignored if @a outbound_notify is NULLL
1116 * @param handlers callbacks for messages we care about, NULL-terminated
1117 * @return handle to the core service (only useful for disconnect until 'init' is called);
1118 * NULL on error (in this case, init is never called)
1120 struct GNUNET_CORE_Handle *
1121 GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1123 GNUNET_CORE_StartupCallback init,
1124 GNUNET_CORE_ConnectEventHandler connects,
1125 GNUNET_CORE_DisconnectEventHandler disconnects,
1126 GNUNET_CORE_MessageCallback inbound_notify,
1127 int inbound_hdr_only,
1128 GNUNET_CORE_MessageCallback outbound_notify,
1129 int outbound_hdr_only,
1130 const struct GNUNET_CORE_MessageHandler *handlers)
1132 struct GNUNET_CORE_Handle *h;
1134 GNUNET_assert (NULL != cfg);
1135 h = GNUNET_new (struct GNUNET_CORE_Handle);
1139 h->connects = connects;
1140 h->disconnects = disconnects;
1141 h->inbound_notify = inbound_notify;
1142 h->outbound_notify = outbound_notify;
1143 h->inbound_hdr_only = inbound_hdr_only;
1144 h->outbound_hdr_only = outbound_hdr_only;
1145 h->handlers = handlers;
1147 h->currently_down = GNUNET_YES;
1148 h->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1149 if (NULL != handlers)
1150 while (NULL != handlers[h->hcnt].callback)
1152 GNUNET_assert (h->hcnt <
1153 (GNUNET_SERVER_MAX_MESSAGE_SIZE -
1154 sizeof (struct InitMessage)) / sizeof (uint16_t));
1155 LOG (GNUNET_ERROR_TYPE_DEBUG,
1156 "Connecting to CORE service\n");
1163 * Disconnect from the core service. This function can only
1164 * be called *after* all pending #GNUNET_CORE_notify_transmit_ready()
1165 * requests have been explicitly canceled.
1167 * @param handle connection to core to disconnect
1170 GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
1172 struct ControlMessage *cm;
1174 GNUNET_assert (NULL != handle);
1175 LOG (GNUNET_ERROR_TYPE_DEBUG,
1176 "Disconnecting from CORE service\n");
1177 if (NULL != handle->cth)
1179 GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth);
1182 while (NULL != (cm = handle->control_pending_head))
1184 GNUNET_CONTAINER_DLL_remove (handle->control_pending_head,
1185 handle->control_pending_tail,
1189 if (NULL != cm->cont)
1190 cm->cont (cm->cont_cls, GNUNET_SYSERR);
1193 if (NULL != handle->client)
1195 GNUNET_CLIENT_disconnect (handle->client);
1196 handle->client = NULL;
1198 GNUNET_CONTAINER_multipeermap_iterate (handle->peers,
1199 &disconnect_and_free_peer_entry,
1201 if (NULL != handle->reconnect_task)
1203 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1204 handle->reconnect_task = NULL;
1206 GNUNET_CONTAINER_multipeermap_destroy (handle->peers);
1207 handle->peers = NULL;
1208 GNUNET_break (NULL == handle->ready_peer_head);
1209 GNUNET_free (handle);
1214 * Task that calls #request_next_transmission().
1216 * @param cls the `struct PeerRecord *`
1217 * @param tc scheduler context
1220 run_request_next_transmission (void *cls,
1221 const struct GNUNET_SCHEDULER_TaskContext *tc)
1223 struct PeerRecord *pr = cls;
1225 pr->ntr_task = NULL;
1226 request_next_transmission (pr);
1231 * Ask the core to call @a notify once it is ready to transmit the
1232 * given number of bytes to the specified @a target. Must only be
1233 * called after a connection to the respective peer has been
1234 * established (and the client has been informed about this). You may
1235 * have one request of this type pending for each connected peer at
1236 * any time. If a peer disconnects, the application MUST call
1237 * #GNUNET_CORE_notify_transmit_ready_cancel on the respective
1238 * transmission request, if one such request is pending.
1240 * @param handle connection to core service
1241 * @param cork is corking allowed for this transmission?
1242 * @param priority how important is the message?
1243 * @param maxdelay how long can the message wait? Only effective if @a cork is #GNUNET_YES
1244 * @param target who should receive the message, never NULL (can be this peer's identity for loopback)
1245 * @param notify_size how many bytes of buffer space does @a notify want?
1246 * @param notify function to call when buffer space is available;
1247 * will be called with NULL on timeout; clients MUST cancel
1248 * all pending transmission requests DURING the disconnect
1250 * @param notify_cls closure for @a notify
1251 * @return non-NULL if the notify callback was queued,
1252 * NULL if we can not even queue the request (request already pending);
1253 * if NULL is returned, @a notify will NOT be called.
1255 struct GNUNET_CORE_TransmitHandle *
1256 GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle,
1258 enum GNUNET_CORE_Priority priority,
1259 struct GNUNET_TIME_Relative maxdelay,
1260 const struct GNUNET_PeerIdentity *target,
1262 GNUNET_CONNECTION_TransmitReadyNotify notify,
1265 struct PeerRecord *pr;
1266 struct GNUNET_CORE_TransmitHandle *th;
1268 if (notify_size > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1273 GNUNET_assert (NULL != notify);
1274 LOG (GNUNET_ERROR_TYPE_DEBUG,
1275 "Asking core for transmission of %u bytes to `%s'\n",
1276 (unsigned int) notify_size,
1277 GNUNET_i2s (target));
1278 pr = GNUNET_CONTAINER_multipeermap_get (handle->peers,
1282 /* attempt to send to peer that is not connected */
1286 if (NULL != pr->th.peer)
1288 /* attempting to queue a second request for the same destination */
1292 GNUNET_assert (notify_size + sizeof (struct SendMessage) <
1293 GNUNET_SERVER_MAX_MESSAGE_SIZE);
1295 memset (th, 0, sizeof (struct GNUNET_CORE_TransmitHandle));
1297 th->get_message = notify;
1298 th->get_message_cls = notify_cls;
1299 th->request_time = GNUNET_TIME_absolute_get ();
1300 if (GNUNET_YES == cork)
1301 th->deadline = GNUNET_TIME_relative_to_absolute (maxdelay);
1303 th->deadline = th->request_time;
1304 th->priority = priority;
1305 th->msize = notify_size;
1307 GNUNET_assert (NULL == pr->ntr_task);
1309 GNUNET_SCHEDULER_add_now (&run_request_next_transmission, pr);
1310 LOG (GNUNET_ERROR_TYPE_DEBUG,
1311 "Transmission request added to queue\n");
1317 * Cancel the specified transmission-ready notification.
1319 * @param th handle that was returned by #GNUNET_CORE_notify_transmit_ready().
1322 GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th)
1324 struct PeerRecord *pr = th->peer;
1325 struct GNUNET_CORE_Handle *h;
1327 GNUNET_assert (NULL != th);
1328 GNUNET_assert (NULL != pr);
1329 LOG (GNUNET_ERROR_TYPE_DEBUG,
1330 "Aborting transmission request to core for %u bytes to `%s'\n",
1331 (unsigned int) th->msize,
1332 GNUNET_i2s (&pr->peer));
1337 /* we're currently in the control queue, remove */
1338 GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
1339 h->control_pending_tail,
1341 GNUNET_free (th->cm);
1344 if ( (NULL != pr->prev) ||
1345 (NULL != pr->next) ||
1346 (pr == h->ready_peer_head) )
1348 /* the request that was 'approved' by core was
1349 * canceled before it could be transmitted; remove
1350 * us from the 'ready' list */
1351 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
1355 if (NULL != pr->ntr_task)
1357 GNUNET_SCHEDULER_cancel (pr->ntr_task);
1358 pr->ntr_task = NULL;
1364 * Check if the given peer is currently connected. This function is for special
1365 * cirumstances (GNUNET_TESTBED uses it), normal users of the CORE API are
1366 * expected to track which peers are connected based on the connect/disconnect
1367 * callbacks from #GNUNET_CORE_connect(). This function is NOT part of the
1368 * 'versioned', 'official' API. The difference between this function and the
1369 * function GNUNET_CORE_is_peer_connected() is that this one returns
1370 * synchronously after looking in the CORE API cache. The function
1371 * GNUNET_CORE_is_peer_connected() sends a message to the CORE service and hence
1372 * its response is given asynchronously.
1374 * @param h the core handle
1375 * @param pid the identity of the peer to check if it has been connected to us
1376 * @return #GNUNET_YES if the peer is connected to us; #GNUNET_NO if not
1379 GNUNET_CORE_is_peer_connected_sync (const struct GNUNET_CORE_Handle *h,
1380 const struct GNUNET_PeerIdentity *pid)
1382 GNUNET_assert (NULL != h);
1383 GNUNET_assert (NULL != pid);
1384 return GNUNET_CONTAINER_multipeermap_contains (h->peers, pid);
1388 /* end of core_api.c */