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