2 This file is part of GNUnet.
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.
22 * @file rps/gnunet-service-rps_peers.c
23 * @brief utilities for managing (information about) peers
24 * @author Julius Bünger
27 #include "gnunet_applications.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_cadet_service.h"
32 #include "gnunet-service-rps_peers.h"
36 #define LOG(kind, ...) GNUNET_log_from(kind,"rps-peers",__VA_ARGS__)
40 * Set a peer flag of given peer context.
42 #define set_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) |= (mask))
45 * Get peer flag of given peer context.
47 #define check_peer_flag_set(peer_ctx, mask)\
48 ((peer_ctx->peer_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
51 * Unset flag of given peer context.
53 #define unset_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) &= ~(mask))
56 * Set a channel flag of given channel context.
58 #define set_channel_flag(channel_flags, mask) ((*channel_flags) |= (mask))
61 * Get channel flag of given channel context.
63 #define check_channel_flag_set(channel_flags, mask)\
64 ((*channel_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
67 * Unset flag of given channel context.
69 #define unset_channel_flag(channel_flags, mask) ((*channel_flags) &= ~(mask))
74 * Pending operation on peer consisting of callback and closure
76 * When an operation cannot be executed right now this struct is used to store
77 * the callback and closure for later execution.
93 * List containing all messages that are yet to be send
95 * This is used to keep track of all messages that have not been sent yet. When
96 * a peer is to be removed the pending messages can be removed properly.
103 struct PendingMessage *next;
104 struct PendingMessage *prev;
107 * The envelope to the corresponding message
109 struct GNUNET_MQ_Envelope *ev;
112 * The corresponding context
114 struct PeerContext *peer_ctx;
123 * Struct used to keep track of other peer's status
125 * This is stored in a multipeermap.
126 * It contains information such as cadet channels, a message queue for sending,
127 * status about the channels, the pending operations on this peer and some flags
128 * about the status of the peer itself. (live, valid, ...)
133 * Message queue open to client
135 struct GNUNET_MQ_Handle *mq;
138 * Channel open to client.
140 struct GNUNET_CADET_Channel *send_channel;
143 * Flags to the sending channel
145 uint32_t *send_channel_flags;
148 * Channel open from client.
150 struct GNUNET_CADET_Channel *recv_channel; // unneeded?
153 * Flags to the receiving channel
155 uint32_t *recv_channel_flags;
158 * Array of pending operations on this peer.
160 struct PeerPendingOp *pending_ops;
163 * Handle to the callback given to cadet_ntfy_tmt_rdy()
165 * To be canceled on shutdown.
167 struct PendingMessage *liveliness_check_pending;
170 * Number of pending operations.
172 unsigned int num_pending_ops;
175 * Identity of the peer
177 struct GNUNET_PeerIdentity peer_id;
180 * Flags indicating status of peer
185 * Last time we received something from that peer.
187 struct GNUNET_TIME_Absolute last_message_recv;
190 * Last time we received a keepalive message.
192 struct GNUNET_TIME_Absolute last_keepalive;
195 * DLL with all messages that are yet to be sent
197 struct PendingMessage *pending_messages_head;
198 struct PendingMessage *pending_messages_tail;
201 * This is pobably followed by 'statistical' data (when we first saw
202 * him, how did we get his ID, how many pushes (in a timeinterval),
208 * @brief Closure to #valid_peer_iterator
210 struct PeersIteratorCls
215 PeersIterator iterator;
218 * Closure to iterator
224 * @brief Hashmap of valid peers.
226 static struct GNUNET_CONTAINER_MultiPeerMap *valid_peers;
229 * @brief Maximum number of valid peers to keep.
230 * TODO read from config
232 static uint32_t num_valid_peers_max = UINT32_MAX;
235 * @brief Filename of the file that stores the valid peers persistently.
237 static char *filename_valid_peers;
240 * Set of all peers to keep track of them.
242 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
245 * Own #GNUNET_PeerIdentity.
247 static const struct GNUNET_PeerIdentity *own_identity;
252 static struct GNUNET_CADET_Handle *cadet_handle;
255 * @brief Disconnect handler
257 static GNUNET_CADET_DisconnectEventHandler cleanup_destroyed_channel;
260 * @brief cadet handlers
262 static const struct GNUNET_MQ_MessageHandler *cadet_handlers;
267 * @brief Get the #PeerContext associated with a peer
269 * @param peer the peer id
271 * @return the #PeerContext
273 static struct PeerContext *
274 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
276 struct PeerContext *ctx;
279 ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
280 GNUNET_assert (GNUNET_YES == ret);
281 ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
282 GNUNET_assert (NULL != ctx);
288 * @brief Create a new #PeerContext and insert it into the peer map
290 * @param peer the peer to create the #PeerContext for
292 * @return the #PeerContext
294 static struct PeerContext *
295 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
297 struct PeerContext *ctx;
300 GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
302 ctx = GNUNET_new (struct PeerContext);
303 ctx->peer_id = *peer;
304 ctx->send_channel_flags = GNUNET_new (uint32_t);
305 ctx->recv_channel_flags = GNUNET_new (uint32_t);
306 ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
308 GNUNET_assert (GNUNET_OK == ret);
314 * @brief Create or get a #PeerContext
316 * @param peer the peer to get the associated context to
318 * @return the context
320 static struct PeerContext *
321 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
323 if (GNUNET_NO == Peers_check_peer_known (peer))
325 return create_peer_ctx (peer);
327 return get_peer_ctx (peer);
332 * @brief Check whether we have a connection to this @a peer
334 * Also sets the #Peers_ONLINE flag accordingly
336 * @param peer the peer in question
338 * @return #GNUNET_YES if we are connected
339 * #GNUNET_NO otherwise
342 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
344 const struct PeerContext *peer_ctx;
346 /* If we don't know about this peer we don't know whether it's online */
347 if (GNUNET_NO == Peers_check_peer_known (peer))
351 /* Get the context */
352 peer_ctx = get_peer_ctx (peer);
353 /* If we have no channel to this peer we don't know whether it's online */
354 if ( (NULL == peer_ctx->send_channel) &&
355 (NULL == peer_ctx->recv_channel) )
357 Peers_unset_peer_flag (peer, Peers_ONLINE);
360 /* Otherwise (if we have a channel, we know that it's online */
361 Peers_set_peer_flag (peer, Peers_ONLINE);
367 * @brief The closure to #get_rand_peer_iterator.
369 struct GetRandPeerIteratorCls
372 * @brief The index of the peer to return.
373 * Will be decreased until 0.
374 * Then current peer is returned.
379 * @brief Pointer to peer to return.
381 const struct GNUNET_PeerIdentity *peer;
386 * @brief Iterator function for #get_random_peer_from_peermap.
388 * Implements #GNUNET_CONTAINER_PeerMapIterator.
389 * Decreases the index until the index is null.
390 * Then returns the current peer.
392 * @param cls the #GetRandPeerIteratorCls containing index and peer
393 * @param peer current peer
394 * @param value unused
396 * @return #GNUNET_YES if we should continue to
401 get_rand_peer_iterator (void *cls,
402 const struct GNUNET_PeerIdentity *peer,
405 struct GetRandPeerIteratorCls *iterator_cls = cls;
406 if (0 >= iterator_cls->index)
408 iterator_cls->peer = peer;
411 iterator_cls->index--;
417 * @brief Get a random peer from @a peer_map
419 * @param peer_map the peer_map to get the peer from
421 * @return a random peer
423 static const struct GNUNET_PeerIdentity *
424 get_random_peer_from_peermap (const struct
425 GNUNET_CONTAINER_MultiPeerMap *peer_map)
427 struct GetRandPeerIteratorCls *iterator_cls;
428 const struct GNUNET_PeerIdentity *ret;
430 iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls);
431 iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
432 GNUNET_CONTAINER_multipeermap_size (peer_map));
433 (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
434 get_rand_peer_iterator,
436 ret = iterator_cls->peer;
437 GNUNET_free (iterator_cls);
443 * @brief Add a given @a peer to valid peers.
445 * If valid peers are already #num_valid_peers_max, delete a peer previously.
447 * @param peer the peer that is added to the valid peers.
449 * @return #GNUNET_YES if no other peer had to be removed
450 * #GNUNET_NO otherwise
453 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
455 const struct GNUNET_PeerIdentity *rand_peer;
459 while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
461 rand_peer = get_random_peer_from_peermap (valid_peers);
462 GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
465 (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
466 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
472 * @brief Set the peer flag to living and
473 * call the pending operations on this peer.
475 * Also adds peer to #valid_peers.
477 * @param peer_ctx the #PeerContext of the peer to set live
480 set_peer_live (struct PeerContext *peer_ctx)
482 struct GNUNET_PeerIdentity *peer;
485 peer = &peer_ctx->peer_id;
486 LOG (GNUNET_ERROR_TYPE_DEBUG,
487 "Peer %s is live and valid, calling %i pending operations on it\n",
489 peer_ctx->num_pending_ops);
491 if (NULL != peer_ctx->liveliness_check_pending)
493 LOG (GNUNET_ERROR_TYPE_DEBUG,
494 "Removing pending liveliness check for peer %s\n",
495 GNUNET_i2s (&peer_ctx->peer_id));
496 // TODO wait until cadet sets mq->cancel_impl
497 //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
498 GNUNET_free (peer_ctx->liveliness_check_pending);
499 peer_ctx->liveliness_check_pending = NULL;
502 (void) add_valid_peer (peer);
503 set_peer_flag (peer_ctx, Peers_ONLINE);
505 /* Call pending operations */
506 for (i = 0; i < peer_ctx->num_pending_ops; i++)
508 peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
510 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
515 * @brief Get the channel of a peer. If not existing, create.
517 * @param peer the peer id
518 * @return the #GNUNET_CADET_Channel used to send data to @a peer
520 struct GNUNET_CADET_Channel *
521 get_channel (const struct GNUNET_PeerIdentity *peer)
523 struct PeerContext *peer_ctx;
524 struct GNUNET_HashCode port;
526 peer_ctx = get_peer_ctx (peer);
527 if (NULL == peer_ctx->send_channel)
529 LOG (GNUNET_ERROR_TYPE_DEBUG,
530 "Trying to establish channel to peer %s\n",
532 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
533 strlen (GNUNET_APPLICATION_PORT_RPS),
535 peer_ctx->send_channel =
536 GNUNET_CADET_channel_create (cadet_handle,
537 (struct GNUNET_PeerIdentity *) peer, /* context */
540 GNUNET_CADET_OPTION_RELIABLE,
541 NULL, /* WindowSize handler */
542 cleanup_destroyed_channel, /* Disconnect handler */
545 GNUNET_assert (NULL != peer_ctx->send_channel);
546 return peer_ctx->send_channel;
551 * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
553 * If we already have a message queue open to this client,
554 * simply return it, otherways create one.
556 * @param peer the peer to get the mq to
557 * @return the #GNUNET_MQ_Handle
559 static struct GNUNET_MQ_Handle *
560 get_mq (const struct GNUNET_PeerIdentity *peer)
562 struct PeerContext *peer_ctx;
564 peer_ctx = get_peer_ctx (peer);
566 if (NULL == peer_ctx->mq)
568 (void) get_channel (peer);
569 peer_ctx->mq = GNUNET_CADET_get_mq (peer_ctx->send_channel);
576 * @brief This is called in response to the first message we sent as a
579 * @param cls #PeerContext of peer with pending liveliness check
582 mq_liveliness_check_successful (void *cls)
584 struct PeerContext *peer_ctx = cls;
586 if (NULL != peer_ctx->liveliness_check_pending)
588 LOG (GNUNET_ERROR_TYPE_DEBUG,
589 "Liveliness check for peer %s was successfull\n",
590 GNUNET_i2s (&peer_ctx->peer_id));
591 GNUNET_free (peer_ctx->liveliness_check_pending);
592 peer_ctx->liveliness_check_pending = NULL;
593 set_peer_live (peer_ctx);
598 * Issue a check whether peer is live
600 * @param peer_ctx the context of the peer
603 check_peer_live (struct PeerContext *peer_ctx)
605 LOG (GNUNET_ERROR_TYPE_DEBUG,
606 "Get informed about peer %s getting live\n",
607 GNUNET_i2s (&peer_ctx->peer_id));
609 struct GNUNET_MQ_Handle *mq;
610 struct GNUNET_MQ_Envelope *ev;
612 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE);
613 peer_ctx->liveliness_check_pending = GNUNET_new (struct PendingMessage);
614 peer_ctx->liveliness_check_pending->ev = ev;
615 peer_ctx->liveliness_check_pending->peer_ctx = peer_ctx;
616 peer_ctx->liveliness_check_pending->type = "Check liveliness";
617 mq = get_mq (&peer_ctx->peer_id);
618 GNUNET_MQ_notify_sent (ev,
619 mq_liveliness_check_successful,
621 GNUNET_MQ_send (mq, ev);
625 * @brief Add an envelope to a message passed to mq to list of pending messages
627 * @param peer peer the message was sent to
628 * @param ev envelope to the message
629 * @param type type of the message to be sent
630 * @return pointer to pending message
632 static struct PendingMessage *
633 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
634 struct GNUNET_MQ_Envelope *ev,
637 struct PendingMessage *pending_msg;
638 struct PeerContext *peer_ctx;
640 peer_ctx = get_peer_ctx (peer);
641 pending_msg = GNUNET_new (struct PendingMessage);
642 pending_msg->ev = ev;
643 pending_msg->peer_ctx = peer_ctx;
644 pending_msg->type = type;
645 GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
646 peer_ctx->pending_messages_tail,
653 * @brief Remove a pending message from the respective DLL
655 * @param pending_msg the pending message to remove
656 * @param cancel cancel the pending message, too
659 remove_pending_message (struct PendingMessage *pending_msg, int cancel)
661 struct PeerContext *peer_ctx;
663 peer_ctx = pending_msg->peer_ctx;
664 GNUNET_assert (NULL != peer_ctx);
665 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
666 peer_ctx->pending_messages_tail,
668 // TODO wait for the cadet implementation of message cancellation
669 //if (GNUNET_YES == cancel)
671 // GNUNET_MQ_send_cancel (pending_msg->ev);
673 GNUNET_free (pending_msg);
678 * @brief Check whether function of type #PeerOp was already scheduled
680 * The array with pending operations will probably never grow really big, so
681 * iterating over it should be ok.
683 * @param peer the peer to check
684 * @param peer_op the operation (#PeerOp) on the peer
686 * @return #GNUNET_YES if this operation is scheduled on that peer
687 * #GNUNET_NO otherwise
690 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
691 const PeerOp peer_op)
693 const struct PeerContext *peer_ctx;
696 peer_ctx = get_peer_ctx (peer);
697 for (i = 0; i < peer_ctx->num_pending_ops; i++)
698 if (peer_op == peer_ctx->pending_ops[i].op)
705 * Iterator over hash map entries. Deletes all contexts of peers.
708 * @param key current public key
709 * @param value value in the hash map
710 * @return #GNUNET_YES if we should continue to iterate,
714 peermap_clear_iterator (void *cls,
715 const struct GNUNET_PeerIdentity *key,
718 Peers_remove_peer (key);
724 * @brief This is called once a message is sent.
726 * Removes the pending message
728 * @param cls type of the message that was sent
731 mq_notify_sent_cb (void *cls)
733 struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
734 LOG (GNUNET_ERROR_TYPE_DEBUG,
737 /* Do not cancle message */
738 remove_pending_message (pending_msg, GNUNET_NO);
743 * @brief Iterator function for #store_valid_peers.
745 * Implements #GNUNET_CONTAINER_PeerMapIterator.
746 * Writes single peer to disk.
748 * @param cls the file handle to write to.
749 * @param peer current peer
750 * @param value unused
752 * @return #GNUNET_YES if we should continue to
757 store_peer_presistently_iterator (void *cls,
758 const struct GNUNET_PeerIdentity *peer,
761 const struct GNUNET_DISK_FileHandle *fh = cls;
762 char peer_string[128];
770 size = GNUNET_snprintf (peer_string,
771 sizeof (peer_string),
773 GNUNET_i2s_full (peer));
774 GNUNET_assert (53 == size);
775 ret = GNUNET_DISK_file_write (fh,
778 GNUNET_assert (size == ret);
784 * @brief Store the peers currently in #valid_peers to disk.
789 struct GNUNET_DISK_FileHandle *fh;
790 uint32_t number_written_peers;
793 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
798 ret = GNUNET_DISK_directory_create_for_file (filename_valid_peers);
799 if (GNUNET_SYSERR == ret)
801 LOG (GNUNET_ERROR_TYPE_WARNING,
802 "Not able to create directory for file `%s'\n",
803 filename_valid_peers);
806 else if (GNUNET_NO == ret)
808 LOG (GNUNET_ERROR_TYPE_WARNING,
809 "Directory for file `%s' exists but is not writable for us\n",
810 filename_valid_peers);
813 fh = GNUNET_DISK_file_open (filename_valid_peers,
814 GNUNET_DISK_OPEN_WRITE |
815 GNUNET_DISK_OPEN_CREATE,
816 GNUNET_DISK_PERM_USER_READ |
817 GNUNET_DISK_PERM_USER_WRITE);
820 LOG (GNUNET_ERROR_TYPE_WARNING,
821 "Not able to write valid peers to file `%s'\n",
822 filename_valid_peers);
825 LOG (GNUNET_ERROR_TYPE_DEBUG,
826 "Writing %u valid peers to disk\n",
827 GNUNET_CONTAINER_multipeermap_size (valid_peers));
828 number_written_peers =
829 GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
830 store_peer_presistently_iterator,
832 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
833 GNUNET_assert (number_written_peers ==
834 GNUNET_CONTAINER_multipeermap_size (valid_peers));
839 * @brief Convert string representation of peer id to peer id.
841 * Counterpart to #GNUNET_i2s_full.
843 * @param string_repr The string representation of the peer id
845 * @return The peer id
847 static const struct GNUNET_PeerIdentity *
848 s2i_full (const char *string_repr)
850 struct GNUNET_PeerIdentity *peer;
854 peer = GNUNET_new (struct GNUNET_PeerIdentity);
855 len = strlen (string_repr);
858 LOG (GNUNET_ERROR_TYPE_WARNING,
859 "Not able to convert string representation of PeerID to PeerID\n"
860 "Sting representation: %s (len %u) - too short\n",
869 ret = GNUNET_CRYPTO_eddsa_public_key_from_string (string_repr,
872 if (GNUNET_OK != ret)
874 LOG (GNUNET_ERROR_TYPE_WARNING,
875 "Not able to convert string representation of PeerID to PeerID\n"
876 "Sting representation: %s\n",
885 * @brief Restore the peers on disk to #valid_peers.
888 restore_valid_peers ()
892 struct GNUNET_DISK_FileHandle *fh;
897 const struct GNUNET_PeerIdentity *peer;
899 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
904 if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers))
908 fh = GNUNET_DISK_file_open (filename_valid_peers,
909 GNUNET_DISK_OPEN_READ,
910 GNUNET_DISK_PERM_NONE);
911 GNUNET_assert (NULL != fh);
912 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size));
913 num_peers = file_size / 53;
914 buf = GNUNET_malloc (file_size);
915 size_read = GNUNET_DISK_file_read (fh, buf, file_size);
916 GNUNET_assert (size_read == file_size);
917 LOG (GNUNET_ERROR_TYPE_DEBUG,
918 "Restoring %" PRIu32 " peers from file `%s'\n",
920 filename_valid_peers);
921 for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53)
923 str_repr = GNUNET_strndup (iter_buf, 53);
924 peer = s2i_full (str_repr);
925 GNUNET_free (str_repr);
926 add_valid_peer (peer);
927 LOG (GNUNET_ERROR_TYPE_DEBUG,
928 "Restored valid peer %s from disk\n",
929 GNUNET_i2s_full (peer));
933 LOG (GNUNET_ERROR_TYPE_DEBUG,
934 "num_peers: %" PRIu32 ", _size (valid_peers): %u\n",
936 GNUNET_CONTAINER_multipeermap_size (valid_peers));
937 if (num_peers != GNUNET_CONTAINER_multipeermap_size (valid_peers))
939 LOG (GNUNET_ERROR_TYPE_WARNING,
940 "Number of restored peers does not match file size. Have probably duplicates.\n");
942 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
943 LOG (GNUNET_ERROR_TYPE_DEBUG,
944 "Restored %u valid peers from disk\n",
945 GNUNET_CONTAINER_multipeermap_size (valid_peers));
950 * @brief Initialise storage of peers
952 * @param fn_valid_peers filename of the file used to store valid peer ids
953 * @param cadet_h cadet handle
954 * @param disconnect_handler Disconnect handler
955 * @param c_handlers cadet handlers
956 * @param own_id own peer identity
959 Peers_initialise (char* fn_valid_peers,
960 struct GNUNET_CADET_Handle *cadet_h,
961 GNUNET_CADET_DisconnectEventHandler disconnect_handler,
962 const struct GNUNET_MQ_MessageHandler *c_handlers,
963 const struct GNUNET_PeerIdentity *own_id)
965 filename_valid_peers = GNUNET_strdup (fn_valid_peers);
966 cadet_handle = cadet_h;
967 cleanup_destroyed_channel = disconnect_handler;
968 cadet_handlers = c_handlers;
969 own_identity = own_id;
970 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
971 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
972 restore_valid_peers ();
977 * @brief Delete storage of peers that was created with #Peers_initialise ()
983 GNUNET_CONTAINER_multipeermap_iterate (peer_map,
984 peermap_clear_iterator,
987 LOG (GNUNET_ERROR_TYPE_WARNING,
988 "Iteration destroying peers was aborted.\n");
990 GNUNET_CONTAINER_multipeermap_destroy (peer_map);
991 store_valid_peers ();
992 GNUNET_free (filename_valid_peers);
993 GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
998 * Iterator over #valid_peers hash map entries.
1000 * @param cls closure - unused
1001 * @param peer current peer id
1002 * @param value value in the hash map - unused
1003 * @return #GNUNET_YES if we should continue to
1005 * #GNUNET_NO if not.
1008 valid_peer_iterator (void *cls,
1009 const struct GNUNET_PeerIdentity *peer,
1012 struct PeersIteratorCls *it_cls = cls;
1014 return it_cls->iterator (it_cls->cls,
1020 * @brief Get all currently known, valid peer ids.
1022 * @param it function to call on each peer id
1023 * @param it_cls extra argument to @a it
1024 * @return the number of key value pairs processed,
1025 * #GNUNET_SYSERR if it aborted iteration
1028 Peers_get_valid_peers (PeersIterator iterator,
1031 struct PeersIteratorCls *cls;
1034 cls = GNUNET_new (struct PeersIteratorCls);
1035 cls->iterator = iterator;
1037 ret = GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
1038 valid_peer_iterator,
1046 * @brief Add peer to known peers.
1048 * This function is called on new peer_ids from 'external' sources
1049 * (client seed, cadet get_peers(), ...)
1051 * @param peer the new #GNUNET_PeerIdentity
1053 * @return #GNUNET_YES if peer was inserted
1054 * #GNUNET_NO otherwise (if peer was already known or
1055 * peer was #own_identity)
1058 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
1060 if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
1061 (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
1063 return GNUNET_NO; /* We already know this peer - nothing to do */
1065 (void) create_peer_ctx (peer);
1071 * @brief Try connecting to a peer to see whether it is online
1073 * If not known yet, insert into known peers
1075 * @param peer the peer whose liveliness is to be checked
1076 * @return #GNUNET_YES if peer had to be inserted
1077 * #GNUNET_NO otherwise (if peer was already known or
1078 * peer was #own_identity)
1081 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1083 struct PeerContext *peer_ctx;
1086 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1090 ret = Peers_insert_peer (peer);
1091 peer_ctx = get_peer_ctx (peer);
1092 if (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE))
1094 check_peer_live (peer_ctx);
1101 * @brief Check if peer is removable.
1104 * - a recv channel exists
1105 * - there are pending messages
1106 * - there is no pending pull reply
1108 * @param peer the peer in question
1109 * @return #GNUNET_YES if peer is removable
1110 * #GNUNET_NO if peer is NOT removable
1111 * #GNUNET_SYSERR if peer is not known
1114 Peers_check_removable (const struct GNUNET_PeerIdentity *peer)
1116 struct PeerContext *peer_ctx;
1118 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1120 return GNUNET_SYSERR;
1123 peer_ctx = get_peer_ctx (peer);
1124 if ( (NULL != peer_ctx->recv_channel) ||
1125 (NULL != peer_ctx->pending_messages_head) ||
1126 (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
1135 * @brief Remove peer
1137 * @param peer the peer to clean
1138 * @return #GNUNET_YES if peer was removed
1139 * #GNUNET_NO otherwise
1142 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1144 struct PeerContext *peer_ctx;
1146 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1151 peer_ctx = get_peer_ctx (peer);
1152 set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1153 LOG (GNUNET_ERROR_TYPE_DEBUG,
1154 "Going to remove peer %s\n",
1155 GNUNET_i2s (&peer_ctx->peer_id));
1156 Peers_unset_peer_flag (peer, Peers_ONLINE);
1158 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1159 while (NULL != peer_ctx->pending_messages_head)
1161 LOG (GNUNET_ERROR_TYPE_DEBUG,
1162 "Removing unsent %s\n",
1163 peer_ctx->pending_messages_head->type);
1164 /* Cancle pending message, too */
1165 remove_pending_message (peer_ctx->pending_messages_head, GNUNET_YES);
1167 /* If we are still waiting for notification whether this peer is live
1168 * cancel the according task */
1169 if (NULL != peer_ctx->liveliness_check_pending)
1171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1172 "Removing pending liveliness check for peer %s\n",
1173 GNUNET_i2s (&peer_ctx->peer_id));
1174 // TODO wait until cadet sets mq->cancel_impl
1175 //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
1176 GNUNET_free (peer_ctx->liveliness_check_pending);
1177 peer_ctx->liveliness_check_pending = NULL;
1179 if (NULL != peer_ctx->send_channel)
1181 LOG (GNUNET_ERROR_TYPE_DEBUG,
1182 "Destroying send channel\n");
1183 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1184 peer_ctx->send_channel = NULL;
1186 if (NULL != peer_ctx->recv_channel)
1188 LOG (GNUNET_ERROR_TYPE_DEBUG,
1189 "Destroying recv channel\n");
1190 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1191 peer_ctx->recv_channel = NULL;
1194 GNUNET_free (peer_ctx->send_channel_flags);
1195 GNUNET_free (peer_ctx->recv_channel_flags);
1197 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1199 LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1201 GNUNET_free (peer_ctx);
1207 * @brief set flags on a given peer.
1209 * @param peer the peer to set flags on
1210 * @param flags the flags
1213 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1215 struct PeerContext *peer_ctx;
1217 peer_ctx = get_peer_ctx (peer);
1218 set_peer_flag (peer_ctx, flags);
1223 * @brief unset flags on a given peer.
1225 * @param peer the peer to unset flags on
1226 * @param flags the flags
1229 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1231 struct PeerContext *peer_ctx;
1233 peer_ctx = get_peer_ctx (peer);
1234 unset_peer_flag (peer_ctx, flags);
1239 * @brief Check whether flags on a peer are set.
1241 * @param peer the peer to check the flag of
1242 * @param flags the flags to check
1244 * @return #GNUNET_SYSERR if peer is not known
1245 * #GNUNET_YES if all given flags are set
1246 * #GNUNET_NO otherwise
1249 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1251 struct PeerContext *peer_ctx;
1253 if (GNUNET_NO == Peers_check_peer_known (peer))
1255 return GNUNET_SYSERR;
1257 peer_ctx = get_peer_ctx (peer);
1258 return check_peer_flag_set (peer_ctx, flags);
1263 * @brief set flags on a given channel.
1265 * @param channel the channel to set flags on
1266 * @param flags the flags
1269 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1271 set_channel_flag (channel_flags, flags);
1276 * @brief unset flags on a given channel.
1278 * @param channel the channel to unset flags on
1279 * @param flags the flags
1282 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1284 unset_channel_flag (channel_flags, flags);
1289 * @brief Check whether flags on a channel are set.
1291 * @param channel the channel to check the flag of
1292 * @param flags the flags to check
1294 * @return #GNUNET_YES if all given flags are set
1295 * #GNUNET_NO otherwise
1298 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1300 return check_channel_flag_set (channel_flags, flags);
1304 * @brief Get the flags for the channel in @a role for @a peer.
1306 * @param peer Peer to get the channel flags for.
1307 * @param role Role of channel to get flags for
1309 * @return The flags.
1312 Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
1313 enum Peers_ChannelRole role)
1315 const struct PeerContext *peer_ctx;
1317 peer_ctx = get_peer_ctx (peer);
1318 if (Peers_CHANNEL_ROLE_SENDING == role)
1320 return peer_ctx->send_channel_flags;
1322 else if (Peers_CHANNEL_ROLE_RECEIVING == role)
1324 return peer_ctx->recv_channel_flags;
1333 * @brief Check whether we have information about the given peer.
1335 * FIXME probably deprecated. Make this the new _online.
1337 * @param peer peer in question
1339 * @return #GNUNET_YES if peer is known
1340 * #GNUNET_NO if peer is not knwon
1343 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1345 return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1350 * @brief Check whether @a peer is actually a peer.
1352 * A valid peer is a peer that we know exists eg. we were connected to once.
1354 * @param peer peer in question
1356 * @return #GNUNET_YES if peer is valid
1357 * #GNUNET_NO if peer is not valid
1360 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1362 return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1367 * @brief Indicate that we want to send to the other peer
1369 * This establishes a sending channel
1371 * @param peer the peer to establish channel to
1374 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1376 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1377 (void) get_channel (peer);
1382 * @brief Check whether other peer has the intention to send/opened channel
1385 * @param peer the peer in question
1387 * @return #GNUNET_YES if peer has the intention to send
1388 * #GNUNET_NO otherwise
1391 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1393 const struct PeerContext *peer_ctx;
1395 peer_ctx = get_peer_ctx (peer);
1396 if (NULL != peer_ctx->recv_channel)
1405 * Handle the channel a peer opens to us.
1407 * @param cls The closure
1408 * @param channel The channel the peer wants to establish
1409 * @param initiator The peer's peer ID
1411 * @return initial channel context for the channel
1412 * (can be NULL -- that's not an error)
1415 Peers_handle_inbound_channel (void *cls,
1416 struct GNUNET_CADET_Channel *channel,
1417 const struct GNUNET_PeerIdentity *initiator)
1419 struct PeerContext *peer_ctx;
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "New channel was established to us (Peer %s).\n",
1423 GNUNET_i2s (initiator));
1424 GNUNET_assert (NULL != channel); /* according to cadet API */
1425 /* Make sure we 'know' about this peer */
1426 peer_ctx = create_or_get_peer_ctx (initiator);
1427 set_peer_live (peer_ctx);
1428 /* We only accept one incoming channel per peer */
1429 if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1431 set_channel_flag (peer_ctx->recv_channel_flags,
1432 Peers_CHANNEL_ESTABLISHED_TWICE);
1433 GNUNET_CADET_channel_destroy (channel);
1434 /* return the channel context */
1435 return &peer_ctx->peer_id;
1437 peer_ctx->recv_channel = channel;
1438 return &peer_ctx->peer_id;
1443 * @brief Check whether a sending channel towards the given peer exists
1445 * @param peer the peer to check for
1447 * @return #GNUNET_YES if a sending channel towards that peer exists
1448 * #GNUNET_NO otherwise
1451 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1453 struct PeerContext *peer_ctx;
1455 if (GNUNET_NO == Peers_check_peer_known (peer))
1456 { /* If no such peer exists, there is no channel */
1459 peer_ctx = get_peer_ctx (peer);
1460 if (NULL == peer_ctx->send_channel)
1469 * @brief check whether the given channel is the sending channel of the given
1472 * @param peer the peer in question
1473 * @param channel the channel to check for
1474 * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1475 * #Peers_CHANNEL_ROLE_RECEIVING
1477 * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1478 * #GNUNET_NO otherwise
1481 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1482 const struct GNUNET_CADET_Channel *channel,
1483 enum Peers_ChannelRole role)
1485 const struct PeerContext *peer_ctx;
1487 if (GNUNET_NO == Peers_check_peer_known (peer))
1491 peer_ctx = get_peer_ctx (peer);
1492 if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1493 (channel == peer_ctx->send_channel) )
1497 if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1498 (channel == peer_ctx->recv_channel) )
1507 * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1508 * intention to another peer
1510 * If there is also no channel to receive messages from that peer, remove it
1514 * @peer the peer identity of the peer whose sending channel to destroy
1515 * @return #GNUNET_YES if channel was destroyed
1516 * #GNUNET_NO otherwise
1519 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1521 struct PeerContext *peer_ctx;
1523 if (GNUNET_NO == Peers_check_peer_known (peer))
1527 peer_ctx = get_peer_ctx (peer);
1528 if (NULL != peer_ctx->send_channel)
1530 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1531 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1532 peer_ctx->send_channel = NULL;
1533 (void) Peers_check_connected (peer);
1540 * This is called when a channel is destroyed.
1542 * @param cls The closure
1543 * @param channel The channel being closed
1544 * @param channel_ctx The context associated with this channel
1547 Peers_cleanup_destroyed_channel (void *cls,
1548 const struct GNUNET_CADET_Channel *channel)
1550 struct GNUNET_PeerIdentity *peer = cls;
1551 struct PeerContext *peer_ctx;
1553 if (GNUNET_NO == Peers_check_peer_known (peer))
1554 {/* We don't want to implicitly create a context that we're about to kill */
1555 LOG (GNUNET_ERROR_TYPE_DEBUG,
1556 "channel (%s) without associated context was destroyed\n",
1560 peer_ctx = get_peer_ctx (peer);
1562 /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1563 * flag will be set. In this case simply make sure that the channels are
1565 /* FIXME This distinction seems to be redundant */
1566 if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1567 {/* We initiatad the destruction of this particular peer */
1568 if (channel == peer_ctx->send_channel)
1569 peer_ctx->send_channel = NULL;
1570 else if (channel == peer_ctx->recv_channel)
1571 peer_ctx->recv_channel = NULL;
1573 if (NULL != peer_ctx->send_channel)
1575 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1576 peer_ctx->send_channel = NULL;
1578 if (NULL != peer_ctx->recv_channel)
1580 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1581 peer_ctx->recv_channel = NULL;
1583 /* Set the #Peers_ONLINE flag accordingly */
1584 (void) Peers_check_connected (peer);
1589 { /* We did not initiate the destruction of this peer */
1590 if (channel == peer_ctx->send_channel)
1591 { /* Something (but us) killd the channel - clean up peer */
1592 LOG (GNUNET_ERROR_TYPE_DEBUG,
1593 "send channel (%s) was destroyed - cleaning up\n",
1595 peer_ctx->send_channel = NULL;
1597 else if (channel == peer_ctx->recv_channel)
1598 { /* Other peer doesn't want to send us messages anymore */
1599 LOG (GNUNET_ERROR_TYPE_DEBUG,
1600 "Peer %s destroyed recv channel - cleaning up channel\n",
1602 peer_ctx->recv_channel = NULL;
1606 LOG (GNUNET_ERROR_TYPE_WARNING,
1607 "unknown channel (%s) was destroyed\n",
1611 (void) Peers_check_connected (peer);
1615 * @brief Send a message to another peer.
1617 * Keeps track about pending messages so they can be properly removed when the
1618 * peer is destroyed.
1620 * @param peer receeiver of the message
1621 * @param ev envelope of the message
1622 * @param type type of the message
1625 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1626 struct GNUNET_MQ_Envelope *ev,
1629 struct PendingMessage *pending_msg;
1630 struct GNUNET_MQ_Handle *mq;
1632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1633 "Sending message to %s of type %s\n",
1636 pending_msg = insert_pending_message (peer, ev, type);
1638 GNUNET_MQ_notify_sent (ev,
1641 GNUNET_MQ_send (mq, ev);
1645 * @brief Schedule a operation on given peer
1647 * Avoids scheduling an operation twice.
1649 * @param peer the peer we want to schedule the operation for once it gets live
1651 * @return #GNUNET_YES if the operation was scheduled
1652 * #GNUNET_NO otherwise
1655 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1656 const PeerOp peer_op)
1658 struct PeerPendingOp pending_op;
1659 struct PeerContext *peer_ctx;
1661 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1665 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1667 //TODO if LIVE/ONLINE execute immediately
1669 if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1671 peer_ctx = get_peer_ctx (peer);
1672 pending_op.op = peer_op;
1673 pending_op.op_cls = NULL;
1674 GNUNET_array_append (peer_ctx->pending_ops,
1675 peer_ctx->num_pending_ops,
1683 * @brief Get the recv_channel of @a peer.
1684 * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming
1687 * @param peer The peer to get the recv_channel from.
1689 * @return The recv_channel.
1691 struct GNUNET_CADET_Channel *
1692 Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer)
1694 struct PeerContext *peer_ctx;
1696 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1697 peer_ctx = get_peer_ctx (peer);
1698 return peer_ctx->recv_channel;
1701 /* end of gnunet-service-rps_peers.c */