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_util_lib.h"
28 #include "gnunet_cadet_service.h"
31 #include "gnunet-service-rps_peers.h"
35 #define LOG(kind, ...) GNUNET_log_from(kind,"rps-peers",__VA_ARGS__)
39 * Set a peer flag of given peer context.
41 #define set_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) |= (mask))
44 * Get peer flag of given peer context.
46 #define check_peer_flag_set(peer_ctx, mask)\
47 ((peer_ctx->peer_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
50 * Unset flag of given peer context.
52 #define unset_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) &= ~(mask))
55 * Set a channel flag of given channel context.
57 #define set_channel_flag(channel_flags, mask) ((*channel_flags) |= (mask))
60 * Get channel flag of given channel context.
62 #define check_channel_flag_set(channel_flags, mask)\
63 ((*channel_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
66 * Unset flag of given channel context.
68 #define unset_channel_flag(channel_flags, mask) ((*channel_flags) &= ~(mask))
73 * Pending operation on peer consisting of callback and closure
75 * When an operation cannot be executed right now this struct is used to store
76 * the callback and closure for later execution.
92 * List containing all messages that are yet to be send
94 * This is used to keep track of all messages that have not been sent yet. When
95 * a peer is to be removed the pending messages can be removed properly.
102 struct PendingMessage *next;
103 struct PendingMessage *prev;
106 * The envelope to the corresponding message
108 struct GNUNET_MQ_Envelope *ev;
111 * The corresponding context
113 struct PeerContext *peer_ctx;
122 * Struct used to keep track of other peer's status
124 * This is stored in a multipeermap.
125 * It contains information such as cadet channels, a message queue for sending,
126 * status about the channels, the pending operations on this peer and some flags
127 * about the status of the peer itself. (live, valid, ...)
132 * Message queue open to client
134 struct GNUNET_MQ_Handle *mq;
137 * Channel open to client.
139 struct GNUNET_CADET_Channel *send_channel;
142 * Flags to the sending channel
144 uint32_t *send_channel_flags;
147 * Channel open from client.
149 struct GNUNET_CADET_Channel *recv_channel; // unneeded?
152 * Flags to the receiving channel
154 uint32_t *recv_channel_flags;
157 * Array of pending operations on this peer.
159 struct PeerPendingOp *pending_ops;
162 * Handle to the callback given to cadet_ntfy_tmt_rdy()
164 * To be canceled on shutdown.
166 struct GNUNET_CADET_TransmitHandle *transmit_handle;
169 * Number of pending operations.
171 unsigned int num_pending_ops;
174 * Identity of the peer
176 struct GNUNET_PeerIdentity peer_id;
179 * Flags indicating status of peer
184 * Last time we received something from that peer.
186 struct GNUNET_TIME_Absolute last_message_recv;
189 * Last time we received a keepalive message.
191 struct GNUNET_TIME_Absolute last_keepalive;
194 * DLL with all messages that are yet to be sent
196 struct PendingMessage *pending_messages_head;
197 struct PendingMessage *pending_messages_tail;
200 * This is pobably followed by 'statistical' data (when we first saw
201 * him, how did we get his ID, how many pushes (in a timeinterval),
207 * @brief Hashmap of valid peers.
209 static struct GNUNET_CONTAINER_MultiPeerMap *valid_peers;
212 * @brief Maximum number of valid peers to keep.
213 * TODO read from config
215 static uint32_t num_valid_peers_max = UINT32_MAX;
218 * @brief Filename of the file that stores the valid peers persistently.
220 static char *filename_valid_peers;
223 * Set of all peers to keep track of them.
225 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
228 * Own #GNUNET_PeerIdentity.
230 static const struct GNUNET_PeerIdentity *own_identity;
235 static struct GNUNET_CADET_Handle *cadet_handle;
239 * @brief Get the #PeerContext associated with a peer
241 * @param peer the peer id
243 * @return the #PeerContext
245 static struct PeerContext *
246 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
248 struct PeerContext *ctx;
251 ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
252 GNUNET_assert (GNUNET_YES == ret);
253 ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
254 GNUNET_assert (NULL != ctx);
259 * @brief Create a new #PeerContext and insert it into the peer map
261 * @param peer the peer to create the #PeerContext for
263 * @return the #PeerContext
265 static struct PeerContext *
266 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
268 struct PeerContext *ctx;
271 GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
273 ctx = GNUNET_new (struct PeerContext);
274 ctx->peer_id = *peer;
275 ctx->send_channel_flags = GNUNET_new (uint32_t);
276 ctx->recv_channel_flags = GNUNET_new (uint32_t);
277 ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
278 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
279 GNUNET_assert (GNUNET_OK == ret);
284 * @brief Create or get a #PeerContext
286 * @param peer the peer to get the associated context to
288 * @return the context
290 static struct PeerContext *
291 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
293 if (GNUNET_NO == Peers_check_peer_known (peer))
295 return create_peer_ctx (peer);
297 return get_peer_ctx (peer);
301 * @brief Check whether we have a connection to this @a peer
303 * Also sets the #Peers_ONLINE flag accordingly
305 * @param peer the peer in question
307 * @return #GNUNET_YES if we are connected
308 * #GNUNET_NO otherwise
311 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
313 const struct PeerContext *peer_ctx;
315 /* If we don't know about this peer we don't know whether it's online */
316 if (GNUNET_NO == Peers_check_peer_known (peer))
320 /* Get the context */
321 peer_ctx = get_peer_ctx (peer);
322 /* If we have no channel to this peer we don't know whether it's online */
323 if ( (NULL == peer_ctx->send_channel) &&
324 (NULL == peer_ctx->recv_channel) )
326 Peers_unset_peer_flag (peer, Peers_ONLINE);
329 /* Otherwise (if we have a channel, we know that it's online */
330 Peers_set_peer_flag (peer, Peers_ONLINE);
335 * @brief The closure to #get_rand_peer_iterator.
337 struct GetRandPeerIteratorCls
340 * @brief The index of the peer to return.
341 * Will be decreased until 0.
342 * Then current peer is returned.
347 * @brief Pointer to peer to return.
349 const struct GNUNET_PeerIdentity *peer;
353 * @brief Iterator function for #get_random_peer_from_peermap.
355 * Implements #GNUNET_CONTAINER_PeerMapIterator.
356 * Decreases the index until the index is null.
357 * Then returns the current peer.
359 * @param cls the #GetRandPeerIteratorCls containing index and peer
360 * @param peer current peer
361 * @param value unused
363 * @return #GNUNET_YES if we should continue to
368 get_rand_peer_iterator (void *cls,
369 const struct GNUNET_PeerIdentity *peer,
372 struct GetRandPeerIteratorCls *iterator_cls = cls;
373 if (0 >= iterator_cls->index)
375 iterator_cls->peer = peer;
378 iterator_cls->index--;
383 * @brief Get a random peer from @a peer_map
385 * @param peer_map the peer_map to get the peer from
387 * @return a random peer
389 static const struct GNUNET_PeerIdentity *
390 get_random_peer_from_peermap (const struct
391 GNUNET_CONTAINER_MultiPeerMap *peer_map)
393 struct GetRandPeerIteratorCls *iterator_cls;
394 const struct GNUNET_PeerIdentity *ret;
396 iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls);
397 iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
398 GNUNET_CONTAINER_multipeermap_size (peer_map));
399 (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
400 get_rand_peer_iterator,
402 ret = iterator_cls->peer;
403 GNUNET_free (iterator_cls);
408 * @brief Add a given @a peer to valid peers.
410 * If valid peers are already #num_valid_peers_max, delete a peer previously.
412 * @param peer the peer that is added to the valid peers.
414 * @return #GNUNET_YES if no other peer had to be removed
415 * #GNUNET_NO otherwise
418 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
420 const struct GNUNET_PeerIdentity *rand_peer;
424 while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
426 rand_peer = get_random_peer_from_peermap (valid_peers);
427 GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
430 (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
431 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
436 * @brief Set the peer flag to living and
437 * call the pending operations on this peer.
439 * Also adds peer to #valid_peers.
441 * @param peer_ctx the #PeerContext of the peer to set live
444 set_peer_live (struct PeerContext *peer_ctx)
446 struct GNUNET_PeerIdentity *peer;
449 /* Cancle cadet transmit_handle if still scheduled */
450 if (NULL != peer_ctx->transmit_handle)
452 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
453 peer_ctx->transmit_handle = NULL;
456 peer = &peer_ctx->peer_id;
457 (void) add_valid_peer (peer);
458 set_peer_flag (peer_ctx, Peers_ONLINE);
459 LOG (GNUNET_ERROR_TYPE_DEBUG,
460 "Peer %s is live and valid\n",
463 /* Call pending operations */
464 for (i = 0; i < peer_ctx->num_pending_ops; i++)
466 peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
468 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
472 * @brief Get the channel of a peer. If not existing, create.
474 * @param peer the peer id
475 * @return the #GNUNET_CADET_Channel used to send data to @a peer
477 struct GNUNET_CADET_Channel *
478 get_channel (const struct GNUNET_PeerIdentity *peer)
480 struct PeerContext *peer_ctx;
482 peer_ctx = get_peer_ctx (peer);
483 if (NULL == peer_ctx->send_channel)
485 LOG (GNUNET_ERROR_TYPE_DEBUG,
486 "Trying to establish channel to peer %s\n",
488 peer_ctx->send_channel =
489 GNUNET_CADET_channel_create (cadet_handle,
490 peer_ctx->send_channel_flags, /* context */
492 GNUNET_RPS_CADET_PORT,
493 GNUNET_CADET_OPTION_RELIABLE);
495 return peer_ctx->send_channel;
499 * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
501 * If we already have a message queue open to this client,
502 * simply return it, otherways create one.
504 * @param peer the peer to get the mq to
505 * @return the #GNUNET_MQ_Handle
507 static struct GNUNET_MQ_Handle *
508 get_mq (const struct GNUNET_PeerIdentity *peer)
510 struct PeerContext *peer_ctx;
512 peer_ctx = get_peer_ctx (peer);
513 GNUNET_assert (NULL == peer_ctx->transmit_handle);
515 if (NULL == peer_ctx->mq)
517 (void) get_channel (peer);
518 peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
524 * @brief Callback that is called when a channel was effectively established.
526 * This is an implementation of #GNUNET_CONNECTION_TransmitReadyNotify and
527 * given to #GNUNET_CADET_notify_transmit_ready_cancel and called when the
528 * channel was successfully established.
530 * This function type was originally ment to be called to provide the data to
531 * be sent. This is called when the connection is ready to queue more data.
532 * However we use it to get notified about the successful establishement of a
535 * @a buf will be NULL and @a size zero if the
536 * connection was closed for writing in the meantime.
539 * @param size number of bytes available in @a buf
540 * @param buf where the callee should write the message
541 * @return number of bytes written to @a buf
545 cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
547 struct PeerContext *peer_ctx = (struct PeerContext *) cls;
548 // TODO make sure the context is not deleted or the establishing of the
549 // channel is cancelled
551 peer_ctx->transmit_handle = NULL;
552 LOG (GNUNET_ERROR_TYPE_DEBUG,
553 "Set ->transmit_handle = NULL for peer %s\n",
554 GNUNET_i2s (&peer_ctx->peer_id));
556 if ( (NULL != buf) &&
559 set_peer_live (peer_ctx);
563 LOG (GNUNET_ERROR_TYPE_WARNING,
564 "Problems establishing a connection to peer %s in order to check liveliness\n",
565 GNUNET_i2s (&peer_ctx->peer_id));
566 // TODO reschedule? cleanup?
572 * Issue a check whether peer is live
574 * @param peer_ctx the context of the peer
577 check_peer_live (struct PeerContext *peer_ctx)
579 LOG (GNUNET_ERROR_TYPE_DEBUG,
580 "Get informed about peer %s getting live\n",
581 GNUNET_i2s (&peer_ctx->peer_id));
583 if (NULL == peer_ctx->transmit_handle &&
584 NULL == peer_ctx->send_channel)
586 (void) get_channel (&peer_ctx->peer_id);
587 peer_ctx->transmit_handle =
588 GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
590 GNUNET_TIME_UNIT_FOREVER_REL,
591 sizeof (struct GNUNET_MessageHeader),
592 cadet_notify_transmit_ready_cb,
595 else if (NULL != peer_ctx->transmit_handle)
596 LOG (GNUNET_ERROR_TYPE_DEBUG,
597 "Already waiting for notification\n");
598 else if (NULL != peer_ctx->send_channel)
599 LOG (GNUNET_ERROR_TYPE_DEBUG,
600 "Already have established channel to peer\n");
604 * @brief Add an envelope to a message passed to mq to list of pending messages
606 * @param peer peer the message was sent to
607 * @param ev envelope to the message
608 * @param type type of the message to be sent
609 * @return pointer to pending message
611 static struct PendingMessage *
612 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
613 struct GNUNET_MQ_Envelope *ev,
616 struct PendingMessage *pending_msg;
617 struct PeerContext *peer_ctx;
619 peer_ctx = get_peer_ctx (peer);
620 pending_msg = GNUNET_new (struct PendingMessage);
621 pending_msg->ev = ev;
622 pending_msg->peer_ctx = peer_ctx;
623 pending_msg->type = type;
624 GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
625 peer_ctx->pending_messages_tail,
631 * @brief Remove a pending message from the respective DLL
633 * @param pending_msg the pending message to remove
636 remove_pending_message (struct PendingMessage *pending_msg)
638 struct PeerContext *peer_ctx;
640 peer_ctx = pending_msg->peer_ctx;
641 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
642 peer_ctx->pending_messages_tail,
644 /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does
645 * not set a #GNUNET_MQ_CancelImpl */
646 /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
647 GNUNET_free (pending_msg);
651 * @brief Check whether function of type #PeerOp was already scheduled
653 * The array with pending operations will probably never grow really big, so
654 * iterating over it should be ok.
656 * @param peer the peer to check
657 * @param peer_op the operation (#PeerOp) on the peer
659 * @return #GNUNET_YES if this operation is scheduled on that peer
660 * #GNUNET_NO otherwise
663 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
664 const PeerOp peer_op)
666 const struct PeerContext *peer_ctx;
669 peer_ctx = get_peer_ctx (peer);
670 for (i = 0; i < peer_ctx->num_pending_ops; i++)
671 if (peer_op == peer_ctx->pending_ops[i].op)
677 * Iterator over hash map entries. Deletes all contexts of peers.
680 * @param key current public key
681 * @param value value in the hash map
682 * @return #GNUNET_YES if we should continue to iterate,
686 peermap_clear_iterator (void *cls,
687 const struct GNUNET_PeerIdentity *key,
690 Peers_remove_peer (key);
695 * @brief This is called once a message is sent.
697 * Removes the pending message
699 * @param cls type of the message that was sent
702 mq_notify_sent_cb (void *cls)
704 struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
705 LOG (GNUNET_ERROR_TYPE_DEBUG,
708 remove_pending_message (pending_msg);
712 * @brief Clear the stored valid peers.
715 clear_valid_peer_storage ()
717 struct GNUNET_DISK_FileHandle *fh;
719 if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers))
723 fh = GNUNET_DISK_file_open (filename_valid_peers,
724 GNUNET_DISK_OPEN_WRITE,
725 GNUNET_DISK_PERM_USER_READ |
726 GNUNET_DISK_PERM_USER_WRITE);
729 LOG (GNUNET_ERROR_TYPE_WARNING,
730 "Not able to clear file `%s' containing valid peers\n",
731 filename_valid_peers);
734 GNUNET_DISK_file_write (fh, "", 0);
735 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
739 * @brief Iterator function for #store_valid_peers.
741 * Implements #GNUNET_CONTAINER_PeerMapIterator.
742 * Writes single peer to disk.
744 * @param cls the file handle to write to.
745 * @param peer current peer
746 * @param value unused
748 * @return #GNUNET_YES if we should continue to
753 store_peer_presistently_iterator (void *cls,
754 const struct GNUNET_PeerIdentity *peer,
757 const struct GNUNET_DISK_FileHandle *fh = cls;
758 char peer_string[128];
766 size = GNUNET_snprintf (peer_string,
767 sizeof (peer_string),
769 GNUNET_i2s_full (peer));
770 GNUNET_assert (53 == size);
771 ret = GNUNET_DISK_file_write (fh,
774 GNUNET_assert (size == ret);
779 * @brief Store the peers currently in #valid_peers to disk.
784 struct GNUNET_DISK_FileHandle *fh;
785 uint32_t number_written_peers;
788 GNUNET_DISK_directory_create_for_file (filename_valid_peers))
792 clear_valid_peer_storage ();
793 fh = GNUNET_DISK_file_open (filename_valid_peers,
794 GNUNET_DISK_OPEN_WRITE |
795 GNUNET_DISK_OPEN_CREATE |
796 GNUNET_DISK_OPEN_APPEND,
797 GNUNET_DISK_PERM_USER_READ |
798 GNUNET_DISK_PERM_USER_WRITE);
801 LOG (GNUNET_ERROR_TYPE_WARNING,
802 "Not able to write valid peers to file `%s'\n",
803 filename_valid_peers);
806 LOG (GNUNET_ERROR_TYPE_DEBUG,
807 "Writing %u valid peers to disk\n",
808 GNUNET_CONTAINER_multipeermap_size (valid_peers));
809 number_written_peers =
810 GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
811 store_peer_presistently_iterator,
813 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
814 GNUNET_assert (number_written_peers ==
815 GNUNET_CONTAINER_multipeermap_size (valid_peers));
819 * @brief Convert string representation of peer id to peer id.
821 * Counterpart to #GNUNET_i2s_full.
823 * @param string_repr The string representation of the peer id
825 * @return The peer id
827 static const struct GNUNET_PeerIdentity *
828 s2i_full (const char *string_repr)
830 struct GNUNET_PeerIdentity *peer;
834 peer = GNUNET_new (struct GNUNET_PeerIdentity);
835 len = strlen (string_repr);
838 LOG (GNUNET_ERROR_TYPE_WARNING,
839 "Not able to convert string representation of PeerID to PeerID\n"
840 "Sting representation: %s (len %u) - too short\n",
849 ret = GNUNET_CRYPTO_eddsa_public_key_from_string (string_repr,
852 if (GNUNET_OK != ret)
854 LOG (GNUNET_ERROR_TYPE_WARNING,
855 "Not able to convert string representation of PeerID to PeerID\n"
856 "Sting representation: %s\n",
864 * @brief Restore the peers on disk to #valid_peers.
867 restore_valid_peers ()
871 struct GNUNET_DISK_FileHandle *fh;
875 const char *str_repr;
876 const struct GNUNET_PeerIdentity *peer;
878 if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers))
882 fh = GNUNET_DISK_file_open (filename_valid_peers,
883 GNUNET_DISK_OPEN_READ,
884 GNUNET_DISK_PERM_USER_READ);
885 GNUNET_assert (NULL != fh);
886 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size));
887 num_peers = file_size / 53;
888 buf = GNUNET_malloc (file_size);
889 size_read = GNUNET_DISK_file_read (fh, buf, file_size);
890 GNUNET_assert (size_read == file_size);
891 for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53)
893 str_repr = GNUNET_strndup (iter_buf, 53);
894 peer = s2i_full (str_repr);
895 add_valid_peer (peer);
896 LOG (GNUNET_ERROR_TYPE_DEBUG,
897 "Restored valid peer %s from disk\n",
898 GNUNET_i2s_full (peer));
900 GNUNET_assert (num_peers == GNUNET_CONTAINER_multipeermap_size (valid_peers));
901 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
902 LOG (GNUNET_ERROR_TYPE_DEBUG,
903 "Restored %u valid peers from disk\n",
908 * @brief Initialise storage of peers
910 * @param fn_valid_peers filename of the file used to store valid peer ids
911 * @param cadet_h cadet handle
912 * @param own_id own peer identity
915 Peers_initialise (char* fn_valid_peers,
916 struct GNUNET_CADET_Handle *cadet_h,
917 const struct GNUNET_PeerIdentity *own_id)
919 filename_valid_peers = GNUNET_strdup (fn_valid_peers);
920 cadet_handle = cadet_h;
921 own_identity = own_id;
922 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
923 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
924 restore_valid_peers ();
928 * @brief Delete storage of peers that was created with #Peers_initialise ()
934 GNUNET_CONTAINER_multipeermap_iterate (peer_map,
935 peermap_clear_iterator,
938 LOG (GNUNET_ERROR_TYPE_WARNING,
939 "Iteration destroying peers was aborted.\n");
941 GNUNET_CONTAINER_multipeermap_destroy (peer_map);
942 store_valid_peers ();
943 GNUNET_free (filename_valid_peers);
944 GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
947 // TODO store valid peers
950 * @brief Add peer to known peers.
952 * This function is called on new peer_ids from 'external' sources
953 * (client seed, cadet get_peers(), ...)
955 * @param peer the new #GNUNET_PeerIdentity
957 * @return #GNUNET_YES if peer was inserted
958 * #GNUNET_NO if peer was already known
961 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
963 if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
964 (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
966 return GNUNET_NO; /* We already know this peer - nothing to do */
968 (void) create_peer_ctx (peer);
974 * @brief Add peer to known peers and check for liveliness.
976 * This function is called on new peer_ids from 'external' sources
977 * (client seed, cadet get_peers(), ...)
979 * @param peer the new #GNUNET_PeerIdentity
981 * @return #GNUNET_YES if peer was inserted
982 * #GNUNET_NO if peer was already known
985 Peers_insert_peer_check_liveliness (const struct GNUNET_PeerIdentity *peer)
987 struct PeerContext *peer_ctx;
990 ret = Peers_insert_peer (peer);
991 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
995 peer_ctx = get_peer_ctx (peer);
996 if (GNUNET_NO == Peers_check_peer_valid (peer))
998 check_peer_live (peer_ctx);
1004 * @brief Remove unecessary data
1006 * If the other peer is not intending to send messages, we have messages pending
1007 * to be sent to this peer and we are not waiting for a reply, remove the
1008 * information about it (its #PeerContext).
1010 * @param peer the peer to clean
1011 * @return #GNUNET_YES if peer was removed
1012 * #GNUNET_NO otherwise
1015 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
1017 struct PeerContext *peer_ctx;
1019 // TODO actually remove unnecessary data
1021 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1026 peer_ctx = get_peer_ctx (peer);
1027 if ( (NULL != peer_ctx->recv_channel) ||
1028 (NULL != peer_ctx->pending_messages_head) ||
1029 (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
1033 Peers_remove_peer (peer);
1038 * @brief Remove peer
1040 * @param peer the peer to clean
1041 * @return #GNUNET_YES if peer was removed
1042 * #GNUNET_NO otherwise
1045 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1047 struct PeerContext *peer_ctx;
1049 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1054 peer_ctx = get_peer_ctx (peer);
1055 set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1056 LOG (GNUNET_ERROR_TYPE_DEBUG,
1057 "Going to remove peer %s\n",
1058 GNUNET_i2s (&peer_ctx->peer_id));
1059 Peers_unset_peer_flag (peer, Peers_ONLINE);
1061 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1062 // TODO delete struct GNUNET_TRANSPORT_TransmitHandle *transmit_handle
1063 /* Cancle messages that have not been sent yet */
1064 while (NULL != peer_ctx->pending_messages_head)
1066 LOG (GNUNET_ERROR_TYPE_DEBUG,
1067 "Removing unsent %s\n",
1068 peer_ctx->pending_messages_head->type);
1069 remove_pending_message (peer_ctx->pending_messages_head);
1071 /* If we are still waiting for notification whether this peer is live
1072 * cancel the according task */
1073 if (NULL != peer_ctx->transmit_handle)
1075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1076 "Trying to cancle transmit_handle for peer %s\n",
1077 GNUNET_i2s (&peer_ctx->peer_id));
1078 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
1079 peer_ctx->transmit_handle = NULL;
1081 if (NULL != peer_ctx->send_channel)
1083 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1084 peer_ctx->send_channel = NULL;
1086 if (NULL != peer_ctx->recv_channel)
1088 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1089 peer_ctx->recv_channel = NULL;
1091 if (NULL != peer_ctx->mq)
1093 GNUNET_MQ_destroy (peer_ctx->mq);
1094 peer_ctx->mq = NULL;
1097 GNUNET_free (peer_ctx->send_channel_flags);
1098 GNUNET_free (peer_ctx->recv_channel_flags);
1100 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1102 LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1104 GNUNET_free (peer_ctx);
1109 * @brief set flags on a given peer.
1111 * @param peer the peer to set flags on
1112 * @param flags the flags
1115 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1117 struct PeerContext *peer_ctx;
1119 peer_ctx = get_peer_ctx (peer);
1120 set_peer_flag (peer_ctx, flags);
1124 * @brief unset flags on a given peer.
1126 * @param peer the peer to unset flags on
1127 * @param flags the flags
1130 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1132 struct PeerContext *peer_ctx;
1134 peer_ctx = get_peer_ctx (peer);
1135 unset_peer_flag (peer_ctx, flags);
1139 * @brief Check whether flags on a peer are set.
1141 * @param peer the peer to check the flag of
1142 * @param flags the flags to check
1144 * @return #GNUNET_YES if all given flags are set
1145 * #GNUNET_NO otherwise
1148 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1150 struct PeerContext *peer_ctx;
1152 peer_ctx = get_peer_ctx (peer);
1153 return check_peer_flag_set (peer_ctx, flags);
1158 * @brief set flags on a given channel.
1160 * @param channel the channel to set flags on
1161 * @param flags the flags
1164 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1166 set_channel_flag (channel_flags, flags);
1170 * @brief unset flags on a given channel.
1172 * @param channel the channel to unset flags on
1173 * @param flags the flags
1176 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1178 unset_channel_flag (channel_flags, flags);
1182 * @brief Check whether flags on a channel are set.
1184 * @param channel the channel to check the flag of
1185 * @param flags the flags to check
1187 * @return #GNUNET_YES if all given flags are set
1188 * #GNUNET_NO otherwise
1191 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1193 return check_channel_flag_set (channel_flags, flags);
1197 * @brief Check whether we have information about the given peer.
1199 * FIXME probably deprecated. Make this the new _online.
1201 * @param peer peer in question
1203 * @return #GNUNET_YES if peer is known
1204 * #GNUNET_NO if peer is not knwon
1207 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1209 return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1213 * @brief Check whether @a peer is actually a peer.
1215 * A valid peer is a peer that we know exists eg. we were connected to once.
1217 * @param peer peer in question
1219 * @return #GNUNET_YES if peer is valid
1220 * #GNUNET_NO if peer is not valid
1223 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1225 return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1229 * @brief Indicate that we want to send to the other peer
1231 * This establishes a sending channel
1233 * @param peer the peer to establish channel to
1236 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1238 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1239 (void) get_channel (peer);
1243 * @brief Check whether other peer has the intention to send/opened channel
1246 * @param peer the peer in question
1248 * @return #GNUNET_YES if peer has the intention to send
1249 * #GNUNET_NO otherwise
1252 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1254 const struct PeerContext *peer_ctx;
1256 peer_ctx = get_peer_ctx (peer);
1257 if (NULL != peer_ctx->recv_channel)
1265 * Handle the channel a peer opens to us.
1267 * @param cls The closure
1268 * @param channel The channel the peer wants to establish
1269 * @param initiator The peer's peer ID
1270 * @param port The port the channel is being established over
1271 * @param options Further options
1273 * @return initial channel context for the channel
1274 * (can be NULL -- that's not an error)
1277 Peers_handle_inbound_channel (void *cls,
1278 struct GNUNET_CADET_Channel *channel,
1279 const struct GNUNET_PeerIdentity *initiator,
1281 enum GNUNET_CADET_ChannelOption options)
1283 struct PeerContext *peer_ctx;
1285 LOG (GNUNET_ERROR_TYPE_DEBUG,
1286 "New channel was established to us (Peer %s).\n",
1287 GNUNET_i2s (initiator));
1288 GNUNET_assert (NULL != channel); /* according to cadet API */
1289 /* Make sure we 'know' about this peer */
1290 peer_ctx = create_or_get_peer_ctx (initiator);
1291 set_peer_live (peer_ctx);
1292 /* We only accept one incoming channel per peer */
1293 if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1295 set_channel_flag (peer_ctx->recv_channel_flags,
1296 Peers_CHANNEL_ESTABLISHED_TWICE);
1297 GNUNET_CADET_channel_destroy (channel);
1298 /* return the channel context */
1299 return peer_ctx->recv_channel_flags;
1301 peer_ctx->recv_channel = channel;
1302 return peer_ctx->recv_channel_flags;
1306 * @brief Check whether a sending channel towards the given peer exists
1308 * @param peer the peer to check for
1310 * @return #GNUNET_YES if a sending channel towards that peer exists
1311 * #GNUNET_NO otherwise
1314 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1316 struct PeerContext *peer_ctx;
1318 if (GNUNET_NO == Peers_check_peer_known (peer))
1319 { /* If no such peer exists, there is no channel */
1322 peer_ctx = get_peer_ctx (peer);
1323 if (NULL == peer_ctx->send_channel)
1331 * @brief check whether the given channel is the sending channel of the given
1334 * @param peer the peer in question
1335 * @param channel the channel to check for
1336 * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1337 * #Peers_CHANNEL_ROLE_RECEIVING
1339 * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1340 * #GNUNET_NO otherwise
1343 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1344 const struct GNUNET_CADET_Channel *channel,
1345 enum Peers_ChannelRole role)
1347 const struct PeerContext *peer_ctx;
1349 if (GNUNET_NO == Peers_check_peer_known (peer))
1353 peer_ctx = get_peer_ctx (peer);
1354 if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1355 (channel == peer_ctx->send_channel) )
1359 if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1360 (channel == peer_ctx->recv_channel) )
1368 * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1369 * intention to another peer
1371 * If there is also no channel to receive messages from that peer, remove it
1375 * @peer the peer identity of the peer whose sending channel to destroy
1376 * @return #GNUNET_YES if channel was destroyed
1377 * #GNUNET_NO otherwise
1380 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1382 struct PeerContext *peer_ctx;
1384 if (GNUNET_NO == Peers_check_peer_known (peer))
1388 peer_ctx = get_peer_ctx (peer);
1389 if (NULL != peer_ctx->send_channel)
1391 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1392 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1393 peer_ctx->send_channel = NULL;
1394 (void) Peers_check_connected (peer);
1401 * This is called when a channel is destroyed.
1403 * @param cls The closure
1404 * @param channel The channel being closed
1405 * @param channel_ctx The context associated with this channel
1408 Peers_cleanup_destroyed_channel (void *cls,
1409 const struct GNUNET_CADET_Channel *channel,
1412 struct GNUNET_PeerIdentity *peer;
1413 struct PeerContext *peer_ctx;
1415 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1416 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1417 // FIXME wait for cadet to change this function
1419 if (GNUNET_NO == Peers_check_peer_known (peer))
1420 {/* We don't want to implicitly create a context that we're about to kill */
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "channel (%s) without associated context was destroyed\n",
1426 peer_ctx = get_peer_ctx (peer);
1428 /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1429 * flag will be set. In this case simply make sure that the channels are
1431 /* FIXME This distinction seems to be redundant */
1432 if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1433 {/* We initiatad the destruction of this particular peer */
1434 if (channel == peer_ctx->send_channel)
1435 peer_ctx->send_channel = NULL;
1436 else if (channel == peer_ctx->recv_channel)
1437 peer_ctx->recv_channel = NULL;
1439 if (NULL != peer_ctx->send_channel)
1441 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1442 peer_ctx->send_channel = NULL;
1444 if (NULL != peer_ctx->recv_channel)
1446 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1447 peer_ctx->recv_channel = NULL;
1449 /* Set the #Peers_ONLINE flag accordingly */
1450 (void) Peers_check_connected (peer);
1455 { /* We did not initiate the destruction of this peer */
1456 if (channel == peer_ctx->send_channel)
1457 { /* Something (but us) killd the channel - clean up peer */
1458 LOG (GNUNET_ERROR_TYPE_DEBUG,
1459 "send channel (%s) was destroyed - cleaning up\n",
1461 peer_ctx->send_channel = NULL;
1463 else if (channel == peer_ctx->recv_channel)
1464 { /* Other peer doesn't want to send us messages anymore */
1465 LOG (GNUNET_ERROR_TYPE_DEBUG,
1466 "Peer %s destroyed recv channel - cleaning up channel\n",
1468 peer_ctx->recv_channel = NULL;
1472 LOG (GNUNET_ERROR_TYPE_WARNING,
1473 "unknown channel (%s) was destroyed\n",
1477 (void) Peers_check_connected (peer);
1481 * @brief Issue a check whether peer is live
1483 * This tries to establish a channel to the given peer. Once the channel is
1484 * established successfully, we know the peer is live.
1486 * @param peer the peer to check liveliness
1489 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1491 struct PeerContext *peer_ctx;
1493 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1495 return; /* We know that we are online */
1498 peer_ctx = create_or_get_peer_ctx (peer);
1499 // TODO if LIVE/ONLINE
1500 check_peer_live (peer_ctx);
1504 * @brief Send a message to another peer.
1506 * Keeps track about pending messages so they can be properly removed when the
1507 * peer is destroyed.
1509 * @param peer receeiver of the message
1510 * @param ev envelope of the message
1511 * @param type type of the message
1514 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1515 struct GNUNET_MQ_Envelope *ev,
1518 struct PendingMessage *pending_msg;
1519 struct GNUNET_MQ_Handle *mq;
1521 pending_msg = insert_pending_message (peer, ev, "PULL REPLY");
1523 GNUNET_MQ_notify_sent (ev,
1526 GNUNET_MQ_send (mq, ev);
1530 * @brief Schedule a operation on given peer
1532 * Avoids scheduling an operation twice.
1534 * @param peer the peer we want to schedule the operation for once it gets live
1536 * @return #GNUNET_YES if the operation was scheduled
1537 * #GNUNET_NO otherwise
1540 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1541 const PeerOp peer_op)
1543 struct PeerPendingOp pending_op;
1544 struct PeerContext *peer_ctx;
1546 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1550 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1552 //TODO if LIVE/ONLINE execute immediately
1554 if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1556 peer_ctx = get_peer_ctx (peer);
1557 pending_op.op = peer_op;
1558 pending_op.op_cls = NULL;
1559 GNUNET_array_append (peer_ctx->pending_ops,
1560 peer_ctx->num_pending_ops,
1567 /* end of gnunet-service-rps_peers.c */