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 * Set of all peers to keep track of them.
220 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
223 * Own #GNUNET_PeerIdentity.
225 static const struct GNUNET_PeerIdentity *own_identity;
230 static struct GNUNET_CADET_Handle *cadet_handle;
234 * @brief Get the #PeerContext associated with a peer
236 * @param peer the peer id
238 * @return the #PeerContext
240 static struct PeerContext *
241 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
243 struct PeerContext *ctx;
246 ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
247 GNUNET_assert (GNUNET_YES == ret);
248 ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
249 GNUNET_assert (NULL != ctx);
254 * @brief Create a new #PeerContext and insert it into the peer map
256 * @param peer the peer to create the #PeerContext for
258 * @return the #PeerContext
260 static struct PeerContext *
261 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
263 struct PeerContext *ctx;
266 GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
268 ctx = GNUNET_new (struct PeerContext);
269 ctx->peer_id = *peer;
270 ctx->send_channel_flags = GNUNET_new (uint32_t);
271 ctx->recv_channel_flags = GNUNET_new (uint32_t);
272 ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
273 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
274 GNUNET_assert (GNUNET_OK == ret);
279 * @brief Create or get a #PeerContext
281 * @param peer the peer to get the associated context to
283 * @return the context
285 static struct PeerContext *
286 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
288 if (GNUNET_NO == Peers_check_peer_known (peer))
290 return create_peer_ctx (peer);
292 return get_peer_ctx (peer);
296 * @brief Check whether we have a connection to this @a peer
298 * Also sets the #Peers_ONLINE flag accordingly
300 * @param peer the peer in question
302 * @return #GNUNET_YES if we are connected
303 * #GNUNET_NO otherwise
306 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
308 const struct PeerContext *peer_ctx;
310 /* If we don't know about this peer we don't know whether it's online */
311 if (GNUNET_NO == Peers_check_peer_known (peer))
315 /* Get the context */
316 peer_ctx = get_peer_ctx (peer);
317 /* If we have no channel to this peer we don't know whether it's online */
318 if ( (NULL == peer_ctx->send_channel) &&
319 (NULL == peer_ctx->recv_channel) )
321 Peers_unset_peer_flag (peer, Peers_ONLINE);
324 /* Otherwise (if we have a channel, we know that it's online */
325 Peers_set_peer_flag (peer, Peers_ONLINE);
330 * @brief The closure to #get_rand_peer_iterator.
332 struct GetRandPeerIteratorCls
335 * @brief The index of the peer to return.
336 * Will be decreased until 0.
337 * Then current peer is returned.
342 * @brief Pointer to peer to return.
344 const struct GNUNET_PeerIdentity *peer;
348 * @brief Iterator function for #get_random_peer_from_peermap.
350 * Implements #GNUNET_CONTAINER_PeerMapIterator.
351 * Decreases the index until the index is null.
352 * Then returns the current peer.
354 * @param cls the #GetRandPeerIteratorCls containing index and peer
355 * @param peer current peer
356 * @param value unused
358 * @return #GNUNET_YES if we should continue to
363 get_rand_peer_iterator (void *cls,
364 const struct GNUNET_PeerIdentity *peer,
367 struct GetRandPeerIteratorCls *iterator_cls = cls;
368 if (0 >= iterator_cls->index)
370 iterator_cls->peer = peer;
373 iterator_cls->index--;
378 * @brief Get a random peer from @a peer_map
380 * @param peer_map the peer_map to get the peer from
382 * @return a random peer
384 static const struct GNUNET_PeerIdentity *
385 get_random_peer_from_peermap (const struct
386 GNUNET_CONTAINER_MultiPeerMap *peer_map)
389 struct GetRandPeerIteratorCls *iterator_cls;
390 const struct GNUNET_PeerIdentity *ret;
392 iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls);
393 iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
394 GNUNET_CONTAINER_multipeermap_size (peer_map));
395 (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
396 get_rand_peer_iterator,
398 ret = iterator_cls->peer;
399 GNUNET_free (iterator_cls);
404 * @brief Add a given @a peer to valid peers.
406 * If valid peers are already #num_valid_peers_max, delete a peer previously.
408 * @param peer the peer that is added to the valid peers.
410 * @return #GNUNET_YES if no other peer had to be removed
411 * #GNUNET_NO otherwise
414 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
416 const struct GNUNET_PeerIdentity *rand_peer;
420 while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
422 rand_peer = get_random_peer_from_peermap (valid_peers);
423 GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
426 (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
427 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
432 * @brief Set the peer flag to living and
433 * call the pending operations on this peer.
435 * Also adds peer to #valid_peers.
437 * @param peer_ctx the #PeerContext of the peer to set live
440 set_peer_live (struct PeerContext *peer_ctx)
442 struct GNUNET_PeerIdentity *peer;
445 /* Cancle cadet transmit_handle if still scheduled */
446 if (NULL != peer_ctx->transmit_handle)
448 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
449 peer_ctx->transmit_handle = NULL;
452 peer = &peer_ctx->peer_id;
453 (void) add_valid_peer (peer);
454 set_peer_flag (peer_ctx, Peers_ONLINE);
455 LOG (GNUNET_ERROR_TYPE_DEBUG,
456 "Peer %s is live and valid\n",
459 /* Call pending operations */
460 for (i = 0; i < peer_ctx->num_pending_ops; i++)
462 peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
464 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
468 * @brief Get the channel of a peer. If not existing, create.
470 * @param peer the peer id
471 * @return the #GNUNET_CADET_Channel used to send data to @a peer
473 struct GNUNET_CADET_Channel *
474 get_channel (const struct GNUNET_PeerIdentity *peer)
476 struct PeerContext *peer_ctx;
478 peer_ctx = get_peer_ctx (peer);
479 if (NULL == peer_ctx->send_channel)
481 LOG (GNUNET_ERROR_TYPE_DEBUG,
482 "Trying to establish channel to peer %s\n",
484 peer_ctx->send_channel =
485 GNUNET_CADET_channel_create (cadet_handle,
486 peer_ctx->send_channel_flags, /* context */
488 GNUNET_RPS_CADET_PORT,
489 GNUNET_CADET_OPTION_RELIABLE);
491 return peer_ctx->send_channel;
495 * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
497 * If we already have a message queue open to this client,
498 * simply return it, otherways create one.
500 * @param peer the peer to get the mq to
501 * @return the #GNUNET_MQ_Handle
503 static struct GNUNET_MQ_Handle *
504 get_mq (const struct GNUNET_PeerIdentity *peer)
506 struct PeerContext *peer_ctx;
508 peer_ctx = get_peer_ctx (peer);
509 GNUNET_assert (NULL == peer_ctx->transmit_handle);
511 if (NULL == peer_ctx->mq)
513 (void) get_channel (peer);
514 peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
520 * @brief Callback that is called when a channel was effectively established.
522 * This is an implementation of #GNUNET_CONNECTION_TransmitReadyNotify and
523 * given to #GNUNET_CADET_notify_transmit_ready_cancel and called when the
524 * channel was successfully established.
526 * This function type was originally ment to be called to provide the data to
527 * be sent. This is called when the connection is ready to queue more data.
528 * However we use it to get notified about the successful establishement of a
531 * @a buf will be NULL and @a size zero if the
532 * connection was closed for writing in the meantime.
535 * @param size number of bytes available in @a buf
536 * @param buf where the callee should write the message
537 * @return number of bytes written to @a buf
541 cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
543 struct PeerContext *peer_ctx = (struct PeerContext *) cls;
544 // TODO make sure the context is not deleted or the establishing of the
545 // channel is cancelled
547 peer_ctx->transmit_handle = NULL;
548 LOG (GNUNET_ERROR_TYPE_DEBUG,
549 "Set ->transmit_handle = NULL for peer %s\n",
550 GNUNET_i2s (&peer_ctx->peer_id));
552 if ( (NULL != buf) &&
555 set_peer_live (peer_ctx);
559 LOG (GNUNET_ERROR_TYPE_WARNING,
560 "Problems establishing a connection to peer %s in order to check liveliness\n",
561 GNUNET_i2s (&peer_ctx->peer_id));
562 // TODO reschedule? cleanup?
568 * Issue a check whether peer is live
570 * @param peer_ctx the context of the peer
573 check_peer_live (struct PeerContext *peer_ctx)
575 LOG (GNUNET_ERROR_TYPE_DEBUG,
576 "Get informed about peer %s getting live\n",
577 GNUNET_i2s (&peer_ctx->peer_id));
579 if (NULL == peer_ctx->transmit_handle &&
580 NULL == peer_ctx->send_channel)
582 (void) get_channel (&peer_ctx->peer_id);
583 peer_ctx->transmit_handle =
584 GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
586 GNUNET_TIME_UNIT_FOREVER_REL,
587 sizeof (struct GNUNET_MessageHeader),
588 cadet_notify_transmit_ready_cb,
591 else if (NULL != peer_ctx->transmit_handle)
592 LOG (GNUNET_ERROR_TYPE_DEBUG,
593 "Already waiting for notification\n");
594 else if (NULL != peer_ctx->send_channel)
595 LOG (GNUNET_ERROR_TYPE_DEBUG,
596 "Already have established channel to peer\n");
600 * @brief Add an envelope to a message passed to mq to list of pending messages
602 * @param peer peer the message was sent to
603 * @param ev envelope to the message
604 * @param type type of the message to be sent
605 * @return pointer to pending message
607 static struct PendingMessage *
608 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
609 struct GNUNET_MQ_Envelope *ev,
612 struct PendingMessage *pending_msg;
613 struct PeerContext *peer_ctx;
615 peer_ctx = get_peer_ctx (peer);
616 pending_msg = GNUNET_new (struct PendingMessage);
617 pending_msg->ev = ev;
618 pending_msg->peer_ctx = peer_ctx;
619 pending_msg->type = type;
620 GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
621 peer_ctx->pending_messages_tail,
627 * @brief Remove a pending message from the respective DLL
629 * @param pending_msg the pending message to remove
632 remove_pending_message (struct PendingMessage *pending_msg)
634 struct PeerContext *peer_ctx;
636 peer_ctx = pending_msg->peer_ctx;
637 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
638 peer_ctx->pending_messages_tail,
640 /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does
641 * not set a #GNUNET_MQ_CancelImpl */
642 /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
643 GNUNET_free (pending_msg);
647 * @brief Check whether function of type #PeerOp was already scheduled
649 * The array with pending operations will probably never grow really big, so
650 * iterating over it should be ok.
652 * @param peer the peer to check
653 * @param peer_op the operation (#PeerOp) on the peer
655 * @return #GNUNET_YES if this operation is scheduled on that peer
656 * #GNUNET_NO otherwise
659 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
660 const PeerOp peer_op)
662 const struct PeerContext *peer_ctx;
665 peer_ctx = get_peer_ctx (peer);
666 for (i = 0; i < peer_ctx->num_pending_ops; i++)
667 if (peer_op == peer_ctx->pending_ops[i].op)
673 * Iterator over hash map entries. Deletes all contexts of peers.
676 * @param key current public key
677 * @param value value in the hash map
678 * @return #GNUNET_YES if we should continue to iterate,
682 peermap_clear_iterator (void *cls,
683 const struct GNUNET_PeerIdentity *key,
686 Peers_remove_peer (key);
691 * @brief This is called once a message is sent.
693 * Removes the pending message
695 * @param cls type of the message that was sent
698 mq_notify_sent_cb (void *cls)
700 struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
701 LOG (GNUNET_ERROR_TYPE_DEBUG,
704 remove_pending_message (pending_msg);
709 * @brief Initialise storage of peers
711 * @param cadet_h cadet handle
712 * @param own_id own peer identity
715 Peers_initialise (struct GNUNET_CADET_Handle *cadet_h,
716 const struct GNUNET_PeerIdentity *own_id)
718 cadet_handle = cadet_h;
719 own_identity = own_id;
720 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
721 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
724 // TODO read stored valid peers
727 * @brief Delete storage of peers that was created with #Peers_initialise ()
733 GNUNET_CONTAINER_multipeermap_iterate (peer_map,
734 peermap_clear_iterator,
737 LOG (GNUNET_ERROR_TYPE_WARNING,
738 "Iteration destroying peers was aborted.\n");
740 GNUNET_CONTAINER_multipeermap_destroy (peer_map);
741 GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
744 // TODO store valid peers
747 * @brief Add peer to known peers.
749 * This function is called on new peer_ids from 'external' sources
750 * (client seed, cadet get_peers(), ...)
752 * @param peer the new #GNUNET_PeerIdentity
754 * @return #GNUNET_YES if peer was inserted
755 * #GNUNET_NO if peer was already known
758 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
760 if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
761 (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
763 return GNUNET_NO; /* We already know this peer - nothing to do */
765 (void) create_peer_ctx (peer);
771 * @brief Add peer to known peers and check for liveliness.
773 * This function is called on new peer_ids from 'external' sources
774 * (client seed, cadet get_peers(), ...)
776 * @param peer the new #GNUNET_PeerIdentity
778 * @return #GNUNET_YES if peer was inserted
779 * #GNUNET_NO if peer was already known
782 Peers_insert_peer_check_liveliness (const struct GNUNET_PeerIdentity *peer)
784 struct PeerContext *peer_ctx;
787 ret = Peers_insert_peer (peer);
788 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
792 peer_ctx = get_peer_ctx (peer);
793 if (GNUNET_NO == Peers_check_peer_valid (peer))
795 check_peer_live (peer_ctx);
801 * @brief Remove unecessary data
803 * If the other peer is not intending to send messages, we have messages pending
804 * to be sent to this peer and we are not waiting for a reply, remove the
805 * information about it (its #PeerContext).
807 * @param peer the peer to clean
808 * @return #GNUNET_YES if peer was removed
809 * #GNUNET_NO otherwise
812 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
814 struct PeerContext *peer_ctx;
816 // TODO actually remove unnecessary data
818 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
823 peer_ctx = get_peer_ctx (peer);
824 if ( (NULL != peer_ctx->recv_channel) ||
825 (NULL != peer_ctx->pending_messages_head) ||
826 (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
830 Peers_remove_peer (peer);
837 * @param peer the peer to clean
838 * @return #GNUNET_YES if peer was removed
839 * #GNUNET_NO otherwise
842 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
844 struct PeerContext *peer_ctx;
846 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
851 peer_ctx = get_peer_ctx (peer);
852 set_peer_flag (peer_ctx, Peers_TO_DESTROY);
853 LOG (GNUNET_ERROR_TYPE_DEBUG,
854 "Going to remove peer %s\n",
855 GNUNET_i2s (&peer_ctx->peer_id));
856 Peers_unset_peer_flag (peer, Peers_ONLINE);
858 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
859 // TODO delete struct GNUNET_TRANSPORT_TransmitHandle *transmit_handle
860 /* Cancle messages that have not been sent yet */
861 while (NULL != peer_ctx->pending_messages_head)
863 LOG (GNUNET_ERROR_TYPE_DEBUG,
864 "Removing unsent %s\n",
865 peer_ctx->pending_messages_head->type);
866 remove_pending_message (peer_ctx->pending_messages_head);
868 /* If we are still waiting for notification whether this peer is live
869 * cancel the according task */
870 if (NULL != peer_ctx->transmit_handle)
872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
873 "Trying to cancle transmit_handle for peer %s\n",
874 GNUNET_i2s (&peer_ctx->peer_id));
875 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
876 peer_ctx->transmit_handle = NULL;
878 if (NULL != peer_ctx->send_channel)
880 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
881 peer_ctx->send_channel = NULL;
883 if (NULL != peer_ctx->recv_channel)
885 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
886 peer_ctx->recv_channel = NULL;
888 if (NULL != peer_ctx->mq)
890 GNUNET_MQ_destroy (peer_ctx->mq);
894 GNUNET_free (peer_ctx->send_channel_flags);
895 GNUNET_free (peer_ctx->recv_channel_flags);
897 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
899 LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
901 GNUNET_free (peer_ctx);
906 * @brief set flags on a given peer.
908 * @param peer the peer to set flags on
909 * @param flags the flags
912 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
914 struct PeerContext *peer_ctx;
916 peer_ctx = get_peer_ctx (peer);
917 set_peer_flag (peer_ctx, flags);
921 * @brief unset flags on a given peer.
923 * @param peer the peer to unset flags on
924 * @param flags the flags
927 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
929 struct PeerContext *peer_ctx;
931 peer_ctx = get_peer_ctx (peer);
932 unset_peer_flag (peer_ctx, flags);
936 * @brief Check whether flags on a peer are set.
938 * @param peer the peer to check the flag of
939 * @param flags the flags to check
941 * @return #GNUNET_YES if all given flags are set
942 * #GNUNET_NO otherwise
945 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
947 struct PeerContext *peer_ctx;
949 peer_ctx = get_peer_ctx (peer);
950 return check_peer_flag_set (peer_ctx, flags);
955 * @brief set flags on a given channel.
957 * @param channel the channel to set flags on
958 * @param flags the flags
961 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
963 set_channel_flag (channel_flags, flags);
967 * @brief unset flags on a given channel.
969 * @param channel the channel to unset flags on
970 * @param flags the flags
973 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
975 unset_channel_flag (channel_flags, flags);
979 * @brief Check whether flags on a channel are set.
981 * @param channel the channel to check the flag of
982 * @param flags the flags to check
984 * @return #GNUNET_YES if all given flags are set
985 * #GNUNET_NO otherwise
988 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
990 return check_channel_flag_set (channel_flags, flags);
994 * @brief Check whether we have information about the given peer.
996 * FIXME probably deprecated. Make this the new _online.
998 * @param peer peer in question
1000 * @return #GNUNET_YES if peer is known
1001 * #GNUNET_NO if peer is not knwon
1004 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1006 return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1010 * @brief Check whether @a peer is actually a peer.
1012 * A valid peer is a peer that we know exists eg. we were connected to once.
1014 * @param peer peer in question
1016 * @return #GNUNET_YES if peer is valid
1017 * #GNUNET_NO if peer is not valid
1020 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1022 return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1026 * @brief Indicate that we want to send to the other peer
1028 * This establishes a sending channel
1030 * @param peer the peer to establish channel to
1033 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1035 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1036 (void) get_channel (peer);
1040 * @brief Check whether other peer has the intention to send/opened channel
1043 * @param peer the peer in question
1045 * @return #GNUNET_YES if peer has the intention to send
1046 * #GNUNET_NO otherwise
1049 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1051 const struct PeerContext *peer_ctx;
1053 peer_ctx = get_peer_ctx (peer);
1054 if (NULL != peer_ctx->recv_channel)
1062 * Handle the channel a peer opens to us.
1064 * @param cls The closure
1065 * @param channel The channel the peer wants to establish
1066 * @param initiator The peer's peer ID
1067 * @param port The port the channel is being established over
1068 * @param options Further options
1070 * @return initial channel context for the channel
1071 * (can be NULL -- that's not an error)
1074 Peers_handle_inbound_channel (void *cls,
1075 struct GNUNET_CADET_Channel *channel,
1076 const struct GNUNET_PeerIdentity *initiator,
1078 enum GNUNET_CADET_ChannelOption options)
1080 struct PeerContext *peer_ctx;
1082 LOG (GNUNET_ERROR_TYPE_DEBUG,
1083 "New channel was established to us (Peer %s).\n",
1084 GNUNET_i2s (initiator));
1085 GNUNET_assert (NULL != channel); /* according to cadet API */
1086 /* Make sure we 'know' about this peer */
1087 peer_ctx = create_or_get_peer_ctx (initiator);
1088 set_peer_live (peer_ctx);
1089 /* We only accept one incoming channel per peer */
1090 if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1092 set_channel_flag (peer_ctx->recv_channel_flags,
1093 Peers_CHANNEL_ESTABLISHED_TWICE);
1094 GNUNET_CADET_channel_destroy (channel);
1095 /* return the channel context */
1096 return peer_ctx->recv_channel_flags;
1098 peer_ctx->recv_channel = channel;
1099 return peer_ctx->recv_channel_flags;
1103 * @brief Check whether a sending channel towards the given peer exists
1105 * @param peer the peer to check for
1107 * @return #GNUNET_YES if a sending channel towards that peer exists
1108 * #GNUNET_NO otherwise
1111 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1113 struct PeerContext *peer_ctx;
1115 if (GNUNET_NO == Peers_check_peer_known (peer))
1116 { /* If no such peer exists, there is no channel */
1119 peer_ctx = get_peer_ctx (peer);
1120 if (NULL == peer_ctx->send_channel)
1128 * @brief check whether the given channel is the sending channel of the given
1131 * @param peer the peer in question
1132 * @param channel the channel to check for
1133 * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1134 * #Peers_CHANNEL_ROLE_RECEIVING
1136 * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1137 * #GNUNET_NO otherwise
1140 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1141 const struct GNUNET_CADET_Channel *channel,
1142 enum Peers_ChannelRole role)
1144 const struct PeerContext *peer_ctx;
1146 if (GNUNET_NO == Peers_check_peer_known (peer))
1150 peer_ctx = get_peer_ctx (peer);
1151 if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1152 (channel == peer_ctx->send_channel) )
1156 if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1157 (channel == peer_ctx->recv_channel) )
1165 * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1166 * intention to another peer
1168 * If there is also no channel to receive messages from that peer, remove it
1172 * @peer the peer identity of the peer whose sending channel to destroy
1173 * @return #GNUNET_YES if channel was destroyed
1174 * #GNUNET_NO otherwise
1177 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1179 struct PeerContext *peer_ctx;
1181 if (GNUNET_NO == Peers_check_peer_known (peer))
1185 peer_ctx = get_peer_ctx (peer);
1186 if (NULL != peer_ctx->send_channel)
1188 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1189 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1190 peer_ctx->send_channel = NULL;
1191 (void) Peers_check_connected (peer);
1198 * This is called when a channel is destroyed.
1200 * @param cls The closure
1201 * @param channel The channel being closed
1202 * @param channel_ctx The context associated with this channel
1205 Peers_cleanup_destroyed_channel (void *cls,
1206 const struct GNUNET_CADET_Channel *channel,
1209 struct GNUNET_PeerIdentity *peer;
1210 struct PeerContext *peer_ctx;
1212 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1213 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1214 // FIXME wait for cadet to change this function
1216 if (GNUNET_NO == Peers_check_peer_known (peer))
1217 {/* We don't want to implicitly create a context that we're about to kill */
1218 LOG (GNUNET_ERROR_TYPE_DEBUG,
1219 "channel (%s) without associated context was destroyed\n",
1223 peer_ctx = get_peer_ctx (peer);
1225 /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1226 * flag will be set. In this case simply make sure that the channels are
1228 /* FIXME This distinction seems to be redundant */
1229 if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1230 {/* We initiatad the destruction of this particular peer */
1231 if (channel == peer_ctx->send_channel)
1232 peer_ctx->send_channel = NULL;
1233 else if (channel == peer_ctx->recv_channel)
1234 peer_ctx->recv_channel = NULL;
1235 (void) Peers_check_connected (peer);
1240 { /* We did not initiate the destruction of this peer */
1241 if (channel == peer_ctx->send_channel)
1242 { /* Something (but us) killd the channel - clean up peer */
1243 LOG (GNUNET_ERROR_TYPE_DEBUG,
1244 "send channel (%s) was destroyed - cleaning up\n",
1246 peer_ctx->send_channel = NULL;
1248 else if (channel == peer_ctx->recv_channel)
1249 { /* Other peer doesn't want to send us messages anymore */
1250 LOG (GNUNET_ERROR_TYPE_DEBUG,
1251 "Peer %s destroyed recv channel - cleaning up channel\n",
1253 peer_ctx->recv_channel = NULL;
1257 LOG (GNUNET_ERROR_TYPE_WARNING,
1258 "unknown channel (%s) was destroyed\n",
1262 (void) Peers_check_connected (peer);
1266 * @brief Issue a check whether peer is live
1268 * This tries to establish a channel to the given peer. Once the channel is
1269 * established successfully, we know the peer is live.
1271 * @param peer the peer to check liveliness
1274 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1276 struct PeerContext *peer_ctx;
1278 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1280 return; /* We know that we are online */
1283 peer_ctx = create_or_get_peer_ctx (peer);
1284 // TODO if LIVE/ONLINE
1285 check_peer_live (peer_ctx);
1289 * @brief Send a message to another peer.
1291 * Keeps track about pending messages so they can be properly removed when the
1292 * peer is destroyed.
1294 * @param peer receeiver of the message
1295 * @param ev envelope of the message
1296 * @param type type of the message
1299 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1300 struct GNUNET_MQ_Envelope *ev,
1303 struct PendingMessage *pending_msg;
1304 struct GNUNET_MQ_Handle *mq;
1306 pending_msg = insert_pending_message (peer, ev, "PULL REPLY");
1308 GNUNET_MQ_notify_sent (ev,
1311 GNUNET_MQ_send (mq, ev);
1315 * @brief Schedule a operation on given peer
1317 * Avoids scheduling an operation twice.
1319 * @param peer the peer we want to schedule the operation for once it gets live
1321 * @return #GNUNET_YES if the operation was scheduled
1322 * #GNUNET_NO otherwise
1325 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1326 const PeerOp peer_op)
1328 struct PeerPendingOp pending_op;
1329 struct PeerContext *peer_ctx;
1331 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1335 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1337 //TODO if LIVE/ONLINE execute immediately
1339 if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1341 peer_ctx = get_peer_ctx (peer);
1342 pending_op.op = peer_op;
1343 pending_op.op_cls = NULL;
1344 GNUNET_array_append (peer_ctx->pending_ops,
1345 peer_ctx->num_pending_ops,
1352 /* end of gnunet-service-rps_peers.c */