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