REST/NAMESTORE: rework API
[oweals/gnunet.git] / src / cadet / cadet_api_list_tunnels.c
index da5f85aa0ada5853360cd1866e1234900cdf6f86..a2ba65993adc1858a3b476116d97f3810ec56a31 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2011, 2017 GNUnet e.V.
+     Copyright (C) 2011, 2017, 2019 GNUnet e.V.
 
      GNUnet is free software: you can redistribute it and/or modify it
      under the terms of the GNU Affero General Public License as published
@@ -18,7 +18,7 @@
      SPDX-License-Identifier: AGPL3.0-or-later
 */
 /**
- * @file cadet/cadet_api.c
+ * @file cadet/cadet_api_list_tunnels.c
  * @brief cadet api: client implementation of cadet service
  * @author Bartlomiej Polot
  * @author Christian Grothoff
@@ -31,9 +31,8 @@
 #include "cadet_protocol.h"
 
 
-
 /**
- * Ugly legacy hack.
+ * Operation handle.
  */
 struct GNUNET_CADET_ListTunnels
 {
@@ -47,83 +46,138 @@ struct GNUNET_CADET_ListTunnels
    * Info callback closure for @c tunnels_cb.
    */
   void *tunnels_cb_cls;
+  
+  /**
+   * Message queue to talk to CADET service.
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Configuration we use.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Task to reconnect.
+   */
+  struct GNUNET_SCHEDULER_Task *reconnect_task;
+
+  /**
+   * Backoff for reconnect attempts.
+   */
+  struct GNUNET_TIME_Relative backoff;
+
 };
 
 
 /**
- * Send message of @a type to CADET service of @a h
+ * Process a local reply about info on all tunnels, pass info to the user.
  *
- * @param h handle to CADET service
- * @param type message type of trivial information request to send
+ * @param cls a `struct GNUNET_CADET_ListTunnels *`
+ * @param info Message itself.
  */
 static void
-send_info_request (struct GNUNET_CADET_Handle *h,
-                   uint16_t type)
+handle_get_tunnels (void *cls,
+                   const struct GNUNET_CADET_LocalInfoTunnel *info)
 {
-  struct GNUNET_MessageHeader *msg;
-  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_ListTunnels *lt = cls;
+  struct GNUNET_CADET_TunnelDetails td;
+  
+  td.peer = info->destination;
+  td.channels = ntohl (info->channels);
+  td.connections = ntohl (info->connections);
+  td.estate = ntohs (info->estate);
+  td.cstate = ntohs (info->cstate);
+  lt->tunnels_cb (lt->tunnels_cb_cls,
+                 &td);
+}
 
-  env = GNUNET_MQ_msg (msg,
-                       type);
-  GNUNET_MQ_send (h->mq,
-                  env);
+
+/**
+ * Process a local reply about info on all tunnels, pass info to the user.
+ *
+ * @param cls a `struct GNUNET_CADET_ListTunnels *`
+ * @param message Message itself.
+ */
+static void
+handle_get_tunnels_end (void *cls,
+                       const struct GNUNET_MessageHeader *msg)
+{
+  struct GNUNET_CADET_ListTunnels *lt = cls;
+  (void) msg;
+  
+  lt->tunnels_cb (lt->tunnels_cb_cls,
+                 NULL);
+  GNUNET_CADET_list_tunnels_cancel (lt);
 }
 
 
 /**
- * Check that message received from CADET service is well-formed.
+ * Reconnect to the service and try again.
+ *
+ * @param cls a `struct GNUNET_CADET_ListTunnels` operation
+ */
+static void
+reconnect (void *cls);
+
+
+/**
+ * Function called on connection trouble.  Reconnects.
  *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param message the message we got
- * @return #GNUNET_OK if the message is well-formed,
- *         #GNUNET_SYSERR otherwise
+ * @param cls a `struct GNUNET_CADET_ListTunnels`
+ * @param error error code from MQ
  */
-static int
-check_get_tunnels (void *cls,
-                   const struct GNUNET_MessageHeader *message)
+static void
+error_handler (void *cls,
+              enum GNUNET_MQ_Error error)
 {
-  size_t esize;
-
-  (void) cls;
-  esize = ntohs (message->size);
-  if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) == esize)
-    return GNUNET_OK;
-  if (sizeof (struct GNUNET_MessageHeader) == esize)
-    return GNUNET_OK;
-  return GNUNET_SYSERR;
+  struct GNUNET_CADET_ListTunnels *lt = cls;
+
+  GNUNET_MQ_destroy (lt->mq);
+  lt->mq = NULL;
+  lt->backoff = GNUNET_TIME_randomized_backoff (lt->backoff,
+                                               GNUNET_TIME_UNIT_MINUTES);
+  lt->reconnect_task = GNUNET_SCHEDULER_add_delayed (lt->backoff,
+                                                    &reconnect,
+                                                    lt);
 }
 
 
 /**
- * Process a local reply about info on all tunnels, pass info to the user.
+ * Reconnect to the service and try again.
  *
- * @param cls Closure (Cadet handle).
- * @param message Message itself.
+ * @param cls a `struct GNUNET_CADET_ListTunnels` operation
  */
 static void
-handle_get_tunnels (void *cls,
-                    const struct GNUNET_MessageHeader *msg)
+reconnect (void *cls)
 {
-  struct GNUNET_CADET_Handle *h = cls;
-  const struct GNUNET_CADET_LocalInfoTunnel *info =
-    (const struct GNUNET_CADET_LocalInfoTunnel *) msg;
+  struct GNUNET_CADET_ListTunnels *lt = cls;
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_fixed_size (get_tunnels,
+                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+                            struct GNUNET_CADET_LocalInfoTunnel,
+                            lt),
+    GNUNET_MQ_hd_fixed_size (get_tunnels_end,
+                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS_END,
+                            struct GNUNET_MessageHeader,
+                            lt),
+    GNUNET_MQ_handler_end ()
+  };
+  struct GNUNET_MessageHeader *msg;
+  struct GNUNET_MQ_Envelope *env;
 
-  if (NULL == h->info_cb.tunnels_cb)
+  lt->reconnect_task = NULL;
+  lt->mq = GNUNET_CLIENT_connect (lt->cfg,
+                                 "cadet",
+                                 handlers,
+                                 &error_handler,
+                                 lt);  
+  if (NULL == lt->mq)
     return;
-  if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) == ntohs (msg->size))
-    h->info_cb.tunnels_cb (h->info_cls,
-                           &info->destination,
-                           ntohl (info->channels),
-                           ntohl (info->connections),
-                           ntohs (info->estate),
-                           ntohs (info->cstate));
-  else
-    h->info_cb.tunnels_cb (h->info_cls,
-                           NULL,
-                           0,
-                           0,
-                           0,
-                           0);
+  env = GNUNET_MQ_msg (msg,
+                      GNUNET_MESSAGE_TYPE_CADET_LOCAL_REQUEST_INFO_TUNNELS);
+  GNUNET_MQ_send (lt->mq,
+                  env);
 }
 
 
@@ -132,56 +186,55 @@ handle_get_tunnels (void *cls,
  * The callback will be called for every tunnel of the service.
  * Only one info request (of any kind) can be active at once.
  *
- * WARNING: unstable API, likely to change in the future!
- *
- * @param h Handle to the cadet peer.
+ * @param cfg configuration to use
  * @param callback Function to call with the requested data.
  * @param callback_cls Closure for @c callback.
- * @return #GNUNET_OK / #GNUNET_SYSERR
+ * @return NULL on error
  */
-int
+struct GNUNET_CADET_ListTunnels *
 GNUNET_CADET_list_tunnels (const struct GNUNET_CONFIGURATION_Handle *cfg,
                           GNUNET_CADET_TunnelsCB callback,
                           void *callback_cls)
 {
+  struct GNUNET_CADET_ListTunnels *lt;
 
-      GNUNET_MQ_hd_var_size (get_tunnels,
-                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
-                           struct GNUNET_MessageHeader,
-                           h),
-    GNUNET_MQ_hd_var_size (get_tunnel,
-                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
-                           struct GNUNET_CADET_LocalInfoTunnel,
-                           h),
-    GNUNET_MQ_handler_end ()
-
-  if (NULL != h->info_cb.tunnels_cb)
+  if (NULL == callback)
   {
     GNUNET_break (0);
-    return GNUNET_SYSERR;
+    return NULL;
   }
-  send_info_request (h,
-                     GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
-  h->info_cb.tunnels_cb = callback;
-  h->info_cls = callback_cls;
-  return GNUNET_OK;
+  lt = GNUNET_new (struct GNUNET_CADET_ListTunnels);
+  lt->tunnels_cb = callback;
+  lt->tunnels_cb_cls = callback_cls;
+  lt->cfg = cfg;
+  reconnect (lt);
+  if (NULL == lt->mq)
+  {
+    GNUNET_free (lt);
+    return NULL;
+  }
+  return lt;
 }
 
 
 /**
  * Cancel a monitor request. The monitor callback will not be called.
  *
- * @param h Cadet handle.
+ * @param lt operation handle
  * @return Closure given to GNUNET_CADET_list_tunnels().
  */
 void *
 GNUNET_CADET_list_tunnels_cancel (struct GNUNET_CADET_ListTunnels *lt)
 {
-  void *cls = h->info_cls;
-
-  h->info_cb.tunnels_cb = NULL;
-  h->info_cls = NULL;
-  return cls;
+  void *ret = lt->tunnels_cb_cls;
+
+  if (NULL != lt->mq)
+    GNUNET_MQ_destroy (lt->mq);
+  if (NULL != lt->reconnect_task)
+    GNUNET_SCHEDULER_cancel (lt->reconnect_task);
+  GNUNET_free (lt);
+  return ret;
 }
 
 
+/* end of cadet_api_list_tunnels.c */