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