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)
344 struct GNUNET_CORE_Handle *h = cls;
346 h->reconnect_task = NULL;
347 LOG (GNUNET_ERROR_TYPE_DEBUG,
348 "Connecting to CORE service after delay\n");
354 * Notify clients about disconnect and free
355 * the entry for connected peer.
357 * @param cls the `struct GNUNET_CORE_Handle *`
358 * @param key the peer identity (not used)
359 * @param value the `struct PeerRecord` to free.
360 * @return #GNUNET_YES (continue)
363 disconnect_and_free_peer_entry (void *cls,
364 const struct GNUNET_PeerIdentity *key,
367 struct GNUNET_CORE_Handle *h = cls;
368 struct GNUNET_CORE_TransmitHandle *th;
369 struct PeerRecord *pr = value;
371 if (NULL != pr->ntr_task)
373 GNUNET_SCHEDULER_cancel (pr->ntr_task);
376 if ( (NULL != pr->prev) ||
377 (NULL != pr->next) ||
378 (h->ready_peer_head == pr) )
379 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
382 if (NULL != h->disconnects)
383 h->disconnects (h->cls,
385 /* all requests should have been cancelled, clean up anyway, just in case */
387 if (NULL != th->peer)
394 /* done with 'voluntary' cleanups, now on to normal freeing */
395 GNUNET_assert (GNUNET_YES ==
396 GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr));
397 GNUNET_assert (pr->ch == h);
398 GNUNET_assert (NULL == pr->ntr_task);
405 * Close down any existing connection to the CORE service and
406 * try re-establishing it later.
408 * @param h our handle
411 reconnect_later (struct GNUNET_CORE_Handle *h)
413 struct ControlMessage *cm;
414 struct PeerRecord *pr;
416 GNUNET_assert (NULL == h->reconnect_task);
419 GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth);
422 if (NULL != h->client)
424 GNUNET_CLIENT_disconnect (h->client);
427 h->currently_down = GNUNET_YES;
428 GNUNET_assert (h->reconnect_task == NULL);
430 GNUNET_SCHEDULER_add_delayed (h->retry_backoff,
432 while (NULL != (cm = h->control_pending_head))
434 GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
435 h->control_pending_tail,
439 if (NULL != cm->cont)
440 cm->cont (cm->cont_cls, GNUNET_NO);
443 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
444 &disconnect_and_free_peer_entry, h);
445 while (NULL != (pr = h->ready_peer_head))
446 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
449 GNUNET_assert (NULL == h->control_pending_head);
450 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
455 * Check the list of pending requests, send the next
458 * @param h core handle
459 * @param ignore_currently_down transmit message even if not initialized?
462 trigger_next_request (struct GNUNET_CORE_Handle *h,
463 int ignore_currently_down);
467 * Send a control message to the peer asking for transmission
468 * of the message in the given peer record.
470 * @param pr peer to request transmission to
473 request_next_transmission (struct PeerRecord *pr)
475 struct GNUNET_CORE_Handle *h = pr->ch;
476 struct ControlMessage *cm;
477 struct SendMessageRequest *smr;
478 struct GNUNET_CORE_TransmitHandle *th;
481 if (NULL == th->peer)
483 trigger_next_request (h, GNUNET_NO);
487 return; /* already done */
488 GNUNET_assert (NULL == pr->prev);
489 GNUNET_assert (NULL == pr->next);
490 cm = GNUNET_malloc (sizeof (struct ControlMessage) +
491 sizeof (struct SendMessageRequest));
494 smr = (struct SendMessageRequest *) &cm[1];
495 smr->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
496 smr->header.size = htons (sizeof (struct SendMessageRequest));
497 smr->priority = htonl ((uint32_t) th->priority);
498 smr->deadline = GNUNET_TIME_absolute_hton (th->deadline);
499 smr->peer = pr->peer;
500 smr->reserved = htonl (0);
501 smr->size = htons (th->msize);
502 smr->smr_id = htons (th->smr_id = pr->smr_id_gen++);
503 GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
504 h->control_pending_tail, cm);
505 LOG (GNUNET_ERROR_TYPE_DEBUG,
506 "Adding SEND REQUEST for peer `%s' to message queue\n",
507 GNUNET_i2s (&pr->peer));
508 trigger_next_request (h, GNUNET_NO);
513 * Transmit the next message to the core service.
515 * @param cls closure with the `struct GNUNET_CORE_Handle`
516 * @param size number of bytes available in @a buf
517 * @param buf where the callee should write the message
518 * @return number of bytes written to @a buf
521 transmit_message (void *cls,
525 struct GNUNET_CORE_Handle *h = cls;
526 struct ControlMessage *cm;
527 struct GNUNET_CORE_TransmitHandle *th;
528 struct GNUNET_TIME_Relative delay;
529 struct GNUNET_TIME_Relative overdue;
530 struct PeerRecord *pr;
531 struct SendMessage *sm;
532 const struct GNUNET_MessageHeader *hdr;
536 GNUNET_assert (h->reconnect_task == NULL);
540 LOG (GNUNET_ERROR_TYPE_DEBUG,
541 "Transmission failed, initiating reconnect\n");
545 /* first check for control messages */
546 if (NULL != (cm = h->control_pending_head))
548 hdr = (const struct GNUNET_MessageHeader *) &cm[1];
549 msize = ntohs (hdr->size);
552 trigger_next_request (h, GNUNET_NO);
555 LOG (GNUNET_ERROR_TYPE_DEBUG,
556 "Transmitting control message with %u bytes of type %u to core.\n",
557 (unsigned int) msize,
558 (unsigned int) ntohs (hdr->type));
559 memcpy (buf, hdr, msize);
560 GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
561 h->control_pending_tail, cm);
564 if (NULL != cm->cont)
565 cm->cont (cm->cont_cls, GNUNET_OK);
567 trigger_next_request (h, GNUNET_NO);
570 /* now check for 'ready' P2P messages */
571 if (NULL == (pr = h->ready_peer_head))
573 GNUNET_assert (NULL != pr->th.peer);
575 if (size < th->msize + sizeof (struct SendMessage))
577 trigger_next_request (h, GNUNET_NO);
580 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
584 LOG (GNUNET_ERROR_TYPE_DEBUG,
585 "Transmitting SEND request to `%s' with %u bytes.\n",
586 GNUNET_i2s (&pr->peer),
587 (unsigned int) th->msize);
588 sm = (struct SendMessage *) buf;
589 sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND);
590 sm->priority = htonl ((uint32_t) th->priority);
591 sm->deadline = GNUNET_TIME_absolute_hton (th->deadline);
593 sm->cork = htonl ((uint32_t) th->cork);
594 sm->reserved = htonl (0);
596 th->get_message (th->get_message_cls,
597 size - sizeof (struct SendMessage),
599 delay = GNUNET_TIME_absolute_get_duration (th->request_time);
600 overdue = GNUNET_TIME_absolute_get_duration (th->deadline);
601 if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
602 LOG (GNUNET_ERROR_TYPE_WARNING,
603 "Transmitting overdue %u bytes to `%s' at priority %u with %s delay%s\n",
605 GNUNET_i2s (&pr->peer),
606 (unsigned int) th->priority,
607 GNUNET_STRINGS_relative_time_to_string (delay,
609 (th->cork) ? " (corked)" : "");
611 LOG (GNUNET_ERROR_TYPE_DEBUG,
612 "Transmitting %u bytes to `%s' at priority %u with %s delay%s\n",
614 GNUNET_i2s (&pr->peer),
615 (unsigned int) th->priority,
616 GNUNET_STRINGS_relative_time_to_string (delay,
618 (th->cork) ? " (corked)" : "");
620 (GNUNET_CORE_PRIO_BACKGROUND == th->priority) )
622 /* client decided to send nothing; as the priority was
623 BACKGROUND, we can just not send anything to core.
624 For higher-priority messages, we must give an
625 empty message to CORE so that it knows that this
626 message is no longer pending. */
627 LOG (GNUNET_ERROR_TYPE_DEBUG,
628 "Size of clients message to peer %s is 0!\n",
629 GNUNET_i2s (&pr->peer));
630 request_next_transmission (pr);
633 LOG (GNUNET_ERROR_TYPE_DEBUG,
634 "Produced SEND message to core with %u bytes payload\n",
636 if (ret + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
639 request_next_transmission (pr);
642 ret += sizeof (struct SendMessage);
643 sm->header.size = htons (ret);
644 GNUNET_assert (ret <= size);
645 request_next_transmission (pr);
651 * Check the list of pending requests, send the next one to the core.
653 * @param h core handle
654 * @param ignore_currently_down transmit message even if not initialized?
657 trigger_next_request (struct GNUNET_CORE_Handle *h,
658 int ignore_currently_down)
662 if ( (GNUNET_YES == h->currently_down) &&
663 (GNUNET_NO == ignore_currently_down) )
665 LOG (GNUNET_ERROR_TYPE_DEBUG,
666 "Core connection down, not processing queue\n");
671 LOG (GNUNET_ERROR_TYPE_DEBUG,
672 "Request pending, not processing queue\n");
675 if (NULL != h->control_pending_head)
677 ntohs (((struct GNUNET_MessageHeader *) &h->
678 control_pending_head[1])->size);
679 else if (h->ready_peer_head != NULL)
681 h->ready_peer_head->th.msize + sizeof (struct SendMessage);
684 LOG (GNUNET_ERROR_TYPE_DEBUG,
685 "Request queue empty, not processing queue\n");
686 return; /* no pending message */
689 GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
690 GNUNET_TIME_UNIT_FOREVER_REL,
692 &transmit_message, h);
697 * Handler for notification messages received from the core.
699 * @param cls our `struct GNUNET_CORE_Handle`
700 * @param msg the message received from the core service
703 main_notify_handler (void *cls,
704 const struct GNUNET_MessageHeader *msg)
706 struct GNUNET_CORE_Handle *h = cls;
707 const struct InitReplyMessage *m;
708 const struct ConnectNotifyMessage *cnm;
709 const struct DisconnectNotifyMessage *dnm;
710 const struct NotifyTrafficMessage *ntm;
711 const struct GNUNET_MessageHeader *em;
712 const struct SendMessageReady *smr;
713 const struct GNUNET_CORE_MessageHandler *mh;
714 GNUNET_CORE_StartupCallback init;
715 struct PeerRecord *pr;
716 struct GNUNET_CORE_TransmitHandle *th;
724 LOG (GNUNET_ERROR_TYPE_INFO,
725 _("Client was disconnected from core service, trying to reconnect.\n"));
729 msize = ntohs (msg->size);
730 LOG (GNUNET_ERROR_TYPE_DEBUG,
731 "Processing message of type %u and size %u from core service\n",
732 ntohs (msg->type), msize);
733 switch (ntohs (msg->type))
735 case GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY:
736 if (ntohs (msg->size) != sizeof (struct InitReplyMessage))
742 m = (const struct InitReplyMessage *) msg;
743 GNUNET_break (0 == ntohl (m->reserved));
744 /* start our message processing loop */
745 if (GNUNET_YES == h->currently_down)
747 h->currently_down = GNUNET_NO;
748 trigger_next_request (h, GNUNET_NO);
750 h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
751 h->me = m->my_identity;
752 if (NULL != (init = h->init))
754 /* mark so we don't call init on reconnect */
756 LOG (GNUNET_ERROR_TYPE_DEBUG,
757 "Connected to core service of peer `%s'.\n",
758 GNUNET_i2s (&h->me));
759 init (h->cls, &h->me);
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Successfully reconnected to core service.\n");
766 /* fake 'connect to self' */
767 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &h->me);
768 GNUNET_assert (NULL == pr);
769 pr = GNUNET_new (struct PeerRecord);
772 GNUNET_assert (GNUNET_YES ==
773 GNUNET_CONTAINER_multipeermap_put (h->peers,
775 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
776 if (NULL != h->connects)
777 h->connects (h->cls, &pr->peer);
779 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT:
780 if (msize < sizeof (struct ConnectNotifyMessage))
786 cnm = (const struct ConnectNotifyMessage *) msg;
788 sizeof (struct ConnectNotifyMessage))
794 LOG (GNUNET_ERROR_TYPE_DEBUG,
795 "Received notification about connection from `%s'.\n",
796 GNUNET_i2s (&cnm->peer));
797 if (0 == memcmp (&h->me,
799 sizeof (struct GNUNET_PeerIdentity)))
801 /* connect to self!? */
805 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer);
812 pr = GNUNET_new (struct PeerRecord);
813 pr->peer = cnm->peer;
815 GNUNET_assert (GNUNET_YES ==
816 GNUNET_CONTAINER_multipeermap_put (h->peers,
818 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
819 if (NULL != h->connects)
820 h->connects (h->cls, &pr->peer);
822 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT:
823 if (msize != sizeof (struct DisconnectNotifyMessage))
829 dnm = (const struct DisconnectNotifyMessage *) msg;
830 if (0 == memcmp (&h->me,
832 sizeof (struct GNUNET_PeerIdentity)))
834 /* connection to self!? */
838 GNUNET_break (0 == ntohl (dnm->reserved));
839 LOG (GNUNET_ERROR_TYPE_DEBUG,
840 "Received notification about disconnect from `%s'.\n",
841 GNUNET_i2s (&dnm->peer));
842 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer);
849 trigger = ((pr->prev != NULL) || (pr->next != NULL) ||
850 (h->ready_peer_head == pr));
851 disconnect_and_free_peer_entry (h, &dnm->peer, pr);
853 trigger_next_request (h, GNUNET_NO);
855 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND:
856 if (msize < sizeof (struct NotifyTrafficMessage))
862 ntm = (const struct NotifyTrafficMessage *) msg;
864 sizeof (struct NotifyTrafficMessage) +
865 sizeof (struct GNUNET_MessageHeader)) )
871 em = (const struct GNUNET_MessageHeader *) &ntm[1];
872 LOG (GNUNET_ERROR_TYPE_DEBUG,
873 "Received message of type %u and size %u from peer `%s'\n",
874 ntohs (em->type), ntohs (em->size), GNUNET_i2s (&ntm->peer));
875 if ((GNUNET_NO == h->inbound_hdr_only) &&
877 ntohs (em->size) + sizeof (struct NotifyTrafficMessage)))
883 et = ntohs (em->type);
884 for (hpos = 0; hpos < h->hcnt; hpos++)
886 mh = &h->handlers[hpos];
889 if ((mh->expected_size != ntohs (em->size)) && (mh->expected_size != 0))
891 LOG (GNUNET_ERROR_TYPE_ERROR,
892 "Unexpected message size %u for message of type %u from peer `%s'\n",
893 htons (em->size), mh->type, GNUNET_i2s (&ntm->peer));
897 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer);
905 h->handlers[hpos].callback (h->cls, &ntm->peer, em))
907 /* error in processing, do not process other messages! */
911 if (NULL != h->inbound_notify)
912 h->inbound_notify (h->cls, &ntm->peer, em);
914 case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND:
915 if (msize < sizeof (struct NotifyTrafficMessage))
921 ntm = (const struct NotifyTrafficMessage *) msg;
923 sizeof (struct NotifyTrafficMessage) +
924 sizeof (struct GNUNET_MessageHeader)) )
930 em = (const struct GNUNET_MessageHeader *) &ntm[1];
931 LOG (GNUNET_ERROR_TYPE_DEBUG,
932 "Received notification about transmission to `%s'.\n",
933 GNUNET_i2s (&ntm->peer));
934 if ((GNUNET_NO == h->outbound_hdr_only) &&
936 ntohs (em->size) + sizeof (struct NotifyTrafficMessage)))
942 if (NULL == h->outbound_notify)
947 h->outbound_notify (h->cls, &ntm->peer, em);
949 case GNUNET_MESSAGE_TYPE_CORE_SEND_READY:
950 if (msize != sizeof (struct SendMessageReady))
956 smr = (const struct SendMessageReady *) msg;
957 pr = GNUNET_CONTAINER_multipeermap_get (h->peers,
965 LOG (GNUNET_ERROR_TYPE_DEBUG,
966 "Received notification about transmission readiness to `%s'.\n",
967 GNUNET_i2s (&smr->peer));
968 if (NULL == pr->th.peer)
970 /* request must have been cancelled between the original request
971 * and the response from core, ignore core's readiness */
976 if (ntohs (smr->smr_id) != th->smr_id)
978 /* READY message is for expired or cancelled message,
979 * ignore! (we should have already sent another request) */
982 if ( (NULL != pr->prev) ||
983 (NULL != pr->next) ||
984 (h->ready_peer_head == pr) )
986 /* we should not already be on the ready list... */
991 GNUNET_CONTAINER_DLL_insert (h->ready_peer_head,
994 trigger_next_request (h, GNUNET_NO);
1000 GNUNET_CLIENT_receive (h->client,
1001 &main_notify_handler, h,
1002 GNUNET_TIME_UNIT_FOREVER_REL);
1007 * Task executed once we are done transmitting the INIT message.
1008 * Starts our 'receive' loop.
1010 * @param cls the 'struct GNUNET_CORE_Handle'
1011 * @param success were we successful
1014 init_done_task (void *cls, int success)
1016 struct GNUNET_CORE_Handle *h = cls;
1018 if (GNUNET_SYSERR == success)
1019 return; /* shutdown */
1020 if (GNUNET_NO == success)
1022 LOG (GNUNET_ERROR_TYPE_DEBUG,
1023 "Failed to exchange INIT with core, retrying\n");
1024 if (h->reconnect_task == NULL)
1025 reconnect_later (h);
1028 GNUNET_CLIENT_receive (h->client,
1029 &main_notify_handler, h,
1030 GNUNET_TIME_UNIT_FOREVER_REL);
1035 * Our current client connection went down. Clean it up
1036 * and try to reconnect!
1038 * @param h our handle to the core service
1041 reconnect (struct GNUNET_CORE_Handle *h)
1043 struct ControlMessage *cm;
1044 struct InitMessage *init;
1050 GNUNET_assert (NULL == h->client);
1051 GNUNET_assert (GNUNET_YES == h->currently_down);
1052 GNUNET_assert (NULL != h->cfg);
1053 h->client = GNUNET_CLIENT_connect ("core", h->cfg);
1054 if (NULL == h->client)
1056 reconnect_later (h);
1059 msize = h->hcnt * sizeof (uint16_t) + sizeof (struct InitMessage);
1060 cm = GNUNET_malloc (sizeof (struct ControlMessage) + msize);
1061 cm->cont = &init_done_task;
1063 init = (struct InitMessage *) &cm[1];
1064 init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT);
1065 init->header.size = htons (msize);
1067 if (NULL != h->inbound_notify)
1069 if (h->inbound_hdr_only)
1070 opt |= GNUNET_CORE_OPTION_SEND_HDR_INBOUND;
1072 opt |= GNUNET_CORE_OPTION_SEND_FULL_INBOUND;
1074 if (NULL != h->outbound_notify)
1076 if (h->outbound_hdr_only)
1077 opt |= GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND;
1079 opt |= GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND;
1081 LOG (GNUNET_ERROR_TYPE_INFO,
1082 "(Re)connecting to CORE service, monitoring messages of type %u\n",
1085 init->options = htonl (opt);
1086 ts = (uint16_t *) & init[1];
1087 for (hpos = 0; hpos < h->hcnt; hpos++)
1088 ts[hpos] = htons (h->handlers[hpos].type);
1089 GNUNET_CONTAINER_DLL_insert (h->control_pending_head,
1090 h->control_pending_tail,
1092 trigger_next_request (h, GNUNET_YES);
1098 * Connect to the core service. Note that the connection may
1099 * complete (or fail) asynchronously.
1101 * @param cfg configuration to use
1102 * @param cls closure for the various callbacks that follow (including handlers in the handlers array)
1103 * @param init callback to call once we have successfully
1104 * connected to the core service
1105 * @param connects function to call on peer connect, can be NULL
1106 * @param disconnects function to call on peer disconnect / timeout, can be NULL
1107 * @param inbound_notify function to call for all inbound messages, can be NULL
1108 * @param inbound_hdr_only set to #GNUNET_YES if inbound_notify will only read the
1109 * GNUNET_MessageHeader and hence we do not need to give it the full message;
1110 * can be used to improve efficiency, ignored if @a inbound_notify is NULLL
1111 * @param outbound_notify function to call for all outbound messages, can be NULL
1112 * @param outbound_hdr_only set to #GNUNET_YES if outbound_notify will only read the
1113 * GNUNET_MessageHeader and hence we do not need to give it the full message
1114 * can be used to improve efficiency, ignored if @a outbound_notify is NULLL
1115 * @param handlers callbacks for messages we care about, NULL-terminated
1116 * @return handle to the core service (only useful for disconnect until 'init' is called);
1117 * NULL on error (in this case, init is never called)
1119 struct GNUNET_CORE_Handle *
1120 GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1122 GNUNET_CORE_StartupCallback init,
1123 GNUNET_CORE_ConnectEventHandler connects,
1124 GNUNET_CORE_DisconnectEventHandler disconnects,
1125 GNUNET_CORE_MessageCallback inbound_notify,
1126 int inbound_hdr_only,
1127 GNUNET_CORE_MessageCallback outbound_notify,
1128 int outbound_hdr_only,
1129 const struct GNUNET_CORE_MessageHandler *handlers)
1131 struct GNUNET_CORE_Handle *h;
1133 GNUNET_assert (NULL != cfg);
1134 h = GNUNET_new (struct GNUNET_CORE_Handle);
1138 h->connects = connects;
1139 h->disconnects = disconnects;
1140 h->inbound_notify = inbound_notify;
1141 h->outbound_notify = outbound_notify;
1142 h->inbound_hdr_only = inbound_hdr_only;
1143 h->outbound_hdr_only = outbound_hdr_only;
1144 h->handlers = handlers;
1146 h->currently_down = GNUNET_YES;
1147 h->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1148 if (NULL != handlers)
1149 while (NULL != handlers[h->hcnt].callback)
1151 GNUNET_assert (h->hcnt <
1152 (GNUNET_SERVER_MAX_MESSAGE_SIZE -
1153 sizeof (struct InitMessage)) / sizeof (uint16_t));
1154 LOG (GNUNET_ERROR_TYPE_DEBUG,
1155 "Connecting to CORE service\n");
1162 * Disconnect from the core service. This function can only
1163 * be called *after* all pending #GNUNET_CORE_notify_transmit_ready()
1164 * requests have been explicitly canceled.
1166 * @param handle connection to core to disconnect
1169 GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
1171 struct ControlMessage *cm;
1173 GNUNET_assert (NULL != handle);
1174 LOG (GNUNET_ERROR_TYPE_DEBUG,
1175 "Disconnecting from CORE service\n");
1176 if (NULL != handle->cth)
1178 GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth);
1181 while (NULL != (cm = handle->control_pending_head))
1183 GNUNET_CONTAINER_DLL_remove (handle->control_pending_head,
1184 handle->control_pending_tail,
1188 if (NULL != cm->cont)
1189 cm->cont (cm->cont_cls, GNUNET_SYSERR);
1192 if (NULL != handle->client)
1194 GNUNET_CLIENT_disconnect (handle->client);
1195 handle->client = NULL;
1197 GNUNET_CONTAINER_multipeermap_iterate (handle->peers,
1198 &disconnect_and_free_peer_entry,
1200 if (NULL != handle->reconnect_task)
1202 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1203 handle->reconnect_task = NULL;
1205 GNUNET_CONTAINER_multipeermap_destroy (handle->peers);
1206 handle->peers = NULL;
1207 GNUNET_break (NULL == handle->ready_peer_head);
1208 GNUNET_free (handle);
1213 * Task that calls #request_next_transmission().
1215 * @param cls the `struct PeerRecord *`
1218 run_request_next_transmission (void *cls)
1220 struct PeerRecord *pr = cls;
1222 pr->ntr_task = NULL;
1223 request_next_transmission (pr);
1228 * Ask the core to call @a notify once it is ready to transmit the
1229 * given number of bytes to the specified @a target. Must only be
1230 * called after a connection to the respective peer has been
1231 * established (and the client has been informed about this). You may
1232 * have one request of this type pending for each connected peer at
1233 * any time. If a peer disconnects, the application MUST call
1234 * #GNUNET_CORE_notify_transmit_ready_cancel on the respective
1235 * transmission request, if one such request is pending.
1237 * @param handle connection to core service
1238 * @param cork is corking allowed for this transmission?
1239 * @param priority how important is the message?
1240 * @param maxdelay how long can the message wait? Only effective if @a cork is #GNUNET_YES
1241 * @param target who should receive the message, never NULL (can be this peer's identity for loopback)
1242 * @param notify_size how many bytes of buffer space does @a notify want?
1243 * @param notify function to call when buffer space is available;
1244 * will be called with NULL on timeout; clients MUST cancel
1245 * all pending transmission requests DURING the disconnect
1247 * @param notify_cls closure for @a notify
1248 * @return non-NULL if the notify callback was queued,
1249 * NULL if we can not even queue the request (request already pending);
1250 * if NULL is returned, @a notify will NOT be called.
1252 struct GNUNET_CORE_TransmitHandle *
1253 GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle,
1255 enum GNUNET_CORE_Priority priority,
1256 struct GNUNET_TIME_Relative maxdelay,
1257 const struct GNUNET_PeerIdentity *target,
1259 GNUNET_CONNECTION_TransmitReadyNotify notify,
1262 struct PeerRecord *pr;
1263 struct GNUNET_CORE_TransmitHandle *th;
1265 if (notify_size > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1270 GNUNET_assert (NULL != notify);
1271 LOG (GNUNET_ERROR_TYPE_DEBUG,
1272 "Asking core for transmission of %u bytes to `%s'\n",
1273 (unsigned int) notify_size,
1274 GNUNET_i2s (target));
1275 pr = GNUNET_CONTAINER_multipeermap_get (handle->peers,
1279 /* attempt to send to peer that is not connected */
1283 if (NULL != pr->th.peer)
1285 /* attempting to queue a second request for the same destination */
1289 GNUNET_assert (notify_size + sizeof (struct SendMessage) <
1290 GNUNET_SERVER_MAX_MESSAGE_SIZE);
1292 memset (th, 0, sizeof (struct GNUNET_CORE_TransmitHandle));
1294 th->get_message = notify;
1295 th->get_message_cls = notify_cls;
1296 th->request_time = GNUNET_TIME_absolute_get ();
1297 if (GNUNET_YES == cork)
1298 th->deadline = GNUNET_TIME_relative_to_absolute (maxdelay);
1300 th->deadline = th->request_time;
1301 th->priority = priority;
1302 th->msize = notify_size;
1304 GNUNET_assert (NULL == pr->ntr_task);
1306 GNUNET_SCHEDULER_add_now (&run_request_next_transmission, pr);
1307 LOG (GNUNET_ERROR_TYPE_DEBUG,
1308 "Transmission request added to queue\n");
1314 * Cancel the specified transmission-ready notification.
1316 * @param th handle that was returned by #GNUNET_CORE_notify_transmit_ready().
1319 GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th)
1321 struct PeerRecord *pr = th->peer;
1322 struct GNUNET_CORE_Handle *h;
1324 GNUNET_assert (NULL != th);
1325 GNUNET_assert (NULL != pr);
1326 LOG (GNUNET_ERROR_TYPE_DEBUG,
1327 "Aborting transmission request to core for %u bytes to `%s'\n",
1328 (unsigned int) th->msize,
1329 GNUNET_i2s (&pr->peer));
1334 /* we're currently in the control queue, remove */
1335 GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
1336 h->control_pending_tail,
1338 GNUNET_free (th->cm);
1341 if ( (NULL != pr->prev) ||
1342 (NULL != pr->next) ||
1343 (pr == h->ready_peer_head) )
1345 /* the request that was 'approved' by core was
1346 * canceled before it could be transmitted; remove
1347 * us from the 'ready' list */
1348 GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
1352 if (NULL != pr->ntr_task)
1354 GNUNET_SCHEDULER_cancel (pr->ntr_task);
1355 pr->ntr_task = NULL;
1361 * Check if the given peer is currently connected. This function is for special
1362 * cirumstances (GNUNET_TESTBED uses it), normal users of the CORE API are
1363 * expected to track which peers are connected based on the connect/disconnect
1364 * callbacks from #GNUNET_CORE_connect(). This function is NOT part of the
1365 * 'versioned', 'official' API. The difference between this function and the
1366 * function GNUNET_CORE_is_peer_connected() is that this one returns
1367 * synchronously after looking in the CORE API cache. The function
1368 * GNUNET_CORE_is_peer_connected() sends a message to the CORE service and hence
1369 * its response is given asynchronously.
1371 * @param h the core handle
1372 * @param pid the identity of the peer to check if it has been connected to us
1373 * @return #GNUNET_YES if the peer is connected to us; #GNUNET_NO if not
1376 GNUNET_CORE_is_peer_connected_sync (const struct GNUNET_CORE_Handle *h,
1377 const struct GNUNET_PeerIdentity *pid)
1379 GNUNET_assert (NULL != h);
1380 GNUNET_assert (NULL != pid);
1381 return GNUNET_CONTAINER_multipeermap_contains (h->peers, pid);
1385 /* end of core_api.c */