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