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(kind, __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),
208 * Set of all peers to keep track of them.
210 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
213 * Own #GNUNET_PeerIdentity.
215 static const struct GNUNET_PeerIdentity *own_identity;
220 static struct GNUNET_CADET_Handle *cadet_handle;
225 * @brief Get the #PeerContext associated with a peer
227 * @param peer the peer id
229 * @return the #PeerContext
231 static struct PeerContext *
232 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
234 struct PeerContext *ctx;
237 ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
238 GNUNET_assert (GNUNET_YES == ret);
239 ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
240 GNUNET_assert (NULL != ctx);
245 * @brief Create a new #PeerContext and insert it into the peer map
247 * @param peer the peer to create the #PeerContext for
249 * @return the #PeerContext
251 static struct PeerContext *
252 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
254 struct PeerContext *ctx;
257 GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
259 ctx = GNUNET_new (struct PeerContext);
260 ctx->peer_id = *peer;
261 ctx->send_channel_flags = GNUNET_new (uint32_t);
262 ctx->recv_channel_flags = GNUNET_new (uint32_t);
263 ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
264 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
265 GNUNET_assert (GNUNET_OK == ret);
270 * @brief Create or get a #PeerContext
272 * @param peer the peer to get the associated context to
274 * @return the context
276 static struct PeerContext *
277 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
279 if (GNUNET_NO == Peers_check_peer_known (peer))
281 return create_peer_ctx (peer);
283 return get_peer_ctx (peer);
287 * @brief Check whether we have a connection to this @a peer
289 * Also sets the #Peers_ONLINE flag accordingly
291 * @param peer the peer in question
293 * @return #GNUNET_YES if we are connected
294 * #GNUNET_NO otherwise
297 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
299 const struct PeerContext *peer_ctx;
301 /* If we don't know about this peer we don't know whether it's online */
302 if (GNUNET_NO == Peers_check_peer_known (peer))
306 /* Get the context */
307 peer_ctx = get_peer_ctx (peer);
308 /* If we have no channel to this peer we don't know whether it's online */
309 if ( (NULL == peer_ctx->send_channel) &&
310 (NULL == peer_ctx->recv_channel) )
312 Peers_unset_peer_flag (peer, Peers_ONLINE);
315 /* Otherwise (if we have a channel, we know that it's online */
316 Peers_set_peer_flag (peer, Peers_ONLINE);
321 * @brief Set the peer flag to living and
322 * call the pending operations on this peer.
324 * Also sets the #Peers_VALID flag
326 * @param peer_ctx the #PeerContext of the peer to set live
329 set_peer_live (struct PeerContext *peer_ctx)
331 struct GNUNET_PeerIdentity *peer;
334 /* Cancle cadet transmit_handle if still scheduled */
335 if (NULL != peer_ctx->transmit_handle)
337 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
338 peer_ctx->transmit_handle = NULL;
341 peer = &peer_ctx->peer_id;
342 set_peer_flag (peer_ctx, Peers_VALID);
343 set_peer_flag (peer_ctx, Peers_ONLINE);
344 LOG (GNUNET_ERROR_TYPE_DEBUG,
345 "Peer %s is live and valid\n",
348 /* Call pending operations */
349 for (i = 0; i < peer_ctx->num_pending_ops; i++)
351 peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
353 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
357 * @brief Get the channel of a peer. If not existing, create.
359 * @param peer the peer id
360 * @return the #GNUNET_CADET_Channel used to send data to @a peer
362 struct GNUNET_CADET_Channel *
363 get_channel (const struct GNUNET_PeerIdentity *peer)
365 struct PeerContext *peer_ctx;
367 peer_ctx = get_peer_ctx (peer);
368 if (NULL == peer_ctx->send_channel)
370 LOG (GNUNET_ERROR_TYPE_DEBUG,
371 "Trying to establish channel to peer %s\n",
373 peer_ctx->send_channel =
374 GNUNET_CADET_channel_create (cadet_handle,
375 peer_ctx->send_channel_flags, /* context */
377 GNUNET_RPS_CADET_PORT,
378 GNUNET_CADET_OPTION_RELIABLE);
380 return peer_ctx->send_channel;
384 * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
386 * If we already have a message queue open to this client,
387 * simply return it, otherways create one.
389 * @param peer the peer to get the mq to
390 * @return the #GNUNET_MQ_Handle
392 static struct GNUNET_MQ_Handle *
393 get_mq (const struct GNUNET_PeerIdentity *peer)
395 struct PeerContext *peer_ctx;
397 peer_ctx = get_peer_ctx (peer);
398 GNUNET_assert (NULL == peer_ctx->transmit_handle);
400 if (NULL == peer_ctx->mq)
402 (void) get_channel (peer);
403 peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
409 * @brief Callback that is called when a channel was effectively established.
411 * This is an implementation of #GNUNET_CONNECTION_TransmitReadyNotify and
412 * given to #GNUNET_CADET_notify_transmit_ready_cancel and called when the
413 * channel was successfully established.
415 * This function type was originally ment to be called to provide the data to
416 * be sent. This is called when the connection is ready to queue more data.
417 * However we use it to get notified about the successful establishement of a
420 * @a buf will be NULL and @a size zero if the
421 * connection was closed for writing in the meantime.
424 * @param size number of bytes available in @a buf
425 * @param buf where the callee should write the message
426 * @return number of bytes written to @a buf
430 cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
432 struct PeerContext *peer_ctx = (struct PeerContext *) cls;
433 // TODO make sure the context is not deleted or the establishing of the
434 // channel is cancelled
436 peer_ctx->transmit_handle = NULL;
437 LOG (GNUNET_ERROR_TYPE_DEBUG,
438 "Set ->transmit_handle = NULL for peer %s\n",
439 GNUNET_i2s (&peer_ctx->peer_id));
441 if ( (NULL != buf) &&
444 set_peer_live (peer_ctx);
448 LOG (GNUNET_ERROR_TYPE_WARNING,
449 "Problems establishing a connection to peer %s in order to check liveliness\n",
450 GNUNET_i2s (&peer_ctx->peer_id));
451 // TODO reschedule? cleanup?
457 * Issue a check whether peer is live
459 * @param peer_ctx the context of the peer
462 check_peer_live (struct PeerContext *peer_ctx)
464 LOG (GNUNET_ERROR_TYPE_DEBUG,
465 "Get informed about peer %s getting live\n",
466 GNUNET_i2s (&peer_ctx->peer_id));
468 if (NULL == peer_ctx->transmit_handle &&
469 NULL == peer_ctx->send_channel)
471 (void) get_channel (&peer_ctx->peer_id);
472 peer_ctx->transmit_handle =
473 GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
475 GNUNET_TIME_UNIT_FOREVER_REL,
476 sizeof (struct GNUNET_MessageHeader),
477 cadet_notify_transmit_ready_cb,
480 else if (NULL != peer_ctx->transmit_handle)
481 LOG (GNUNET_ERROR_TYPE_DEBUG,
482 "Already waiting for notification\n");
483 else if (NULL != peer_ctx->send_channel)
484 LOG (GNUNET_ERROR_TYPE_DEBUG,
485 "Already have established channel to peer\n");
489 * @brief Add an envelope to a message passed to mq to list of pending messages
491 * @param peer peer the message was sent to
492 * @param ev envelope to the message
493 * @param type type of the message to be sent
494 * @return pointer to pending message
496 static struct PendingMessage *
497 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
498 struct GNUNET_MQ_Envelope *ev,
501 struct PendingMessage *pending_msg;
502 struct PeerContext *peer_ctx;
504 peer_ctx = get_peer_ctx (peer);
505 pending_msg = GNUNET_new (struct PendingMessage);
506 pending_msg->ev = ev;
507 pending_msg->peer_ctx = peer_ctx;
508 pending_msg->type = type;
509 GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
510 peer_ctx->pending_messages_tail,
516 * @brief Remove a pending message from the respective DLL
518 * @param pending_msg the pending message to remove
521 remove_pending_message (struct PendingMessage *pending_msg)
523 struct PeerContext *peer_ctx;
525 peer_ctx = pending_msg->peer_ctx;
526 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
527 peer_ctx->pending_messages_tail,
529 /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does
530 * not set a #GNUNET_MQ_CancelImpl */
531 /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
532 GNUNET_free (pending_msg);
536 * @brief Check whether function of type #PeerOp was already scheduled
538 * The array with pending operations will probably never grow really big, so
539 * iterating over it should be ok.
541 * @param peer the peer to check
542 * @param peer_op the operation (#PeerOp) on the peer
544 * @return #GNUNET_YES if this operation is scheduled on that peer
545 * #GNUNET_NO otherwise
548 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
549 const PeerOp peer_op)
551 const struct PeerContext *peer_ctx;
554 peer_ctx = get_peer_ctx (peer);
555 for (i = 0; i < peer_ctx->num_pending_ops; i++)
556 if (peer_op == peer_ctx->pending_ops[i].op)
562 * Iterator over hash map entries. Deletes all contexts of peers.
565 * @param key current public key
566 * @param value value in the hash map
567 * @return #GNUNET_YES if we should continue to iterate,
571 peermap_clear_iterator (void *cls,
572 const struct GNUNET_PeerIdentity *key,
575 Peers_remove_peer (key);
580 * @brief This is called once a message is sent.
582 * Removes the pending message
584 * @param cls type of the message that was sent
587 mq_notify_sent_cb (void *cls)
589 struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
590 LOG (GNUNET_ERROR_TYPE_DEBUG,
593 remove_pending_message (pending_msg);
598 * @brief Initialise storage of peers
600 * @param cadet_h cadet handle
601 * @param own_id own peer identity
604 Peers_initialise (struct GNUNET_CADET_Handle *cadet_h,
605 const struct GNUNET_PeerIdentity *own_id)
607 cadet_handle = cadet_h;
608 own_identity = own_id;
609 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
613 * @brief Delete storage of peers that was created with #Peers_initialise ()
619 GNUNET_CONTAINER_multipeermap_iterate (peer_map,
620 peermap_clear_iterator,
623 LOG (GNUNET_ERROR_TYPE_WARNING,
624 "Iteration destroying peers was aborted.\n");
626 GNUNET_CONTAINER_multipeermap_destroy (peer_map);
630 * @brief Add peer to known peers.
632 * This function is called on new peer_ids from 'external' sources
633 * (client seed, cadet get_peers(), ...)
635 * @param peer the new #GNUNET_PeerIdentity
637 * @return #GNUNET_YES if peer was inserted
638 * #GNUNET_NO if peer was already known
641 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
643 if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
644 (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
646 return GNUNET_NO; /* We already know this peer - nothing to do */
648 (void) create_peer_ctx (peer);
654 * @brief Add peer to known peers and check for liveliness.
656 * This function is called on new peer_ids from 'external' sources
657 * (client seed, cadet get_peers(), ...)
659 * @param peer the new #GNUNET_PeerIdentity
661 * @return #GNUNET_YES if peer was inserted
662 * #GNUNET_NO if peer was already known
665 Peers_insert_peer_check_liveliness (const struct GNUNET_PeerIdentity *peer)
667 struct PeerContext *peer_ctx;
670 ret = Peers_insert_peer (peer);
671 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
675 peer_ctx = get_peer_ctx (peer);
676 if (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_VALID))
678 check_peer_live (peer_ctx);
684 * @brief Remove unecessary data
686 * If the other peer is not intending to send messages, we have messages pending
687 * to be sent to this peer and we are not waiting for a reply, remove the
688 * information about it (its #PeerContext).
690 * @param peer the peer to clean
691 * @return #GNUNET_YES if peer was removed
692 * #GNUNET_NO otherwise
695 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
697 struct PeerContext *peer_ctx;
699 // TODO actually remove unnecessary data
701 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
706 peer_ctx = get_peer_ctx (peer);
707 if ( (NULL != peer_ctx->recv_channel) ||
708 (NULL != peer_ctx->pending_messages_head) ||
709 (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
713 Peers_remove_peer (peer);
720 * @param peer the peer to clean
721 * @return #GNUNET_YES if peer was removed
722 * #GNUNET_NO otherwise
725 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
727 struct PeerContext *peer_ctx;
729 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
734 peer_ctx = get_peer_ctx (peer);
735 set_peer_flag (peer_ctx, Peers_TO_DESTROY);
736 LOG (GNUNET_ERROR_TYPE_DEBUG,
737 "Going to remove peer %s\n",
738 GNUNET_i2s (&peer_ctx->peer_id));
739 Peers_unset_peer_flag (peer, Peers_ONLINE);
741 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
742 // TODO delete struct GNUNET_TRANSPORT_TransmitHandle *transmit_handle
743 /* Cancle messages that have not been sent yet */
744 while (NULL != peer_ctx->pending_messages_head)
746 LOG (GNUNET_ERROR_TYPE_DEBUG,
747 "Removing unsent %s\n",
748 peer_ctx->pending_messages_head->type);
749 remove_pending_message (peer_ctx->pending_messages_head);
751 /* If we are still waiting for notification whether this peer is live
752 * cancel the according task */
753 if (NULL != peer_ctx->transmit_handle)
755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756 "Trying to cancle transmit_handle for peer %s\n",
757 GNUNET_i2s (&peer_ctx->peer_id));
758 GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
759 peer_ctx->transmit_handle = NULL;
761 if (NULL != peer_ctx->send_channel)
763 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
764 peer_ctx->send_channel = NULL;
766 if (NULL != peer_ctx->recv_channel)
768 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
769 peer_ctx->recv_channel = NULL;
771 if (NULL != peer_ctx->mq)
773 GNUNET_MQ_destroy (peer_ctx->mq);
777 GNUNET_free (peer_ctx->send_channel_flags);
778 GNUNET_free (peer_ctx->recv_channel_flags);
780 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
782 LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
784 GNUNET_free (peer_ctx);
789 * @brief set flags on a given peer.
791 * @param peer the peer to set flags on
792 * @param flags the flags
795 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
797 struct PeerContext *peer_ctx;
799 peer_ctx = get_peer_ctx (peer);
800 set_peer_flag (peer_ctx, flags);
804 * @brief unset flags on a given peer.
806 * @param peer the peer to unset flags on
807 * @param flags the flags
810 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
812 struct PeerContext *peer_ctx;
814 peer_ctx = get_peer_ctx (peer);
815 unset_peer_flag (peer_ctx, flags);
819 * @brief Check whether flags on a peer are set.
821 * @param peer the peer to check the flag of
822 * @param flags the flags to check
824 * @return #GNUNET_YES if all given flags are set
825 * #GNUNET_NO otherwise
828 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
830 struct PeerContext *peer_ctx;
832 peer_ctx = get_peer_ctx (peer);
833 return check_peer_flag_set (peer_ctx, flags);
838 * @brief set flags on a given channel.
840 * @param channel the channel to set flags on
841 * @param flags the flags
844 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
846 set_channel_flag (channel_flags, flags);
850 * @brief unset flags on a given channel.
852 * @param channel the channel to unset flags on
853 * @param flags the flags
856 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
858 unset_channel_flag (channel_flags, flags);
862 * @brief Check whether flags on a channel are set.
864 * @param channel the channel to check the flag of
865 * @param flags the flags to check
867 * @return #GNUNET_YES if all given flags are set
868 * #GNUNET_NO otherwise
871 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
873 return check_channel_flag_set (channel_flags, flags);
877 * @brief Check whether we have information about the given peer.
879 * @param peer peer in question
881 * @return #GNUNET_YES if peer is known
882 * #GNUNET_NO if peer is not knwon
885 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
887 return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
891 * @brief Indicate that we want to send to the other peer
893 * This establishes a sending channel
895 * @param peer the peer to establish channel to
898 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
900 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
901 (void) get_channel (peer);
905 * @brief Check whether other peer has the intention to send/opened channel
908 * @param peer the peer in question
910 * @return #GNUNET_YES if peer has the intention to send
911 * #GNUNET_NO otherwise
914 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
916 const struct PeerContext *peer_ctx;
918 peer_ctx = get_peer_ctx (peer);
919 if (NULL != peer_ctx->recv_channel)
927 * Handle the channel a peer opens to us.
929 * @param cls The closure
930 * @param channel The channel the peer wants to establish
931 * @param initiator The peer's peer ID
932 * @param port The port the channel is being established over
933 * @param options Further options
935 * @return initial channel context for the channel
936 * (can be NULL -- that's not an error)
939 Peers_handle_inbound_channel (void *cls,
940 struct GNUNET_CADET_Channel *channel,
941 const struct GNUNET_PeerIdentity *initiator,
943 enum GNUNET_CADET_ChannelOption options)
945 struct PeerContext *peer_ctx;
947 LOG (GNUNET_ERROR_TYPE_DEBUG,
948 "New channel was established to us (Peer %s).\n",
949 GNUNET_i2s (initiator));
950 GNUNET_assert (NULL != channel); /* according to cadet API */
951 /* Make sure we 'know' about this peer */
952 peer_ctx = create_or_get_peer_ctx (initiator);
953 set_peer_live (peer_ctx);
954 /* We only accept one incoming channel per peer */
955 if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
957 set_channel_flag (peer_ctx->recv_channel_flags,
958 Peers_CHANNEL_ESTABLISHED_TWICE);
959 GNUNET_CADET_channel_destroy (channel);
960 /* return the channel context */
961 return peer_ctx->recv_channel_flags;
963 peer_ctx->recv_channel = channel;
964 return peer_ctx->recv_channel_flags;
968 * @brief Check whether a sending channel towards the given peer exists
970 * @param peer the peer to check for
972 * @return #GNUNET_YES if a sending channel towards that peer exists
973 * #GNUNET_NO otherwise
976 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
978 struct PeerContext *peer_ctx;
980 if (GNUNET_NO == Peers_check_peer_known (peer))
981 { /* If no such peer exists, there is no channel */
984 peer_ctx = get_peer_ctx (peer);
985 if (NULL == peer_ctx->send_channel)
993 * @brief check whether the given channel is the sending channel of the given
996 * @param peer the peer in question
997 * @param channel the channel to check for
998 * @param role either #Peers_CHANNEL_ROLE_SENDING, or
999 * #Peers_CHANNEL_ROLE_RECEIVING
1001 * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1002 * #GNUNET_NO otherwise
1005 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1006 const struct GNUNET_CADET_Channel *channel,
1007 enum Peers_ChannelRole role)
1009 const struct PeerContext *peer_ctx;
1011 if (GNUNET_NO == Peers_check_peer_known (peer))
1015 peer_ctx = get_peer_ctx (peer);
1016 if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1017 (channel == peer_ctx->send_channel) )
1021 if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1022 (channel == peer_ctx->recv_channel) )
1030 * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1031 * intention to another peer
1033 * If there is also no channel to receive messages from that peer, remove it
1037 * @peer the peer identity of the peer whose sending channel to destroy
1038 * @return #GNUNET_YES if channel was destroyed
1039 * #GNUNET_NO otherwise
1042 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1044 struct PeerContext *peer_ctx;
1046 if (GNUNET_NO == Peers_check_peer_known (peer))
1050 peer_ctx = get_peer_ctx (peer);
1051 if (NULL != peer_ctx->send_channel)
1053 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1054 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1055 peer_ctx->send_channel = NULL;
1056 (void) Peers_check_connected (peer);
1063 * This is called when a channel is destroyed.
1065 * Removes peer completely from our knowledge if the send_channel was destroyed
1066 * Otherwise simply delete the recv_channel
1068 * @param cls The closure
1069 * @param channel The channel being closed
1070 * @param channel_ctx The context associated with this channel
1073 Peers_cleanup_destroyed_channel (void *cls,
1074 const struct GNUNET_CADET_Channel *channel,
1077 struct GNUNET_PeerIdentity *peer;
1078 struct PeerContext *peer_ctx;
1080 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1081 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1082 // FIXME wait for cadet to change this function
1084 if (GNUNET_NO == Peers_check_peer_known (peer))
1085 {/* We don't want to implicitly create a context that we're about to kill */
1086 LOG (GNUNET_ERROR_TYPE_DEBUG,
1087 "channel (%s) without associated context was destroyed\n",
1091 peer_ctx = get_peer_ctx (peer);
1093 /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1094 * flag will be set. In this case simply make sure that the channels are
1096 if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1097 {/* We initiatad the destruction of this particular peer */
1098 if (channel == peer_ctx->send_channel)
1099 peer_ctx->send_channel = NULL;
1100 else if (channel == peer_ctx->recv_channel)
1101 peer_ctx->recv_channel = NULL;
1102 (void) Peers_check_connected (peer);
1107 { /* We did not initiate the destruction of this peer */
1108 if (channel == peer_ctx->send_channel)
1109 { /* Something (but us) killd the channel - clean up peer */
1110 LOG (GNUNET_ERROR_TYPE_DEBUG,
1111 "send channel (%s) was destroyed - cleaning up\n",
1113 peer_ctx->send_channel = NULL;
1115 else if (channel == peer_ctx->recv_channel)
1116 { /* Other peer doesn't want to send us messages anymore */
1117 LOG (GNUNET_ERROR_TYPE_DEBUG,
1118 "Peer %s destroyed recv channel - cleaning up channel\n",
1120 peer_ctx->recv_channel = NULL;
1124 LOG (GNUNET_ERROR_TYPE_WARNING,
1125 "unknown channel (%s) was destroyed\n",
1129 (void) Peers_check_connected (peer);
1133 * @brief Issue a check whether peer is live
1135 * This tries to establish a channel to the given peer. Once the channel is
1136 * established successfully, we know the peer is live.
1138 * @param peer the peer to check liveliness
1141 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1143 struct PeerContext *peer_ctx;
1145 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1147 return; /* We know that we are online */
1150 peer_ctx = create_or_get_peer_ctx (peer);
1151 // TODO if LIVE/ONLINE
1152 check_peer_live (peer_ctx);
1156 * @brief Send a message to another peer.
1158 * Keeps track about pending messages so they can be properly removed when the
1159 * peer is destroyed.
1161 * @param peer receeiver of the message
1162 * @param ev envelope of the message
1163 * @param type type of the message
1166 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1167 struct GNUNET_MQ_Envelope *ev,
1170 struct PendingMessage *pending_msg;
1171 struct GNUNET_MQ_Handle *mq;
1173 pending_msg = insert_pending_message (peer, ev, "PULL REPLY");
1175 GNUNET_MQ_notify_sent (ev,
1178 GNUNET_MQ_send (mq, ev);
1182 * @brief Schedule a operation on given peer
1184 * Avoids scheduling an operation twice.
1186 * @param peer the peer we want to schedule the operation for once it gets live
1188 * @return #GNUNET_YES if the operation was scheduled
1189 * #GNUNET_NO otherwise
1192 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1193 const PeerOp peer_op)
1195 struct PeerPendingOp pending_op;
1196 struct PeerContext *peer_ctx;
1198 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1202 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1204 //TODO if LIVE/ONLINE execute immediately
1206 if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1208 peer_ctx = get_peer_ctx (peer);
1209 pending_op.op = peer_op;
1210 pending_op.op_cls = NULL;
1211 GNUNET_array_append (peer_ctx->pending_ops,
1212 peer_ctx->num_pending_ops,
1219 /* end of gnunet-service-rps_peers.c */