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