933e3cb8735ed336c9c1359156cba4857f47e691
[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_applications.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_cadet_service.h"
30 #include <inttypes.h>
31 #include "rps.h"
32 #include "gnunet-service-rps_peers.h"
33
34
35
36 #define LOG(kind, ...) GNUNET_log_from(kind,"rps-peers",__VA_ARGS__)
37
38
39 /**
40  * Set a peer flag of given peer context.
41  */
42 #define set_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) |= (mask))
43
44 /**
45  * Get peer flag of given peer context.
46  */
47 #define check_peer_flag_set(peer_ctx, mask)\
48   ((peer_ctx->peer_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
49
50 /**
51  * Unset flag of given peer context.
52  */
53 #define unset_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) &= ~(mask))
54
55 /**
56  * Set a channel flag of given channel context.
57  */
58 #define set_channel_flag(channel_flags, mask) ((*channel_flags) |= (mask))
59
60 /**
61  * Get channel flag of given channel context.
62  */
63 #define check_channel_flag_set(channel_flags, mask)\
64   ((*channel_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
65
66 /**
67  * Unset flag of given channel context.
68  */
69 #define unset_channel_flag(channel_flags, mask) ((*channel_flags) &= ~(mask))
70
71
72
73 /**
74  * Pending operation on peer consisting of callback and closure
75  *
76  * When an operation cannot be executed right now this struct is used to store
77  * the callback and closure for later execution.
78  */
79 struct PeerPendingOp
80 {
81   /**
82    * Callback
83    */
84   PeerOp op;
85
86   /**
87    * Closure
88    */
89   void *op_cls;
90 };
91
92 /**
93  * List containing all messages that are yet to be send
94  *
95  * This is used to keep track of all messages that have not been sent yet. When
96  * a peer is to be removed the pending messages can be removed properly.
97  */
98 struct PendingMessage
99 {
100   /**
101    * DLL next, prev
102    */
103   struct PendingMessage *next;
104   struct PendingMessage *prev;
105
106   /**
107    * The envelope to the corresponding message
108    */
109   struct GNUNET_MQ_Envelope *ev;
110
111   /**
112    * The corresponding context
113    */
114   struct PeerContext *peer_ctx;
115
116   /**
117    * The message type
118    */
119   const char *type;
120 };
121
122 /**
123  * Struct used to keep track of other peer's status
124  *
125  * This is stored in a multipeermap.
126  * It contains information such as cadet channels, a message queue for sending,
127  * status about the channels, the pending operations on this peer and some flags
128  * about the status of the peer itself. (live, valid, ...)
129  */
130 struct PeerContext
131 {
132   /**
133    * Message queue open to client
134    */
135   struct GNUNET_MQ_Handle *mq;
136
137   /**
138    * Channel open to client.
139    */
140   struct GNUNET_CADET_Channel *send_channel;
141
142   /**
143    * Flags to the sending channel
144    */
145   uint32_t *send_channel_flags;
146
147   /**
148    * Channel open from client.
149    */
150   struct GNUNET_CADET_Channel *recv_channel; // unneeded?
151
152   /**
153    * Flags to the receiving channel
154    */
155   uint32_t *recv_channel_flags;
156
157   /**
158    * Array of pending operations on this peer.
159    */
160   struct PeerPendingOp *pending_ops;
161
162   /**
163    * Handle to the callback given to cadet_ntfy_tmt_rdy()
164    *
165    * To be canceled on shutdown.
166    */
167   struct PendingMessage *liveliness_check_pending;
168
169   /**
170    * Number of pending operations.
171    */
172   unsigned int num_pending_ops;
173
174   /**
175    * Identity of the peer
176    */
177   struct GNUNET_PeerIdentity peer_id;
178
179   /**
180    * Flags indicating status of peer
181    */
182   uint32_t peer_flags;
183
184   /**
185    * Last time we received something from that peer.
186    */
187   struct GNUNET_TIME_Absolute last_message_recv;
188
189   /**
190    * Last time we received a keepalive message.
191    */
192   struct GNUNET_TIME_Absolute last_keepalive;
193
194   /**
195    * DLL with all messages that are yet to be sent
196    */
197   struct PendingMessage *pending_messages_head;
198   struct PendingMessage *pending_messages_tail;
199
200   /**
201    * This is pobably followed by 'statistical' data (when we first saw
202    * him, how did we get his ID, how many pushes (in a timeinterval),
203    * ...)
204    */
205 };
206
207 /**
208  * @brief Closure to #valid_peer_iterator
209  */
210 struct PeersIteratorCls
211 {
212   /**
213    * Iterator function
214    */
215   PeersIterator iterator;
216
217   /**
218    * Closure to iterator
219    */
220   void *cls;
221 };
222
223 /**
224  * @brief Hashmap of valid peers.
225  */
226 static struct GNUNET_CONTAINER_MultiPeerMap *valid_peers;
227
228 /**
229  * @brief Maximum number of valid peers to keep.
230  * TODO read from config
231  */
232 static uint32_t num_valid_peers_max = UINT32_MAX;
233
234 /**
235  * @brief Filename of the file that stores the valid peers persistently.
236  */
237 static char *filename_valid_peers;
238
239 /**
240  * Set of all peers to keep track of them.
241  */
242 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
243
244 /**
245  * Own #GNUNET_PeerIdentity.
246  */
247 static const struct GNUNET_PeerIdentity *own_identity;
248
249 /**
250  * Cadet handle.
251  */
252 static struct GNUNET_CADET_Handle *cadet_handle;
253
254 /**
255  * @brief Disconnect handler
256  */
257 static GNUNET_CADET_DisconnectEventHandler cleanup_destroyed_channel;
258
259 /**
260  * @brief cadet handlers
261  */
262 static const struct GNUNET_MQ_MessageHandler *cadet_handlers;
263
264
265
266 /**
267  * @brief Get the #PeerContext associated with a peer
268  *
269  * @param peer the peer id
270  *
271  * @return the #PeerContext
272  */
273 static struct PeerContext *
274 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
275 {
276   struct PeerContext *ctx;
277   int ret;
278
279   ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
280   GNUNET_assert (GNUNET_YES == ret);
281   ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
282   GNUNET_assert (NULL != ctx);
283   return ctx;
284 }
285
286
287 /**
288  * @brief Create a new #PeerContext and insert it into the peer map
289  *
290  * @param peer the peer to create the #PeerContext for
291  *
292  * @return the #PeerContext
293  */
294 static struct PeerContext *
295 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
296 {
297   struct PeerContext *ctx;
298   int ret;
299
300   GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
301
302   ctx = GNUNET_new (struct PeerContext);
303   ctx->peer_id = *peer;
304   ctx->send_channel_flags = GNUNET_new (uint32_t);
305   ctx->recv_channel_flags = GNUNET_new (uint32_t);
306   ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
307       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
308   GNUNET_assert (GNUNET_OK == ret);
309   return ctx;
310 }
311
312
313 /**
314  * @brief Create or get a #PeerContext
315  *
316  * @param peer the peer to get the associated context to
317  *
318  * @return the context
319  */
320 static struct PeerContext *
321 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
322 {
323   if (GNUNET_NO == Peers_check_peer_known (peer))
324   {
325     return create_peer_ctx (peer);
326   }
327   return get_peer_ctx (peer);
328 }
329
330
331 /**
332  * @brief Check whether we have a connection to this @a peer
333  *
334  * Also sets the #Peers_ONLINE flag accordingly
335  *
336  * @param peer the peer in question
337  *
338  * @return #GNUNET_YES if we are connected
339  *         #GNUNET_NO  otherwise
340  */
341 int
342 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
343 {
344   const struct PeerContext *peer_ctx;
345
346   /* If we don't know about this peer we don't know whether it's online */
347   if (GNUNET_NO == Peers_check_peer_known (peer))
348   {
349     return GNUNET_NO;
350   }
351   /* Get the context */
352   peer_ctx = get_peer_ctx (peer);
353   /* If we have no channel to this peer we don't know whether it's online */
354   if ( (NULL == peer_ctx->send_channel) &&
355        (NULL == peer_ctx->recv_channel) )
356   {
357     Peers_unset_peer_flag (peer, Peers_ONLINE);
358     return GNUNET_NO;
359   }
360   /* Otherwise (if we have a channel, we know that it's online */
361   Peers_set_peer_flag (peer, Peers_ONLINE);
362   return GNUNET_YES;
363 }
364
365
366 /**
367  * @brief The closure to #get_rand_peer_iterator.
368  */
369 struct GetRandPeerIteratorCls
370 {
371   /**
372    * @brief The index of the peer to return.
373    * Will be decreased until 0.
374    * Then current peer is returned.
375    */
376   uint32_t index;
377
378   /**
379    * @brief Pointer to peer to return.
380    */
381   const struct GNUNET_PeerIdentity *peer;
382 };
383
384
385 /**
386  * @brief Iterator function for #get_random_peer_from_peermap.
387  *
388  * Implements #GNUNET_CONTAINER_PeerMapIterator.
389  * Decreases the index until the index is null.
390  * Then returns the current peer.
391  *
392  * @param cls the #GetRandPeerIteratorCls containing index and peer
393  * @param peer current peer
394  * @param value unused
395  *
396  * @return  #GNUNET_YES if we should continue to
397  *          iterate,
398  *          #GNUNET_NO if not.
399  */
400 static int
401 get_rand_peer_iterator (void *cls,
402                         const struct GNUNET_PeerIdentity *peer,
403                         void *value)
404 {
405   struct GetRandPeerIteratorCls *iterator_cls = cls;
406   if (0 >= iterator_cls->index)
407   {
408     iterator_cls->peer = peer;
409     return GNUNET_NO;
410   }
411   iterator_cls->index--;
412   return GNUNET_YES;
413 }
414
415
416 /**
417  * @brief Get a random peer from @a peer_map
418  *
419  * @param peer_map the peer_map to get the peer from
420  *
421  * @return a random peer
422  */
423 static const struct GNUNET_PeerIdentity *
424 get_random_peer_from_peermap (const struct
425                               GNUNET_CONTAINER_MultiPeerMap *peer_map)
426 {
427   struct GetRandPeerIteratorCls *iterator_cls;
428   const struct GNUNET_PeerIdentity *ret;
429
430   iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls);
431   iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
432       GNUNET_CONTAINER_multipeermap_size (peer_map));
433   (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
434                                                 get_rand_peer_iterator,
435                                                 iterator_cls);
436   ret = iterator_cls->peer;
437   GNUNET_free (iterator_cls);
438   return ret;
439 }
440
441
442 /**
443  * @brief Add a given @a peer to valid peers.
444  *
445  * If valid peers are already #num_valid_peers_max, delete a peer previously.
446  *
447  * @param peer the peer that is added to the valid peers.
448  *
449  * @return #GNUNET_YES if no other peer had to be removed
450  *         #GNUNET_NO  otherwise
451  */
452 static int
453 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
454 {
455   const struct GNUNET_PeerIdentity *rand_peer;
456   int ret;
457
458   ret = GNUNET_YES;
459   while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
460   {
461     rand_peer = get_random_peer_from_peermap (valid_peers);
462     GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
463     ret = GNUNET_NO;
464   }
465   (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
466       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
467   return ret;
468 }
469
470
471 /**
472  * @brief Set the peer flag to living and
473  *        call the pending operations on this peer.
474  *
475  * Also adds peer to #valid_peers.
476  *
477  * @param peer_ctx the #PeerContext of the peer to set live
478  */
479 static void
480 set_peer_live (struct PeerContext *peer_ctx)
481 {
482   struct GNUNET_PeerIdentity *peer;
483   unsigned int i;
484
485   peer = &peer_ctx->peer_id;
486   LOG (GNUNET_ERROR_TYPE_DEBUG,
487       "Peer %s is live and valid, calling %i pending operations on it\n",
488       GNUNET_i2s (peer),
489       peer_ctx->num_pending_ops);
490
491   if (NULL != peer_ctx->liveliness_check_pending)
492   {
493     LOG (GNUNET_ERROR_TYPE_DEBUG,
494          "Removing pending liveliness check for peer %s\n",
495          GNUNET_i2s (&peer_ctx->peer_id));
496     // TODO wait until cadet sets mq->cancel_impl
497     //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
498     GNUNET_free (peer_ctx->liveliness_check_pending);
499     peer_ctx->liveliness_check_pending = NULL;
500   }
501
502   (void) add_valid_peer (peer);
503   set_peer_flag (peer_ctx, Peers_ONLINE);
504
505   /* Call pending operations */
506   for (i = 0; i < peer_ctx->num_pending_ops; i++)
507   {
508     peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
509   }
510   GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
511 }
512
513
514 /**
515  * @brief Get the channel of a peer. If not existing, create.
516  *
517  * @param peer the peer id
518  * @return the #GNUNET_CADET_Channel used to send data to @a peer
519  */
520 struct GNUNET_CADET_Channel *
521 get_channel (const struct GNUNET_PeerIdentity *peer)
522 {
523   struct PeerContext *peer_ctx;
524   struct GNUNET_HashCode port;
525
526   peer_ctx = get_peer_ctx (peer);
527   if (NULL == peer_ctx->send_channel)
528   {
529     LOG (GNUNET_ERROR_TYPE_DEBUG,
530          "Trying to establish channel to peer %s\n",
531          GNUNET_i2s (peer));
532     GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
533                         strlen (GNUNET_APPLICATION_PORT_RPS),
534                         &port);
535     peer_ctx->send_channel =
536       GNUNET_CADET_channel_create (cadet_handle,
537                                    (struct GNUNET_PeerIdentity *) peer, /* context */
538                                    peer,
539                                    &port,
540                                    GNUNET_CADET_OPTION_RELIABLE,
541                                    NULL, /* WindowSize handler */
542                                    cleanup_destroyed_channel, /* Disconnect handler */
543                                    cadet_handlers);
544   }
545   GNUNET_assert (NULL != peer_ctx->send_channel);
546   return peer_ctx->send_channel;
547 }
548
549
550 /**
551  * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
552  *
553  * If we already have a message queue open to this client,
554  * simply return it, otherways create one.
555  *
556  * @param peer the peer to get the mq to
557  * @return the #GNUNET_MQ_Handle
558  */
559 static struct GNUNET_MQ_Handle *
560 get_mq (const struct GNUNET_PeerIdentity *peer)
561 {
562   struct PeerContext *peer_ctx;
563
564   peer_ctx = get_peer_ctx (peer);
565
566   if (NULL == peer_ctx->mq)
567   {
568     (void) get_channel (peer);
569     peer_ctx->mq = GNUNET_CADET_get_mq (peer_ctx->send_channel);
570   }
571   return peer_ctx->mq;
572 }
573
574
575 /**
576  * @brief This is called in response to the first message we sent as a
577  * liveliness check.
578  *
579  * @param cls #PeerContext of peer with pending liveliness check
580  */
581 static void
582 mq_liveliness_check_successful (void *cls)
583 {
584   struct PeerContext *peer_ctx = cls;
585
586   if (NULL != peer_ctx->liveliness_check_pending)
587   {
588     LOG (GNUNET_ERROR_TYPE_DEBUG,
589         "Liveliness check for peer %s was successfull\n",
590         GNUNET_i2s (&peer_ctx->peer_id));
591     GNUNET_free (peer_ctx->liveliness_check_pending);
592     peer_ctx->liveliness_check_pending = NULL;
593     set_peer_live (peer_ctx);
594   }
595 }
596
597 /**
598  * Issue a check whether peer is live
599  *
600  * @param peer_ctx the context of the peer
601  */
602 static void
603 check_peer_live (struct PeerContext *peer_ctx)
604 {
605   LOG (GNUNET_ERROR_TYPE_DEBUG,
606        "Get informed about peer %s getting live\n",
607        GNUNET_i2s (&peer_ctx->peer_id));
608
609   struct GNUNET_MQ_Handle *mq;
610   struct GNUNET_MQ_Envelope *ev;
611
612   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE);
613   peer_ctx->liveliness_check_pending = GNUNET_new (struct PendingMessage);
614   peer_ctx->liveliness_check_pending->ev = ev;
615   peer_ctx->liveliness_check_pending->peer_ctx = peer_ctx;
616   peer_ctx->liveliness_check_pending->type = "Check liveliness";
617   mq = get_mq (&peer_ctx->peer_id);
618   GNUNET_MQ_notify_sent (ev,
619                          mq_liveliness_check_successful,
620                          peer_ctx);
621   GNUNET_MQ_send (mq, ev);
622 }
623
624 /**
625  * @brief Add an envelope to a message passed to mq to list of pending messages
626  *
627  * @param peer peer the message was sent to
628  * @param ev envelope to the message
629  * @param type type of the message to be sent
630  * @return pointer to pending message
631  */
632 static struct PendingMessage *
633 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
634                         struct GNUNET_MQ_Envelope *ev,
635                         const char *type)
636 {
637   struct PendingMessage *pending_msg;
638   struct PeerContext *peer_ctx;
639
640   peer_ctx = get_peer_ctx (peer);
641   pending_msg = GNUNET_new (struct PendingMessage);
642   pending_msg->ev = ev;
643   pending_msg->peer_ctx = peer_ctx;
644   pending_msg->type = type;
645   GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
646                                peer_ctx->pending_messages_tail,
647                                pending_msg);
648   return pending_msg;
649 }
650
651
652 /**
653  * @brief Remove a pending message from the respective DLL
654  *
655  * @param pending_msg the pending message to remove
656  * @param cancel cancel the pending message, too
657  */
658 static void
659 remove_pending_message (struct PendingMessage *pending_msg, int cancel)
660 {
661   struct PeerContext *peer_ctx;
662
663   peer_ctx = pending_msg->peer_ctx;
664   GNUNET_assert (NULL != peer_ctx);
665   GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
666                                peer_ctx->pending_messages_tail,
667                                pending_msg);
668   // TODO wait for the cadet implementation of message cancellation
669   //if (GNUNET_YES == cancel)
670   //{
671   //  GNUNET_MQ_send_cancel (pending_msg->ev);
672   //}
673   GNUNET_free (pending_msg);
674 }
675
676
677 /**
678  * @brief Check whether function of type #PeerOp was already scheduled
679  *
680  * The array with pending operations will probably never grow really big, so
681  * iterating over it should be ok.
682  *
683  * @param peer the peer to check
684  * @param peer_op the operation (#PeerOp) on the peer
685  *
686  * @return #GNUNET_YES if this operation is scheduled on that peer
687  *         #GNUNET_NO  otherwise
688  */
689 static int
690 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
691                            const PeerOp peer_op)
692 {
693   const struct PeerContext *peer_ctx;
694   unsigned int i;
695
696   peer_ctx = get_peer_ctx (peer);
697   for (i = 0; i < peer_ctx->num_pending_ops; i++)
698     if (peer_op == peer_ctx->pending_ops[i].op)
699       return GNUNET_YES;
700   return GNUNET_NO;
701 }
702
703
704 /**
705  * Iterator over hash map entries. Deletes all contexts of peers.
706  *
707  * @param cls closure
708  * @param key current public key
709  * @param value value in the hash map
710  * @return #GNUNET_YES if we should continue to iterate,
711  *         #GNUNET_NO if not.
712  */
713 static int
714 peermap_clear_iterator (void *cls,
715                         const struct GNUNET_PeerIdentity *key,
716                         void *value)
717 {
718   Peers_remove_peer (key);
719   return GNUNET_YES;
720 }
721
722
723 /**
724  * @brief This is called once a message is sent.
725  *
726  * Removes the pending message
727  *
728  * @param cls type of the message that was sent
729  */
730 static void
731 mq_notify_sent_cb (void *cls)
732 {
733   struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
734   LOG (GNUNET_ERROR_TYPE_DEBUG,
735       "%s was sent.\n",
736       pending_msg->type);
737   /* Do not cancle message */
738   remove_pending_message (pending_msg, GNUNET_NO);
739 }
740
741
742 /**
743  * @brief Iterator function for #store_valid_peers.
744  *
745  * Implements #GNUNET_CONTAINER_PeerMapIterator.
746  * Writes single peer to disk.
747  *
748  * @param cls the file handle to write to.
749  * @param peer current peer
750  * @param value unused
751  *
752  * @return  #GNUNET_YES if we should continue to
753  *          iterate,
754  *          #GNUNET_NO if not.
755  */
756 static int
757 store_peer_presistently_iterator (void *cls,
758                                   const struct GNUNET_PeerIdentity *peer,
759                                   void *value)
760 {
761   const struct GNUNET_DISK_FileHandle *fh = cls;
762   char peer_string[128];
763   int size;
764   ssize_t ret;
765
766   if (NULL == peer)
767   {
768     return GNUNET_YES;
769   }
770   size = GNUNET_snprintf (peer_string,
771                           sizeof (peer_string),
772                           "%s\n",
773                           GNUNET_i2s_full (peer));
774   GNUNET_assert (53 == size);
775   ret = GNUNET_DISK_file_write (fh,
776                                 peer_string,
777                                 size);
778   GNUNET_assert (size == ret);
779   return GNUNET_YES;
780 }
781
782
783 /**
784  * @brief Store the peers currently in #valid_peers to disk.
785  */
786 static void
787 store_valid_peers ()
788 {
789   struct GNUNET_DISK_FileHandle *fh;
790   uint32_t number_written_peers;
791   int ret;
792
793   if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
794   {
795     return;
796   }
797
798   ret = GNUNET_DISK_directory_create_for_file (filename_valid_peers);
799   if (GNUNET_SYSERR == ret)
800   {
801     LOG (GNUNET_ERROR_TYPE_WARNING,
802         "Not able to create directory for file `%s'\n",
803         filename_valid_peers);
804     GNUNET_break (0);
805   }
806   else if (GNUNET_NO == ret)
807   {
808     LOG (GNUNET_ERROR_TYPE_WARNING,
809         "Directory for file `%s' exists but is not writable for us\n",
810         filename_valid_peers);
811     GNUNET_break (0);
812   }
813   fh = GNUNET_DISK_file_open (filename_valid_peers,
814                               GNUNET_DISK_OPEN_WRITE |
815                                   GNUNET_DISK_OPEN_CREATE,
816                               GNUNET_DISK_PERM_USER_READ |
817                                   GNUNET_DISK_PERM_USER_WRITE);
818   if (NULL == fh)
819   {
820     LOG (GNUNET_ERROR_TYPE_WARNING,
821         "Not able to write valid peers to file `%s'\n",
822         filename_valid_peers);
823     return;
824   }
825   LOG (GNUNET_ERROR_TYPE_DEBUG,
826       "Writing %u valid peers to disk\n",
827       GNUNET_CONTAINER_multipeermap_size (valid_peers));
828   number_written_peers =
829     GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
830                                            store_peer_presistently_iterator,
831                                            fh);
832   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
833   GNUNET_assert (number_written_peers ==
834       GNUNET_CONTAINER_multipeermap_size (valid_peers));
835 }
836
837
838 /**
839  * @brief Convert string representation of peer id to peer id.
840  *
841  * Counterpart to #GNUNET_i2s_full.
842  *
843  * @param string_repr The string representation of the peer id
844  *
845  * @return The peer id
846  */
847 static const struct GNUNET_PeerIdentity *
848 s2i_full (const char *string_repr)
849 {
850   struct GNUNET_PeerIdentity *peer;
851   size_t len;
852   int ret;
853
854   peer = GNUNET_new (struct GNUNET_PeerIdentity);
855   len = strlen (string_repr);
856   if (52 > len)
857   {
858     LOG (GNUNET_ERROR_TYPE_WARNING,
859         "Not able to convert string representation of PeerID to PeerID\n"
860         "Sting representation: %s (len %u) - too short\n",
861         string_repr,
862         len);
863     GNUNET_break (0);
864   }
865   else if (52 < len)
866   {
867     len = 52;
868   }
869   ret = GNUNET_CRYPTO_eddsa_public_key_from_string (string_repr,
870                                                     len,
871                                                     &peer->public_key);
872   if (GNUNET_OK != ret)
873   {
874     LOG (GNUNET_ERROR_TYPE_WARNING,
875         "Not able to convert string representation of PeerID to PeerID\n"
876         "Sting representation: %s\n",
877         string_repr);
878     GNUNET_break (0);
879   }
880   return peer;
881 }
882
883
884 /**
885  * @brief Restore the peers on disk to #valid_peers.
886  */
887 static void
888 restore_valid_peers ()
889 {
890   off_t file_size;
891   uint32_t num_peers;
892   struct GNUNET_DISK_FileHandle *fh;
893   char *buf;
894   ssize_t size_read;
895   char *iter_buf;
896   char *str_repr;
897   const struct GNUNET_PeerIdentity *peer;
898
899   if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
900   {
901     return;
902   }
903
904   if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers))
905   {
906     return;
907   }
908   fh = GNUNET_DISK_file_open (filename_valid_peers,
909                               GNUNET_DISK_OPEN_READ,
910                               GNUNET_DISK_PERM_NONE);
911   GNUNET_assert (NULL != fh);
912   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size));
913   num_peers = file_size / 53;
914   buf = GNUNET_malloc (file_size);
915   size_read = GNUNET_DISK_file_read (fh, buf, file_size);
916   GNUNET_assert (size_read == file_size);
917   LOG (GNUNET_ERROR_TYPE_DEBUG,
918       "Restoring %" PRIu32 " peers from file `%s'\n",
919       num_peers,
920       filename_valid_peers);
921   for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53)
922   {
923     str_repr = GNUNET_strndup (iter_buf, 53);
924     peer = s2i_full (str_repr);
925     GNUNET_free (str_repr);
926     add_valid_peer (peer);
927     LOG (GNUNET_ERROR_TYPE_DEBUG,
928         "Restored valid peer %s from disk\n",
929         GNUNET_i2s_full (peer));
930   }
931   iter_buf = NULL;
932   GNUNET_free (buf);
933   LOG (GNUNET_ERROR_TYPE_DEBUG,
934       "num_peers: %" PRIu32 ", _size (valid_peers): %u\n",
935       num_peers,
936       GNUNET_CONTAINER_multipeermap_size (valid_peers));
937   if (num_peers != GNUNET_CONTAINER_multipeermap_size (valid_peers))
938   {
939     LOG (GNUNET_ERROR_TYPE_WARNING,
940         "Number of restored peers does not match file size. Have probably duplicates.\n");
941   }
942   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
943   LOG (GNUNET_ERROR_TYPE_DEBUG,
944       "Restored %u valid peers from disk\n",
945       GNUNET_CONTAINER_multipeermap_size (valid_peers));
946 }
947
948
949 /**
950  * @brief Initialise storage of peers
951  *
952  * @param fn_valid_peers filename of the file used to store valid peer ids
953  * @param cadet_h cadet handle
954  * @param disconnect_handler Disconnect handler
955  * @param c_handlers cadet handlers
956  * @param own_id own peer identity
957  */
958 void
959 Peers_initialise (char* fn_valid_peers,
960                   struct GNUNET_CADET_Handle *cadet_h,
961                   GNUNET_CADET_DisconnectEventHandler disconnect_handler,
962                   const struct GNUNET_MQ_MessageHandler *c_handlers,
963                   const struct GNUNET_PeerIdentity *own_id)
964 {
965   filename_valid_peers = GNUNET_strdup (fn_valid_peers);
966   cadet_handle = cadet_h;
967   cleanup_destroyed_channel = disconnect_handler;
968   cadet_handlers = c_handlers;
969   own_identity = own_id;
970   peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
971   valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
972   restore_valid_peers ();
973 }
974
975
976 /**
977  * @brief Delete storage of peers that was created with #Peers_initialise ()
978  */
979 void
980 Peers_terminate ()
981 {
982   if (GNUNET_SYSERR ==
983       GNUNET_CONTAINER_multipeermap_iterate (peer_map,
984                                              peermap_clear_iterator,
985                                              NULL))
986   {
987     LOG (GNUNET_ERROR_TYPE_WARNING,
988         "Iteration destroying peers was aborted.\n");
989   }
990   GNUNET_CONTAINER_multipeermap_destroy (peer_map);
991   store_valid_peers ();
992   GNUNET_free (filename_valid_peers);
993   GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
994 }
995
996
997 /**
998  * Iterator over #valid_peers hash map entries.
999  *
1000  * @param cls closure - unused
1001  * @param peer current peer id
1002  * @param value value in the hash map - unused
1003  * @return #GNUNET_YES if we should continue to
1004  *         iterate,
1005  *         #GNUNET_NO if not.
1006  */
1007 static int
1008 valid_peer_iterator (void *cls,
1009                      const struct GNUNET_PeerIdentity *peer,
1010                      void *value)
1011 {
1012   struct PeersIteratorCls *it_cls = cls;
1013
1014   return it_cls->iterator (it_cls->cls,
1015                            peer);
1016 }
1017
1018
1019 /**
1020  * @brief Get all currently known, valid peer ids.
1021  *
1022  * @param it function to call on each peer id
1023  * @param it_cls extra argument to @a it
1024  * @return the number of key value pairs processed,
1025  *         #GNUNET_SYSERR if it aborted iteration
1026  */
1027 int
1028 Peers_get_valid_peers (PeersIterator iterator,
1029                        void *it_cls)
1030 {
1031   struct PeersIteratorCls *cls;
1032   int ret;
1033
1034   cls = GNUNET_new (struct PeersIteratorCls);
1035   cls->iterator = iterator;
1036   cls->cls = it_cls;
1037   ret = GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
1038                                                valid_peer_iterator,
1039                                                cls);
1040   GNUNET_free (cls);
1041   return ret;
1042 }
1043
1044
1045 /**
1046  * @brief Add peer to known peers.
1047  *
1048  * This function is called on new peer_ids from 'external' sources
1049  * (client seed, cadet get_peers(), ...)
1050  *
1051  * @param peer the new #GNUNET_PeerIdentity
1052  *
1053  * @return #GNUNET_YES if peer was inserted
1054  *         #GNUNET_NO  otherwise (if peer was already known or
1055  *                     peer was #own_identity)
1056  */
1057 int
1058 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
1059 {
1060   if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
1061        (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
1062   {
1063     return GNUNET_NO; /* We already know this peer - nothing to do */
1064   }
1065   (void) create_peer_ctx (peer);
1066   return GNUNET_YES;
1067 }
1068
1069
1070 /**
1071  * @brief Try connecting to a peer to see whether it is online
1072  *
1073  * If not known yet, insert into known peers
1074  *
1075  * @param peer the peer whose liveliness is to be checked
1076  * @return #GNUNET_YES if peer had to be inserted
1077  *         #GNUNET_NO  otherwise (if peer was already known or
1078  *                     peer was #own_identity)
1079  */
1080 int
1081 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1082 {
1083   struct PeerContext *peer_ctx;
1084   int ret;
1085
1086   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1087   {
1088     return GNUNET_NO;
1089   }
1090   ret = Peers_insert_peer (peer);
1091   peer_ctx = get_peer_ctx (peer);
1092   if (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE))
1093   {
1094     check_peer_live (peer_ctx);
1095   }
1096   return ret;
1097 }
1098
1099
1100 /**
1101  * @brief Check if peer is removable.
1102  *
1103  * Check if
1104  *  - a recv channel exists
1105  *  - there are pending messages
1106  *  - there is no pending pull reply
1107  *
1108  * @param peer the peer in question
1109  * @return #GNUNET_YES    if peer is removable
1110  *         #GNUNET_NO     if peer is NOT removable
1111  *         #GNUNET_SYSERR if peer is not known
1112  */
1113 int
1114 Peers_check_removable (const struct GNUNET_PeerIdentity *peer)
1115 {
1116   struct PeerContext *peer_ctx;
1117
1118   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1119   {
1120     return GNUNET_SYSERR;
1121   }
1122
1123   peer_ctx = get_peer_ctx (peer);
1124   if ( (NULL != peer_ctx->recv_channel) ||
1125        (NULL != peer_ctx->pending_messages_head) ||
1126        (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
1127   {
1128     return GNUNET_NO;
1129   }
1130   return GNUNET_YES;
1131 }
1132
1133
1134 /**
1135  * @brief Remove peer
1136  *
1137  * @param peer the peer to clean
1138  * @return #GNUNET_YES if peer was removed
1139  *         #GNUNET_NO  otherwise
1140  */
1141 int
1142 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1143 {
1144   struct PeerContext *peer_ctx;
1145
1146   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1147   {
1148     return GNUNET_NO;
1149   }
1150
1151   peer_ctx = get_peer_ctx (peer);
1152   set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1153   LOG (GNUNET_ERROR_TYPE_DEBUG,
1154        "Going to remove peer %s\n",
1155        GNUNET_i2s (&peer_ctx->peer_id));
1156   Peers_unset_peer_flag (peer, Peers_ONLINE);
1157
1158   GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1159   while (NULL != peer_ctx->pending_messages_head)
1160   {
1161     LOG (GNUNET_ERROR_TYPE_DEBUG,
1162         "Removing unsent %s\n",
1163         peer_ctx->pending_messages_head->type);
1164     /* Cancle pending message, too */
1165     remove_pending_message (peer_ctx->pending_messages_head, GNUNET_YES);
1166   }
1167   /* If we are still waiting for notification whether this peer is live
1168    * cancel the according task */
1169   if (NULL != peer_ctx->liveliness_check_pending)
1170   {
1171     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1172          "Removing pending liveliness check for peer %s\n",
1173          GNUNET_i2s (&peer_ctx->peer_id));
1174     // TODO wait until cadet sets mq->cancel_impl
1175     //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
1176     GNUNET_free (peer_ctx->liveliness_check_pending);
1177     peer_ctx->liveliness_check_pending = NULL;
1178   }
1179   if (NULL != peer_ctx->send_channel)
1180   {
1181     LOG (GNUNET_ERROR_TYPE_DEBUG,
1182         "Destroying send channel\n");
1183     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1184     peer_ctx->send_channel = NULL;
1185   }
1186   if (NULL != peer_ctx->recv_channel)
1187   {
1188     LOG (GNUNET_ERROR_TYPE_DEBUG,
1189         "Destroying recv channel\n");
1190     GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1191     peer_ctx->recv_channel = NULL;
1192   }
1193
1194   GNUNET_free (peer_ctx->send_channel_flags);
1195   GNUNET_free (peer_ctx->recv_channel_flags);
1196
1197   if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1198   {
1199     LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1200   }
1201   GNUNET_free (peer_ctx);
1202   return GNUNET_YES;
1203 }
1204
1205
1206 /**
1207  * @brief set flags on a given peer.
1208  *
1209  * @param peer the peer to set flags on
1210  * @param flags the flags
1211  */
1212 void
1213 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1214 {
1215   struct PeerContext *peer_ctx;
1216
1217   peer_ctx = get_peer_ctx (peer);
1218   set_peer_flag (peer_ctx, flags);
1219 }
1220
1221
1222 /**
1223  * @brief unset flags on a given peer.
1224  *
1225  * @param peer the peer to unset flags on
1226  * @param flags the flags
1227  */
1228 void
1229 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1230 {
1231   struct PeerContext *peer_ctx;
1232
1233   peer_ctx = get_peer_ctx (peer);
1234   unset_peer_flag (peer_ctx, flags);
1235 }
1236
1237
1238 /**
1239  * @brief Check whether flags on a peer are set.
1240  *
1241  * @param peer the peer to check the flag of
1242  * @param flags the flags to check
1243  *
1244  * @return #GNUNET_SYSERR if peer is not known
1245  *         #GNUNET_YES    if all given flags are set
1246  *         #GNUNET_NO     otherwise
1247  */
1248 int
1249 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1250 {
1251   struct PeerContext *peer_ctx;
1252
1253   if (GNUNET_NO == Peers_check_peer_known (peer))
1254   {
1255     return GNUNET_SYSERR;
1256   }
1257   peer_ctx = get_peer_ctx (peer);
1258   return check_peer_flag_set (peer_ctx, flags);
1259 }
1260
1261
1262 /**
1263  * @brief set flags on a given channel.
1264  *
1265  * @param channel the channel to set flags on
1266  * @param flags the flags
1267  */
1268 void
1269 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1270 {
1271   set_channel_flag (channel_flags, flags);
1272 }
1273
1274
1275 /**
1276  * @brief unset flags on a given channel.
1277  *
1278  * @param channel the channel to unset flags on
1279  * @param flags the flags
1280  */
1281 void
1282 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1283 {
1284   unset_channel_flag (channel_flags, flags);
1285 }
1286
1287
1288 /**
1289  * @brief Check whether flags on a channel are set.
1290  *
1291  * @param channel the channel to check the flag of
1292  * @param flags the flags to check
1293  *
1294  * @return #GNUNET_YES if all given flags are set
1295  *         #GNUNET_NO  otherwise
1296  */
1297 int
1298 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1299 {
1300   return check_channel_flag_set (channel_flags, flags);
1301 }
1302
1303 /**
1304  * @brief Get the flags for the channel in @a role for @a peer.
1305  *
1306  * @param peer Peer to get the channel flags for.
1307  * @param role Role of channel to get flags for
1308  *
1309  * @return The flags.
1310  */
1311 uint32_t *
1312 Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
1313                         enum Peers_ChannelRole role)
1314 {
1315   const struct PeerContext *peer_ctx;
1316
1317   peer_ctx = get_peer_ctx (peer);
1318   if (Peers_CHANNEL_ROLE_SENDING == role)
1319   {
1320     return peer_ctx->send_channel_flags;
1321   }
1322   else if (Peers_CHANNEL_ROLE_RECEIVING == role)
1323   {
1324     return peer_ctx->recv_channel_flags;
1325   }
1326   else
1327   {
1328     GNUNET_assert (0);
1329   }
1330 }
1331
1332 /**
1333  * @brief Check whether we have information about the given peer.
1334  *
1335  * FIXME probably deprecated. Make this the new _online.
1336  *
1337  * @param peer peer in question
1338  *
1339  * @return #GNUNET_YES if peer is known
1340  *         #GNUNET_NO  if peer is not knwon
1341  */
1342 int
1343 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1344 {
1345   return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1346 }
1347
1348
1349 /**
1350  * @brief Check whether @a peer is actually a peer.
1351  *
1352  * A valid peer is a peer that we know exists eg. we were connected to once.
1353  *
1354  * @param peer peer in question
1355  *
1356  * @return #GNUNET_YES if peer is valid
1357  *         #GNUNET_NO  if peer is not valid
1358  */
1359 int
1360 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1361 {
1362   return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1363 }
1364
1365
1366 /**
1367  * @brief Indicate that we want to send to the other peer
1368  *
1369  * This establishes a sending channel
1370  *
1371  * @param peer the peer to establish channel to
1372  */
1373 void
1374 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1375 {
1376   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1377   (void) get_channel (peer);
1378 }
1379
1380
1381 /**
1382  * @brief Check whether other peer has the intention to send/opened channel
1383  *        towars us
1384  *
1385  * @param peer the peer in question
1386  *
1387  * @return #GNUNET_YES if peer has the intention to send
1388  *         #GNUNET_NO  otherwise
1389  */
1390 int
1391 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1392 {
1393   const struct PeerContext *peer_ctx;
1394
1395   peer_ctx = get_peer_ctx (peer);
1396   if (NULL != peer_ctx->recv_channel)
1397   {
1398     return GNUNET_YES;
1399   }
1400   return GNUNET_NO;
1401 }
1402
1403
1404 /**
1405  * Handle the channel a peer opens to us.
1406  *
1407  * @param cls The closure
1408  * @param channel The channel the peer wants to establish
1409  * @param initiator The peer's peer ID
1410  *
1411  * @return initial channel context for the channel
1412  *         (can be NULL -- that's not an error)
1413  */
1414 void *
1415 Peers_handle_inbound_channel (void *cls,
1416                               struct GNUNET_CADET_Channel *channel,
1417                               const struct GNUNET_PeerIdentity *initiator)
1418 {
1419   struct PeerContext *peer_ctx;
1420
1421   LOG (GNUNET_ERROR_TYPE_DEBUG,
1422       "New channel was established to us (Peer %s).\n",
1423       GNUNET_i2s (initiator));
1424   GNUNET_assert (NULL != channel); /* according to cadet API */
1425   /* Make sure we 'know' about this peer */
1426   peer_ctx = create_or_get_peer_ctx (initiator);
1427   set_peer_live (peer_ctx);
1428   /* We only accept one incoming channel per peer */
1429   if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1430   {
1431     set_channel_flag (peer_ctx->recv_channel_flags,
1432                       Peers_CHANNEL_ESTABLISHED_TWICE);
1433     GNUNET_CADET_channel_destroy (channel);
1434     /* return the channel context */
1435     return &peer_ctx->peer_id;
1436   }
1437   peer_ctx->recv_channel = channel;
1438   return &peer_ctx->peer_id;
1439 }
1440
1441
1442 /**
1443  * @brief Check whether a sending channel towards the given peer exists
1444  *
1445  * @param peer the peer to check for
1446  *
1447  * @return #GNUNET_YES if a sending channel towards that peer exists
1448  *         #GNUNET_NO  otherwise
1449  */
1450 int
1451 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1452 {
1453   struct PeerContext *peer_ctx;
1454
1455   if (GNUNET_NO == Peers_check_peer_known (peer))
1456   { /* If no such peer exists, there is no channel */
1457     return GNUNET_NO;
1458   }
1459   peer_ctx = get_peer_ctx (peer);
1460   if (NULL == peer_ctx->send_channel)
1461   {
1462     return GNUNET_NO;
1463   }
1464   return GNUNET_YES;
1465 }
1466
1467
1468 /**
1469  * @brief check whether the given channel is the sending channel of the given
1470  *        peer
1471  *
1472  * @param peer the peer in question
1473  * @param channel the channel to check for
1474  * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1475  *                    #Peers_CHANNEL_ROLE_RECEIVING
1476  *
1477  * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1478  *         #GNUNET_NO  otherwise
1479  */
1480 int
1481 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1482                           const struct GNUNET_CADET_Channel *channel,
1483                           enum Peers_ChannelRole role)
1484 {
1485   const struct PeerContext *peer_ctx;
1486
1487   if (GNUNET_NO == Peers_check_peer_known (peer))
1488   {
1489     return GNUNET_NO;
1490   }
1491   peer_ctx = get_peer_ctx (peer);
1492   if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1493        (channel == peer_ctx->send_channel) )
1494   {
1495     return GNUNET_YES;
1496   }
1497   if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1498        (channel == peer_ctx->recv_channel) )
1499   {
1500     return GNUNET_YES;
1501   }
1502   return GNUNET_NO;
1503 }
1504
1505
1506 /**
1507  * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1508  *        intention to another peer
1509  *
1510  * If there is also no channel to receive messages from that peer, remove it
1511  * from the peermap.
1512  * TODO really?
1513  *
1514  * @peer the peer identity of the peer whose sending channel to destroy
1515  * @return #GNUNET_YES if channel was destroyed
1516  *         #GNUNET_NO  otherwise
1517  */
1518 int
1519 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1520 {
1521   struct PeerContext *peer_ctx;
1522
1523   if (GNUNET_NO == Peers_check_peer_known (peer))
1524   {
1525     return GNUNET_NO;
1526   }
1527   peer_ctx = get_peer_ctx (peer);
1528   if (NULL != peer_ctx->send_channel)
1529   {
1530     set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1531     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1532     peer_ctx->send_channel = NULL;
1533     (void) Peers_check_connected (peer);
1534     return GNUNET_YES;
1535   }
1536   return GNUNET_NO;
1537 }
1538
1539 /**
1540  * This is called when a channel is destroyed.
1541  *
1542  * @param cls The closure
1543  * @param channel The channel being closed
1544  * @param channel_ctx The context associated with this channel
1545  */
1546 void
1547 Peers_cleanup_destroyed_channel (void *cls,
1548                                  const struct GNUNET_CADET_Channel *channel)
1549 {
1550   struct GNUNET_PeerIdentity *peer = cls;
1551   struct PeerContext *peer_ctx;
1552
1553   if (GNUNET_NO == Peers_check_peer_known (peer))
1554   {/* We don't want to implicitly create a context that we're about to kill */
1555   LOG (GNUNET_ERROR_TYPE_DEBUG,
1556        "channel (%s) without associated context was destroyed\n",
1557        GNUNET_i2s (peer));
1558     return;
1559   }
1560   peer_ctx = get_peer_ctx (peer);
1561
1562   /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1563    * flag will be set. In this case simply make sure that the channels are
1564    * cleaned. */
1565   /* FIXME This distinction seems to be redundant */
1566   if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1567   {/* We initiatad the destruction of this particular peer */
1568     if (channel == peer_ctx->send_channel)
1569       peer_ctx->send_channel = NULL;
1570     else if (channel == peer_ctx->recv_channel)
1571       peer_ctx->recv_channel = NULL;
1572
1573     if (NULL != peer_ctx->send_channel)
1574     {
1575       GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1576       peer_ctx->send_channel = NULL;
1577     }
1578     if (NULL != peer_ctx->recv_channel)
1579     {
1580       GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1581       peer_ctx->recv_channel = NULL;
1582     }
1583     /* Set the #Peers_ONLINE flag accordingly */
1584     (void) Peers_check_connected (peer);
1585     return;
1586   }
1587
1588   else
1589   { /* We did not initiate the destruction of this peer */
1590     if (channel == peer_ctx->send_channel)
1591     { /* Something (but us) killd the channel - clean up peer */
1592       LOG (GNUNET_ERROR_TYPE_DEBUG,
1593           "send channel (%s) was destroyed - cleaning up\n",
1594           GNUNET_i2s (peer));
1595       peer_ctx->send_channel = NULL;
1596     }
1597     else if (channel == peer_ctx->recv_channel)
1598     { /* Other peer doesn't want to send us messages anymore */
1599       LOG (GNUNET_ERROR_TYPE_DEBUG,
1600            "Peer %s destroyed recv channel - cleaning up channel\n",
1601            GNUNET_i2s (peer));
1602       peer_ctx->recv_channel = NULL;
1603     }
1604     else
1605     {
1606       LOG (GNUNET_ERROR_TYPE_WARNING,
1607            "unknown channel (%s) was destroyed\n",
1608            GNUNET_i2s (peer));
1609     }
1610   }
1611   (void) Peers_check_connected (peer);
1612 }
1613
1614 /**
1615  * @brief Send a message to another peer.
1616  *
1617  * Keeps track about pending messages so they can be properly removed when the
1618  * peer is destroyed.
1619  *
1620  * @param peer receeiver of the message
1621  * @param ev envelope of the message
1622  * @param type type of the message
1623  */
1624 void
1625 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1626                     struct GNUNET_MQ_Envelope *ev,
1627                     const char *type)
1628 {
1629   struct PendingMessage *pending_msg;
1630   struct GNUNET_MQ_Handle *mq;
1631
1632   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1633               "Sending message to %s of type %s\n",
1634               GNUNET_i2s (peer),
1635               type);
1636   pending_msg = insert_pending_message (peer, ev, type);
1637   mq = get_mq (peer);
1638   GNUNET_MQ_notify_sent (ev,
1639                          mq_notify_sent_cb,
1640                          pending_msg);
1641   GNUNET_MQ_send (mq, ev);
1642 }
1643
1644 /**
1645  * @brief Schedule a operation on given peer
1646  *
1647  * Avoids scheduling an operation twice.
1648  *
1649  * @param peer the peer we want to schedule the operation for once it gets live
1650  *
1651  * @return #GNUNET_YES if the operation was scheduled
1652  *         #GNUNET_NO  otherwise
1653  */
1654 int
1655 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1656                           const PeerOp peer_op)
1657 {
1658   struct PeerPendingOp pending_op;
1659   struct PeerContext *peer_ctx;
1660
1661   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1662   {
1663     return GNUNET_NO;
1664   }
1665   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1666
1667   //TODO if LIVE/ONLINE execute immediately
1668
1669   if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1670   {
1671     peer_ctx = get_peer_ctx (peer);
1672     pending_op.op = peer_op;
1673     pending_op.op_cls = NULL;
1674     GNUNET_array_append (peer_ctx->pending_ops,
1675                          peer_ctx->num_pending_ops,
1676                          pending_op);
1677     return GNUNET_YES;
1678   }
1679   return GNUNET_NO;
1680 }
1681
1682 /**
1683  * @brief Get the recv_channel of @a peer.
1684  * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming
1685  * messages.
1686  *
1687  * @param peer The peer to get the recv_channel from.
1688  *
1689  * @return The recv_channel.
1690  */
1691 struct GNUNET_CADET_Channel *
1692 Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer)
1693 {
1694   struct PeerContext *peer_ctx;
1695
1696   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1697   peer_ctx = get_peer_ctx (peer);
1698   return peer_ctx->recv_channel;
1699 }
1700
1701 /* end of gnunet-service-rps_peers.c */