-rps _peers: prevent leaking of storage
[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   LOG (GNUNET_ERROR_TYPE_DEBUG,
913       "num_peers: %" PRIu32 ", _size (valid_peers): %u\n",
914       num_peers,
915       GNUNET_CONTAINER_multipeermap_size (valid_peers));
916   if (num_peers != GNUNET_CONTAINER_multipeermap_size (valid_peers))
917   {
918     LOG (GNUNET_ERROR_TYPE_WARNING,
919         "Number of restored peers does not match file size. Have probably duplicates.\n");
920   }
921   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
922   LOG (GNUNET_ERROR_TYPE_DEBUG,
923       "Restored %u valid peers from disk\n",
924       GNUNET_CONTAINER_multipeermap_size (valid_peers));
925 }
926
927
928 /**
929  * @brief Initialise storage of peers
930  *
931  * @param fn_valid_peers filename of the file used to store valid peer ids
932  * @param cadet_h cadet handle
933  * @param own_id own peer identity
934  */
935 void
936 Peers_initialise (char* fn_valid_peers,
937                   struct GNUNET_CADET_Handle *cadet_h,
938                   const struct GNUNET_PeerIdentity *own_id)
939 {
940   filename_valid_peers = GNUNET_strdup (fn_valid_peers);
941   cadet_handle = cadet_h;
942   own_identity = own_id;
943   peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
944   valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
945   restore_valid_peers ();
946 }
947
948
949 /**
950  * @brief Delete storage of peers that was created with #Peers_initialise ()
951  */
952 void
953 Peers_terminate ()
954 {
955   if (GNUNET_SYSERR ==
956       GNUNET_CONTAINER_multipeermap_iterate (peer_map,
957                                              peermap_clear_iterator,
958                                              NULL))
959   {
960     LOG (GNUNET_ERROR_TYPE_WARNING,
961         "Iteration destroying peers was aborted.\n");
962   }
963   GNUNET_CONTAINER_multipeermap_destroy (peer_map);
964   store_valid_peers ();
965   GNUNET_free (filename_valid_peers);
966   GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
967 }
968
969
970 /**
971  * Iterator over #valid_peers hash map entries.
972  *
973  * @param cls closure - unused
974  * @param peer current peer id
975  * @param value value in the hash map - unused
976  * @return #GNUNET_YES if we should continue to
977  *         iterate,
978  *         #GNUNET_NO if not.
979  */
980 static int
981 valid_peer_iterator (void *cls,
982                      const struct GNUNET_PeerIdentity *peer,
983                      void *value)
984 {
985   struct PeersIteratorCls *it_cls = cls;
986
987   return it_cls->iterator (it_cls->cls,
988                            peer);
989 }
990
991
992 /**
993  * @brief Get all currently known, valid peer ids.
994  *
995  * @param it function to call on each peer id
996  * @param it_cls extra argument to @a it
997  * @return the number of key value pairs processed,
998  *         #GNUNET_SYSERR if it aborted iteration
999  */
1000 int
1001 Peers_get_valid_peers (PeersIterator iterator,
1002                        void *it_cls)
1003 {
1004   struct PeersIteratorCls *cls;
1005   int ret;
1006
1007   cls = GNUNET_new (struct PeersIteratorCls);
1008   cls->iterator = iterator;
1009   cls->cls = it_cls;
1010   ret = GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
1011                                                valid_peer_iterator,
1012                                                cls);
1013   GNUNET_free (cls);
1014   return ret;
1015 }
1016
1017
1018 /**
1019  * @brief Add peer to known peers.
1020  *
1021  * This function is called on new peer_ids from 'external' sources
1022  * (client seed, cadet get_peers(), ...)
1023  *
1024  * @param peer the new #GNUNET_PeerIdentity
1025  *
1026  * @return #GNUNET_YES if peer was inserted
1027  *         #GNUNET_NO  otherwise (if peer was already known or
1028  *                     peer was #own_identity)
1029  */
1030 int
1031 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
1032 {
1033   if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
1034        (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
1035   {
1036     return GNUNET_NO; /* We already know this peer - nothing to do */
1037   }
1038   (void) create_peer_ctx (peer);
1039   return GNUNET_YES;
1040 }
1041
1042
1043 /**
1044  * @brief Try connecting to a peer to see whether it is online
1045  *
1046  * If not known yet, insert into known peers
1047  *
1048  * @param peer the peer whose liveliness is to be checked
1049  * @return #GNUNET_YES if peer had to be inserted
1050  *         #GNUNET_NO  otherwise (if peer was already known or
1051  *                     peer was #own_identity)
1052  */
1053 int
1054 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1055 {
1056   struct PeerContext *peer_ctx;
1057   int ret;
1058
1059   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1060   {
1061     return GNUNET_NO;
1062   }
1063   ret = Peers_insert_peer (peer);
1064   peer_ctx = get_peer_ctx (peer);
1065   if (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE))
1066   {
1067     check_peer_live (peer_ctx);
1068   }
1069   return ret;
1070 }
1071
1072
1073 /**
1074  * @brief Remove unecessary data
1075  *
1076  * If the other peer is not intending to send messages, we have messages pending
1077  * to be sent to this peer and we are not waiting for a reply, remove the
1078  * information about it (its #PeerContext).
1079  *
1080  * @param peer the peer to clean
1081  * @return #GNUNET_YES if peer was removed
1082  *         #GNUNET_NO  otherwise
1083  */
1084 int
1085 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
1086 {
1087   struct PeerContext *peer_ctx;
1088
1089   // TODO actually remove unnecessary data
1090
1091   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1092   {
1093     return GNUNET_NO;
1094   }
1095
1096   peer_ctx = get_peer_ctx (peer);
1097   if ( (NULL != peer_ctx->recv_channel) ||
1098        (NULL != peer_ctx->pending_messages_head) ||
1099        (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
1100   {
1101     return GNUNET_NO;
1102   }
1103   Peers_remove_peer (peer);
1104   return GNUNET_YES;
1105 }
1106
1107
1108 /**
1109  * @brief Remove peer
1110  *
1111  * @param peer the peer to clean
1112  * @return #GNUNET_YES if peer was removed
1113  *         #GNUNET_NO  otherwise
1114  */
1115 int
1116 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1117 {
1118   struct PeerContext *peer_ctx;
1119
1120   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1121   {
1122     return GNUNET_NO;
1123   }
1124
1125   peer_ctx = get_peer_ctx (peer);
1126   set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1127   LOG (GNUNET_ERROR_TYPE_DEBUG,
1128        "Going to remove peer %s\n",
1129        GNUNET_i2s (&peer_ctx->peer_id));
1130   Peers_unset_peer_flag (peer, Peers_ONLINE);
1131
1132   GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1133   while (NULL != peer_ctx->pending_messages_head)
1134   {
1135     LOG (GNUNET_ERROR_TYPE_DEBUG,
1136         "Removing unsent %s\n",
1137         peer_ctx->pending_messages_head->type);
1138     remove_pending_message (peer_ctx->pending_messages_head);
1139   }
1140   /* If we are still waiting for notification whether this peer is live
1141    * cancel the according task */
1142   if (NULL != peer_ctx->liveliness_check_pending)
1143   {
1144     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1145          "Removing pending liveliness check for peer %s\n",
1146          GNUNET_i2s (&peer_ctx->peer_id));
1147     // TODO wait until cadet sets mq->cancel_impl
1148     //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
1149     GNUNET_free (peer_ctx->liveliness_check_pending);
1150     peer_ctx->liveliness_check_pending = NULL;
1151   }
1152   if (NULL != peer_ctx->send_channel)
1153   {
1154     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1155     peer_ctx->send_channel = NULL;
1156   }
1157   if (NULL != peer_ctx->recv_channel)
1158   {
1159     GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1160     peer_ctx->recv_channel = NULL;
1161   }
1162   if (NULL != peer_ctx->mq)
1163   {
1164     GNUNET_MQ_destroy (peer_ctx->mq);
1165     peer_ctx->mq = NULL;
1166   }
1167
1168   GNUNET_free (peer_ctx->send_channel_flags);
1169   GNUNET_free (peer_ctx->recv_channel_flags);
1170
1171   if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1172   {
1173     LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1174   }
1175   GNUNET_free (peer_ctx);
1176   return GNUNET_YES;
1177 }
1178
1179
1180 /**
1181  * @brief set flags on a given peer.
1182  *
1183  * @param peer the peer to set flags on
1184  * @param flags the flags
1185  */
1186 void
1187 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1188 {
1189   struct PeerContext *peer_ctx;
1190
1191   peer_ctx = get_peer_ctx (peer);
1192   set_peer_flag (peer_ctx, flags);
1193 }
1194
1195
1196 /**
1197  * @brief unset flags on a given peer.
1198  *
1199  * @param peer the peer to unset flags on
1200  * @param flags the flags
1201  */
1202 void
1203 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1204 {
1205   struct PeerContext *peer_ctx;
1206
1207   peer_ctx = get_peer_ctx (peer);
1208   unset_peer_flag (peer_ctx, flags);
1209 }
1210
1211
1212 /**
1213  * @brief Check whether flags on a peer are set.
1214  *
1215  * @param peer the peer to check the flag of
1216  * @param flags the flags to check
1217  *
1218  * @return #GNUNET_SYSERR if peer is not known
1219  *         #GNUNET_YES    if all given flags are set
1220  *         #GNUNET_NO     otherwise
1221  */
1222 int
1223 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1224 {
1225   struct PeerContext *peer_ctx;
1226
1227   if (GNUNET_NO == Peers_check_peer_known (peer))
1228   {
1229     return GNUNET_SYSERR;
1230   }
1231   peer_ctx = get_peer_ctx (peer);
1232   return check_peer_flag_set (peer_ctx, flags);
1233 }
1234
1235
1236 /**
1237  * @brief set flags on a given channel.
1238  *
1239  * @param channel the channel to set flags on
1240  * @param flags the flags
1241  */
1242 void
1243 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1244 {
1245   set_channel_flag (channel_flags, flags);
1246 }
1247
1248
1249 /**
1250  * @brief unset flags on a given channel.
1251  *
1252  * @param channel the channel to unset flags on
1253  * @param flags the flags
1254  */
1255 void
1256 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1257 {
1258   unset_channel_flag (channel_flags, flags);
1259 }
1260
1261
1262 /**
1263  * @brief Check whether flags on a channel are set.
1264  *
1265  * @param channel the channel to check the flag of
1266  * @param flags the flags to check
1267  *
1268  * @return #GNUNET_YES if all given flags are set
1269  *         #GNUNET_NO  otherwise
1270  */
1271 int
1272 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1273 {
1274   return check_channel_flag_set (channel_flags, flags);
1275 }
1276
1277
1278 /**
1279  * @brief Check whether we have information about the given peer.
1280  *
1281  * FIXME probably deprecated. Make this the new _online.
1282  *
1283  * @param peer peer in question
1284  *
1285  * @return #GNUNET_YES if peer is known
1286  *         #GNUNET_NO  if peer is not knwon
1287  */
1288 int
1289 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1290 {
1291   return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1292 }
1293
1294
1295 /**
1296  * @brief Check whether @a peer is actually a peer.
1297  *
1298  * A valid peer is a peer that we know exists eg. we were connected to once.
1299  *
1300  * @param peer peer in question
1301  *
1302  * @return #GNUNET_YES if peer is valid
1303  *         #GNUNET_NO  if peer is not valid
1304  */
1305 int
1306 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1307 {
1308   return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1309 }
1310
1311
1312 /**
1313  * @brief Indicate that we want to send to the other peer
1314  *
1315  * This establishes a sending channel
1316  *
1317  * @param peer the peer to establish channel to
1318  */
1319 void
1320 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1321 {
1322   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1323   (void) get_channel (peer);
1324 }
1325
1326
1327 /**
1328  * @brief Check whether other peer has the intention to send/opened channel
1329  *        towars us
1330  *
1331  * @param peer the peer in question
1332  *
1333  * @return #GNUNET_YES if peer has the intention to send
1334  *         #GNUNET_NO  otherwise
1335  */
1336 int
1337 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1338 {
1339   const struct PeerContext *peer_ctx;
1340
1341   peer_ctx = get_peer_ctx (peer);
1342   if (NULL != peer_ctx->recv_channel)
1343   {
1344     return GNUNET_YES;
1345   }
1346   return GNUNET_NO;
1347 }
1348
1349
1350 /**
1351  * Handle the channel a peer opens to us.
1352  *
1353  * @param cls The closure
1354  * @param channel The channel the peer wants to establish
1355  * @param initiator The peer's peer ID
1356  * @param port The port the channel is being established over
1357  * @param options Further options
1358  *
1359  * @return initial channel context for the channel
1360  *         (can be NULL -- that's not an error)
1361  */
1362 void *
1363 Peers_handle_inbound_channel (void *cls,
1364                               struct GNUNET_CADET_Channel *channel,
1365                               const struct GNUNET_PeerIdentity *initiator,
1366                               const struct GNUNET_HashCode *port,
1367                               enum GNUNET_CADET_ChannelOption options)
1368 {
1369   struct PeerContext *peer_ctx;
1370
1371   LOG (GNUNET_ERROR_TYPE_DEBUG,
1372       "New channel was established to us (Peer %s).\n",
1373       GNUNET_i2s (initiator));
1374   GNUNET_assert (NULL != channel); /* according to cadet API */
1375   /* Make sure we 'know' about this peer */
1376   peer_ctx = create_or_get_peer_ctx (initiator);
1377   set_peer_live (peer_ctx);
1378   /* We only accept one incoming channel per peer */
1379   if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1380   {
1381     set_channel_flag (peer_ctx->recv_channel_flags,
1382                       Peers_CHANNEL_ESTABLISHED_TWICE);
1383     GNUNET_CADET_channel_destroy (channel);
1384     /* return the channel context */
1385     return peer_ctx->recv_channel_flags;
1386   }
1387   peer_ctx->recv_channel = channel;
1388   return peer_ctx->recv_channel_flags;
1389 }
1390
1391
1392 /**
1393  * @brief Check whether a sending channel towards the given peer exists
1394  *
1395  * @param peer the peer to check for
1396  *
1397  * @return #GNUNET_YES if a sending channel towards that peer exists
1398  *         #GNUNET_NO  otherwise
1399  */
1400 int
1401 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1402 {
1403   struct PeerContext *peer_ctx;
1404
1405   if (GNUNET_NO == Peers_check_peer_known (peer))
1406   { /* If no such peer exists, there is no channel */
1407     return GNUNET_NO;
1408   }
1409   peer_ctx = get_peer_ctx (peer);
1410   if (NULL == peer_ctx->send_channel)
1411   {
1412     return GNUNET_NO;
1413   }
1414   return GNUNET_YES;
1415 }
1416
1417
1418 /**
1419  * @brief check whether the given channel is the sending channel of the given
1420  *        peer
1421  *
1422  * @param peer the peer in question
1423  * @param channel the channel to check for
1424  * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1425  *                    #Peers_CHANNEL_ROLE_RECEIVING
1426  *
1427  * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1428  *         #GNUNET_NO  otherwise
1429  */
1430 int
1431 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1432                           const struct GNUNET_CADET_Channel *channel,
1433                           enum Peers_ChannelRole role)
1434 {
1435   const struct PeerContext *peer_ctx;
1436
1437   if (GNUNET_NO == Peers_check_peer_known (peer))
1438   {
1439     return GNUNET_NO;
1440   }
1441   peer_ctx = get_peer_ctx (peer);
1442   if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1443        (channel == peer_ctx->send_channel) )
1444   {
1445     return GNUNET_YES;
1446   }
1447   if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1448        (channel == peer_ctx->recv_channel) )
1449   {
1450     return GNUNET_YES;
1451   }
1452   return GNUNET_NO;
1453 }
1454
1455
1456 /**
1457  * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1458  *        intention to another peer
1459  *
1460  * If there is also no channel to receive messages from that peer, remove it
1461  * from the peermap.
1462  * TODO really?
1463  *
1464  * @peer the peer identity of the peer whose sending channel to destroy
1465  * @return #GNUNET_YES if channel was destroyed
1466  *         #GNUNET_NO  otherwise
1467  */
1468 int
1469 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1470 {
1471   struct PeerContext *peer_ctx;
1472
1473   if (GNUNET_NO == Peers_check_peer_known (peer))
1474   {
1475     return GNUNET_NO;
1476   }
1477   peer_ctx = get_peer_ctx (peer);
1478   if (NULL != peer_ctx->send_channel)
1479   {
1480     set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1481     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1482     peer_ctx->send_channel = NULL;
1483     (void) Peers_check_connected (peer);
1484     return GNUNET_YES;
1485   }
1486   return GNUNET_NO;
1487 }
1488
1489 /**
1490  * This is called when a channel is destroyed.
1491  *
1492  * @param cls The closure
1493  * @param channel The channel being closed
1494  * @param channel_ctx The context associated with this channel
1495  */
1496 void
1497 Peers_cleanup_destroyed_channel (void *cls,
1498                                  const struct GNUNET_CADET_Channel *channel,
1499                                  void *channel_ctx)
1500 {
1501   struct GNUNET_PeerIdentity *peer;
1502   struct PeerContext *peer_ctx;
1503
1504   peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1505       (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1506        // FIXME wait for cadet to change this function
1507
1508   if (GNUNET_NO == Peers_check_peer_known (peer))
1509   {/* We don't want to implicitly create a context that we're about to kill */
1510   LOG (GNUNET_ERROR_TYPE_DEBUG,
1511        "channel (%s) without associated context was destroyed\n",
1512        GNUNET_i2s (peer));
1513     return;
1514   }
1515   peer_ctx = get_peer_ctx (peer);
1516
1517   /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1518    * flag will be set. In this case simply make sure that the channels are
1519    * cleaned. */
1520   /* FIXME This distinction seems to be redundant */
1521   if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1522   {/* We initiatad the destruction of this particular peer */
1523     if (channel == peer_ctx->send_channel)
1524       peer_ctx->send_channel = NULL;
1525     else if (channel == peer_ctx->recv_channel)
1526       peer_ctx->recv_channel = NULL;
1527
1528     if (NULL != peer_ctx->send_channel)
1529     {
1530       GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1531       peer_ctx->send_channel = NULL;
1532     }
1533     if (NULL != peer_ctx->recv_channel)
1534     {
1535       GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1536       peer_ctx->recv_channel = NULL;
1537     }
1538     /* Set the #Peers_ONLINE flag accordingly */
1539     (void) Peers_check_connected (peer);
1540     return;
1541   }
1542
1543   else
1544   { /* We did not initiate the destruction of this peer */
1545     if (channel == peer_ctx->send_channel)
1546     { /* Something (but us) killd the channel - clean up peer */
1547       LOG (GNUNET_ERROR_TYPE_DEBUG,
1548           "send channel (%s) was destroyed - cleaning up\n",
1549           GNUNET_i2s (peer));
1550       peer_ctx->send_channel = NULL;
1551     }
1552     else if (channel == peer_ctx->recv_channel)
1553     { /* Other peer doesn't want to send us messages anymore */
1554       LOG (GNUNET_ERROR_TYPE_DEBUG,
1555            "Peer %s destroyed recv channel - cleaning up channel\n",
1556            GNUNET_i2s (peer));
1557       peer_ctx->recv_channel = NULL;
1558     }
1559     else
1560     {
1561       LOG (GNUNET_ERROR_TYPE_WARNING,
1562            "unknown channel (%s) was destroyed\n",
1563            GNUNET_i2s (peer));
1564     }
1565   }
1566   (void) Peers_check_connected (peer);
1567 }
1568
1569 /**
1570  * @brief Send a message to another peer.
1571  *
1572  * Keeps track about pending messages so they can be properly removed when the
1573  * peer is destroyed.
1574  *
1575  * @param peer receeiver of the message
1576  * @param ev envelope of the message
1577  * @param type type of the message
1578  */
1579 void
1580 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1581                     struct GNUNET_MQ_Envelope *ev,
1582                     const char *type)
1583 {
1584   struct PendingMessage *pending_msg;
1585   struct GNUNET_MQ_Handle *mq;
1586
1587   pending_msg = insert_pending_message (peer, ev, type);
1588   mq = get_mq (peer);
1589   GNUNET_MQ_notify_sent (ev,
1590                          mq_notify_sent_cb,
1591                          pending_msg);
1592   GNUNET_MQ_send (mq, ev);
1593 }
1594
1595 /**
1596  * @brief Schedule a operation on given peer
1597  *
1598  * Avoids scheduling an operation twice.
1599  *
1600  * @param peer the peer we want to schedule the operation for once it gets live
1601  *
1602  * @return #GNUNET_YES if the operation was scheduled
1603  *         #GNUNET_NO  otherwise
1604  */
1605 int
1606 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1607                           const PeerOp peer_op)
1608 {
1609   struct PeerPendingOp pending_op;
1610   struct PeerContext *peer_ctx;
1611
1612   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1613   {
1614     return GNUNET_NO;
1615   }
1616   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1617
1618   //TODO if LIVE/ONLINE execute immediately
1619
1620   if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1621   {
1622     peer_ctx = get_peer_ctx (peer);
1623     pending_op.op = peer_op;
1624     pending_op.op_cls = NULL;
1625     GNUNET_array_append (peer_ctx->pending_ops,
1626                          peer_ctx->num_pending_ops,
1627                          pending_op);
1628     return GNUNET_YES;
1629   }
1630   return GNUNET_NO;
1631 }
1632
1633 /* end of gnunet-service-rps_peers.c */