-rps: proper setting of "online" flag
[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(kind, __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 /**
208  * Set of all peers to keep track of them.
209  */
210 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
211
212 /**
213  * Own #GNUNET_PeerIdentity.
214  */
215 static const struct GNUNET_PeerIdentity *own_identity;
216
217 /**
218  * Cadet handle.
219  */
220 static struct GNUNET_CADET_Handle *cadet_handle;
221
222
223
224 /**
225  * @brief Get the #PeerContext associated with a peer
226  *
227  * @param peer the peer id
228  *
229  * @return the #PeerContext
230  */
231 static struct PeerContext *
232 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
233 {
234   struct PeerContext *ctx;
235   int ret;
236
237   ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
238   GNUNET_assert (GNUNET_YES == ret);
239   ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
240   GNUNET_assert (NULL != ctx);
241   return ctx;
242 }
243
244 /**
245  * @brief Create a new #PeerContext and insert it into the peer map
246  *
247  * @param peer the peer to create the #PeerContext for
248  *
249  * @return the #PeerContext
250  */
251 static struct PeerContext *
252 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
253 {
254   struct PeerContext *ctx;
255   int ret;
256
257   GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
258
259   ctx = GNUNET_new (struct PeerContext);
260   ctx->peer_id = *peer;
261   ctx->send_channel_flags = GNUNET_new (uint32_t);
262   ctx->recv_channel_flags = GNUNET_new (uint32_t);
263   ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
264       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
265   GNUNET_assert (GNUNET_OK == ret);
266   return ctx;
267 }
268
269 /**
270  * @brief Create or get a #PeerContext
271  *
272  * @param peer the peer to get the associated context to
273  *
274  * @return the context
275  */
276 static struct PeerContext *
277 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
278 {
279   if (GNUNET_NO == Peers_check_peer_known (peer))
280   {
281     return create_peer_ctx (peer);
282   }
283   return get_peer_ctx (peer);
284 }
285
286 /**
287  * @brief Check whether we have a connection to this @a peer
288  *
289  * Also sets the #Peers_ONLINE flag accordingly
290  *
291  * @param peer the peer in question
292  *
293  * @return #GNUNET_YES if we are connected
294  *         #GNUNET_NO  otherwise
295  */
296 int
297 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
298 {
299   const struct PeerContext *peer_ctx;
300
301   /* If we don't know about this peer we don't know whether it's online */
302   if (GNUNET_NO == Peers_check_peer_known (peer))
303   {
304     return GNUNET_NO;
305   }
306   /* Get the context */
307   peer_ctx = get_peer_ctx (peer);
308   /* If we have no channel to this peer we don't know whether it's online */
309   if ( (NULL == peer_ctx->send_channel) &&
310        (NULL == peer_ctx->recv_channel) )
311   {
312     Peers_unset_peer_flag (peer, Peers_ONLINE);
313     return GNUNET_NO;
314   }
315   /* Otherwise (if we have a channel, we know that it's online */
316   Peers_set_peer_flag (peer, Peers_ONLINE);
317   return GNUNET_YES;
318 }
319
320 /**
321  * @brief Set the peer flag to living and
322  *        call the pending operations on this peer.
323  *
324  * Also sets the #Peers_VALID flag
325  *
326  * @param peer_ctx the #PeerContext of the peer to set live
327  */
328 static void
329 set_peer_live (struct PeerContext *peer_ctx)
330 {
331   struct GNUNET_PeerIdentity *peer;
332   unsigned int i;
333
334   /* Cancle cadet transmit_handle if still scheduled */
335   if (NULL != peer_ctx->transmit_handle)
336   {
337     GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
338     peer_ctx->transmit_handle = NULL;
339   }
340
341   peer = &peer_ctx->peer_id;
342   set_peer_flag (peer_ctx, Peers_VALID);
343   set_peer_flag (peer_ctx, Peers_ONLINE);
344   LOG (GNUNET_ERROR_TYPE_DEBUG,
345       "Peer %s is live and valid\n",
346       GNUNET_i2s (peer));
347
348   /* Call pending operations */
349   for (i = 0; i < peer_ctx->num_pending_ops; i++)
350   {
351     peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
352   }
353   GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
354 }
355
356 /**
357  * @brief Get the channel of a peer. If not existing, create.
358  *
359  * @param peer the peer id
360  * @return the #GNUNET_CADET_Channel used to send data to @a peer
361  */
362 struct GNUNET_CADET_Channel *
363 get_channel (const struct GNUNET_PeerIdentity *peer)
364 {
365   struct PeerContext *peer_ctx;
366
367   peer_ctx = get_peer_ctx (peer);
368   if (NULL == peer_ctx->send_channel)
369   {
370     LOG (GNUNET_ERROR_TYPE_DEBUG,
371          "Trying to establish channel to peer %s\n",
372          GNUNET_i2s (peer));
373     peer_ctx->send_channel =
374       GNUNET_CADET_channel_create (cadet_handle,
375                                    peer_ctx->send_channel_flags, /* context */
376                                    peer,
377                                    GNUNET_RPS_CADET_PORT,
378                                    GNUNET_CADET_OPTION_RELIABLE);
379   }
380   return peer_ctx->send_channel;
381 }
382
383 /**
384  * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
385  *
386  * If we already have a message queue open to this client,
387  * simply return it, otherways create one.
388  * 
389  * @param peer the peer to get the mq to
390  * @return the #GNUNET_MQ_Handle
391  */
392 static struct GNUNET_MQ_Handle *
393 get_mq (const struct GNUNET_PeerIdentity *peer)
394 {
395   struct PeerContext *peer_ctx;
396
397   peer_ctx = get_peer_ctx (peer);
398   GNUNET_assert (NULL == peer_ctx->transmit_handle);
399
400   if (NULL == peer_ctx->mq)
401   {
402     (void) get_channel (peer);
403     peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
404   }
405   return peer_ctx->mq;
406 }
407
408 /**
409  * @brief Callback that is called when a channel was effectively established.
410  *
411  * This is an implementation of #GNUNET_CONNECTION_TransmitReadyNotify and
412  * given to #GNUNET_CADET_notify_transmit_ready_cancel and called when the
413  * channel was successfully established.
414  *
415  * This function type was originally ment to be called to provide the data to
416  * be sent. This is called when the connection is ready to queue more data.
417  * However we use it to get notified about the successful establishement of a
418  * cadet channel.
419  *
420  * @a buf will be NULL and @a size zero if the
421  * connection was closed for writing in the meantime.
422  *
423  * @param cls closure
424  * @param size number of bytes available in @a buf
425  * @param buf where the callee should write the message
426  * @return number of bytes written to @a buf
427  */
428 //TODO
429 static size_t
430 cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
431 {
432   struct PeerContext *peer_ctx = (struct PeerContext *) cls;
433   // TODO make sure the context is not deleted or the establishing of the
434   //      channel is cancelled
435
436   peer_ctx->transmit_handle = NULL;
437   LOG (GNUNET_ERROR_TYPE_DEBUG,
438        "Set ->transmit_handle = NULL for peer %s\n",
439        GNUNET_i2s (&peer_ctx->peer_id));
440
441   if ( (NULL != buf) &&
442        (0 != size) )
443   {
444     set_peer_live (peer_ctx);
445   }
446   else
447   {
448     LOG (GNUNET_ERROR_TYPE_WARNING,
449          "Problems establishing a connection to peer %s in order to check liveliness\n",
450          GNUNET_i2s (&peer_ctx->peer_id));
451     // TODO reschedule? cleanup?
452   }
453   return 0;
454 }
455
456 /**
457  * Issue a check whether peer is live
458  *
459  * @param peer_ctx the context of the peer
460  */
461 static void
462 check_peer_live (struct PeerContext *peer_ctx)
463 {
464   LOG (GNUNET_ERROR_TYPE_DEBUG,
465        "Get informed about peer %s getting live\n",
466        GNUNET_i2s (&peer_ctx->peer_id));
467
468   if (NULL == peer_ctx->transmit_handle &&
469       NULL == peer_ctx->send_channel)
470   {
471     (void) get_channel (&peer_ctx->peer_id);
472     peer_ctx->transmit_handle =
473         GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
474                                             GNUNET_NO,
475                                             GNUNET_TIME_UNIT_FOREVER_REL,
476                                             sizeof (struct GNUNET_MessageHeader),
477                                             cadet_notify_transmit_ready_cb,
478                                             peer_ctx);
479   }
480   else if (NULL != peer_ctx->transmit_handle)
481     LOG (GNUNET_ERROR_TYPE_DEBUG,
482          "Already waiting for notification\n");
483   else if (NULL != peer_ctx->send_channel)
484     LOG (GNUNET_ERROR_TYPE_DEBUG,
485          "Already have established channel to peer\n");
486 }
487
488 /**
489  * @brief Add an envelope to a message passed to mq to list of pending messages
490  *
491  * @param peer peer the message was sent to
492  * @param ev envelope to the message
493  * @param type type of the message to be sent
494  * @return pointer to pending message
495  */
496 static struct PendingMessage *
497 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
498                         struct GNUNET_MQ_Envelope *ev,
499                         const char *type)
500 {
501   struct PendingMessage *pending_msg;
502   struct PeerContext *peer_ctx;
503
504   peer_ctx = get_peer_ctx (peer);
505   pending_msg = GNUNET_new (struct PendingMessage);
506   pending_msg->ev = ev;
507   pending_msg->peer_ctx = peer_ctx;
508   pending_msg->type = type;
509   GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
510                                peer_ctx->pending_messages_tail,
511                                pending_msg);
512   return pending_msg;
513 }
514
515 /**
516  * @brief Remove a pending message from the respective DLL
517  *
518  * @param pending_msg the pending message to remove
519  */
520 static void
521 remove_pending_message (struct PendingMessage *pending_msg)
522 {
523   struct PeerContext *peer_ctx;
524
525   peer_ctx = pending_msg->peer_ctx;
526   GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
527                                peer_ctx->pending_messages_tail,
528                                pending_msg);
529   /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does
530    * not set a #GNUNET_MQ_CancelImpl */
531   /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
532   GNUNET_free (pending_msg);
533 }
534
535 /**
536  * @brief Check whether function of type #PeerOp was already scheduled
537  *
538  * The array with pending operations will probably never grow really big, so
539  * iterating over it should be ok.
540  *
541  * @param peer the peer to check
542  * @param peer_op the operation (#PeerOp) on the peer
543  *
544  * @return #GNUNET_YES if this operation is scheduled on that peer
545  *         #GNUNET_NO  otherwise
546  */
547 static int
548 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
549                            const PeerOp peer_op)
550 {
551   const struct PeerContext *peer_ctx;
552   unsigned int i;
553
554   peer_ctx = get_peer_ctx (peer);
555   for (i = 0; i < peer_ctx->num_pending_ops; i++)
556     if (peer_op == peer_ctx->pending_ops[i].op)
557       return GNUNET_YES;
558   return GNUNET_NO;
559 }
560
561 /**
562  * Iterator over hash map entries. Deletes all contexts of peers.
563  *
564  * @param cls closure
565  * @param key current public key
566  * @param value value in the hash map
567  * @return #GNUNET_YES if we should continue to iterate,
568  *         #GNUNET_NO if not.
569  */
570 static int
571 peermap_clear_iterator (void *cls,
572                         const struct GNUNET_PeerIdentity *key,
573                         void *value)
574 {
575   Peers_remove_peer (key);
576   return GNUNET_YES;
577 }
578
579 /**
580  * @brief This is called once a message is sent.
581  *
582  * Removes the pending message
583  *
584  * @param cls type of the message that was sent
585  */
586 static void
587 mq_notify_sent_cb (void *cls)
588 {
589   struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
590   LOG (GNUNET_ERROR_TYPE_DEBUG,
591       "%s was sent.\n",
592       pending_msg->type);
593   remove_pending_message (pending_msg);
594 }
595
596
597 /**
598  * @brief Initialise storage of peers
599  *
600  * @param cadet_h cadet handle
601  * @param own_id own peer identity
602  */
603 void
604 Peers_initialise (struct GNUNET_CADET_Handle *cadet_h,
605                   const struct GNUNET_PeerIdentity *own_id)
606 {
607   cadet_handle = cadet_h;
608   own_identity = own_id;
609   peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
610 }
611
612 /**
613  * @brief Delete storage of peers that was created with #Peers_initialise ()
614  */
615 void
616 Peers_terminate ()
617 {
618   if (GNUNET_SYSERR ==
619       GNUNET_CONTAINER_multipeermap_iterate (peer_map,
620                                              peermap_clear_iterator,
621                                              NULL))
622   {
623     LOG (GNUNET_ERROR_TYPE_WARNING,
624         "Iteration destroying peers was aborted.\n");
625   }
626   GNUNET_CONTAINER_multipeermap_destroy (peer_map);
627 }
628
629 /**
630  * @brief Add peer to known peers.
631  *
632  * This function is called on new peer_ids from 'external' sources
633  * (client seed, cadet get_peers(), ...)
634  *
635  * @param peer the new #GNUNET_PeerIdentity
636  *
637  * @return #GNUNET_YES if peer was inserted
638  *         #GNUNET_NO  if peer was already known
639  */
640 int
641 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
642 {
643   if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
644        (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
645   {
646     return GNUNET_NO; /* We already know this peer - nothing to do */
647   }
648   (void) create_peer_ctx (peer);
649   return GNUNET_YES;
650 }
651
652
653 /**
654  * @brief Add peer to known peers and check for liveliness.
655  *
656  * This function is called on new peer_ids from 'external' sources
657  * (client seed, cadet get_peers(), ...)
658  *
659  * @param peer the new #GNUNET_PeerIdentity
660  *
661  * @return #GNUNET_YES if peer was inserted
662  *         #GNUNET_NO  if peer was already known
663  */
664 int
665 Peers_insert_peer_check_liveliness (const struct GNUNET_PeerIdentity *peer)
666 {
667   struct PeerContext *peer_ctx;
668   int ret;
669
670   ret = Peers_insert_peer (peer);
671   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
672   {
673     return ret;
674   }
675   peer_ctx = get_peer_ctx (peer);
676   if (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_VALID))
677   {
678     check_peer_live (peer_ctx);
679   }
680   return ret;
681 }
682
683 /**
684  * @brief Remove unecessary data
685  *
686  * If the other peer is not intending to send messages, we have messages pending
687  * to be sent to this peer and we are not waiting for a reply, remove the
688  * information about it (its #PeerContext).
689  *
690  * @param peer the peer to clean
691  * @return #GNUNET_YES if peer was removed
692  *         #GNUNET_NO  otherwise
693  */
694 int
695 Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
696 {
697   struct PeerContext *peer_ctx;
698
699   // TODO actually remove unnecessary data
700
701   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer)) 
702   {
703     return GNUNET_NO;
704   }
705
706   peer_ctx = get_peer_ctx (peer);
707   if ( (NULL != peer_ctx->recv_channel) ||
708        (NULL != peer_ctx->pending_messages_head) ||
709        (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
710   {
711     return GNUNET_NO;
712   }
713   Peers_remove_peer (peer);
714   return GNUNET_YES;
715 }
716
717 /**
718  * @brief Remove peer
719  * 
720  * @param peer the peer to clean
721  * @return #GNUNET_YES if peer was removed
722  *         #GNUNET_NO  otherwise
723  */
724 int
725 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
726 {
727   struct PeerContext *peer_ctx;
728
729   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer)) 
730   {
731     return GNUNET_NO;
732   }
733
734   peer_ctx = get_peer_ctx (peer);
735   set_peer_flag (peer_ctx, Peers_TO_DESTROY);
736   LOG (GNUNET_ERROR_TYPE_DEBUG,
737        "Going to remove peer %s\n",
738        GNUNET_i2s (&peer_ctx->peer_id));
739   Peers_unset_peer_flag (peer, Peers_ONLINE);
740
741   GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
742   // TODO delete struct GNUNET_TRANSPORT_TransmitHandle *transmit_handle
743   /* Cancle messages that have not been sent yet */
744   while (NULL != peer_ctx->pending_messages_head)
745   {
746     LOG (GNUNET_ERROR_TYPE_DEBUG,
747         "Removing unsent %s\n",
748         peer_ctx->pending_messages_head->type);
749     remove_pending_message (peer_ctx->pending_messages_head);
750   }
751   /* If we are still waiting for notification whether this peer is live
752    * cancel the according task */
753   if (NULL != peer_ctx->transmit_handle)
754   {
755     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756          "Trying to cancle transmit_handle for peer %s\n",
757          GNUNET_i2s (&peer_ctx->peer_id));
758     GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
759     peer_ctx->transmit_handle = NULL;
760   }
761   if (NULL != peer_ctx->send_channel)
762   {
763     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
764     peer_ctx->send_channel = NULL;
765   }
766   if (NULL != peer_ctx->recv_channel)
767   {
768     GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
769     peer_ctx->recv_channel = NULL;
770   }
771   if (NULL != peer_ctx->mq)
772   {
773     GNUNET_MQ_destroy (peer_ctx->mq);
774     peer_ctx->mq = NULL;
775   }
776
777   GNUNET_free (peer_ctx->send_channel_flags);
778   GNUNET_free (peer_ctx->recv_channel_flags);
779
780   if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
781   {
782     LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
783   }
784   GNUNET_free (peer_ctx);
785   return GNUNET_YES;
786 }
787
788 /**
789  * @brief set flags on a given peer.
790  *
791  * @param peer the peer to set flags on
792  * @param flags the flags
793  */
794 void
795 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
796 {
797   struct PeerContext *peer_ctx;
798
799   peer_ctx = get_peer_ctx (peer);
800   set_peer_flag (peer_ctx, flags);
801 }
802
803 /**
804  * @brief unset flags on a given peer.
805  *
806  * @param peer the peer to unset flags on
807  * @param flags the flags
808  */
809 void
810 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
811 {
812   struct PeerContext *peer_ctx;
813
814   peer_ctx = get_peer_ctx (peer);
815   unset_peer_flag (peer_ctx, flags);
816 }
817
818 /**
819  * @brief Check whether flags on a peer are set.
820  *
821  * @param peer the peer to check the flag of
822  * @param flags the flags to check
823  *
824  * @return #GNUNET_YES if all given flags are set
825  *         #GNUNET_NO  otherwise
826  */
827 int
828 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
829 {
830   struct PeerContext *peer_ctx;
831
832   peer_ctx = get_peer_ctx (peer);
833   return check_peer_flag_set (peer_ctx, flags);
834 }
835
836
837 /**
838  * @brief set flags on a given channel.
839  *
840  * @param channel the channel to set flags on
841  * @param flags the flags
842  */
843 void
844 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
845 {
846   set_channel_flag (channel_flags, flags);
847 }
848
849 /**
850  * @brief unset flags on a given channel.
851  *
852  * @param channel the channel to unset flags on
853  * @param flags the flags
854  */
855 void
856 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
857 {
858   unset_channel_flag (channel_flags, flags);
859 }
860
861 /**
862  * @brief Check whether flags on a channel are set.
863  *
864  * @param channel the channel to check the flag of
865  * @param flags the flags to check
866  *
867  * @return #GNUNET_YES if all given flags are set
868  *         #GNUNET_NO  otherwise
869  */
870 int
871 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
872 {
873   return check_channel_flag_set (channel_flags, flags);
874 }
875
876 /**
877  * @brief Check whether we have information about the given peer.
878  *
879  * @param peer peer in question
880  *
881  * @return #GNUNET_YES if peer is known
882  *         #GNUNET_NO  if peer is not knwon
883  */
884 int
885 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
886 {
887   return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
888 }
889
890 /**
891  * @brief Indicate that we want to send to the other peer
892  *
893  * This establishes a sending channel
894  *
895  * @param peer the peer to establish channel to
896  */
897 void
898 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
899 {
900   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
901   (void) get_channel (peer);
902 }
903
904 /**
905  * @brief Check whether other peer has the intention to send/opened channel
906  *        towars us
907  *
908  * @param peer the peer in question
909  *
910  * @return #GNUNET_YES if peer has the intention to send
911  *         #GNUNET_NO  otherwise
912  */
913 int
914 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
915 {
916   const struct PeerContext *peer_ctx;
917
918   peer_ctx = get_peer_ctx (peer);
919   if (NULL != peer_ctx->recv_channel)
920   {
921     return GNUNET_YES;
922   }
923   return GNUNET_NO;
924 }
925
926 /**
927  * Handle the channel a peer opens to us.
928  *
929  * @param cls The closure
930  * @param channel The channel the peer wants to establish
931  * @param initiator The peer's peer ID
932  * @param port The port the channel is being established over
933  * @param options Further options
934  *
935  * @return initial channel context for the channel
936  *         (can be NULL -- that's not an error)
937  */
938 void *
939 Peers_handle_inbound_channel (void *cls,
940                               struct GNUNET_CADET_Channel *channel,
941                               const struct GNUNET_PeerIdentity *initiator,
942                               uint32_t port,
943                               enum GNUNET_CADET_ChannelOption options)
944 {
945   struct PeerContext *peer_ctx;
946
947   LOG (GNUNET_ERROR_TYPE_DEBUG,
948       "New channel was established to us (Peer %s).\n",
949       GNUNET_i2s (initiator));
950   GNUNET_assert (NULL != channel); /* according to cadet API */
951   /* Make sure we 'know' about this peer */
952   peer_ctx = create_or_get_peer_ctx (initiator);
953   set_peer_live (peer_ctx);
954   /* We only accept one incoming channel per peer */
955   if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
956   {
957     set_channel_flag (peer_ctx->recv_channel_flags,
958                       Peers_CHANNEL_ESTABLISHED_TWICE);
959     GNUNET_CADET_channel_destroy (channel);
960     /* return the channel context */
961     return peer_ctx->recv_channel_flags;
962   }
963   peer_ctx->recv_channel = channel;
964   return peer_ctx->recv_channel_flags;
965 }
966
967 /**
968  * @brief Check whether a sending channel towards the given peer exists
969  *
970  * @param peer the peer to check for
971  *
972  * @return #GNUNET_YES if a sending channel towards that peer exists
973  *         #GNUNET_NO  otherwise
974  */
975 int
976 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
977 {
978   struct PeerContext *peer_ctx;
979
980   if (GNUNET_NO == Peers_check_peer_known (peer))
981   { /* If no such peer exists, there is no channel */
982     return GNUNET_NO;
983   }
984   peer_ctx = get_peer_ctx (peer);
985   if (NULL == peer_ctx->send_channel)
986   {
987     return GNUNET_NO;
988   }
989   return GNUNET_YES;
990 }
991
992 /**
993  * @brief check whether the given channel is the sending channel of the given
994  *        peer
995  *
996  * @param peer the peer in question
997  * @param channel the channel to check for
998  * @param role either #Peers_CHANNEL_ROLE_SENDING, or
999  *                    #Peers_CHANNEL_ROLE_RECEIVING
1000  *
1001  * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1002  *         #GNUNET_NO  otherwise
1003  */
1004 int
1005 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1006                           const struct GNUNET_CADET_Channel *channel,
1007                           enum Peers_ChannelRole role)
1008 {
1009   const struct PeerContext *peer_ctx;
1010
1011   if (GNUNET_NO == Peers_check_peer_known (peer))
1012   {
1013     return GNUNET_NO;
1014   }
1015   peer_ctx = get_peer_ctx (peer);
1016   if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1017        (channel == peer_ctx->send_channel) )
1018   {
1019     return GNUNET_YES;
1020   }
1021   if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1022        (channel == peer_ctx->recv_channel) )
1023   {
1024     return GNUNET_YES;
1025   }
1026   return GNUNET_NO;
1027 }
1028
1029 /**
1030  * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1031  *        intention to another peer
1032  *
1033  * If there is also no channel to receive messages from that peer, remove it
1034  * from the peermap.
1035  * TODO really?
1036  *
1037  * @peer the peer identity of the peer whose sending channel to destroy
1038  * @return #GNUNET_YES if channel was destroyed
1039  *         #GNUNET_NO  otherwise
1040  */
1041 int
1042 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1043 {
1044   struct PeerContext *peer_ctx;
1045
1046   if (GNUNET_NO == Peers_check_peer_known (peer))
1047   {
1048     return GNUNET_NO;
1049   }
1050   peer_ctx = get_peer_ctx (peer);
1051   if (NULL != peer_ctx->send_channel)
1052   {
1053     set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1054     GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1055     peer_ctx->send_channel = NULL;
1056     (void) Peers_check_connected (peer);
1057     return GNUNET_YES;
1058   }
1059   return GNUNET_NO;
1060 }
1061
1062 /**
1063  * This is called when a channel is destroyed.
1064  *
1065  * Removes peer completely from our knowledge if the send_channel was destroyed
1066  * Otherwise simply delete the recv_channel
1067  *
1068  * @param cls The closure
1069  * @param channel The channel being closed
1070  * @param channel_ctx The context associated with this channel
1071  */
1072 void
1073 Peers_cleanup_destroyed_channel (void *cls,
1074                                  const struct GNUNET_CADET_Channel *channel,
1075                                  void *channel_ctx)
1076 {
1077   struct GNUNET_PeerIdentity *peer;
1078   struct PeerContext *peer_ctx;
1079
1080   peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1081       (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1082        // FIXME wait for cadet to change this function
1083
1084   if (GNUNET_NO == Peers_check_peer_known (peer))
1085   {/* We don't want to implicitly create a context that we're about to kill */
1086   LOG (GNUNET_ERROR_TYPE_DEBUG,
1087        "channel (%s) without associated context was destroyed\n",
1088        GNUNET_i2s (peer));
1089     return;
1090   }
1091   peer_ctx = get_peer_ctx (peer);
1092
1093   /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1094    * flag will be set. In this case simply make sure that the channels are
1095    * cleaned. */
1096   if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1097   {/* We initiatad the destruction of this particular peer */
1098     if (channel == peer_ctx->send_channel)
1099       peer_ctx->send_channel = NULL;
1100     else if (channel == peer_ctx->recv_channel)
1101       peer_ctx->recv_channel = NULL;
1102     (void) Peers_check_connected (peer);
1103     return;
1104   }
1105
1106   else
1107   { /* We did not initiate the destruction of this peer */
1108     if (channel == peer_ctx->send_channel)
1109     { /* Something (but us) killd the channel - clean up peer */
1110       LOG (GNUNET_ERROR_TYPE_DEBUG,
1111           "send channel (%s) was destroyed - cleaning up\n",
1112           GNUNET_i2s (peer));
1113       peer_ctx->send_channel = NULL;
1114     }
1115     else if (channel == peer_ctx->recv_channel)
1116     { /* Other peer doesn't want to send us messages anymore */
1117       LOG (GNUNET_ERROR_TYPE_DEBUG,
1118            "Peer %s destroyed recv channel - cleaning up channel\n",
1119            GNUNET_i2s (peer));
1120       peer_ctx->recv_channel = NULL;
1121     }
1122     else
1123     {
1124       LOG (GNUNET_ERROR_TYPE_WARNING,
1125            "unknown channel (%s) was destroyed\n",
1126            GNUNET_i2s (peer));
1127     }
1128   }
1129   (void) Peers_check_connected (peer);
1130 }
1131
1132 /**
1133  * @brief Issue a check whether peer is live
1134  *
1135  * This tries to establish a channel to the given peer. Once the channel is
1136  * established successfully, we know the peer is live.
1137  *
1138  * @param peer the peer to check liveliness
1139  */
1140 void
1141 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1142 {
1143   struct PeerContext *peer_ctx;
1144
1145   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1146   {
1147     return; /* We know that we are online */
1148   }
1149
1150   peer_ctx = create_or_get_peer_ctx (peer);
1151   // TODO if LIVE/ONLINE
1152   check_peer_live (peer_ctx);
1153 }
1154
1155 /**
1156  * @brief Send a message to another peer.
1157  *
1158  * Keeps track about pending messages so they can be properly removed when the
1159  * peer is destroyed.
1160  *
1161  * @param peer receeiver of the message
1162  * @param ev envelope of the message
1163  * @param type type of the message
1164  */
1165 void
1166 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1167                     struct GNUNET_MQ_Envelope *ev,
1168                     const char *type)
1169 {
1170   struct PendingMessage *pending_msg;
1171   struct GNUNET_MQ_Handle *mq;
1172
1173   pending_msg = insert_pending_message (peer, ev, "PULL REPLY");
1174   mq = get_mq (peer);
1175   GNUNET_MQ_notify_sent (ev,
1176                          mq_notify_sent_cb,
1177                          pending_msg);
1178   GNUNET_MQ_send (mq, ev);
1179 }
1180
1181 /**
1182  * @brief Schedule a operation on given peer
1183  *
1184  * Avoids scheduling an operation twice.
1185  *
1186  * @param peer the peer we want to schedule the operation for once it gets live
1187  *
1188  * @return #GNUNET_YES if the operation was scheduled
1189  *         #GNUNET_NO  otherwise
1190  */
1191 int
1192 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1193                           const PeerOp peer_op)
1194 {
1195   struct PeerPendingOp pending_op;
1196   struct PeerContext *peer_ctx;
1197
1198   if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
1199   {
1200     return GNUNET_NO;
1201   }
1202   GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1203
1204   //TODO if LIVE/ONLINE execute immediately
1205
1206   if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1207   {
1208     peer_ctx = get_peer_ctx (peer);
1209     pending_op.op = peer_op;
1210     pending_op.op_cls = NULL;
1211     GNUNET_array_append (peer_ctx->pending_ops,
1212                          peer_ctx->num_pending_ops,
1213                          pending_op);
1214     return GNUNET_YES;
1215   }
1216   return GNUNET_NO;
1217 }
1218
1219 /* end of gnunet-service-rps_peers.c */