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