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 Closure to #valid_peer_iterator
209 struct PeersIteratorCls
214 PeersIterator iterator;
217 * Closure to iterator
223 * @brief Hashmap of valid peers.
225 static struct GNUNET_CONTAINER_MultiPeerMap *valid_peers;
228 * @brief Maximum number of valid peers to keep.
229 * TODO read from config
231 static uint32_t num_valid_peers_max = UINT32_MAX;
234 * @brief Filename of the file that stores the valid peers persistently.
236 static char *filename_valid_peers;
239 * Set of all peers to keep track of them.
241 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
244 * Own #GNUNET_PeerIdentity.
246 static const struct GNUNET_PeerIdentity *own_identity;
251 static struct GNUNET_CADET_Handle *cadet_handle;
255 * @brief Get the #PeerContext associated with a peer
257 * @param peer the peer id
259 * @return the #PeerContext
261 static struct PeerContext *
262 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
264 struct PeerContext *ctx;
267 ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
268 GNUNET_assert (GNUNET_YES == ret);
269 ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
270 GNUNET_assert (NULL != ctx);
275 * @brief Create a new #PeerContext and insert it into the peer map
277 * @param peer the peer to create the #PeerContext for
279 * @return the #PeerContext
281 static struct PeerContext *
282 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
284 struct PeerContext *ctx;
287 GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
289 ctx = GNUNET_new (struct PeerContext);
290 ctx->peer_id = *peer;
291 ctx->send_channel_flags = GNUNET_new (uint32_t);
292 ctx->recv_channel_flags = GNUNET_new (uint32_t);
293 ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
294 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
295 GNUNET_assert (GNUNET_OK == ret);
300 * @brief Create or get a #PeerContext
302 * @param peer the peer to get the associated context to
304 * @return the context
306 static struct PeerContext *
307 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
309 if (GNUNET_NO == Peers_check_peer_known (peer))
311 return create_peer_ctx (peer);
313 return get_peer_ctx (peer);
317 * @brief Check whether we have a connection to this @a peer
319 * Also sets the #Peers_ONLINE flag accordingly
321 * @param peer the peer in question
323 * @return #GNUNET_YES if we are connected
324 * #GNUNET_NO otherwise
327 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
329 const struct PeerContext *peer_ctx;
331 /* If we don't know about this peer we don't know whether it's online */
332 if (GNUNET_NO == Peers_check_peer_known (peer))
336 /* Get the context */
337 peer_ctx = get_peer_ctx (peer);
338 /* If we have no channel to this peer we don't know whether it's online */
339 if ( (NULL == peer_ctx->send_channel) &&
340 (NULL == peer_ctx->recv_channel) )
342 Peers_unset_peer_flag (peer, Peers_ONLINE);
345 /* Otherwise (if we have a channel, we know that it's online */
346 Peers_set_peer_flag (peer, Peers_ONLINE);
351 * @brief The closure to #get_rand_peer_iterator.
353 struct GetRandPeerIteratorCls
356 * @brief The index of the peer to return.
357 * Will be decreased until 0.
358 * Then current peer is returned.
363 * @brief Pointer to peer to return.
365 const struct GNUNET_PeerIdentity *peer;
369 * @brief Iterator function for #get_random_peer_from_peermap.
371 * Implements #GNUNET_CONTAINER_PeerMapIterator.
372 * Decreases the index until the index is null.
373 * Then returns the current peer.
375 * @param cls the #GetRandPeerIteratorCls containing index and peer
376 * @param peer current peer
377 * @param value unused
379 * @return #GNUNET_YES if we should continue to
384 get_rand_peer_iterator (void *cls,
385 const struct GNUNET_PeerIdentity *peer,
388 struct GetRandPeerIteratorCls *iterator_cls = cls;
389 if (0 >= iterator_cls->index)
391 iterator_cls->peer = peer;
394 iterator_cls->index--;
399 * @brief Get a random peer from @a peer_map
401 * @param peer_map the peer_map to get the peer from
403 * @return a random peer
405 static const struct GNUNET_PeerIdentity *
406 get_random_peer_from_peermap (const struct
407 GNUNET_CONTAINER_MultiPeerMap *peer_map)
409 struct GetRandPeerIteratorCls *iterator_cls;
410 const struct GNUNET_PeerIdentity *ret;
412 iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls);
413 iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
414 GNUNET_CONTAINER_multipeermap_size (peer_map));
415 (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
416 get_rand_peer_iterator,
418 ret = iterator_cls->peer;
419 GNUNET_free (iterator_cls);
424 * @brief Add a given @a peer to valid peers.
426 * If valid peers are already #num_valid_peers_max, delete a peer previously.
428 * @param peer the peer that is added to the valid peers.
430 * @return #GNUNET_YES if no other peer had to be removed
431 * #GNUNET_NO otherwise
434 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
436 const struct GNUNET_PeerIdentity *rand_peer;
440 while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
442 rand_peer = get_random_peer_from_peermap (valid_peers);
443 GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
446 (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
447 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
452 * @brief Set the peer flag to living and
453 * call the pending operations on this peer.
455 * Also adds peer to #valid_peers.
457 * @param peer_ctx the #PeerContext of the peer to set live
460 set_peer_live (struct PeerContext *peer_ctx)
462 struct GNUNET_PeerIdentity *peer;
465 /* Cancle cadet transmit_handle if still scheduled */
466 if (NULL != peer_ctx->transmit_handle)
468 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
469 peer_ctx->transmit_handle = NULL;
472 peer = &peer_ctx->peer_id;
473 (void) add_valid_peer (peer);
474 set_peer_flag (peer_ctx, Peers_ONLINE);
475 LOG (GNUNET_ERROR_TYPE_DEBUG,
476 "Peer %s is live and valid, calling %i pending operations on it\n",
478 peer_ctx->num_pending_ops);
480 /* Call pending operations */
481 for (i = 0; i < peer_ctx->num_pending_ops; i++)
483 peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
485 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
489 * @brief Get the channel of a peer. If not existing, create.
491 * @param peer the peer id
492 * @return the #GNUNET_CADET_Channel used to send data to @a peer
494 struct GNUNET_CADET_Channel *
495 get_channel (const struct GNUNET_PeerIdentity *peer)
497 struct PeerContext *peer_ctx;
499 peer_ctx = get_peer_ctx (peer);
500 if (NULL == peer_ctx->send_channel)
502 LOG (GNUNET_ERROR_TYPE_DEBUG,
503 "Trying to establish channel to peer %s\n",
505 peer_ctx->send_channel =
506 GNUNET_CADET_channel_create (cadet_handle,
507 peer_ctx->send_channel_flags, /* context */
509 GC_u2h (GNUNET_RPS_CADET_PORT),
510 GNUNET_CADET_OPTION_RELIABLE);
512 GNUNET_assert (NULL != peer_ctx->send_channel);
513 return peer_ctx->send_channel;
517 * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
519 * If we already have a message queue open to this client,
520 * simply return it, otherways create one.
522 * @param peer the peer to get the mq to
523 * @return the #GNUNET_MQ_Handle
525 static struct GNUNET_MQ_Handle *
526 get_mq (const struct GNUNET_PeerIdentity *peer)
528 struct PeerContext *peer_ctx;
530 peer_ctx = get_peer_ctx (peer);
531 GNUNET_assert (NULL == peer_ctx->transmit_handle);
533 if (NULL == peer_ctx->mq)
535 (void) get_channel (peer);
536 peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
542 * @brief Callback that is called when a channel was effectively established.
544 * This is an implementation of #GNUNET_CONNECTION_TransmitReadyNotify and
545 * given to #GNUNET_CADET_notify_transmit_ready_cancel and called when the
546 * channel was successfully established.
548 * This function type was originally ment to be called to provide the data to
549 * be sent. This is called when the connection is ready to queue more data.
550 * However we use it to get notified about the successful establishement of a
553 * @a buf will be NULL and @a size zero if the
554 * connection was closed for writing in the meantime.
557 * @param size number of bytes available in @a buf
558 * @param buf where the callee should write the message
559 * @return number of bytes written to @a buf
563 cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
565 struct PeerContext *peer_ctx = (struct PeerContext *) cls;
566 // TODO make sure the context is not deleted or the establishing of the
567 // channel is cancelled
569 peer_ctx->transmit_handle = NULL;
570 LOG (GNUNET_ERROR_TYPE_DEBUG,
571 "Set ->transmit_handle = NULL for peer %s\n",
572 GNUNET_i2s (&peer_ctx->peer_id));
574 if ( (NULL != buf) &&
577 set_peer_live (peer_ctx);
581 LOG (GNUNET_ERROR_TYPE_WARNING,
582 "Problems establishing a connection to peer %s in order to check liveliness\n",
583 GNUNET_i2s (&peer_ctx->peer_id));
584 // TODO reschedule? cleanup?
590 * Issue a check whether peer is live
592 * @param peer_ctx the context of the peer
595 check_peer_live (struct PeerContext *peer_ctx)
597 LOG (GNUNET_ERROR_TYPE_DEBUG,
598 "Get informed about peer %s getting live\n",
599 GNUNET_i2s (&peer_ctx->peer_id));
601 if (NULL != peer_ctx->transmit_handle)
603 LOG (GNUNET_ERROR_TYPE_DEBUG,
604 "Already waiting for notification\n");
607 if (NULL != peer_ctx->send_channel)
609 LOG (GNUNET_ERROR_TYPE_DEBUG,
610 "Already have established channel to peer\n");
613 (void) get_channel (&peer_ctx->peer_id);
614 peer_ctx->transmit_handle =
615 GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
617 GNUNET_TIME_UNIT_FOREVER_REL,
618 sizeof (struct GNUNET_MessageHeader),
619 cadet_notify_transmit_ready_cb,
621 if (NULL == peer_ctx->transmit_handle)
623 LOG (GNUNET_ERROR_TYPE_WARNING,
624 "Cadet was not able to queue the request (insufficient memory)\n");
630 * @brief Add an envelope to a message passed to mq to list of pending messages
632 * @param peer peer the message was sent to
633 * @param ev envelope to the message
634 * @param type type of the message to be sent
635 * @return pointer to pending message
637 static struct PendingMessage *
638 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
639 struct GNUNET_MQ_Envelope *ev,
642 struct PendingMessage *pending_msg;
643 struct PeerContext *peer_ctx;
645 peer_ctx = get_peer_ctx (peer);
646 pending_msg = GNUNET_new (struct PendingMessage);
647 pending_msg->ev = ev;
648 pending_msg->peer_ctx = peer_ctx;
649 pending_msg->type = type;
650 GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
651 peer_ctx->pending_messages_tail,
657 * @brief Remove a pending message from the respective DLL
659 * @param pending_msg the pending message to remove
662 remove_pending_message (struct PendingMessage *pending_msg)
664 struct PeerContext *peer_ctx;
666 peer_ctx = pending_msg->peer_ctx;
667 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
668 peer_ctx->pending_messages_tail,
670 /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does
671 * not set a #GNUNET_MQ_CancelImpl */
672 /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
673 GNUNET_free (pending_msg);
677 * @brief Check whether function of type #PeerOp was already scheduled
679 * The array with pending operations will probably never grow really big, so
680 * iterating over it should be ok.
682 * @param peer the peer to check
683 * @param peer_op the operation (#PeerOp) on the peer
685 * @return #GNUNET_YES if this operation is scheduled on that peer
686 * #GNUNET_NO otherwise
689 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
690 const PeerOp peer_op)
692 const struct PeerContext *peer_ctx;
695 peer_ctx = get_peer_ctx (peer);
696 for (i = 0; i < peer_ctx->num_pending_ops; i++)
697 if (peer_op == peer_ctx->pending_ops[i].op)
703 * Iterator over hash map entries. Deletes all contexts of peers.
706 * @param key current public key
707 * @param value value in the hash map
708 * @return #GNUNET_YES if we should continue to iterate,
712 peermap_clear_iterator (void *cls,
713 const struct GNUNET_PeerIdentity *key,
716 Peers_remove_peer (key);
721 * @brief This is called once a message is sent.
723 * Removes the pending message
725 * @param cls type of the message that was sent
728 mq_notify_sent_cb (void *cls)
730 struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
731 LOG (GNUNET_ERROR_TYPE_DEBUG,
734 remove_pending_message (pending_msg);
738 * @brief Iterator function for #store_valid_peers.
740 * Implements #GNUNET_CONTAINER_PeerMapIterator.
741 * Writes single peer to disk.
743 * @param cls the file handle to write to.
744 * @param peer current peer
745 * @param value unused
747 * @return #GNUNET_YES if we should continue to
752 store_peer_presistently_iterator (void *cls,
753 const struct GNUNET_PeerIdentity *peer,
756 const struct GNUNET_DISK_FileHandle *fh = cls;
757 char peer_string[128];
765 size = GNUNET_snprintf (peer_string,
766 sizeof (peer_string),
768 GNUNET_i2s_full (peer));
769 GNUNET_assert (53 == size);
770 ret = GNUNET_DISK_file_write (fh,
773 GNUNET_assert (size == ret);
778 * @brief Store the peers currently in #valid_peers to disk.
783 struct GNUNET_DISK_FileHandle *fh;
784 uint32_t number_written_peers;
787 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
792 ret = GNUNET_DISK_directory_create_for_file (filename_valid_peers);
793 if (GNUNET_SYSERR == ret)
795 LOG (GNUNET_ERROR_TYPE_WARNING,
796 "Not able to create directory for file `%s'\n",
797 filename_valid_peers);
800 else if (GNUNET_NO == ret)
802 LOG (GNUNET_ERROR_TYPE_WARNING,
803 "Directory for file `%s' exists but is not writable for us\n",
804 filename_valid_peers);
807 fh = GNUNET_DISK_file_open (filename_valid_peers,
808 GNUNET_DISK_OPEN_WRITE |
809 GNUNET_DISK_OPEN_CREATE,
810 GNUNET_DISK_PERM_USER_READ |
811 GNUNET_DISK_PERM_USER_WRITE);
814 LOG (GNUNET_ERROR_TYPE_WARNING,
815 "Not able to write valid peers to file `%s'\n",
816 filename_valid_peers);
819 LOG (GNUNET_ERROR_TYPE_DEBUG,
820 "Writing %u valid peers to disk\n",
821 GNUNET_CONTAINER_multipeermap_size (valid_peers));
822 number_written_peers =
823 GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
824 store_peer_presistently_iterator,
826 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
827 GNUNET_assert (number_written_peers ==
828 GNUNET_CONTAINER_multipeermap_size (valid_peers));
832 * @brief Convert string representation of peer id to peer id.
834 * Counterpart to #GNUNET_i2s_full.
836 * @param string_repr The string representation of the peer id
838 * @return The peer id
840 static const struct GNUNET_PeerIdentity *
841 s2i_full (const char *string_repr)
843 struct GNUNET_PeerIdentity *peer;
847 peer = GNUNET_new (struct GNUNET_PeerIdentity);
848 len = strlen (string_repr);
851 LOG (GNUNET_ERROR_TYPE_WARNING,
852 "Not able to convert string representation of PeerID to PeerID\n"
853 "Sting representation: %s (len %u) - too short\n",
862 ret = GNUNET_CRYPTO_eddsa_public_key_from_string (string_repr,
865 if (GNUNET_OK != ret)
867 LOG (GNUNET_ERROR_TYPE_WARNING,
868 "Not able to convert string representation of PeerID to PeerID\n"
869 "Sting representation: %s\n",
877 * @brief Restore the peers on disk to #valid_peers.
880 restore_valid_peers ()
884 struct GNUNET_DISK_FileHandle *fh;
888 const char *str_repr;
889 const struct GNUNET_PeerIdentity *peer;
891 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
896 if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers))
900 fh = GNUNET_DISK_file_open (filename_valid_peers,
901 GNUNET_DISK_OPEN_READ,
902 GNUNET_DISK_PERM_NONE);
903 GNUNET_assert (NULL != fh);
904 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size));
905 num_peers = file_size / 53;
906 buf = GNUNET_malloc (file_size);
907 size_read = GNUNET_DISK_file_read (fh, buf, file_size);
908 GNUNET_assert (size_read == file_size);
909 for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53)
911 str_repr = GNUNET_strndup (iter_buf, 53);
912 peer = s2i_full (str_repr);
913 add_valid_peer (peer);
914 LOG (GNUNET_ERROR_TYPE_DEBUG,
915 "Restored valid peer %s from disk\n",
916 GNUNET_i2s_full (peer));
918 LOG (GNUNET_ERROR_TYPE_DEBUG,
919 "num_peers: %" PRIu32 ", _size (valid_peers): %u\n",
921 GNUNET_CONTAINER_multipeermap_size (valid_peers));
922 GNUNET_assert (num_peers == GNUNET_CONTAINER_multipeermap_size (valid_peers));
923 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
924 LOG (GNUNET_ERROR_TYPE_DEBUG,
925 "Restored %u valid peers from disk\n",
930 * @brief Initialise storage of peers
932 * @param fn_valid_peers filename of the file used to store valid peer ids
933 * @param cadet_h cadet handle
934 * @param own_id own peer identity
937 Peers_initialise (char* fn_valid_peers,
938 struct GNUNET_CADET_Handle *cadet_h,
939 const struct GNUNET_PeerIdentity *own_id)
941 filename_valid_peers = GNUNET_strdup (fn_valid_peers);
942 cadet_handle = cadet_h;
943 own_identity = own_id;
944 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
945 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
946 restore_valid_peers ();
950 * @brief Delete storage of peers that was created with #Peers_initialise ()
956 GNUNET_CONTAINER_multipeermap_iterate (peer_map,
957 peermap_clear_iterator,
960 LOG (GNUNET_ERROR_TYPE_WARNING,
961 "Iteration destroying peers was aborted.\n");
963 GNUNET_CONTAINER_multipeermap_destroy (peer_map);
964 store_valid_peers ();
965 GNUNET_free (filename_valid_peers);
966 GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
971 * Iterator over #valid_peers hash map entries.
973 * @param cls closure - unused
974 * @param peer current peer id
975 * @param value value in the hash map - unused
976 * @return #GNUNET_YES if we should continue to
981 valid_peer_iterator (void *cls,
982 const struct GNUNET_PeerIdentity *peer,
985 struct PeersIteratorCls *it_cls = cls;
987 return it_cls->iterator (it_cls->cls,
993 * @brief Get all currently known, valid peer ids.
995 * @param it function to call on each peer id
996 * @param it_cls extra argument to @a it
997 * @return the number of key value pairs processed,
998 * #GNUNET_SYSERR if it aborted iteration
1001 Peers_get_valid_peers (PeersIterator iterator,
1004 struct PeersIteratorCls *cls;
1007 cls = GNUNET_new (struct PeersIteratorCls);
1008 cls->iterator = iterator;
1010 ret = GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
1011 valid_peer_iterator,
1018 * @brief Add peer to known peers.
1020 * This function is called on new peer_ids from 'external' sources
1021 * (client seed, cadet get_peers(), ...)
1023 * @param peer the new #GNUNET_PeerIdentity
1025 * @return #GNUNET_YES if peer was inserted
1026 * #GNUNET_NO otherwise (if peer was already known or
1027 * peer was #own_identity)
1030 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
1032 if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
1033 (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
1035 return GNUNET_NO; /* We already know this peer - nothing to do */
1037 (void) create_peer_ctx (peer);
1043 * @brief Try connecting to a peer to see whether it is online
1045 * If not known yet, insert into known peers
1047 * @param peer the peer whose liveliness is to be checked
1048 * @return #GNUNET_YES if peer had to be inserted
1049 * #GNUNET_NO otherwise (if peer was already known or
1050 * peer was #own_identity)
1053 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1055 struct PeerContext *peer_ctx;
1058 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1062 ret = Peers_insert_peer (peer);
1063 peer_ctx = get_peer_ctx (peer);
1064 if (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE))
1066 check_peer_live (peer_ctx);
1072 * @brief Remove unecessary data
1074 * If the other peer is not intending to send messages, we have messages pending
1075 * to be sent to this peer and we are not waiting for a reply, remove the
1076 * information about it (its #PeerContext).
1078 * @param peer the peer to clean
1079 * @return #GNUNET_YES if peer was removed
1080 * #GNUNET_NO otherwise
1083 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
1085 struct PeerContext *peer_ctx;
1087 // TODO actually remove unnecessary data
1089 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1094 peer_ctx = get_peer_ctx (peer);
1095 if ( (NULL != peer_ctx->recv_channel) ||
1096 (NULL != peer_ctx->pending_messages_head) ||
1097 (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
1101 Peers_remove_peer (peer);
1106 * @brief Remove peer
1108 * @param peer the peer to clean
1109 * @return #GNUNET_YES if peer was removed
1110 * #GNUNET_NO otherwise
1113 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1115 struct PeerContext *peer_ctx;
1117 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1122 peer_ctx = get_peer_ctx (peer);
1123 set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1124 LOG (GNUNET_ERROR_TYPE_DEBUG,
1125 "Going to remove peer %s\n",
1126 GNUNET_i2s (&peer_ctx->peer_id));
1127 Peers_unset_peer_flag (peer, Peers_ONLINE);
1129 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1130 // TODO delete struct GNUNET_TRANSPORT_TransmitHandle *transmit_handle
1131 /* Cancle messages that have not been sent yet */
1132 while (NULL != peer_ctx->pending_messages_head)
1134 LOG (GNUNET_ERROR_TYPE_DEBUG,
1135 "Removing unsent %s\n",
1136 peer_ctx->pending_messages_head->type);
1137 remove_pending_message (peer_ctx->pending_messages_head);
1139 /* If we are still waiting for notification whether this peer is live
1140 * cancel the according task */
1141 if (NULL != peer_ctx->transmit_handle)
1143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1144 "Trying to cancle transmit_handle for peer %s\n",
1145 GNUNET_i2s (&peer_ctx->peer_id));
1146 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
1147 peer_ctx->transmit_handle = NULL;
1149 if (NULL != peer_ctx->send_channel)
1151 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1152 peer_ctx->send_channel = NULL;
1154 if (NULL != peer_ctx->recv_channel)
1156 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1157 peer_ctx->recv_channel = NULL;
1159 if (NULL != peer_ctx->mq)
1161 GNUNET_MQ_destroy (peer_ctx->mq);
1162 peer_ctx->mq = NULL;
1165 GNUNET_free (peer_ctx->send_channel_flags);
1166 GNUNET_free (peer_ctx->recv_channel_flags);
1168 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1170 LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1172 GNUNET_free (peer_ctx);
1177 * @brief set flags on a given peer.
1179 * @param peer the peer to set flags on
1180 * @param flags the flags
1183 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1185 struct PeerContext *peer_ctx;
1187 peer_ctx = get_peer_ctx (peer);
1188 set_peer_flag (peer_ctx, flags);
1192 * @brief unset flags on a given peer.
1194 * @param peer the peer to unset flags on
1195 * @param flags the flags
1198 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1200 struct PeerContext *peer_ctx;
1202 peer_ctx = get_peer_ctx (peer);
1203 unset_peer_flag (peer_ctx, flags);
1207 * @brief Check whether flags on a peer are set.
1209 * @param peer the peer to check the flag of
1210 * @param flags the flags to check
1212 * @return #GNUNET_SYSERR if peer is not known
1213 * #GNUNET_YES if all given flags are set
1214 * #GNUNET_NO otherwise
1217 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1219 struct PeerContext *peer_ctx;
1221 if (GNUNET_NO == Peers_check_peer_known (peer))
1223 return GNUNET_SYSERR;
1225 peer_ctx = get_peer_ctx (peer);
1226 return check_peer_flag_set (peer_ctx, flags);
1231 * @brief set flags on a given channel.
1233 * @param channel the channel to set flags on
1234 * @param flags the flags
1237 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1239 set_channel_flag (channel_flags, flags);
1243 * @brief unset flags on a given channel.
1245 * @param channel the channel to unset flags on
1246 * @param flags the flags
1249 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1251 unset_channel_flag (channel_flags, flags);
1255 * @brief Check whether flags on a channel are set.
1257 * @param channel the channel to check the flag of
1258 * @param flags the flags to check
1260 * @return #GNUNET_YES if all given flags are set
1261 * #GNUNET_NO otherwise
1264 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1266 return check_channel_flag_set (channel_flags, flags);
1270 * @brief Check whether we have information about the given peer.
1272 * FIXME probably deprecated. Make this the new _online.
1274 * @param peer peer in question
1276 * @return #GNUNET_YES if peer is known
1277 * #GNUNET_NO if peer is not knwon
1280 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1282 return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1286 * @brief Check whether @a peer is actually a peer.
1288 * A valid peer is a peer that we know exists eg. we were connected to once.
1290 * @param peer peer in question
1292 * @return #GNUNET_YES if peer is valid
1293 * #GNUNET_NO if peer is not valid
1296 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1298 return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1302 * @brief Indicate that we want to send to the other peer
1304 * This establishes a sending channel
1306 * @param peer the peer to establish channel to
1309 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1311 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1312 (void) get_channel (peer);
1316 * @brief Check whether other peer has the intention to send/opened channel
1319 * @param peer the peer in question
1321 * @return #GNUNET_YES if peer has the intention to send
1322 * #GNUNET_NO otherwise
1325 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1327 const struct PeerContext *peer_ctx;
1329 peer_ctx = get_peer_ctx (peer);
1330 if (NULL != peer_ctx->recv_channel)
1338 * Handle the channel a peer opens to us.
1340 * @param cls The closure
1341 * @param channel The channel the peer wants to establish
1342 * @param initiator The peer's peer ID
1343 * @param port The port the channel is being established over
1344 * @param options Further options
1346 * @return initial channel context for the channel
1347 * (can be NULL -- that's not an error)
1350 Peers_handle_inbound_channel (void *cls,
1351 struct GNUNET_CADET_Channel *channel,
1352 const struct GNUNET_PeerIdentity *initiator,
1353 const struct GNUNET_HashCode *port,
1354 enum GNUNET_CADET_ChannelOption options)
1356 struct PeerContext *peer_ctx;
1358 LOG (GNUNET_ERROR_TYPE_DEBUG,
1359 "New channel was established to us (Peer %s).\n",
1360 GNUNET_i2s (initiator));
1361 GNUNET_assert (NULL != channel); /* according to cadet API */
1362 /* Make sure we 'know' about this peer */
1363 peer_ctx = create_or_get_peer_ctx (initiator);
1364 set_peer_live (peer_ctx);
1365 /* We only accept one incoming channel per peer */
1366 if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1368 set_channel_flag (peer_ctx->recv_channel_flags,
1369 Peers_CHANNEL_ESTABLISHED_TWICE);
1370 GNUNET_CADET_channel_destroy (channel);
1371 /* return the channel context */
1372 return peer_ctx->recv_channel_flags;
1374 peer_ctx->recv_channel = channel;
1375 return peer_ctx->recv_channel_flags;
1379 * @brief Check whether a sending channel towards the given peer exists
1381 * @param peer the peer to check for
1383 * @return #GNUNET_YES if a sending channel towards that peer exists
1384 * #GNUNET_NO otherwise
1387 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1389 struct PeerContext *peer_ctx;
1391 if (GNUNET_NO == Peers_check_peer_known (peer))
1392 { /* If no such peer exists, there is no channel */
1395 peer_ctx = get_peer_ctx (peer);
1396 if (NULL == peer_ctx->send_channel)
1404 * @brief check whether the given channel is the sending channel of the given
1407 * @param peer the peer in question
1408 * @param channel the channel to check for
1409 * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1410 * #Peers_CHANNEL_ROLE_RECEIVING
1412 * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1413 * #GNUNET_NO otherwise
1416 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1417 const struct GNUNET_CADET_Channel *channel,
1418 enum Peers_ChannelRole role)
1420 const struct PeerContext *peer_ctx;
1422 if (GNUNET_NO == Peers_check_peer_known (peer))
1426 peer_ctx = get_peer_ctx (peer);
1427 if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1428 (channel == peer_ctx->send_channel) )
1432 if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1433 (channel == peer_ctx->recv_channel) )
1441 * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1442 * intention to another peer
1444 * If there is also no channel to receive messages from that peer, remove it
1448 * @peer the peer identity of the peer whose sending channel to destroy
1449 * @return #GNUNET_YES if channel was destroyed
1450 * #GNUNET_NO otherwise
1453 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1455 struct PeerContext *peer_ctx;
1457 if (GNUNET_NO == Peers_check_peer_known (peer))
1461 peer_ctx = get_peer_ctx (peer);
1462 if (NULL != peer_ctx->send_channel)
1464 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1465 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1466 peer_ctx->send_channel = NULL;
1467 (void) Peers_check_connected (peer);
1474 * This is called when a channel is destroyed.
1476 * @param cls The closure
1477 * @param channel The channel being closed
1478 * @param channel_ctx The context associated with this channel
1481 Peers_cleanup_destroyed_channel (void *cls,
1482 const struct GNUNET_CADET_Channel *channel,
1485 struct GNUNET_PeerIdentity *peer;
1486 struct PeerContext *peer_ctx;
1488 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1489 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1490 // FIXME wait for cadet to change this function
1492 if (GNUNET_NO == Peers_check_peer_known (peer))
1493 {/* We don't want to implicitly create a context that we're about to kill */
1494 LOG (GNUNET_ERROR_TYPE_DEBUG,
1495 "channel (%s) without associated context was destroyed\n",
1499 peer_ctx = get_peer_ctx (peer);
1501 /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1502 * flag will be set. In this case simply make sure that the channels are
1504 /* FIXME This distinction seems to be redundant */
1505 if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1506 {/* We initiatad the destruction of this particular peer */
1507 if (channel == peer_ctx->send_channel)
1508 peer_ctx->send_channel = NULL;
1509 else if (channel == peer_ctx->recv_channel)
1510 peer_ctx->recv_channel = NULL;
1512 if (NULL != peer_ctx->send_channel)
1514 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1515 peer_ctx->send_channel = NULL;
1517 if (NULL != peer_ctx->recv_channel)
1519 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1520 peer_ctx->recv_channel = NULL;
1522 /* Set the #Peers_ONLINE flag accordingly */
1523 (void) Peers_check_connected (peer);
1528 { /* We did not initiate the destruction of this peer */
1529 if (channel == peer_ctx->send_channel)
1530 { /* Something (but us) killd the channel - clean up peer */
1531 LOG (GNUNET_ERROR_TYPE_DEBUG,
1532 "send channel (%s) was destroyed - cleaning up\n",
1534 peer_ctx->send_channel = NULL;
1536 else if (channel == peer_ctx->recv_channel)
1537 { /* Other peer doesn't want to send us messages anymore */
1538 LOG (GNUNET_ERROR_TYPE_DEBUG,
1539 "Peer %s destroyed recv channel - cleaning up channel\n",
1541 peer_ctx->recv_channel = NULL;
1545 LOG (GNUNET_ERROR_TYPE_WARNING,
1546 "unknown channel (%s) was destroyed\n",
1550 (void) Peers_check_connected (peer);
1554 * @brief Send a message to another peer.
1556 * Keeps track about pending messages so they can be properly removed when the
1557 * peer is destroyed.
1559 * @param peer receeiver of the message
1560 * @param ev envelope of the message
1561 * @param type type of the message
1564 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1565 struct GNUNET_MQ_Envelope *ev,
1568 struct PendingMessage *pending_msg;
1569 struct GNUNET_MQ_Handle *mq;
1571 pending_msg = insert_pending_message (peer, ev, type);
1573 GNUNET_MQ_notify_sent (ev,
1576 GNUNET_MQ_send (mq, ev);
1580 * @brief Schedule a operation on given peer
1582 * Avoids scheduling an operation twice.
1584 * @param peer the peer we want to schedule the operation for once it gets live
1586 * @return #GNUNET_YES if the operation was scheduled
1587 * #GNUNET_NO otherwise
1590 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1591 const PeerOp peer_op)
1593 struct PeerPendingOp pending_op;
1594 struct PeerContext *peer_ctx;
1596 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1600 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1602 //TODO if LIVE/ONLINE execute immediately
1604 if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1606 peer_ctx = get_peer_ctx (peer);
1607 pending_op.op = peer_op;
1608 pending_op.op_cls = NULL;
1609 GNUNET_array_append (peer_ctx->pending_ops,
1610 peer_ctx->num_pending_ops,
1617 /* end of gnunet-service-rps_peers.c */