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 GNUNET_CADET_TransmitHandle *transmit_handle;
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;
256 * @brief Get the #PeerContext associated with a peer
258 * @param peer the peer id
260 * @return the #PeerContext
262 static struct PeerContext *
263 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
265 struct PeerContext *ctx;
268 ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
269 GNUNET_assert (GNUNET_YES == ret);
270 ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
271 GNUNET_assert (NULL != ctx);
277 * @brief Create a new #PeerContext and insert it into the peer map
279 * @param peer the peer to create the #PeerContext for
281 * @return the #PeerContext
283 static struct PeerContext *
284 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
286 struct PeerContext *ctx;
289 GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
291 ctx = GNUNET_new (struct PeerContext);
292 ctx->peer_id = *peer;
293 ctx->send_channel_flags = GNUNET_new (uint32_t);
294 ctx->recv_channel_flags = GNUNET_new (uint32_t);
295 ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
296 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
297 GNUNET_assert (GNUNET_OK == ret);
303 * @brief Create or get a #PeerContext
305 * @param peer the peer to get the associated context to
307 * @return the context
309 static struct PeerContext *
310 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
312 if (GNUNET_NO == Peers_check_peer_known (peer))
314 return create_peer_ctx (peer);
316 return get_peer_ctx (peer);
321 * @brief Check whether we have a connection to this @a peer
323 * Also sets the #Peers_ONLINE flag accordingly
325 * @param peer the peer in question
327 * @return #GNUNET_YES if we are connected
328 * #GNUNET_NO otherwise
331 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
333 const struct PeerContext *peer_ctx;
335 /* If we don't know about this peer we don't know whether it's online */
336 if (GNUNET_NO == Peers_check_peer_known (peer))
340 /* Get the context */
341 peer_ctx = get_peer_ctx (peer);
342 /* If we have no channel to this peer we don't know whether it's online */
343 if ( (NULL == peer_ctx->send_channel) &&
344 (NULL == peer_ctx->recv_channel) )
346 Peers_unset_peer_flag (peer, Peers_ONLINE);
349 /* Otherwise (if we have a channel, we know that it's online */
350 Peers_set_peer_flag (peer, Peers_ONLINE);
356 * @brief The closure to #get_rand_peer_iterator.
358 struct GetRandPeerIteratorCls
361 * @brief The index of the peer to return.
362 * Will be decreased until 0.
363 * Then current peer is returned.
368 * @brief Pointer to peer to return.
370 const struct GNUNET_PeerIdentity *peer;
375 * @brief Iterator function for #get_random_peer_from_peermap.
377 * Implements #GNUNET_CONTAINER_PeerMapIterator.
378 * Decreases the index until the index is null.
379 * Then returns the current peer.
381 * @param cls the #GetRandPeerIteratorCls containing index and peer
382 * @param peer current peer
383 * @param value unused
385 * @return #GNUNET_YES if we should continue to
390 get_rand_peer_iterator (void *cls,
391 const struct GNUNET_PeerIdentity *peer,
394 struct GetRandPeerIteratorCls *iterator_cls = cls;
395 if (0 >= iterator_cls->index)
397 iterator_cls->peer = peer;
400 iterator_cls->index--;
406 * @brief Get a random peer from @a peer_map
408 * @param peer_map the peer_map to get the peer from
410 * @return a random peer
412 static const struct GNUNET_PeerIdentity *
413 get_random_peer_from_peermap (const struct
414 GNUNET_CONTAINER_MultiPeerMap *peer_map)
416 struct GetRandPeerIteratorCls *iterator_cls;
417 const struct GNUNET_PeerIdentity *ret;
419 iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls);
420 iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
421 GNUNET_CONTAINER_multipeermap_size (peer_map));
422 (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
423 get_rand_peer_iterator,
425 ret = iterator_cls->peer;
426 GNUNET_free (iterator_cls);
432 * @brief Add a given @a peer to valid peers.
434 * If valid peers are already #num_valid_peers_max, delete a peer previously.
436 * @param peer the peer that is added to the valid peers.
438 * @return #GNUNET_YES if no other peer had to be removed
439 * #GNUNET_NO otherwise
442 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
444 const struct GNUNET_PeerIdentity *rand_peer;
448 while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
450 rand_peer = get_random_peer_from_peermap (valid_peers);
451 GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
454 (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
455 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
461 * @brief Set the peer flag to living and
462 * call the pending operations on this peer.
464 * Also adds peer to #valid_peers.
466 * @param peer_ctx the #PeerContext of the peer to set live
469 set_peer_live (struct PeerContext *peer_ctx)
471 struct GNUNET_PeerIdentity *peer;
474 /* Cancle cadet transmit_handle if still scheduled */
475 if (NULL != peer_ctx->transmit_handle)
477 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
478 peer_ctx->transmit_handle = NULL;
481 peer = &peer_ctx->peer_id;
482 (void) add_valid_peer (peer);
483 set_peer_flag (peer_ctx, Peers_ONLINE);
484 LOG (GNUNET_ERROR_TYPE_DEBUG,
485 "Peer %s is live and valid, calling %i pending operations on it\n",
487 peer_ctx->num_pending_ops);
489 /* Call pending operations */
490 for (i = 0; i < peer_ctx->num_pending_ops; i++)
492 peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
494 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
499 * @brief Get the channel of a peer. If not existing, create.
501 * @param peer the peer id
502 * @return the #GNUNET_CADET_Channel used to send data to @a peer
504 struct GNUNET_CADET_Channel *
505 get_channel (const struct GNUNET_PeerIdentity *peer)
507 struct PeerContext *peer_ctx;
508 struct GNUNET_HashCode port;
510 peer_ctx = get_peer_ctx (peer);
511 if (NULL == peer_ctx->send_channel)
513 LOG (GNUNET_ERROR_TYPE_DEBUG,
514 "Trying to establish channel to peer %s\n",
516 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
517 strlen (GNUNET_APPLICATION_PORT_RPS),
519 peer_ctx->send_channel =
520 GNUNET_CADET_channel_create (cadet_handle,
521 peer_ctx->send_channel_flags, /* context */
524 GNUNET_CADET_OPTION_RELIABLE);
526 GNUNET_assert (NULL != peer_ctx->send_channel);
527 return peer_ctx->send_channel;
532 * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
534 * If we already have a message queue open to this client,
535 * simply return it, otherways create one.
537 * @param peer the peer to get the mq to
538 * @return the #GNUNET_MQ_Handle
540 static struct GNUNET_MQ_Handle *
541 get_mq (const struct GNUNET_PeerIdentity *peer)
543 struct PeerContext *peer_ctx;
545 peer_ctx = get_peer_ctx (peer);
546 GNUNET_assert (NULL == peer_ctx->transmit_handle);
548 if (NULL == peer_ctx->mq)
550 (void) get_channel (peer);
551 peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
557 * @brief Callback that is called when a channel was effectively established.
559 * This is an implementation of #GNUNET_CONNECTION_TransmitReadyNotify and
560 * given to #GNUNET_CADET_notify_transmit_ready_cancel and called when the
561 * channel was successfully established.
563 * This function type was originally ment to be called to provide the data to
564 * be sent. This is called when the connection is ready to queue more data.
565 * However we use it to get notified about the successful establishement of a
568 * @a buf will be NULL and @a size zero if the
569 * connection was closed for writing in the meantime.
572 * @param size number of bytes available in @a buf
573 * @param buf where the callee should write the message
574 * @return number of bytes written to @a buf
578 cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
580 struct PeerContext *peer_ctx = (struct PeerContext *) cls;
581 // TODO make sure the context is not deleted or the establishing of the
582 // channel is cancelled
584 peer_ctx->transmit_handle = NULL;
585 LOG (GNUNET_ERROR_TYPE_DEBUG,
586 "Set ->transmit_handle = NULL for peer %s\n",
587 GNUNET_i2s (&peer_ctx->peer_id));
589 if ( (NULL != buf) &&
592 set_peer_live (peer_ctx);
596 LOG (GNUNET_ERROR_TYPE_WARNING,
597 "Problems establishing a connection to peer %s in order to check liveliness\n",
598 GNUNET_i2s (&peer_ctx->peer_id));
599 // TODO reschedule? cleanup?
605 * Issue a check whether peer is live
607 * @param peer_ctx the context of the peer
610 check_peer_live (struct PeerContext *peer_ctx)
612 LOG (GNUNET_ERROR_TYPE_DEBUG,
613 "Get informed about peer %s getting live\n",
614 GNUNET_i2s (&peer_ctx->peer_id));
616 if (NULL != peer_ctx->transmit_handle)
618 LOG (GNUNET_ERROR_TYPE_DEBUG,
619 "Already waiting for notification\n");
622 if (NULL != peer_ctx->send_channel)
624 LOG (GNUNET_ERROR_TYPE_DEBUG,
625 "Already have established channel to peer\n");
628 (void) get_channel (&peer_ctx->peer_id);
629 peer_ctx->transmit_handle =
630 GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
632 GNUNET_TIME_UNIT_FOREVER_REL,
633 sizeof (struct GNUNET_MessageHeader),
634 cadet_notify_transmit_ready_cb,
636 if (NULL == peer_ctx->transmit_handle)
638 LOG (GNUNET_ERROR_TYPE_WARNING,
639 "Cadet was not able to queue the request (insufficient memory)\n");
645 * @brief Add an envelope to a message passed to mq to list of pending messages
647 * @param peer peer the message was sent to
648 * @param ev envelope to the message
649 * @param type type of the message to be sent
650 * @return pointer to pending message
652 static struct PendingMessage *
653 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
654 struct GNUNET_MQ_Envelope *ev,
657 struct PendingMessage *pending_msg;
658 struct PeerContext *peer_ctx;
660 peer_ctx = get_peer_ctx (peer);
661 pending_msg = GNUNET_new (struct PendingMessage);
662 pending_msg->ev = ev;
663 pending_msg->peer_ctx = peer_ctx;
664 pending_msg->type = type;
665 GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
666 peer_ctx->pending_messages_tail,
673 * @brief Remove a pending message from the respective DLL
675 * @param pending_msg the pending message to remove
678 remove_pending_message (struct PendingMessage *pending_msg)
680 struct PeerContext *peer_ctx;
682 peer_ctx = pending_msg->peer_ctx;
683 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
684 peer_ctx->pending_messages_tail,
686 /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does
687 * not set a #GNUNET_MQ_CancelImpl */
688 /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
689 GNUNET_free (pending_msg);
694 * @brief Check whether function of type #PeerOp was already scheduled
696 * The array with pending operations will probably never grow really big, so
697 * iterating over it should be ok.
699 * @param peer the peer to check
700 * @param peer_op the operation (#PeerOp) on the peer
702 * @return #GNUNET_YES if this operation is scheduled on that peer
703 * #GNUNET_NO otherwise
706 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
707 const PeerOp peer_op)
709 const struct PeerContext *peer_ctx;
712 peer_ctx = get_peer_ctx (peer);
713 for (i = 0; i < peer_ctx->num_pending_ops; i++)
714 if (peer_op == peer_ctx->pending_ops[i].op)
721 * Iterator over hash map entries. Deletes all contexts of peers.
724 * @param key current public key
725 * @param value value in the hash map
726 * @return #GNUNET_YES if we should continue to iterate,
730 peermap_clear_iterator (void *cls,
731 const struct GNUNET_PeerIdentity *key,
734 Peers_remove_peer (key);
740 * @brief This is called once a message is sent.
742 * Removes the pending message
744 * @param cls type of the message that was sent
747 mq_notify_sent_cb (void *cls)
749 struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
750 LOG (GNUNET_ERROR_TYPE_DEBUG,
753 remove_pending_message (pending_msg);
758 * @brief Iterator function for #store_valid_peers.
760 * Implements #GNUNET_CONTAINER_PeerMapIterator.
761 * Writes single peer to disk.
763 * @param cls the file handle to write to.
764 * @param peer current peer
765 * @param value unused
767 * @return #GNUNET_YES if we should continue to
772 store_peer_presistently_iterator (void *cls,
773 const struct GNUNET_PeerIdentity *peer,
776 const struct GNUNET_DISK_FileHandle *fh = cls;
777 char peer_string[128];
785 size = GNUNET_snprintf (peer_string,
786 sizeof (peer_string),
788 GNUNET_i2s_full (peer));
789 GNUNET_assert (53 == size);
790 ret = GNUNET_DISK_file_write (fh,
793 GNUNET_assert (size == ret);
799 * @brief Store the peers currently in #valid_peers to disk.
804 struct GNUNET_DISK_FileHandle *fh;
805 uint32_t number_written_peers;
808 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
813 ret = GNUNET_DISK_directory_create_for_file (filename_valid_peers);
814 if (GNUNET_SYSERR == ret)
816 LOG (GNUNET_ERROR_TYPE_WARNING,
817 "Not able to create directory for file `%s'\n",
818 filename_valid_peers);
821 else if (GNUNET_NO == ret)
823 LOG (GNUNET_ERROR_TYPE_WARNING,
824 "Directory for file `%s' exists but is not writable for us\n",
825 filename_valid_peers);
828 fh = GNUNET_DISK_file_open (filename_valid_peers,
829 GNUNET_DISK_OPEN_WRITE |
830 GNUNET_DISK_OPEN_CREATE,
831 GNUNET_DISK_PERM_USER_READ |
832 GNUNET_DISK_PERM_USER_WRITE);
835 LOG (GNUNET_ERROR_TYPE_WARNING,
836 "Not able to write valid peers to file `%s'\n",
837 filename_valid_peers);
840 LOG (GNUNET_ERROR_TYPE_DEBUG,
841 "Writing %u valid peers to disk\n",
842 GNUNET_CONTAINER_multipeermap_size (valid_peers));
843 number_written_peers =
844 GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
845 store_peer_presistently_iterator,
847 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
848 GNUNET_assert (number_written_peers ==
849 GNUNET_CONTAINER_multipeermap_size (valid_peers));
854 * @brief Convert string representation of peer id to peer id.
856 * Counterpart to #GNUNET_i2s_full.
858 * @param string_repr The string representation of the peer id
860 * @return The peer id
862 static const struct GNUNET_PeerIdentity *
863 s2i_full (const char *string_repr)
865 struct GNUNET_PeerIdentity *peer;
869 peer = GNUNET_new (struct GNUNET_PeerIdentity);
870 len = strlen (string_repr);
873 LOG (GNUNET_ERROR_TYPE_WARNING,
874 "Not able to convert string representation of PeerID to PeerID\n"
875 "Sting representation: %s (len %u) - too short\n",
884 ret = GNUNET_CRYPTO_eddsa_public_key_from_string (string_repr,
887 if (GNUNET_OK != ret)
889 LOG (GNUNET_ERROR_TYPE_WARNING,
890 "Not able to convert string representation of PeerID to PeerID\n"
891 "Sting representation: %s\n",
900 * @brief Restore the peers on disk to #valid_peers.
903 restore_valid_peers ()
907 struct GNUNET_DISK_FileHandle *fh;
911 const char *str_repr;
912 const struct GNUNET_PeerIdentity *peer;
914 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
919 if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers))
923 fh = GNUNET_DISK_file_open (filename_valid_peers,
924 GNUNET_DISK_OPEN_READ,
925 GNUNET_DISK_PERM_NONE);
926 GNUNET_assert (NULL != fh);
927 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size));
928 num_peers = file_size / 53;
929 buf = GNUNET_malloc (file_size);
930 size_read = GNUNET_DISK_file_read (fh, buf, file_size);
931 GNUNET_assert (size_read == file_size);
932 for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53)
934 str_repr = GNUNET_strndup (iter_buf, 53);
935 peer = s2i_full (str_repr);
936 add_valid_peer (peer);
937 LOG (GNUNET_ERROR_TYPE_DEBUG,
938 "Restored valid peer %s from disk\n",
939 GNUNET_i2s_full (peer));
941 LOG (GNUNET_ERROR_TYPE_DEBUG,
942 "num_peers: %" PRIu32 ", _size (valid_peers): %u\n",
944 GNUNET_CONTAINER_multipeermap_size (valid_peers));
945 GNUNET_assert (num_peers == GNUNET_CONTAINER_multipeermap_size (valid_peers));
946 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
947 LOG (GNUNET_ERROR_TYPE_DEBUG,
948 "Restored %u valid peers from disk\n",
954 * @brief Initialise storage of peers
956 * @param fn_valid_peers filename of the file used to store valid peer ids
957 * @param cadet_h cadet handle
958 * @param own_id own peer identity
961 Peers_initialise (char* fn_valid_peers,
962 struct GNUNET_CADET_Handle *cadet_h,
963 const struct GNUNET_PeerIdentity *own_id)
965 filename_valid_peers = GNUNET_strdup (fn_valid_peers);
966 cadet_handle = cadet_h;
967 own_identity = own_id;
968 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
969 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
970 restore_valid_peers ();
975 * @brief Delete storage of peers that was created with #Peers_initialise ()
981 GNUNET_CONTAINER_multipeermap_iterate (peer_map,
982 peermap_clear_iterator,
985 LOG (GNUNET_ERROR_TYPE_WARNING,
986 "Iteration destroying peers was aborted.\n");
988 GNUNET_CONTAINER_multipeermap_destroy (peer_map);
989 store_valid_peers ();
990 GNUNET_free (filename_valid_peers);
991 GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
996 * Iterator over #valid_peers hash map entries.
998 * @param cls closure - unused
999 * @param peer current peer id
1000 * @param value value in the hash map - unused
1001 * @return #GNUNET_YES if we should continue to
1003 * #GNUNET_NO if not.
1006 valid_peer_iterator (void *cls,
1007 const struct GNUNET_PeerIdentity *peer,
1010 struct PeersIteratorCls *it_cls = cls;
1012 return it_cls->iterator (it_cls->cls,
1018 * @brief Get all currently known, valid peer ids.
1020 * @param it function to call on each peer id
1021 * @param it_cls extra argument to @a it
1022 * @return the number of key value pairs processed,
1023 * #GNUNET_SYSERR if it aborted iteration
1026 Peers_get_valid_peers (PeersIterator iterator,
1029 struct PeersIteratorCls *cls;
1032 cls = GNUNET_new (struct PeersIteratorCls);
1033 cls->iterator = iterator;
1035 ret = GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
1036 valid_peer_iterator,
1044 * @brief Add peer to known peers.
1046 * This function is called on new peer_ids from 'external' sources
1047 * (client seed, cadet get_peers(), ...)
1049 * @param peer the new #GNUNET_PeerIdentity
1051 * @return #GNUNET_YES if peer was inserted
1052 * #GNUNET_NO otherwise (if peer was already known or
1053 * peer was #own_identity)
1056 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
1058 if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
1059 (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
1061 return GNUNET_NO; /* We already know this peer - nothing to do */
1063 (void) create_peer_ctx (peer);
1069 * @brief Try connecting to a peer to see whether it is online
1071 * If not known yet, insert into known peers
1073 * @param peer the peer whose liveliness is to be checked
1074 * @return #GNUNET_YES if peer had to be inserted
1075 * #GNUNET_NO otherwise (if peer was already known or
1076 * peer was #own_identity)
1079 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1081 struct PeerContext *peer_ctx;
1084 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1088 ret = Peers_insert_peer (peer);
1089 peer_ctx = get_peer_ctx (peer);
1090 if (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE))
1092 check_peer_live (peer_ctx);
1099 * @brief Remove unecessary data
1101 * If the other peer is not intending to send messages, we have messages pending
1102 * to be sent to this peer and we are not waiting for a reply, remove the
1103 * information about it (its #PeerContext).
1105 * @param peer the peer to clean
1106 * @return #GNUNET_YES if peer was removed
1107 * #GNUNET_NO otherwise
1110 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
1112 struct PeerContext *peer_ctx;
1114 // TODO actually remove unnecessary data
1116 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1121 peer_ctx = get_peer_ctx (peer);
1122 if ( (NULL != peer_ctx->recv_channel) ||
1123 (NULL != peer_ctx->pending_messages_head) ||
1124 (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
1128 Peers_remove_peer (peer);
1134 * @brief Remove peer
1136 * @param peer the peer to clean
1137 * @return #GNUNET_YES if peer was removed
1138 * #GNUNET_NO otherwise
1141 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1143 struct PeerContext *peer_ctx;
1145 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1150 peer_ctx = get_peer_ctx (peer);
1151 set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1152 LOG (GNUNET_ERROR_TYPE_DEBUG,
1153 "Going to remove peer %s\n",
1154 GNUNET_i2s (&peer_ctx->peer_id));
1155 Peers_unset_peer_flag (peer, Peers_ONLINE);
1157 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1158 // TODO delete struct GNUNET_TRANSPORT_TransmitHandle *transmit_handle
1159 /* Cancle messages that have not been sent yet */
1160 while (NULL != peer_ctx->pending_messages_head)
1162 LOG (GNUNET_ERROR_TYPE_DEBUG,
1163 "Removing unsent %s\n",
1164 peer_ctx->pending_messages_head->type);
1165 remove_pending_message (peer_ctx->pending_messages_head);
1167 /* If we are still waiting for notification whether this peer is live
1168 * cancel the according task */
1169 if (NULL != peer_ctx->transmit_handle)
1171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1172 "Trying to cancle transmit_handle for peer %s\n",
1173 GNUNET_i2s (&peer_ctx->peer_id));
1174 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
1175 peer_ctx->transmit_handle = NULL;
1177 if (NULL != peer_ctx->send_channel)
1179 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1180 peer_ctx->send_channel = NULL;
1182 if (NULL != peer_ctx->recv_channel)
1184 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1185 peer_ctx->recv_channel = NULL;
1187 if (NULL != peer_ctx->mq)
1189 GNUNET_MQ_destroy (peer_ctx->mq);
1190 peer_ctx->mq = NULL;
1193 GNUNET_free (peer_ctx->send_channel_flags);
1194 GNUNET_free (peer_ctx->recv_channel_flags);
1196 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1198 LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1200 GNUNET_free (peer_ctx);
1206 * @brief set flags on a given peer.
1208 * @param peer the peer to set flags on
1209 * @param flags the flags
1212 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1214 struct PeerContext *peer_ctx;
1216 peer_ctx = get_peer_ctx (peer);
1217 set_peer_flag (peer_ctx, flags);
1222 * @brief unset flags on a given peer.
1224 * @param peer the peer to unset flags on
1225 * @param flags the flags
1228 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1230 struct PeerContext *peer_ctx;
1232 peer_ctx = get_peer_ctx (peer);
1233 unset_peer_flag (peer_ctx, flags);
1238 * @brief Check whether flags on a peer are set.
1240 * @param peer the peer to check the flag of
1241 * @param flags the flags to check
1243 * @return #GNUNET_SYSERR if peer is not known
1244 * #GNUNET_YES if all given flags are set
1245 * #GNUNET_NO otherwise
1248 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1250 struct PeerContext *peer_ctx;
1252 if (GNUNET_NO == Peers_check_peer_known (peer))
1254 return GNUNET_SYSERR;
1256 peer_ctx = get_peer_ctx (peer);
1257 return check_peer_flag_set (peer_ctx, flags);
1262 * @brief set flags on a given channel.
1264 * @param channel the channel to set flags on
1265 * @param flags the flags
1268 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1270 set_channel_flag (channel_flags, flags);
1275 * @brief unset flags on a given channel.
1277 * @param channel the channel to unset flags on
1278 * @param flags the flags
1281 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1283 unset_channel_flag (channel_flags, flags);
1288 * @brief Check whether flags on a channel are set.
1290 * @param channel the channel to check the flag of
1291 * @param flags the flags to check
1293 * @return #GNUNET_YES if all given flags are set
1294 * #GNUNET_NO otherwise
1297 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1299 return check_channel_flag_set (channel_flags, flags);
1304 * @brief Check whether we have information about the given peer.
1306 * FIXME probably deprecated. Make this the new _online.
1308 * @param peer peer in question
1310 * @return #GNUNET_YES if peer is known
1311 * #GNUNET_NO if peer is not knwon
1314 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1316 return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1321 * @brief Check whether @a peer is actually a peer.
1323 * A valid peer is a peer that we know exists eg. we were connected to once.
1325 * @param peer peer in question
1327 * @return #GNUNET_YES if peer is valid
1328 * #GNUNET_NO if peer is not valid
1331 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1333 return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1338 * @brief Indicate that we want to send to the other peer
1340 * This establishes a sending channel
1342 * @param peer the peer to establish channel to
1345 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1347 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1348 (void) get_channel (peer);
1353 * @brief Check whether other peer has the intention to send/opened channel
1356 * @param peer the peer in question
1358 * @return #GNUNET_YES if peer has the intention to send
1359 * #GNUNET_NO otherwise
1362 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1364 const struct PeerContext *peer_ctx;
1366 peer_ctx = get_peer_ctx (peer);
1367 if (NULL != peer_ctx->recv_channel)
1376 * Handle the channel a peer opens to us.
1378 * @param cls The closure
1379 * @param channel The channel the peer wants to establish
1380 * @param initiator The peer's peer ID
1381 * @param port The port the channel is being established over
1382 * @param options Further options
1384 * @return initial channel context for the channel
1385 * (can be NULL -- that's not an error)
1388 Peers_handle_inbound_channel (void *cls,
1389 struct GNUNET_CADET_Channel *channel,
1390 const struct GNUNET_PeerIdentity *initiator,
1391 const struct GNUNET_HashCode *port,
1392 enum GNUNET_CADET_ChannelOption options)
1394 struct PeerContext *peer_ctx;
1396 LOG (GNUNET_ERROR_TYPE_DEBUG,
1397 "New channel was established to us (Peer %s).\n",
1398 GNUNET_i2s (initiator));
1399 GNUNET_assert (NULL != channel); /* according to cadet API */
1400 /* Make sure we 'know' about this peer */
1401 peer_ctx = create_or_get_peer_ctx (initiator);
1402 set_peer_live (peer_ctx);
1403 /* We only accept one incoming channel per peer */
1404 if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1406 set_channel_flag (peer_ctx->recv_channel_flags,
1407 Peers_CHANNEL_ESTABLISHED_TWICE);
1408 GNUNET_CADET_channel_destroy (channel);
1409 /* return the channel context */
1410 return peer_ctx->recv_channel_flags;
1412 peer_ctx->recv_channel = channel;
1413 return peer_ctx->recv_channel_flags;
1418 * @brief Check whether a sending channel towards the given peer exists
1420 * @param peer the peer to check for
1422 * @return #GNUNET_YES if a sending channel towards that peer exists
1423 * #GNUNET_NO otherwise
1426 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1428 struct PeerContext *peer_ctx;
1430 if (GNUNET_NO == Peers_check_peer_known (peer))
1431 { /* If no such peer exists, there is no channel */
1434 peer_ctx = get_peer_ctx (peer);
1435 if (NULL == peer_ctx->send_channel)
1444 * @brief check whether the given channel is the sending channel of the given
1447 * @param peer the peer in question
1448 * @param channel the channel to check for
1449 * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1450 * #Peers_CHANNEL_ROLE_RECEIVING
1452 * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1453 * #GNUNET_NO otherwise
1456 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1457 const struct GNUNET_CADET_Channel *channel,
1458 enum Peers_ChannelRole role)
1460 const struct PeerContext *peer_ctx;
1462 if (GNUNET_NO == Peers_check_peer_known (peer))
1466 peer_ctx = get_peer_ctx (peer);
1467 if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1468 (channel == peer_ctx->send_channel) )
1472 if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1473 (channel == peer_ctx->recv_channel) )
1482 * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1483 * intention to another peer
1485 * If there is also no channel to receive messages from that peer, remove it
1489 * @peer the peer identity of the peer whose sending channel to destroy
1490 * @return #GNUNET_YES if channel was destroyed
1491 * #GNUNET_NO otherwise
1494 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1496 struct PeerContext *peer_ctx;
1498 if (GNUNET_NO == Peers_check_peer_known (peer))
1502 peer_ctx = get_peer_ctx (peer);
1503 if (NULL != peer_ctx->send_channel)
1505 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1506 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1507 peer_ctx->send_channel = NULL;
1508 (void) Peers_check_connected (peer);
1515 * This is called when a channel is destroyed.
1517 * @param cls The closure
1518 * @param channel The channel being closed
1519 * @param channel_ctx The context associated with this channel
1522 Peers_cleanup_destroyed_channel (void *cls,
1523 const struct GNUNET_CADET_Channel *channel,
1526 struct GNUNET_PeerIdentity *peer;
1527 struct PeerContext *peer_ctx;
1529 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1530 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1531 // FIXME wait for cadet to change this function
1533 if (GNUNET_NO == Peers_check_peer_known (peer))
1534 {/* We don't want to implicitly create a context that we're about to kill */
1535 LOG (GNUNET_ERROR_TYPE_DEBUG,
1536 "channel (%s) without associated context was destroyed\n",
1540 peer_ctx = get_peer_ctx (peer);
1542 /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1543 * flag will be set. In this case simply make sure that the channels are
1545 /* FIXME This distinction seems to be redundant */
1546 if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1547 {/* We initiatad the destruction of this particular peer */
1548 if (channel == peer_ctx->send_channel)
1549 peer_ctx->send_channel = NULL;
1550 else if (channel == peer_ctx->recv_channel)
1551 peer_ctx->recv_channel = NULL;
1553 if (NULL != peer_ctx->send_channel)
1555 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1556 peer_ctx->send_channel = NULL;
1558 if (NULL != peer_ctx->recv_channel)
1560 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1561 peer_ctx->recv_channel = NULL;
1563 /* Set the #Peers_ONLINE flag accordingly */
1564 (void) Peers_check_connected (peer);
1569 { /* We did not initiate the destruction of this peer */
1570 if (channel == peer_ctx->send_channel)
1571 { /* Something (but us) killd the channel - clean up peer */
1572 LOG (GNUNET_ERROR_TYPE_DEBUG,
1573 "send channel (%s) was destroyed - cleaning up\n",
1575 peer_ctx->send_channel = NULL;
1577 else if (channel == peer_ctx->recv_channel)
1578 { /* Other peer doesn't want to send us messages anymore */
1579 LOG (GNUNET_ERROR_TYPE_DEBUG,
1580 "Peer %s destroyed recv channel - cleaning up channel\n",
1582 peer_ctx->recv_channel = NULL;
1586 LOG (GNUNET_ERROR_TYPE_WARNING,
1587 "unknown channel (%s) was destroyed\n",
1591 (void) Peers_check_connected (peer);
1595 * @brief Send a message to another peer.
1597 * Keeps track about pending messages so they can be properly removed when the
1598 * peer is destroyed.
1600 * @param peer receeiver of the message
1601 * @param ev envelope of the message
1602 * @param type type of the message
1605 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1606 struct GNUNET_MQ_Envelope *ev,
1609 struct PendingMessage *pending_msg;
1610 struct GNUNET_MQ_Handle *mq;
1612 pending_msg = insert_pending_message (peer, ev, type);
1614 GNUNET_MQ_notify_sent (ev,
1617 GNUNET_MQ_send (mq, ev);
1621 * @brief Schedule a operation on given peer
1623 * Avoids scheduling an operation twice.
1625 * @param peer the peer we want to schedule the operation for once it gets live
1627 * @return #GNUNET_YES if the operation was scheduled
1628 * #GNUNET_NO otherwise
1631 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1632 const PeerOp peer_op)
1634 struct PeerPendingOp pending_op;
1635 struct PeerContext *peer_ctx;
1637 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1641 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1643 //TODO if LIVE/ONLINE execute immediately
1645 if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1647 peer_ctx = get_peer_ctx (peer);
1648 pending_op.op = peer_op;
1649 pending_op.op_cls = NULL;
1650 GNUNET_array_append (peer_ctx->pending_ops,
1651 peer_ctx->num_pending_ops,
1658 /* end of gnunet-service-rps_peers.c */