-rps service: prevent division by zero
[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 Remove unecessary data
1077  *
1078  * If the other peer is not intending to send messages, we have messages pending
1079  * to be sent to this peer and we are not waiting for a reply, remove the
1080  * information about it (its #PeerContext).
1081  *
1082  * @param peer the peer to clean
1083  * @return #GNUNET_YES if peer was removed
1084  *         #GNUNET_NO  otherwise
1085  */
1086 int
1087 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
1088 {
1089   struct PeerContext *peer_ctx;
1090
1091   // TODO actually remove unnecessary data
1092
1093   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1094   {
1095     return GNUNET_NO;
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   Peers_remove_peer (peer);
1106   return GNUNET_YES;
1107 }
1108
1109
1110 /**
1111  * @brief Remove peer
1112  *
1113  * @param peer the peer to clean
1114  * @return #GNUNET_YES if peer was removed
1115  *         #GNUNET_NO  otherwise
1116  */
1117 int
1118 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1119 {
1120   struct PeerContext *peer_ctx;
1121
1122   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1123   {
1124     return GNUNET_NO;
1125   }
1126
1127   peer_ctx = get_peer_ctx (peer);
1128   set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1129   LOG (GNUNET_ERROR_TYPE_DEBUG,
1130        "Going to remove peer %s\n",
1131        GNUNET_i2s (&peer_ctx->peer_id));
1132   Peers_unset_peer_flag (peer, Peers_ONLINE);
1133
1134   GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1135   while (NULL != peer_ctx->pending_messages_head)
1136   {
1137     LOG (GNUNET_ERROR_TYPE_DEBUG,
1138         "Removing unsent %s\n",
1139         peer_ctx->pending_messages_head->type);
1140     remove_pending_message (peer_ctx->pending_messages_head);
1141   }
1142   /* If we are still waiting for notification whether this peer is live
1143    * cancel the according task */
1144   if (NULL != peer_ctx->liveliness_check_pending)
1145   {
1146     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1147          "Removing pending liveliness check for peer %s\n",
1148          GNUNET_i2s (&peer_ctx->peer_id));
1149     // TODO wait until cadet sets mq->cancel_impl
1150     //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
1151     GNUNET_free (peer_ctx->liveliness_check_pending);
1152     peer_ctx->liveliness_check_pending = NULL;
1153   }
1154   if (NULL != peer_ctx->send_channel)
1155   {
1156     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1157     peer_ctx->send_channel = NULL;
1158   }
1159   if (NULL != peer_ctx->recv_channel)
1160   {
1161     GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1162     peer_ctx->recv_channel = NULL;
1163   }
1164   if (NULL != peer_ctx->mq)
1165   {
1166     GNUNET_MQ_destroy (peer_ctx->mq);
1167     peer_ctx->mq = NULL;
1168   }
1169
1170   GNUNET_free (peer_ctx->send_channel_flags);
1171   GNUNET_free (peer_ctx->recv_channel_flags);
1172
1173   if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1174   {
1175     LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1176   }
1177   GNUNET_free (peer_ctx);
1178   return GNUNET_YES;
1179 }
1180
1181
1182 /**
1183  * @brief set flags on a given peer.
1184  *
1185  * @param peer the peer to set flags on
1186  * @param flags the flags
1187  */
1188 void
1189 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1190 {
1191   struct PeerContext *peer_ctx;
1192
1193   peer_ctx = get_peer_ctx (peer);
1194   set_peer_flag (peer_ctx, flags);
1195 }
1196
1197
1198 /**
1199  * @brief unset flags on a given peer.
1200  *
1201  * @param peer the peer to unset flags on
1202  * @param flags the flags
1203  */
1204 void
1205 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1206 {
1207   struct PeerContext *peer_ctx;
1208
1209   peer_ctx = get_peer_ctx (peer);
1210   unset_peer_flag (peer_ctx, flags);
1211 }
1212
1213
1214 /**
1215  * @brief Check whether flags on a peer are set.
1216  *
1217  * @param peer the peer to check the flag of
1218  * @param flags the flags to check
1219  *
1220  * @return #GNUNET_SYSERR if peer is not known
1221  *         #GNUNET_YES    if all given flags are set
1222  *         #GNUNET_NO     otherwise
1223  */
1224 int
1225 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1226 {
1227   struct PeerContext *peer_ctx;
1228
1229   if (GNUNET_NO == Peers_check_peer_known (peer))
1230   {
1231     return GNUNET_SYSERR;
1232   }
1233   peer_ctx = get_peer_ctx (peer);
1234   return check_peer_flag_set (peer_ctx, flags);
1235 }
1236
1237
1238 /**
1239  * @brief set flags on a given channel.
1240  *
1241  * @param channel the channel to set flags on
1242  * @param flags the flags
1243  */
1244 void
1245 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1246 {
1247   set_channel_flag (channel_flags, flags);
1248 }
1249
1250
1251 /**
1252  * @brief unset flags on a given channel.
1253  *
1254  * @param channel the channel to unset flags on
1255  * @param flags the flags
1256  */
1257 void
1258 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1259 {
1260   unset_channel_flag (channel_flags, flags);
1261 }
1262
1263
1264 /**
1265  * @brief Check whether flags on a channel are set.
1266  *
1267  * @param channel the channel to check the flag of
1268  * @param flags the flags to check
1269  *
1270  * @return #GNUNET_YES if all given flags are set
1271  *         #GNUNET_NO  otherwise
1272  */
1273 int
1274 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1275 {
1276   return check_channel_flag_set (channel_flags, flags);
1277 }
1278
1279
1280 /**
1281  * @brief Check whether we have information about the given peer.
1282  *
1283  * FIXME probably deprecated. Make this the new _online.
1284  *
1285  * @param peer peer in question
1286  *
1287  * @return #GNUNET_YES if peer is known
1288  *         #GNUNET_NO  if peer is not knwon
1289  */
1290 int
1291 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1292 {
1293   return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1294 }
1295
1296
1297 /**
1298  * @brief Check whether @a peer is actually a peer.
1299  *
1300  * A valid peer is a peer that we know exists eg. we were connected to once.
1301  *
1302  * @param peer peer in question
1303  *
1304  * @return #GNUNET_YES if peer is valid
1305  *         #GNUNET_NO  if peer is not valid
1306  */
1307 int
1308 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1309 {
1310   return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1311 }
1312
1313
1314 /**
1315  * @brief Indicate that we want to send to the other peer
1316  *
1317  * This establishes a sending channel
1318  *
1319  * @param peer the peer to establish channel to
1320  */
1321 void
1322 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1323 {
1324   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1325   (void) get_channel (peer);
1326 }
1327
1328
1329 /**
1330  * @brief Check whether other peer has the intention to send/opened channel
1331  *        towars us
1332  *
1333  * @param peer the peer in question
1334  *
1335  * @return #GNUNET_YES if peer has the intention to send
1336  *         #GNUNET_NO  otherwise
1337  */
1338 int
1339 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1340 {
1341   const struct PeerContext *peer_ctx;
1342
1343   peer_ctx = get_peer_ctx (peer);
1344   if (NULL != peer_ctx->recv_channel)
1345   {
1346     return GNUNET_YES;
1347   }
1348   return GNUNET_NO;
1349 }
1350
1351
1352 /**
1353  * Handle the channel a peer opens to us.
1354  *
1355  * @param cls The closure
1356  * @param channel The channel the peer wants to establish
1357  * @param initiator The peer's peer ID
1358  * @param port The port the channel is being established over
1359  * @param options Further options
1360  *
1361  * @return initial channel context for the channel
1362  *         (can be NULL -- that's not an error)
1363  */
1364 void *
1365 Peers_handle_inbound_channel (void *cls,
1366                               struct GNUNET_CADET_Channel *channel,
1367                               const struct GNUNET_PeerIdentity *initiator,
1368                               const struct GNUNET_HashCode *port,
1369                               enum GNUNET_CADET_ChannelOption options)
1370 {
1371   struct PeerContext *peer_ctx;
1372
1373   LOG (GNUNET_ERROR_TYPE_DEBUG,
1374       "New channel was established to us (Peer %s).\n",
1375       GNUNET_i2s (initiator));
1376   GNUNET_assert (NULL != channel); /* according to cadet API */
1377   /* Make sure we 'know' about this peer */
1378   peer_ctx = create_or_get_peer_ctx (initiator);
1379   set_peer_live (peer_ctx);
1380   /* We only accept one incoming channel per peer */
1381   if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1382   {
1383     set_channel_flag (peer_ctx->recv_channel_flags,
1384                       Peers_CHANNEL_ESTABLISHED_TWICE);
1385     GNUNET_CADET_channel_destroy (channel);
1386     /* return the channel context */
1387     return peer_ctx->recv_channel_flags;
1388   }
1389   peer_ctx->recv_channel = channel;
1390   return peer_ctx->recv_channel_flags;
1391 }
1392
1393
1394 /**
1395  * @brief Check whether a sending channel towards the given peer exists
1396  *
1397  * @param peer the peer to check for
1398  *
1399  * @return #GNUNET_YES if a sending channel towards that peer exists
1400  *         #GNUNET_NO  otherwise
1401  */
1402 int
1403 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1404 {
1405   struct PeerContext *peer_ctx;
1406
1407   if (GNUNET_NO == Peers_check_peer_known (peer))
1408   { /* If no such peer exists, there is no channel */
1409     return GNUNET_NO;
1410   }
1411   peer_ctx = get_peer_ctx (peer);
1412   if (NULL == peer_ctx->send_channel)
1413   {
1414     return GNUNET_NO;
1415   }
1416   return GNUNET_YES;
1417 }
1418
1419
1420 /**
1421  * @brief check whether the given channel is the sending channel of the given
1422  *        peer
1423  *
1424  * @param peer the peer in question
1425  * @param channel the channel to check for
1426  * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1427  *                    #Peers_CHANNEL_ROLE_RECEIVING
1428  *
1429  * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1430  *         #GNUNET_NO  otherwise
1431  */
1432 int
1433 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1434                           const struct GNUNET_CADET_Channel *channel,
1435                           enum Peers_ChannelRole role)
1436 {
1437   const struct PeerContext *peer_ctx;
1438
1439   if (GNUNET_NO == Peers_check_peer_known (peer))
1440   {
1441     return GNUNET_NO;
1442   }
1443   peer_ctx = get_peer_ctx (peer);
1444   if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1445        (channel == peer_ctx->send_channel) )
1446   {
1447     return GNUNET_YES;
1448   }
1449   if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1450        (channel == peer_ctx->recv_channel) )
1451   {
1452     return GNUNET_YES;
1453   }
1454   return GNUNET_NO;
1455 }
1456
1457
1458 /**
1459  * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1460  *        intention to another peer
1461  *
1462  * If there is also no channel to receive messages from that peer, remove it
1463  * from the peermap.
1464  * TODO really?
1465  *
1466  * @peer the peer identity of the peer whose sending channel to destroy
1467  * @return #GNUNET_YES if channel was destroyed
1468  *         #GNUNET_NO  otherwise
1469  */
1470 int
1471 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1472 {
1473   struct PeerContext *peer_ctx;
1474
1475   if (GNUNET_NO == Peers_check_peer_known (peer))
1476   {
1477     return GNUNET_NO;
1478   }
1479   peer_ctx = get_peer_ctx (peer);
1480   if (NULL != peer_ctx->send_channel)
1481   {
1482     set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1483     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1484     peer_ctx->send_channel = NULL;
1485     (void) Peers_check_connected (peer);
1486     return GNUNET_YES;
1487   }
1488   return GNUNET_NO;
1489 }
1490
1491 /**
1492  * This is called when a channel is destroyed.
1493  *
1494  * @param cls The closure
1495  * @param channel The channel being closed
1496  * @param channel_ctx The context associated with this channel
1497  */
1498 void
1499 Peers_cleanup_destroyed_channel (void *cls,
1500                                  const struct GNUNET_CADET_Channel *channel,
1501                                  void *channel_ctx)
1502 {
1503   struct GNUNET_PeerIdentity *peer;
1504   struct PeerContext *peer_ctx;
1505
1506   peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1507       (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1508        // FIXME wait for cadet to change this function
1509
1510   if (GNUNET_NO == Peers_check_peer_known (peer))
1511   {/* We don't want to implicitly create a context that we're about to kill */
1512   LOG (GNUNET_ERROR_TYPE_DEBUG,
1513        "channel (%s) without associated context was destroyed\n",
1514        GNUNET_i2s (peer));
1515     return;
1516   }
1517   peer_ctx = get_peer_ctx (peer);
1518
1519   /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1520    * flag will be set. In this case simply make sure that the channels are
1521    * cleaned. */
1522   /* FIXME This distinction seems to be redundant */
1523   if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1524   {/* We initiatad the destruction of this particular peer */
1525     if (channel == peer_ctx->send_channel)
1526       peer_ctx->send_channel = NULL;
1527     else if (channel == peer_ctx->recv_channel)
1528       peer_ctx->recv_channel = NULL;
1529
1530     if (NULL != peer_ctx->send_channel)
1531     {
1532       GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1533       peer_ctx->send_channel = NULL;
1534     }
1535     if (NULL != peer_ctx->recv_channel)
1536     {
1537       GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1538       peer_ctx->recv_channel = NULL;
1539     }
1540     /* Set the #Peers_ONLINE flag accordingly */
1541     (void) Peers_check_connected (peer);
1542     return;
1543   }
1544
1545   else
1546   { /* We did not initiate the destruction of this peer */
1547     if (channel == peer_ctx->send_channel)
1548     { /* Something (but us) killd the channel - clean up peer */
1549       LOG (GNUNET_ERROR_TYPE_DEBUG,
1550           "send channel (%s) was destroyed - cleaning up\n",
1551           GNUNET_i2s (peer));
1552       peer_ctx->send_channel = NULL;
1553     }
1554     else if (channel == peer_ctx->recv_channel)
1555     { /* Other peer doesn't want to send us messages anymore */
1556       LOG (GNUNET_ERROR_TYPE_DEBUG,
1557            "Peer %s destroyed recv channel - cleaning up channel\n",
1558            GNUNET_i2s (peer));
1559       peer_ctx->recv_channel = NULL;
1560     }
1561     else
1562     {
1563       LOG (GNUNET_ERROR_TYPE_WARNING,
1564            "unknown channel (%s) was destroyed\n",
1565            GNUNET_i2s (peer));
1566     }
1567   }
1568   (void) Peers_check_connected (peer);
1569 }
1570
1571 /**
1572  * @brief Send a message to another peer.
1573  *
1574  * Keeps track about pending messages so they can be properly removed when the
1575  * peer is destroyed.
1576  *
1577  * @param peer receeiver of the message
1578  * @param ev envelope of the message
1579  * @param type type of the message
1580  */
1581 void
1582 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1583                     struct GNUNET_MQ_Envelope *ev,
1584                     const char *type)
1585 {
1586   struct PendingMessage *pending_msg;
1587   struct GNUNET_MQ_Handle *mq;
1588
1589   pending_msg = insert_pending_message (peer, ev, type);
1590   mq = get_mq (peer);
1591   GNUNET_MQ_notify_sent (ev,
1592                          mq_notify_sent_cb,
1593                          pending_msg);
1594   GNUNET_MQ_send (mq, ev);
1595 }
1596
1597 /**
1598  * @brief Schedule a operation on given peer
1599  *
1600  * Avoids scheduling an operation twice.
1601  *
1602  * @param peer the peer we want to schedule the operation for once it gets live
1603  *
1604  * @return #GNUNET_YES if the operation was scheduled
1605  *         #GNUNET_NO  otherwise
1606  */
1607 int
1608 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1609                           const PeerOp peer_op)
1610 {
1611   struct PeerPendingOp pending_op;
1612   struct PeerContext *peer_ctx;
1613
1614   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1615   {
1616     return GNUNET_NO;
1617   }
1618   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1619
1620   //TODO if LIVE/ONLINE execute immediately
1621
1622   if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1623   {
1624     peer_ctx = get_peer_ctx (peer);
1625     pending_op.op = peer_op;
1626     pending_op.op_cls = NULL;
1627     GNUNET_array_append (peer_ctx->pending_ops,
1628                          peer_ctx->num_pending_ops,
1629                          pending_op);
1630     return GNUNET_YES;
1631   }
1632   return GNUNET_NO;
1633 }
1634
1635 /* end of gnunet-service-rps_peers.c */