REST/NAMESTORE: rework API
[oweals/gnunet.git] / src / transport / transport_api_address_to_string.c
index 0cf0111b3bd44bca0877fdb71f32b03da4d7748b..006e81f29edb23a70db4f31a419475dbb6d644b8 100644 (file)
@@ -1,22 +1,27 @@
 /*
      This file is part of GNUnet.
-     (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2009-2014, 2016 GNUnet e.V.
 
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
+     Affero General Public License for more details.
+    
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
+/**
+ * @file transport/transport_api_address_to_string.c
+ * @author Christian Grothoff
+ * @brief enable clients to convert addresses to human readable strings
+ */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_arm_service.h"
@@ -36,68 +41,124 @@ struct GNUNET_TRANSPORT_AddressToStringContext
   GNUNET_TRANSPORT_AddressToStringCallback cb;
 
   /**
-   * Closure for cb.
+   * Closure for @e cb.
    */
   void *cb_cls;
 
   /**
    * Connection to the service.
    */
-  struct GNUNET_CLIENT_Connection *client;
+  struct GNUNET_MQ_Handle *mq;
 
-  /**
-   * When should this operation time out?
-   */
-  struct GNUNET_TIME_Absolute timeout;
 };
 
 
 /**
  * Function called with responses from the service.
  *
- * @param cls our 'struct GNUNET_TRANSPORT_AddressLookupContext*'
- * @param msg NULL on timeout or error, otherwise presumably a
- *        message with the human-readable address
+ * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
+ * @param msg message with the human-readable address
+ * @return #GNUNET_OK if message is well-formed
  */
-static void
-address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg)
+static int
+check_reply (void *cls,
+             const struct AddressToStringResultMessage *atsm)
 {
-  struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
+  uint16_t size = ntohs (atsm->header.size) - sizeof (*atsm);
   const char *address;
-  uint16_t size;
+  int result;
+  uint32_t addr_len;
 
-  if (msg == NULL)
+  result = (int) ntohl (atsm->res);
+  addr_len = ntohl (atsm->addr_len);
+  if (GNUNET_SYSERR == result)
+    return GNUNET_OK;
+  if (0 == size)
   {
-    alucb->cb (alucb->cb_cls, NULL);
-    GNUNET_CLIENT_disconnect (alucb->client);
-    GNUNET_free (alucb);
-    return;
+    if (GNUNET_OK != result)
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    return GNUNET_OK;
+  }
+  address = (const char *) &atsm[1];
+  if ( (addr_len > size) ||
+       (address[addr_len -1] != '\0') )
+  {
+    /* invalid reply */
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-  GNUNET_break (ntohs (msg->type) ==
-                GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
-  size = ntohs (msg->size);
-  if (size == sizeof (struct GNUNET_MessageHeader))
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called with responses from the service.
+ *
+ * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
+ * @param msg message with the human-readable address
+ */
+static void
+handle_reply (void *cls,
+              const struct AddressToStringResultMessage *atsm)
+{
+  struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
+  uint16_t size = ntohs (atsm->header.size) - sizeof (*atsm);
+  const char *address;
+  int result;
+
+  result = (int) ntohl (atsm->res);
+  if (GNUNET_SYSERR == result)
   {
-    /* done! */
-    alucb->cb (alucb->cb_cls, NULL);
-    GNUNET_CLIENT_disconnect (alucb->client);
-    GNUNET_free (alucb);
+    /* expect more replies; as this is not the last
+       call, we must pass the empty string for the address */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Address resolution failed\n");
+    alucb->cb (alucb->cb_cls,
+               "",
+               GNUNET_NO);
     return;
   }
-  address = (const char *) &msg[1];
-  if (address[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
+  if (0 == size)
   {
-    /* invalid reply */
-    GNUNET_break (0);
-    alucb->cb (alucb->cb_cls, NULL);
-    GNUNET_CLIENT_disconnect (alucb->client);
-    GNUNET_free (alucb);
+    /* we are done (successfully, without communication errors) */
+    alucb->cb (alucb->cb_cls,
+               NULL,
+               GNUNET_OK);
+    GNUNET_TRANSPORT_address_to_string_cancel (alucb);
     return;
   }
-  /* expect more replies */
-  GNUNET_CLIENT_receive (alucb->client, &address_response_processor, alucb,
-                         GNUNET_TIME_absolute_get_remaining (alucb->timeout));
-  alucb->cb (alucb->cb_cls, address);
+  address = (const char *) &atsm[1];
+  /* return normal reply to caller, also expect more replies */
+  alucb->cb (alucb->cb_cls,
+             address,
+             GNUNET_OK);
+}
+
+
+/**
+ * Generic error handler, called with the appropriate
+ * error code and the same closure specified at the creation of
+ * the message queue.
+ * Not every message queue implementation supports an error handler.
+ *
+ * @param cls the `struct GNUNET_TRANSPORT_AddressToStringContext *`
+ * @param error error code
+ */
+static void
+mq_error_handler (void *cls,
+                  enum GNUNET_MQ_Error error)
+{
+  struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Disconnected from transport, address resolution failed\n");
+  alucb->cb (alucb->cb_cls,
+             NULL,
+             GNUNET_SYSERR);
+  GNUNET_TRANSPORT_address_to_string_cancel (alucb);
 }
 
 
@@ -110,59 +171,76 @@ address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg)
  *                (otherwise do reverse DNS lookup)
  * @param timeout how long is the lookup allowed to take at most
  * @param aluc function to call with the results
- * @param aluc_cls closure for aluc
+ * @param aluc_cls closure for @a aluc
  * @return handle to cancel the operation, NULL on error
  */
 struct GNUNET_TRANSPORT_AddressToStringContext *
-GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle
-                                    *cfg,
+GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle *cfg,
                                     const struct GNUNET_HELLO_Address *address,
                                     int numeric,
                                     struct GNUNET_TIME_Relative timeout,
-                                    GNUNET_TRANSPORT_AddressToStringCallback
-                                    aluc, void *aluc_cls)
+                                    GNUNET_TRANSPORT_AddressToStringCallback aluc,
+                                    void *aluc_cls)
 {
-  size_t len;
+  struct GNUNET_TRANSPORT_AddressToStringContext *alc
+    = GNUNET_new (struct GNUNET_TRANSPORT_AddressToStringContext);
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (reply,
+                           GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY,
+                           struct AddressToStringResultMessage,
+                           alc),
+    GNUNET_MQ_handler_end ()
+  };
   size_t alen;
   size_t slen;
   struct AddressLookupMessage *msg;
-  struct GNUNET_TRANSPORT_AddressToStringContext *alc;
-  struct GNUNET_CLIENT_Connection *client;
+  struct GNUNET_MQ_Envelope *env;
   char *addrbuf;
 
-  GNUNET_assert (address != NULL);
   alen = address->address_length;
   slen = strlen (address->transport_name) + 1;
-  len = sizeof (struct AddressLookupMessage) + alen + slen;
-  if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if ( (alen + slen >= GNUNET_MAX_MESSAGE_SIZE
+        - sizeof (struct AddressLookupMessage)) ||
+       (alen >= GNUNET_MAX_MESSAGE_SIZE) ||
+       (slen >= GNUNET_MAX_MESSAGE_SIZE) )
   {
     GNUNET_break (0);
+    GNUNET_free (alc);
     return NULL;
   }
-  client = GNUNET_CLIENT_connect ("transport", cfg);
-  if (NULL == client)
+  alc->cb = aluc;
+  alc->cb_cls = aluc_cls;
+  alc->mq = GNUNET_CLIENT_connect (cfg,
+                                   "transport",
+                                   handlers,
+                                   &mq_error_handler,
+                                   alc);
+  if (NULL == alc->mq)
+  {
+    GNUNET_break (0);
+    GNUNET_free (alc);
     return NULL;
-  msg = GNUNET_malloc (len);
-  msg->header.size = htons (len);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING);
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Client tries to resolve for peer `%s' address plugin %s len %u\n",
+              GNUNET_i2s (&address->peer),
+              address->transport_name,
+              (unsigned int) address->address_length);
+  env = GNUNET_MQ_msg_extra (msg,
+                             alen + slen,
+                             GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING);
   msg->numeric_only = htons ((int16_t) numeric);
   msg->addrlen = htons ((uint16_t) alen);
   msg->timeout = GNUNET_TIME_relative_hton (timeout);
   addrbuf = (char *) &msg[1];
-  memcpy (addrbuf, address->address, alen);
-  memcpy (&addrbuf[alen], address->transport_name, slen);
-
-  alc = GNUNET_new (struct GNUNET_TRANSPORT_AddressToStringContext);
-  alc->cb = aluc;
-  alc->cb_cls = aluc_cls;
-  alc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  alc->client = client;
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CLIENT_transmit_and_get_response (client, &msg->header,
-                                                          timeout, GNUNET_YES,
-                                                          &address_response_processor,
-                                                          alc));
-  GNUNET_free (msg);
+  GNUNET_memcpy (addrbuf,
+          address->address,
+          alen);
+  GNUNET_memcpy (&addrbuf[alen],
+          address->transport_name,
+          slen);
+  GNUNET_MQ_send (alc->mq,
+                  env);
   return alc;
 }
 
@@ -170,17 +248,14 @@ GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle
 /**
  * Cancel request for address conversion.
  *
- * @param pic the context handle
+ * @param alc the context handle
  */
 void
-GNUNET_TRANSPORT_address_to_string_cancel (struct
-                                           GNUNET_TRANSPORT_AddressToStringContext
-                                           *pic)
+GNUNET_TRANSPORT_address_to_string_cancel (struct GNUNET_TRANSPORT_AddressToStringContext *alc)
 {
-  GNUNET_CLIENT_disconnect (pic->client);
-  GNUNET_free (pic);
+  GNUNET_MQ_destroy (alc->mq);
+  GNUNET_free (alc);
 }
 
 
-
 /* end of transport_api_address_to_string.c */