indentation, comment and style fixes, no semantic changes
[oweals/gnunet.git] / src / vpn / vpn_api.c
index 8539a6a3732c9d6b7467ad1c1a10b0d1f25c6b55..bc77865a89d0e17799ab2f52079d94a8f494646f 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2012 Christian Grothoff
+     Copyright (C) 2012, 2016 Christian Grothoff
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -14,8 +14,8 @@
 
      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.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
@@ -41,12 +41,7 @@ struct GNUNET_VPN_Handle
   /**
    * Connection to VPN service.
    */
-  struct GNUNET_CLIENT_Connection *client;
-
-  /**
-   * Active transmission request.
-   */
-  struct GNUNET_CLIENT_TransmitHandle *th;
+  struct GNUNET_MQ_Handle *mq;
 
   /**
    * Head of list of active redirection requests.
@@ -61,7 +56,7 @@ struct GNUNET_VPN_Handle
   /**
    * Identifier of a reconnect task.
    */
-  GNUNET_SCHEDULER_TaskIdentifier rt;
+  struct GNUNET_SCHEDULER_Task *rt;
 
   /**
    * How long do we wait until we try to reconnect?
@@ -106,9 +101,9 @@ struct GNUNET_VPN_RedirectionRequest
    * Function to call with the designated IP address.
    */
   GNUNET_VPN_AllocationCallback cb;
-  
+
   /**
-   * Closure for 'cb'.
+   * Closure for @e cb.
    */
   void *cb_cls;
 
@@ -120,7 +115,7 @@ struct GNUNET_VPN_RedirectionRequest
   /**
    * For service redirection, service descriptor.
    */
-  struct GNUNET_HashCode serv;              
+  struct GNUNET_HashCode serv;
 
   /**
    * At what time should the created service mapping expire?
@@ -138,10 +133,10 @@ struct GNUNET_VPN_RedirectionRequest
   int result_af;
 
   /**
-   * Address family of 'addr'.  AF_INET or AF_INET6.
+   * Address family of @e addr.  AF_INET or AF_INET6.
    */
   int addr_af;
-  
+
   /**
    * For service redirection, IPPROT_UDP or IPPROTO_TCP.
    */
@@ -160,35 +155,20 @@ reconnect (struct GNUNET_VPN_Handle *vh);
 
 
 /**
- * Function called when we receive a message from the VPN service.
+ * Check a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
+ * VPN service.
  *
- * @param cls the 'struct GNUNET_VPN_Handle'
- * @param msg message received, NULL on timeout or fatal error
+ * @param cls the `struct GNUNET_VPN_Handle`
+ * @param rm message received
+ * @return #GNUNET_OK if @a rm is well-formed
  */
-static void 
-receive_response (void *cls,
-                 const struct GNUNET_MessageHeader* msg)
+static int
+check_use_ip (void *cls,
+              const struct RedirectToIpResponseMessage *rm)
 {
-  struct GNUNET_VPN_Handle *vh = cls;
-  const struct RedirectToIpResponseMessage *rm;
-  struct GNUNET_VPN_RedirectionRequest *rr;
-  size_t msize;
   size_t alen;
   int af;
 
-  if (NULL == msg) 
-  {
-    reconnect (vh);
-    return;
-  }
-  if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP) ||
-       (sizeof (struct RedirectToIpResponseMessage) > (msize = ntohs (msg->size))) )
-  {
-    GNUNET_break (0);
-    reconnect (vh);
-    return;
-  }
-  rm = (const struct RedirectToIpResponseMessage *) msg;
   af = (int) ntohl (rm->result_af);
   switch (af)
   {
@@ -203,19 +183,34 @@ receive_response (void *cls,
     break;
   default:
     GNUNET_break (0);
-    reconnect (vh);
-    return;
+    return GNUNET_SYSERR;
   }
-  if ( (msize != alen + sizeof (struct RedirectToIpResponseMessage)) ||
+  if ( (ntohs (rm->header.size) != alen + sizeof (*rm)) ||
        (0 == rm->request_id) )
   {
     GNUNET_break (0);
-    reconnect (vh);
-    return;
-  }  
-  GNUNET_CLIENT_receive (vh->client,
-                        &receive_response, vh,
-                        GNUNET_TIME_UNIT_FOREVER_REL);      
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
+ * VPN service.
+ *
+ * @param cls the `struct GNUNET_VPN_Handle`
+ * @param rm message received
+ */
+static void
+handle_use_ip (void *cls,
+               const struct RedirectToIpResponseMessage *rm)
+{
+  struct GNUNET_VPN_Handle *vh = cls;
+  struct GNUNET_VPN_RedirectionRequest *rr;
+  int af;
+
+  af = (int) ntohl (rm->result_af);
   for (rr = vh->rr_head; NULL != rr; rr = rr->next)
   {
     if (rr->request_id == rm->request_id)
@@ -234,59 +229,32 @@ receive_response (void *cls,
 
 
 /**
- * We're ready to transmit a request to the VPN service. Do it.
+ * Add a request to our request queue and transmit it.
  *
- * @param cls the 'struct GNUNET_VPN_Handle*'
- * @param size number of bytes available in buf
- * @param buf where to copy the request
- * @return number of bytes copied to 'buf'
+ * @param rr request to queue and transmit.
  */
-static size_t
-transmit_request (void *cls,
-                 size_t size,
-                 void *buf)
+static void
+send_request (struct GNUNET_VPN_RedirectionRequest *rr)
 {
-  struct GNUNET_VPN_Handle *vh = cls;
-  struct GNUNET_VPN_RedirectionRequest *rr;
-  struct RedirectToIpRequestMessage rip;
-  struct RedirectToServiceRequestMessage rs;
-  char *cbuf;
+  struct GNUNET_VPN_Handle *vh = rr->vh;
+  struct RedirectToIpRequestMessage *rip;
+  struct RedirectToServiceRequestMessage *rs;
+  struct GNUNET_MQ_Envelope *env;
   size_t alen;
-  size_t ret;
-
-  vh->th = NULL;
-  /* find a pending request */
-  rr = vh->rr_head;
-  while ( (NULL != rr) &&
-         (0 != rr->request_id) )
-    rr = rr->next;
-  if (NULL == rr) 
-    return 0;
-  if (0 == size) 
-  {
-    reconnect (vh);
-    return 0;
-  }
 
-  /* if first request, start receive loop */
-  if (0 == vh->request_id_gen)
-    GNUNET_CLIENT_receive (vh->client,
-                          &receive_response, vh,
-                          GNUNET_TIME_UNIT_FOREVER_REL); 
+  if (NULL == vh->mq)
+    return;
   if (NULL == rr->addr)
   {
-    ret = sizeof (struct RedirectToServiceRequestMessage);
-    GNUNET_assert (ret <= size);
-    rs.header.size = htons ((uint16_t) ret);
-    rs.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE);
-    rs.reserved = htonl (0);
-    rs.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
-    rs.protocol = htonl (rr->protocol);
-    rs.result_af = htonl (rr->result_af);
-    rs.target = rr->peer;
-    rs.service_descriptor = rr->serv;
-    rs.request_id = rr->request_id = ++vh->request_id_gen;    
-    memcpy (buf, &rs, sizeof (struct RedirectToServiceRequestMessage));
+    env = GNUNET_MQ_msg (rs,
+                         GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE);
+    rs->reserved = htonl (0);
+    rs->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
+    rs->protocol = htonl (rr->protocol);
+    rs->result_af = htonl (rr->result_af);
+    rs->target = rr->peer;
+    rs->service_descriptor = rr->serv;
+    rs->request_id = rr->request_id = ++vh->request_id_gen;
   }
   else
   {
@@ -300,84 +268,71 @@ transmit_request (void *cls,
       break;
     default:
       GNUNET_assert (0);
-      return 0;
+      return;
     }
-    ret = alen + sizeof (struct RedirectToIpRequestMessage);
-    GNUNET_assert (ret <= size);
-    rip.header.size = htons ((uint16_t) ret);
-    rip.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP);
-    rip.reserved = htonl (0);
-    rip.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
-    rip.result_af = htonl (rr->result_af);
-    rip.addr_af = htonl (rr->addr_af);
-    rip.request_id = rr->request_id = ++vh->request_id_gen;
-    cbuf = buf;
-    memcpy (cbuf, &rip, sizeof (struct RedirectToIpRequestMessage));
-    memcpy (&cbuf[sizeof (struct RedirectToIpRequestMessage)], rr->addr, alen);
+    env = GNUNET_MQ_msg_extra (rip,
+                               alen,
+                               GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP);
+    rip->reserved = htonl (0);
+    rip->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
+    rip->result_af = htonl (rr->result_af);
+    rip->addr_af = htonl (rr->addr_af);
+    rip->request_id = rr->request_id = ++vh->request_id_gen;
+    GNUNET_memcpy (&rip[1],
+                   rr->addr,
+                   alen);
   }
-  /* test if there are more pending requests */
-  while ( (NULL != rr) &&
-         (0 != rr->request_id) )
-    rr = rr->next;
-  if (NULL != rr)
-    vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client,
-                                                 sizeof (struct RedirectToServiceRequestMessage),
-                                                 GNUNET_TIME_UNIT_FOREVER_REL,
-                                                 GNUNET_NO,
-                                                 &transmit_request,
-                                                 vh);
-  return ret;
+  GNUNET_MQ_send (vh->mq,
+                  env);
 }
 
 
 /**
- * Add a request to our request queue and transmit it.
- * 
- * @param rr request to queue and transmit.
+ * 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 closure with the `struct GNUNET_VPN_Handle *`
+ * @param error error code
  */
 static void
-queue_request (struct GNUNET_VPN_RedirectionRequest *rr)
+mq_error_handler (void *cls,
+                  enum GNUNET_MQ_Error error)
 {
-  struct GNUNET_VPN_Handle *vh;
+  struct GNUNET_VPN_Handle *vh = cls;
 
-  vh = rr->vh;
-  GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
-                                   vh->rr_tail,
-                                   rr);
-  if ( (NULL == vh->th) &&
-       (NULL != vh->client) )
-    vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client,
-                                                 sizeof (struct RedirectToServiceRequestMessage),
-                                                 GNUNET_TIME_UNIT_FOREVER_REL,
-                                                 GNUNET_NO,
-                                                 &transmit_request,
-                                                 vh);
+  reconnect (vh);
 }
 
 
 /**
  * Connect to the VPN service and start again to transmit our requests.
  *
- * @param cls the 'struct GNUNET_VPN_Handle *'
- * @param tc scheduler context
+ * @param cls the `struct GNUNET_VPN_Handle *`
  */
 static void
-connect_task (void *cls,
-             const struct GNUNET_SCHEDULER_TaskContext *tc)
+connect_task (void *cls)
 {
   struct GNUNET_VPN_Handle *vh = cls;
-  
-  vh->rt = GNUNET_SCHEDULER_NO_TASK;
-  vh->client = GNUNET_CLIENT_connect ("vpn", vh->cfg);
-  GNUNET_assert (NULL != vh->client);
-  GNUNET_assert (NULL == vh->th);
-  if (NULL != vh->rr_head) 
-    vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client,
-                                                 sizeof (struct RedirectToServiceRequestMessage),
-                                                 GNUNET_TIME_UNIT_FOREVER_REL,
-                                                 GNUNET_NO,
-                                                 &transmit_request,
-                                                 vh);
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (use_ip,
+                           GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP,
+                           struct RedirectToIpResponseMessage,
+                           cls),
+    GNUNET_MQ_handler_end ()
+  };
+  struct GNUNET_VPN_RedirectionRequest *rr;
+
+  vh->rt = NULL;
+  vh->mq = GNUNET_CLIENT_connect (vh->cfg,
+                                  "vpn",
+                                  handlers,
+                                  &mq_error_handler,
+                                  vh);
+  if (NULL == vh->mq)
+    return;
+  for (rr = vh->rr_head; NULL != rr; rr = rr->next)
+    send_request (rr);
 }
 
 
@@ -391,21 +346,16 @@ reconnect (struct GNUNET_VPN_Handle *vh)
 {
   struct GNUNET_VPN_RedirectionRequest *rr;
 
-  if (NULL != vh->th)
-  {
-    GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th);
-    vh->th = NULL;
-  }  
-  GNUNET_CLIENT_disconnect (vh->client);
-  vh->client = NULL;
+  GNUNET_MQ_destroy (vh->mq);
+  vh->mq = NULL;
   vh->request_id_gen = 0;
   for (rr = vh->rr_head; NULL != rr; rr = rr->next)
     rr->request_id = 0;
   vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS,
-                                         GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (vh->backoff, 2),
+                                         GNUNET_TIME_relative_min (GNUNET_TIME_relative_saturating_multiply (vh->backoff, 2),
                                                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)));
   vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff,
-                                        &connect_task, 
+                                        &connect_task,
                                         vh);
 }
 
@@ -445,7 +395,7 @@ GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr)
  * @param expiration_time at what time should the redirection expire?
  *        (this should not impact connections that are active at that time)
  * @param cb function to call with the IP
- * @param cb_cls closure for cb
+ * @param cb_cls closure for @a cb
  * @return handle to cancel the request (means the callback won't be
  *         invoked anymore; the mapping may or may not be established
  *         anyway)
@@ -471,11 +421,14 @@ GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh,
   rr->expiration_time = expiration_time;
   rr->result_af = result_af;
   rr->protocol = protocol;
-  queue_request (rr);
+  GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
+                                   vh->rr_tail,
+                                   rr);
+  send_request (rr);
   return rr;
 }
 
-               
+
 /**
  * Tell the VPN that forwarding to the Internet via some exit node is
  * requested.  Note that both UDP and TCP traffic will be forwarded,
@@ -487,13 +440,13 @@ GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh,
  *
  * @param vh VPN handle
  * @param result_af desired address family for the returned allocation
- * @param addr_af address family for 'addr', AF_INET or AF_INET6
+ * @param addr_af address family for @a addr, AF_INET or AF_INET6
  * @param addr destination IP address on the Internet; destination
  *             port is to be taken from the VPN packet itself
  * @param expiration_time at what time should the redirection expire?
  *        (this should not impact connections that are active at that time)
  * @param cb function to call with the IP
- * @param cb_cls closure for cb
+ * @param cb_cls closure for @a cb
  * @return handle to cancel the request (means the callback won't be
  *         invoked anymore; the mapping may or may not be established
  *         anyway)
@@ -530,8 +483,13 @@ GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh,
   rr->expiration_time = expiration_time;
   rr->result_af = result_af;
   rr->addr_af = addr_af;
-  memcpy (&rr[1], addr, alen);
-  queue_request (rr);
+  GNUNET_memcpy (&rr[1],
+          addr,
+          alen);
+  GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
+                                   vh->rr_tail,
+                                   rr);
+  send_request (rr);
   return rr;
 }
 
@@ -540,17 +498,17 @@ GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh,
  * Connect to the VPN service
  *
  * @param cfg configuration to use
- * @return VPN handle 
+ * @return VPN handle
  */
 struct GNUNET_VPN_Handle *
 GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  struct GNUNET_VPN_Handle *vh;
+  struct GNUNET_VPN_Handle *vh
+    = GNUNET_new (struct GNUNET_VPN_Handle);
 
-  vh = GNUNET_new (struct GNUNET_VPN_Handle);
   vh->cfg = cfg;
-  vh->client = GNUNET_CLIENT_connect ("vpn", cfg);
-  if (NULL == vh->client)
+  connect_task (vh);
+  if (NULL == vh->mq)
   {
     GNUNET_free (vh);
     return NULL;
@@ -568,20 +526,15 @@ void
 GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh)
 {
   GNUNET_assert (NULL == vh->rr_head);
-  if (NULL != vh->th)
-  {
-    GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th);
-    vh->th = NULL;
-  }
-  if (NULL != vh->client)
+  if (NULL != vh->mq)
   {
-    GNUNET_CLIENT_disconnect (vh->client);
-    vh->client = NULL;
+    GNUNET_MQ_destroy (vh->mq);
+    vh->mq = NULL;
   }
-  if (GNUNET_SCHEDULER_NO_TASK != vh->rt)
+  if (NULL != vh->rt)
   {
     GNUNET_SCHEDULER_cancel (vh->rt);
-    vh->rt = GNUNET_SCHEDULER_NO_TASK;
+    vh->rt = NULL;
   }
   GNUNET_free (vh);
 }