rps: keep track of valid peers in peermap
[oweals/gnunet.git] / src / rps / gnunet-service-rps_peers.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file rps/gnunet-service-rps_peers.c
23  * @brief utilities for managing (information about) peers
24  * @author Julius Bünger
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_cadet_service.h"
29 #include <inttypes.h>
30 #include "rps.h"
31 #include "gnunet-service-rps_peers.h"
32
33
34
35 #define LOG(kind, ...) GNUNET_log(kind, __VA_ARGS__)
36
37
38 /**
39  * Set a peer flag of given peer context.
40  */
41 #define set_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) |= (mask))
42
43 /**
44  * Get peer flag of given peer context.
45  */
46 #define check_peer_flag_set(peer_ctx, mask)\
47   ((peer_ctx->peer_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
48
49 /**
50  * Unset flag of given peer context.
51  */
52 #define unset_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) &= ~(mask))
53
54 /**
55  * Set a channel flag of given channel context.
56  */
57 #define set_channel_flag(channel_flags, mask) ((*channel_flags) |= (mask))
58
59 /**
60  * Get channel flag of given channel context.
61  */
62 #define check_channel_flag_set(channel_flags, mask)\
63   ((*channel_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
64
65 /**
66  * Unset flag of given channel context.
67  */
68 #define unset_channel_flag(channel_flags, mask) ((*channel_flags) &= ~(mask))
69
70
71
72 /**
73  * Pending operation on peer consisting of callback and closure
74  *
75  * When an operation cannot be executed right now this struct is used to store
76  * the callback and closure for later execution.
77  */
78 struct PeerPendingOp
79 {
80   /**
81    * Callback
82    */
83   PeerOp op;
84
85   /**
86    * Closure
87    */
88   void *op_cls;
89 };
90
91 /**
92  * List containing all messages that are yet to be send
93  *
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.
96  */
97 struct PendingMessage
98 {
99   /**
100    * DLL next, prev
101    */
102   struct PendingMessage *next;
103   struct PendingMessage *prev;
104
105   /**
106    * The envelope to the corresponding message
107    */
108   struct GNUNET_MQ_Envelope *ev;
109
110   /**
111    * The corresponding context
112    */
113   struct PeerContext *peer_ctx;
114
115   /**
116    * The message type
117    */
118   const char *type;
119 };
120
121 /**
122  * Struct used to keep track of other peer's status
123  *
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, ...)
128  */
129 struct PeerContext
130 {
131   /**
132    * Message queue open to client
133    */
134   struct GNUNET_MQ_Handle *mq;
135
136   /**
137    * Channel open to client.
138    */
139   struct GNUNET_CADET_Channel *send_channel;
140
141   /**
142    * Flags to the sending channel
143    */
144   uint32_t *send_channel_flags;
145
146   /**
147    * Channel open from client.
148    */
149   struct GNUNET_CADET_Channel *recv_channel; // unneeded?
150
151   /**
152    * Flags to the receiving channel
153    */
154   uint32_t *recv_channel_flags;
155
156   /**
157    * Array of pending operations on this peer.
158    */
159   struct PeerPendingOp *pending_ops;
160
161   /**
162    * Handle to the callback given to cadet_ntfy_tmt_rdy()
163    *
164    * To be canceled on shutdown.
165    */
166   struct GNUNET_CADET_TransmitHandle *transmit_handle;
167
168   /**
169    * Number of pending operations.
170    */
171   unsigned int num_pending_ops;
172
173   /**
174    * Identity of the peer
175    */
176   struct GNUNET_PeerIdentity peer_id;
177   
178   /**
179    * Flags indicating status of peer
180    */
181   uint32_t peer_flags;
182
183   /**
184    * Last time we received something from that peer.
185    */
186   struct GNUNET_TIME_Absolute last_message_recv;
187
188   /**
189    * Last time we received a keepalive message.
190    */
191   struct GNUNET_TIME_Absolute last_keepalive;
192
193   /**
194    * DLL with all messages that are yet to be sent
195    */
196   struct PendingMessage *pending_messages_head;
197   struct PendingMessage *pending_messages_tail;
198
199   /**
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),
202    * ...)
203    */
204 };
205
206 /**
207  * @brief Hashmap of valid peers.
208  */
209 static struct GNUNET_CONTAINER_MultiPeerMap *valid_peers;
210
211 /**
212  * @brief Maximum number of valid peers to keep.
213  * TODO read from config
214  */
215 static uint32_t num_valid_peers_max = UINT32_MAX;
216
217 /**
218  * Set of all peers to keep track of them.
219  */
220 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
221
222 /**
223  * Own #GNUNET_PeerIdentity.
224  */
225 static const struct GNUNET_PeerIdentity *own_identity;
226
227 /**
228  * Cadet handle.
229  */
230 static struct GNUNET_CADET_Handle *cadet_handle;
231
232
233 /**
234  * @brief Get the #PeerContext associated with a peer
235  *
236  * @param peer the peer id
237  *
238  * @return the #PeerContext
239  */
240 static struct PeerContext *
241 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
242 {
243   struct PeerContext *ctx;
244   int ret;
245
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);
250   return ctx;
251 }
252
253 /**
254  * @brief Create a new #PeerContext and insert it into the peer map
255  *
256  * @param peer the peer to create the #PeerContext for
257  *
258  * @return the #PeerContext
259  */
260 static struct PeerContext *
261 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
262 {
263   struct PeerContext *ctx;
264   int ret;
265
266   GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
267
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);
275   return ctx;
276 }
277
278 /**
279  * @brief Create or get a #PeerContext
280  *
281  * @param peer the peer to get the associated context to
282  *
283  * @return the context
284  */
285 static struct PeerContext *
286 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
287 {
288   if (GNUNET_NO == Peers_check_peer_known (peer))
289   {
290     return create_peer_ctx (peer);
291   }
292   return get_peer_ctx (peer);
293 }
294
295 /**
296  * @brief Check whether we have a connection to this @a peer
297  *
298  * Also sets the #Peers_ONLINE flag accordingly
299  *
300  * @param peer the peer in question
301  *
302  * @return #GNUNET_YES if we are connected
303  *         #GNUNET_NO  otherwise
304  */
305 int
306 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
307 {
308   const struct PeerContext *peer_ctx;
309
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))
312   {
313     return GNUNET_NO;
314   }
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) )
320   {
321     Peers_unset_peer_flag (peer, Peers_ONLINE);
322     return GNUNET_NO;
323   }
324   /* Otherwise (if we have a channel, we know that it's online */
325   Peers_set_peer_flag (peer, Peers_ONLINE);
326   return GNUNET_YES;
327 }
328
329 /**
330  * @brief The closure to #get_rand_peer_iterator.
331  */
332 struct GetRandPeerIteratorCls
333 {
334   /**
335    * @brief The index of the peer to return.
336    * Will be decreased until 0.
337    * Then current peer is returned.
338    */
339   uint32_t index;
340
341   /**
342    * @brief Pointer to peer to return.
343    */
344   const struct GNUNET_PeerIdentity *peer;
345 };
346
347 /**
348  * @brief Iterator function for #get_random_peer_from_peermap.
349  *
350  * Implements #GNUNET_CONTAINER_PeerMapIterator.
351  * Decreases the index until the index is null.
352  * Then returns the current peer.
353  *
354  * @param cls the #GetRandPeerIteratorCls containing index and peer
355  * @param peer current peer
356  * @param value unused
357  *
358  * @return  #GNUNET_YES if we should continue to
359  *          iterate,
360  *          #GNUNET_NO if not.
361  */
362 static int
363 get_rand_peer_iterator (void *cls,
364                         const struct GNUNET_PeerIdentity *peer,
365                         void *value)
366 {
367   struct GetRandPeerIteratorCls *iterator_cls = cls;
368   if (0 >= iterator_cls->index)
369   {
370     iterator_cls->peer = peer;
371     return GNUNET_NO;
372   }
373   iterator_cls->index--;
374   return GNUNET_YES;
375 }
376
377 /**
378  * @brief Get a random peer from @a peer_map
379  *
380  * @param peer_map the peer_map to get the peer from
381  *
382  * @return a random peer
383  */
384 static const struct GNUNET_PeerIdentity *
385 get_random_peer_from_peermap (const struct
386                               GNUNET_CONTAINER_MultiPeerMap *peer_map)
387 {
388   uint32_t rand_index;
389   struct GetRandPeerIteratorCls *iterator_cls;
390   const struct GNUNET_PeerIdentity *ret;
391
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,
397                                                 iterator_cls);
398   ret = iterator_cls->peer;
399   GNUNET_free (iterator_cls);
400   return ret;
401 }
402
403 /**
404  * @brief Add a given @a peer to valid peers.
405  *
406  * If valid peers are already #num_valid_peers_max, delete a peer previously.
407  *
408  * @param peer the peer that is added to the valid peers.
409  *
410  * @return #GNUNET_YES if no other peer had to be removed
411  *         #GNUNET_NO  otherwise
412  */
413 static int
414 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
415 {
416   const struct GNUNET_PeerIdentity *rand_peer;
417   int ret;
418
419   ret = GNUNET_YES;
420   while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
421   {
422     rand_peer = get_random_peer_from_peermap (valid_peers);
423     GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
424     ret = GNUNET_NO;
425   }
426   (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
427       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
428   return ret;
429 }
430
431 /**
432  * @brief Set the peer flag to living and
433  *        call the pending operations on this peer.
434  *
435  * Also adds peer to #valid_peers.
436  *
437  * @param peer_ctx the #PeerContext of the peer to set live
438  */
439 static void
440 set_peer_live (struct PeerContext *peer_ctx)
441 {
442   struct GNUNET_PeerIdentity *peer;
443   unsigned int i;
444
445   /* Cancle cadet transmit_handle if still scheduled */
446   if (NULL != peer_ctx->transmit_handle)
447   {
448     GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
449     peer_ctx->transmit_handle = NULL;
450   }
451
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",
457       GNUNET_i2s (peer));
458
459   /* Call pending operations */
460   for (i = 0; i < peer_ctx->num_pending_ops; i++)
461   {
462     peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
463   }
464   GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
465 }
466
467 /**
468  * @brief Get the channel of a peer. If not existing, create.
469  *
470  * @param peer the peer id
471  * @return the #GNUNET_CADET_Channel used to send data to @a peer
472  */
473 struct GNUNET_CADET_Channel *
474 get_channel (const struct GNUNET_PeerIdentity *peer)
475 {
476   struct PeerContext *peer_ctx;
477
478   peer_ctx = get_peer_ctx (peer);
479   if (NULL == peer_ctx->send_channel)
480   {
481     LOG (GNUNET_ERROR_TYPE_DEBUG,
482          "Trying to establish channel to peer %s\n",
483          GNUNET_i2s (peer));
484     peer_ctx->send_channel =
485       GNUNET_CADET_channel_create (cadet_handle,
486                                    peer_ctx->send_channel_flags, /* context */
487                                    peer,
488                                    GNUNET_RPS_CADET_PORT,
489                                    GNUNET_CADET_OPTION_RELIABLE);
490   }
491   return peer_ctx->send_channel;
492 }
493
494 /**
495  * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
496  *
497  * If we already have a message queue open to this client,
498  * simply return it, otherways create one.
499  * 
500  * @param peer the peer to get the mq to
501  * @return the #GNUNET_MQ_Handle
502  */
503 static struct GNUNET_MQ_Handle *
504 get_mq (const struct GNUNET_PeerIdentity *peer)
505 {
506   struct PeerContext *peer_ctx;
507
508   peer_ctx = get_peer_ctx (peer);
509   GNUNET_assert (NULL == peer_ctx->transmit_handle);
510
511   if (NULL == peer_ctx->mq)
512   {
513     (void) get_channel (peer);
514     peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
515   }
516   return peer_ctx->mq;
517 }
518
519 /**
520  * @brief Callback that is called when a channel was effectively established.
521  *
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.
525  *
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
529  * cadet channel.
530  *
531  * @a buf will be NULL and @a size zero if the
532  * connection was closed for writing in the meantime.
533  *
534  * @param cls closure
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
538  */
539 //TODO
540 static size_t
541 cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
542 {
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
546
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));
551
552   if ( (NULL != buf) &&
553        (0 != size) )
554   {
555     set_peer_live (peer_ctx);
556   }
557   else
558   {
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?
563   }
564   return 0;
565 }
566
567 /**
568  * Issue a check whether peer is live
569  *
570  * @param peer_ctx the context of the peer
571  */
572 static void
573 check_peer_live (struct PeerContext *peer_ctx)
574 {
575   LOG (GNUNET_ERROR_TYPE_DEBUG,
576        "Get informed about peer %s getting live\n",
577        GNUNET_i2s (&peer_ctx->peer_id));
578
579   if (NULL == peer_ctx->transmit_handle &&
580       NULL == peer_ctx->send_channel)
581   {
582     (void) get_channel (&peer_ctx->peer_id);
583     peer_ctx->transmit_handle =
584         GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
585                                             GNUNET_NO,
586                                             GNUNET_TIME_UNIT_FOREVER_REL,
587                                             sizeof (struct GNUNET_MessageHeader),
588                                             cadet_notify_transmit_ready_cb,
589                                             peer_ctx);
590   }
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");
597 }
598
599 /**
600  * @brief Add an envelope to a message passed to mq to list of pending messages
601  *
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
606  */
607 static struct PendingMessage *
608 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
609                         struct GNUNET_MQ_Envelope *ev,
610                         const char *type)
611 {
612   struct PendingMessage *pending_msg;
613   struct PeerContext *peer_ctx;
614
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,
622                                pending_msg);
623   return pending_msg;
624 }
625
626 /**
627  * @brief Remove a pending message from the respective DLL
628  *
629  * @param pending_msg the pending message to remove
630  */
631 static void
632 remove_pending_message (struct PendingMessage *pending_msg)
633 {
634   struct PeerContext *peer_ctx;
635
636   peer_ctx = pending_msg->peer_ctx;
637   GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
638                                peer_ctx->pending_messages_tail,
639                                pending_msg);
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);
644 }
645
646 /**
647  * @brief Check whether function of type #PeerOp was already scheduled
648  *
649  * The array with pending operations will probably never grow really big, so
650  * iterating over it should be ok.
651  *
652  * @param peer the peer to check
653  * @param peer_op the operation (#PeerOp) on the peer
654  *
655  * @return #GNUNET_YES if this operation is scheduled on that peer
656  *         #GNUNET_NO  otherwise
657  */
658 static int
659 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
660                            const PeerOp peer_op)
661 {
662   const struct PeerContext *peer_ctx;
663   unsigned int i;
664
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)
668       return GNUNET_YES;
669   return GNUNET_NO;
670 }
671
672 /**
673  * Iterator over hash map entries. Deletes all contexts of peers.
674  *
675  * @param cls closure
676  * @param key current public key
677  * @param value value in the hash map
678  * @return #GNUNET_YES if we should continue to iterate,
679  *         #GNUNET_NO if not.
680  */
681 static int
682 peermap_clear_iterator (void *cls,
683                         const struct GNUNET_PeerIdentity *key,
684                         void *value)
685 {
686   Peers_remove_peer (key);
687   return GNUNET_YES;
688 }
689
690 /**
691  * @brief This is called once a message is sent.
692  *
693  * Removes the pending message
694  *
695  * @param cls type of the message that was sent
696  */
697 static void
698 mq_notify_sent_cb (void *cls)
699 {
700   struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
701   LOG (GNUNET_ERROR_TYPE_DEBUG,
702       "%s was sent.\n",
703       pending_msg->type);
704   remove_pending_message (pending_msg);
705 }
706
707
708 /**
709  * @brief Initialise storage of peers
710  *
711  * @param cadet_h cadet handle
712  * @param own_id own peer identity
713  */
714 void
715 Peers_initialise (struct GNUNET_CADET_Handle *cadet_h,
716                   const struct GNUNET_PeerIdentity *own_id)
717 {
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);
722 }
723
724 // TODO read stored valid peers
725
726 /**
727  * @brief Delete storage of peers that was created with #Peers_initialise ()
728  */
729 void
730 Peers_terminate ()
731 {
732   if (GNUNET_SYSERR ==
733       GNUNET_CONTAINER_multipeermap_iterate (peer_map,
734                                              peermap_clear_iterator,
735                                              NULL))
736   {
737     LOG (GNUNET_ERROR_TYPE_WARNING,
738         "Iteration destroying peers was aborted.\n");
739   }
740   GNUNET_CONTAINER_multipeermap_destroy (peer_map);
741   GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
742 }
743
744 // TODO store valid peers
745
746 /**
747  * @brief Add peer to known peers.
748  *
749  * This function is called on new peer_ids from 'external' sources
750  * (client seed, cadet get_peers(), ...)
751  *
752  * @param peer the new #GNUNET_PeerIdentity
753  *
754  * @return #GNUNET_YES if peer was inserted
755  *         #GNUNET_NO  if peer was already known
756  */
757 int
758 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
759 {
760   if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
761        (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
762   {
763     return GNUNET_NO; /* We already know this peer - nothing to do */
764   }
765   (void) create_peer_ctx (peer);
766   return GNUNET_YES;
767 }
768
769
770 /**
771  * @brief Add peer to known peers and check for liveliness.
772  *
773  * This function is called on new peer_ids from 'external' sources
774  * (client seed, cadet get_peers(), ...)
775  *
776  * @param peer the new #GNUNET_PeerIdentity
777  *
778  * @return #GNUNET_YES if peer was inserted
779  *         #GNUNET_NO  if peer was already known
780  */
781 int
782 Peers_insert_peer_check_liveliness (const struct GNUNET_PeerIdentity *peer)
783 {
784   struct PeerContext *peer_ctx;
785   int ret;
786
787   ret = Peers_insert_peer (peer);
788   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
789   {
790     return ret;
791   }
792   peer_ctx = get_peer_ctx (peer);
793   if (GNUNET_NO == Peers_check_peer_valid (peer))
794   {
795     check_peer_live (peer_ctx);
796   }
797   return ret;
798 }
799
800 /**
801  * @brief Remove unecessary data
802  *
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).
806  *
807  * @param peer the peer to clean
808  * @return #GNUNET_YES if peer was removed
809  *         #GNUNET_NO  otherwise
810  */
811 int
812 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
813 {
814   struct PeerContext *peer_ctx;
815
816   // TODO actually remove unnecessary data
817
818   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer)) 
819   {
820     return GNUNET_NO;
821   }
822
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)) )
827   {
828     return GNUNET_NO;
829   }
830   Peers_remove_peer (peer);
831   return GNUNET_YES;
832 }
833
834 /**
835  * @brief Remove peer
836  * 
837  * @param peer the peer to clean
838  * @return #GNUNET_YES if peer was removed
839  *         #GNUNET_NO  otherwise
840  */
841 int
842 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
843 {
844   struct PeerContext *peer_ctx;
845
846   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer)) 
847   {
848     return GNUNET_NO;
849   }
850
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);
857
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)
862   {
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);
867   }
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)
871   {
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;
877   }
878   if (NULL != peer_ctx->send_channel)
879   {
880     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
881     peer_ctx->send_channel = NULL;
882   }
883   if (NULL != peer_ctx->recv_channel)
884   {
885     GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
886     peer_ctx->recv_channel = NULL;
887   }
888   if (NULL != peer_ctx->mq)
889   {
890     GNUNET_MQ_destroy (peer_ctx->mq);
891     peer_ctx->mq = NULL;
892   }
893
894   GNUNET_free (peer_ctx->send_channel_flags);
895   GNUNET_free (peer_ctx->recv_channel_flags);
896
897   if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
898   {
899     LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
900   }
901   GNUNET_free (peer_ctx);
902   return GNUNET_YES;
903 }
904
905 /**
906  * @brief set flags on a given peer.
907  *
908  * @param peer the peer to set flags on
909  * @param flags the flags
910  */
911 void
912 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
913 {
914   struct PeerContext *peer_ctx;
915
916   peer_ctx = get_peer_ctx (peer);
917   set_peer_flag (peer_ctx, flags);
918 }
919
920 /**
921  * @brief unset flags on a given peer.
922  *
923  * @param peer the peer to unset flags on
924  * @param flags the flags
925  */
926 void
927 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
928 {
929   struct PeerContext *peer_ctx;
930
931   peer_ctx = get_peer_ctx (peer);
932   unset_peer_flag (peer_ctx, flags);
933 }
934
935 /**
936  * @brief Check whether flags on a peer are set.
937  *
938  * @param peer the peer to check the flag of
939  * @param flags the flags to check
940  *
941  * @return #GNUNET_YES if all given flags are set
942  *         #GNUNET_NO  otherwise
943  */
944 int
945 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
946 {
947   struct PeerContext *peer_ctx;
948
949   peer_ctx = get_peer_ctx (peer);
950   return check_peer_flag_set (peer_ctx, flags);
951 }
952
953
954 /**
955  * @brief set flags on a given channel.
956  *
957  * @param channel the channel to set flags on
958  * @param flags the flags
959  */
960 void
961 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
962 {
963   set_channel_flag (channel_flags, flags);
964 }
965
966 /**
967  * @brief unset flags on a given channel.
968  *
969  * @param channel the channel to unset flags on
970  * @param flags the flags
971  */
972 void
973 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
974 {
975   unset_channel_flag (channel_flags, flags);
976 }
977
978 /**
979  * @brief Check whether flags on a channel are set.
980  *
981  * @param channel the channel to check the flag of
982  * @param flags the flags to check
983  *
984  * @return #GNUNET_YES if all given flags are set
985  *         #GNUNET_NO  otherwise
986  */
987 int
988 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
989 {
990   return check_channel_flag_set (channel_flags, flags);
991 }
992
993 /**
994  * @brief Check whether we have information about the given peer.
995  *
996  * FIXME probably deprecated. Make this the new _online.
997  *
998  * @param peer peer in question
999  *
1000  * @return #GNUNET_YES if peer is known
1001  *         #GNUNET_NO  if peer is not knwon
1002  */
1003 int
1004 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1005 {
1006   return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1007 }
1008
1009 /**
1010  * @brief Check whether @a peer is actually a peer.
1011  *
1012  * A valid peer is a peer that we know exists eg. we were connected to once.
1013  *
1014  * @param peer peer in question
1015  *
1016  * @return #GNUNET_YES if peer is valid
1017  *         #GNUNET_NO  if peer is not valid
1018  */
1019 int
1020 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1021 {
1022   return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1023 }
1024
1025 /**
1026  * @brief Indicate that we want to send to the other peer
1027  *
1028  * This establishes a sending channel
1029  *
1030  * @param peer the peer to establish channel to
1031  */
1032 void
1033 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1034 {
1035   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1036   (void) get_channel (peer);
1037 }
1038
1039 /**
1040  * @brief Check whether other peer has the intention to send/opened channel
1041  *        towars us
1042  *
1043  * @param peer the peer in question
1044  *
1045  * @return #GNUNET_YES if peer has the intention to send
1046  *         #GNUNET_NO  otherwise
1047  */
1048 int
1049 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1050 {
1051   const struct PeerContext *peer_ctx;
1052
1053   peer_ctx = get_peer_ctx (peer);
1054   if (NULL != peer_ctx->recv_channel)
1055   {
1056     return GNUNET_YES;
1057   }
1058   return GNUNET_NO;
1059 }
1060
1061 /**
1062  * Handle the channel a peer opens to us.
1063  *
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
1069  *
1070  * @return initial channel context for the channel
1071  *         (can be NULL -- that's not an error)
1072  */
1073 void *
1074 Peers_handle_inbound_channel (void *cls,
1075                               struct GNUNET_CADET_Channel *channel,
1076                               const struct GNUNET_PeerIdentity *initiator,
1077                               uint32_t port,
1078                               enum GNUNET_CADET_ChannelOption options)
1079 {
1080   struct PeerContext *peer_ctx;
1081
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))
1091   {
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;
1097   }
1098   peer_ctx->recv_channel = channel;
1099   return peer_ctx->recv_channel_flags;
1100 }
1101
1102 /**
1103  * @brief Check whether a sending channel towards the given peer exists
1104  *
1105  * @param peer the peer to check for
1106  *
1107  * @return #GNUNET_YES if a sending channel towards that peer exists
1108  *         #GNUNET_NO  otherwise
1109  */
1110 int
1111 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1112 {
1113   struct PeerContext *peer_ctx;
1114
1115   if (GNUNET_NO == Peers_check_peer_known (peer))
1116   { /* If no such peer exists, there is no channel */
1117     return GNUNET_NO;
1118   }
1119   peer_ctx = get_peer_ctx (peer);
1120   if (NULL == peer_ctx->send_channel)
1121   {
1122     return GNUNET_NO;
1123   }
1124   return GNUNET_YES;
1125 }
1126
1127 /**
1128  * @brief check whether the given channel is the sending channel of the given
1129  *        peer
1130  *
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
1135  *
1136  * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1137  *         #GNUNET_NO  otherwise
1138  */
1139 int
1140 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1141                           const struct GNUNET_CADET_Channel *channel,
1142                           enum Peers_ChannelRole role)
1143 {
1144   const struct PeerContext *peer_ctx;
1145
1146   if (GNUNET_NO == Peers_check_peer_known (peer))
1147   {
1148     return GNUNET_NO;
1149   }
1150   peer_ctx = get_peer_ctx (peer);
1151   if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1152        (channel == peer_ctx->send_channel) )
1153   {
1154     return GNUNET_YES;
1155   }
1156   if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1157        (channel == peer_ctx->recv_channel) )
1158   {
1159     return GNUNET_YES;
1160   }
1161   return GNUNET_NO;
1162 }
1163
1164 /**
1165  * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1166  *        intention to another peer
1167  *
1168  * If there is also no channel to receive messages from that peer, remove it
1169  * from the peermap.
1170  * TODO really?
1171  *
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
1175  */
1176 int
1177 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1178 {
1179   struct PeerContext *peer_ctx;
1180
1181   if (GNUNET_NO == Peers_check_peer_known (peer))
1182   {
1183     return GNUNET_NO;
1184   }
1185   peer_ctx = get_peer_ctx (peer);
1186   if (NULL != peer_ctx->send_channel)
1187   {
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);
1192     return GNUNET_YES;
1193   }
1194   return GNUNET_NO;
1195 }
1196
1197 /**
1198  * This is called when a channel is destroyed.
1199  *
1200  * @param cls The closure
1201  * @param channel The channel being closed
1202  * @param channel_ctx The context associated with this channel
1203  */
1204 void
1205 Peers_cleanup_destroyed_channel (void *cls,
1206                                  const struct GNUNET_CADET_Channel *channel,
1207                                  void *channel_ctx)
1208 {
1209   struct GNUNET_PeerIdentity *peer;
1210   struct PeerContext *peer_ctx;
1211
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
1215
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",
1220        GNUNET_i2s (peer));
1221     return;
1222   }
1223   peer_ctx = get_peer_ctx (peer);
1224
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
1227    * cleaned. */
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);
1236     return;
1237   }
1238
1239   else
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",
1245           GNUNET_i2s (peer));
1246       peer_ctx->send_channel = NULL;
1247     }
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",
1252            GNUNET_i2s (peer));
1253       peer_ctx->recv_channel = NULL;
1254     }
1255     else
1256     {
1257       LOG (GNUNET_ERROR_TYPE_WARNING,
1258            "unknown channel (%s) was destroyed\n",
1259            GNUNET_i2s (peer));
1260     }
1261   }
1262   (void) Peers_check_connected (peer);
1263 }
1264
1265 /**
1266  * @brief Issue a check whether peer is live
1267  *
1268  * This tries to establish a channel to the given peer. Once the channel is
1269  * established successfully, we know the peer is live.
1270  *
1271  * @param peer the peer to check liveliness
1272  */
1273 void
1274 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1275 {
1276   struct PeerContext *peer_ctx;
1277
1278   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1279   {
1280     return; /* We know that we are online */
1281   }
1282
1283   peer_ctx = create_or_get_peer_ctx (peer);
1284   // TODO if LIVE/ONLINE
1285   check_peer_live (peer_ctx);
1286 }
1287
1288 /**
1289  * @brief Send a message to another peer.
1290  *
1291  * Keeps track about pending messages so they can be properly removed when the
1292  * peer is destroyed.
1293  *
1294  * @param peer receeiver of the message
1295  * @param ev envelope of the message
1296  * @param type type of the message
1297  */
1298 void
1299 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1300                     struct GNUNET_MQ_Envelope *ev,
1301                     const char *type)
1302 {
1303   struct PendingMessage *pending_msg;
1304   struct GNUNET_MQ_Handle *mq;
1305
1306   pending_msg = insert_pending_message (peer, ev, "PULL REPLY");
1307   mq = get_mq (peer);
1308   GNUNET_MQ_notify_sent (ev,
1309                          mq_notify_sent_cb,
1310                          pending_msg);
1311   GNUNET_MQ_send (mq, ev);
1312 }
1313
1314 /**
1315  * @brief Schedule a operation on given peer
1316  *
1317  * Avoids scheduling an operation twice.
1318  *
1319  * @param peer the peer we want to schedule the operation for once it gets live
1320  *
1321  * @return #GNUNET_YES if the operation was scheduled
1322  *         #GNUNET_NO  otherwise
1323  */
1324 int
1325 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1326                           const PeerOp peer_op)
1327 {
1328   struct PeerPendingOp pending_op;
1329   struct PeerContext *peer_ctx;
1330
1331   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1332   {
1333     return GNUNET_NO;
1334   }
1335   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1336
1337   //TODO if LIVE/ONLINE execute immediately
1338
1339   if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1340   {
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,
1346                          pending_op);
1347     return GNUNET_YES;
1348   }
1349   return GNUNET_NO;
1350 }
1351
1352 /* end of gnunet-service-rps_peers.c */