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