gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r33462 - gnunet/src/transport


From: gnunet
Subject: [GNUnet-SVN] r33462 - gnunet/src/transport
Date: Sun, 1 Jun 2014 23:35:18 +0200

Author: amatus
Date: 2014-06-01 23:35:18 +0200 (Sun, 01 Jun 2014)
New Revision: 33462

Modified:
   gnunet/src/transport/plugin_transport_http_server.c
Log:
Support a wider range of http transport clients.

Specifically web clients which cannot maintain permanent
GET and PUT connections.


Modified: gnunet/src/transport/plugin_transport_http_server.c
===================================================================
--- gnunet/src/transport/plugin_transport_http_server.c 2014-06-01 16:54:32 UTC 
(rev 33461)
+++ gnunet/src/transport/plugin_transport_http_server.c 2014-06-01 21:35:18 UTC 
(rev 33462)
@@ -31,6 +31,7 @@
 #include "gnunet_nat_lib.h"
 #include "plugin_transport_http_common.h"
 #include <microhttpd.h>
+#include <regex.h>
 
 
 
@@ -50,17 +51,6 @@
 
 
 /**
- * Enable output for debbuging URL's of incoming requests
- */
-#define DEBUG_URL_PARSE GNUNET_NO
-
-
-/**
- * Encapsulation of all of the state of the plugin.
- */
-struct Plugin;
-
-/**
  * Session handle for connections.
  */
 struct Session
@@ -137,11 +127,6 @@
   int session_ended;
 
   /**
-   * Are incoming connection established at the moment
-   */
-  int connect_in_progress;
-
-  /**
    * Absolute time when to receive data again
    * Used for receive throttling
    */
@@ -151,6 +136,11 @@
    * Session timeout task
    */
   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+  /**
+   * Should this session get disconnected? GNUNET_YES/NO
+   */
+  int disconnect;
 };
 
 
@@ -162,12 +152,8 @@
   int direction;
 
   /**
-   * Should this connection get disconnected? GNUNET_YES/NO
-   */
-  int disconnect;
-
-  /**
    * For PUT connections: Is this the first or last callback with size 0
+   * For GET connections: Have we sent a message
    */
   int connected;
 
@@ -185,6 +171,12 @@
    * The MHD daemon
    */
   struct MHD_Daemon *mhd_daemon;
+
+  /**
+   * Options requested by peer
+   */
+  uint32_t options;
+#define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */
 };
 
 
@@ -345,6 +337,11 @@
    */
   struct MHD_Daemon *server_v6;
 
+  /**
+   * Regex for parsing URLs
+   */
+  regex_t url_regex;
+
 #if BUILD_HTTPS
   /**
    * Crypto related
@@ -549,23 +546,8 @@
       GNUNET_break (0);
       return GNUNET_SYSERR;
   }
-  if (NULL == session->server_send)
-  {
-     if (GNUNET_NO == session->connect_in_progress)
-     {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, session->plugin->name,
-                       "Session %p/connection %p: Sending message with %u 
bytes to peer `%s' with FAILED\n",
-                       session, session->server_send,
-                       msgbuf_size, GNUNET_i2s (&session->target));
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-     }
-  }
-  else
-  {
-    if (GNUNET_YES == session->server_send->disconnect)
-      return GNUNET_SYSERR;
-  }
+  if (session->disconnect)
+    return GNUNET_SYSERR;
 
 
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, session->plugin->name,
@@ -844,15 +826,14 @@
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-
+  s->disconnect = GNUNET_YES;
   send = (struct ServerConnection *) s->server_send;
-  if (s->server_send != NULL)
+  if (send != NULL)
   {
     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
                      "Server: %p / %p Terminating inbound PUT session to peer 
`%s'\n",
-                     s, s->server_send, GNUNET_i2s (&s->target));
+                     s, send, GNUNET_i2s (&s->target));
 
-    send->disconnect = GNUNET_YES;
     MHD_set_connection_option (send->mhd_conn,
                                MHD_CONNECTION_OPTION_TIMEOUT,
                                1);
@@ -864,9 +845,8 @@
   {
     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
                      "Server: %p / %p Terminating inbound GET session to peer 
`%s'\n",
-                     s, s->server_recv, GNUNET_i2s (&s->target));
+                     s, recv, GNUNET_i2s (&s->target));
 
-    recv->disconnect = GNUNET_YES;
     MHD_set_connection_option (recv->mhd_conn,
                                MHD_CONNECTION_OPTION_TIMEOUT,
                                1);
@@ -881,7 +861,7 @@
  * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
  * calculate the interval between keepalive packets.
  *
- * @param cls closure with the `struct Plugin`
+ * @param cls closure with the `struct HTTP_Server_Plugin`
  * @return keepalive factor
  */
 static unsigned int
@@ -947,111 +927,124 @@
  * @param url incoming url
  * @param target where to store the target
  * @param tag where to store the tag
+ * @param options where to store the options
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 server_parse_url (struct HTTP_Server_Plugin *plugin,
                  const char *url,
                  struct GNUNET_PeerIdentity *target,
-                 uint32_t *tag)
+                 uint32_t *tag,
+                 uint32_t *options)
 {
-  char * tag_start = NULL;
-  char * tag_end = NULL;
-  char * target_start = NULL;
-  char * separator = NULL;
-  unsigned int hash_length;
-  unsigned long int ctag;
+  regmatch_t matches[4];
+  const char *tag_start;
+  const char *target_start;
+  char *tag_end;
+  char *options_end;
+  size_t hash_length;
+  unsigned long int rc;
 
-  /* URL parsing
-   * URL is valid if it is in the form [prefix with (multiple) 
'/'][peerid[103];tag]*/
+  /* URL parsing */
+#define URL_REGEX \
+  ("^.*/([0-9A-V]+);([0-9]+)(,[0-9]+)?$")
 
   if (NULL == url)
   {
       GNUNET_break (0);
       return GNUNET_SYSERR;
   }
-  /* convert tag */
 
-  /* find separator */
-  separator = strrchr (url, ';');
-
-  if (NULL == separator)
+  if (regexec(&plugin->url_regex, url, 4, matches, 0))
   {
-      if (DEBUG_URL_PARSE) GNUNET_break (0);
-      return GNUNET_SYSERR;
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+       "URL `%s' did not match regex\n", url);
+    return GNUNET_SYSERR;
   }
-  tag_start = separator + 1;
 
-  if (strlen (tag_start) == 0)
+  target_start = &url[matches[1].rm_so];
+  tag_start = &url[matches[2].rm_so];
+
+  /* convert tag */
+  rc = strtoul (tag_start, &tag_end, 10);
+  if (&url[matches[2].rm_eo] != tag_end)
   {
-    /* No tag after separator */
-    if (DEBUG_URL_PARSE) GNUNET_break (0);
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                     "URL tag did not line up with submatch\n");
     return GNUNET_SYSERR;
   }
-  ctag = strtoul (tag_start, &tag_end, 10);
-  if (ctag == 0)
+  if (rc == 0)
   {
-    /* tag == 0 , invalid */
-    if (DEBUG_URL_PARSE) GNUNET_break (0);
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                     "URL tag is zero\n");
     return GNUNET_SYSERR;
   }
-  if ((ctag == ULONG_MAX) && (ERANGE == errno))
+  if ((rc == ULONG_MAX) && (ERANGE == errno))
   {
-    /* out of range: > ULONG_MAX */
-    if (DEBUG_URL_PARSE) GNUNET_break (0);
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                     "URL tag > ULONG_MAX\n");
     return GNUNET_SYSERR;
   }
-  if (ctag > UINT32_MAX)
+  if (rc > UINT32_MAX)
   {
-    /* out of range: > UINT32_MAX */
-    if (DEBUG_URL_PARSE) GNUNET_break (0);
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                     "URL tag > UINT32_MAX\n");
     return GNUNET_SYSERR;
   }
-  (*tag) = (uint32_t) ctag;
-  if (NULL == tag_end)
-  {
-      /* no char after tag */
-      if (DEBUG_URL_PARSE) GNUNET_break (0);
-      return GNUNET_SYSERR;
-  }
-  if (url[strlen(url)] != tag_end[0])
-  {
-      /* there are more not converted chars after tag */
-      if (DEBUG_URL_PARSE) GNUNET_break (0);
-      return GNUNET_SYSERR;
-  }
-  if (DEBUG_URL_PARSE)
-    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
-       "Found tag `%u' in url\n", (*tag));
+  (*tag) = (uint32_t)rc;
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+     "Found tag `%u' in url\n", *tag);
 
   /* convert peer id */
-  target_start = strrchr (url, '/');
-  if (NULL == target_start)
-  {
-      /* no leading '/' */
-      target_start = (char *) url;
-  }
-  target_start++;
-  hash_length = separator - target_start;
+  hash_length = matches[1].rm_eo - matches[1].rm_so;
   if (hash_length != plugin->peer_id_length)
   {
-      /* no char after tag */
-      if (DEBUG_URL_PARSE) GNUNET_break (0);
-      return GNUNET_SYSERR;
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                     "URL target is %u bytes, expecting %u\n",
+                     hash_length, plugin->peer_id_length);
+    return GNUNET_SYSERR;
   }
   if (GNUNET_OK !=
       GNUNET_CRYPTO_eddsa_public_key_from_string (target_start,
                                                     hash_length,
                                                     &target->public_key))
-    {
-      /* hash conversion failed */
-      if (DEBUG_URL_PARSE) GNUNET_break (0);
-      return GNUNET_SYSERR;
+  {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                     "URL target conversion failed\n");
+    return GNUNET_SYSERR;
   }
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
                   plugin->name,
                   "Found target `%s' in URL\n",
                   GNUNET_i2s_full (target));
+
+  /* convert options */
+  if (-1 == matches[3].rm_so) {
+      *options = 0;
+  } else {
+    rc = strtoul (&url[matches[3].rm_so + 1], &options_end, 10);
+    if (&url[matches[3].rm_eo] != options_end)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                       "URL options did not line up with submatch\n");
+      return GNUNET_SYSERR;
+    }
+    if ((rc == ULONG_MAX) && (ERANGE == errno))
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                       "URL options > ULONG_MAX\n");
+      return GNUNET_SYSERR;
+    }
+    if (rc > UINT32_MAX)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                       "URL options > UINT32_MAX\n");
+      return GNUNET_SYSERR;
+    }
+    (*options) = (uint32_t)rc;
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+       "Found options `%u' in url\n", *options);
+  }
   return GNUNET_OK;
 }
 
@@ -1079,6 +1072,7 @@
   struct GNUNET_PeerIdentity target;
   size_t addr_len;
   uint32_t tag = 0;
+  uint32_t options;
   int direction = GNUNET_SYSERR;
   unsigned int to;
 
@@ -1090,7 +1084,7 @@
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                    "New %s connection from %s\n", method, url);
 
-  if (GNUNET_SYSERR == server_parse_url (plugin, url, &target, &tag))
+  if (GNUNET_SYSERR == server_parse_url (plugin, url, &target, &tag, &options))
   {
       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                        "Invalid url %s\n", url);
@@ -1177,7 +1171,6 @@
     s->server_send = NULL;
     s->session_passed = GNUNET_NO;
     s->session_ended = GNUNET_NO;
-    s->connect_in_progress = GNUNET_YES;
     server_start_session_timeout(s);
     GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
 
@@ -1198,6 +1191,7 @@
   sc->direction = direction;
   sc->connected = GNUNET_NO;
   sc->session = s;
+  sc->options = options;
   if (direction == _SEND)
     s->server_send = sc;
   if (direction == _RECEIVE)
@@ -1205,7 +1199,6 @@
 
   if ((NULL != s->server_send) && (NULL != s->server_recv))
   {
-    s->connect_in_progress = GNUNET_NO; /* PUT and GET are connected */
     plugin->env->session_start (NULL, s->address ,s, NULL, 0);
   }
 
@@ -1277,12 +1270,16 @@
 server_send_callback (void *cls, uint64_t pos, char *buf, size_t max)
 {
   struct Session *s = cls;
+  struct ServerConnection *sc;
   ssize_t bytes_read = 0;
   struct HTTP_Message *msg;
   char *stat_txt;
 
   if (GNUNET_NO == server_exist_session (s->plugin, s))
     return 0;
+  sc = s->server_send;
+  if (NULL == sc)
+    return 0;
   msg = s->msg_head;
   if (NULL != msg)
   {
@@ -1304,6 +1301,7 @@
   }
   if (0 < bytes_read)
   {
+    sc->connected = GNUNET_YES;
     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
                    "Sent %u bytes to peer `%s' with session %p \n", 
bytes_read, GNUNET_i2s (&s->target), s);
     GNUNET_asprintf (&stat_txt, "# bytes currently in %s_server buffers",
@@ -1316,6 +1314,11 @@
     GNUNET_STATISTICS_update (s->plugin->env->stats,
                               stat_txt, bytes_read, GNUNET_NO);
     GNUNET_free (stat_txt);
+  } else if ((sc->options & OPTION_LONG_POLL) && sc->connected) {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
+                     "Completing GET response to peer `%s' with session %p \n",
+                     GNUNET_i2s (&s->target), s);
+    return MHD_CONTENT_READER_END_OF_STREAM;
   }
   return bytes_read;
 }
@@ -1468,7 +1471,7 @@
   s = sc->session;
   GNUNET_assert (NULL != s);
   /* connection is to be disconnected */
-  if (sc->disconnect == GNUNET_YES)
+  if (s->disconnect == GNUNET_YES)
   {
     /* Sent HTTP/1.1: 200 OK as response */
     response = MHD_create_response_from_data (strlen ("Thank you!"),
@@ -1615,9 +1618,9 @@
                          plugin->protocol, s->address->address,
                          s->address->address_length));
     s->server_send = NULL;
-    if (NULL != (s->server_recv))
+    if (!(sc->options & OPTION_LONG_POLL) && NULL != (s->server_recv))
     {
-      s->server_recv->disconnect = GNUNET_YES;
+      s->disconnect = GNUNET_YES;
       GNUNET_assert (NULL != s->server_recv->mhd_conn);
 #if MHD_VERSION >= 0x00090E00
       MHD_set_connection_option (s->server_recv->mhd_conn, 
MHD_CONNECTION_OPTION_TIMEOUT,
@@ -1635,17 +1638,6 @@
                          plugin->protocol, s->address->address,
                          s->address->address_length));
     s->server_recv = NULL;
-    /* Do not terminate session when PUT disconnects
-    if (NULL != (s->server_send))
-    {
-        s->server_send->disconnect = GNUNET_YES;
-      GNUNET_assert (NULL != s->server_send->mhd_conn);
-#if MHD_VERSION >= 0x00090E00
-      MHD_set_connection_option (s->server_send->mhd_conn, 
MHD_CONNECTION_OPTION_TIMEOUT,
-                                 1);
-#endif
-      server_reschedule (plugin, s->server_send->mhd_daemon, GNUNET_NO);
-    }*/
     if (s->msg_tk != NULL)
     {
       GNUNET_SERVER_mst_destroy (s->msg_tk);
@@ -1656,7 +1648,7 @@
   GNUNET_free (sc);
   plugin->cur_connections--;
 
-  if ((s->server_send == NULL) && (s->server_recv == NULL))
+  if (s->disconnect && (s->server_send == NULL) && (s->server_recv == NULL))
   {
     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                      "Peer `%s' on address `%s' disconnected\n",
@@ -3090,6 +3082,7 @@
   GNUNET_free_non_null (plugin->ext_addr);
   GNUNET_free_non_null (plugin->server_addr_v4);
   GNUNET_free_non_null (plugin->server_addr_v6);
+  regfree(&plugin->url_regex);
 
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                    _("Shutdown for plugin `%s' complete\n"),
@@ -3117,7 +3110,7 @@
 /**
  * Function obtain the network type for a session
  *
- * @param cls closure ('struct Plugin*')
+ * @param cls closure ('struct HTTP_Server_Plugin*')
  * @param session the session
  * @return the network type in HBO or GNUNET_SYSERR
  */
@@ -3178,6 +3171,14 @@
   plugin->protocol = "http";
 #endif
 
+  /* Compile URL regex */
+  if (regcomp(&plugin->url_regex, URL_REGEX, REG_EXTENDED)) {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                     _("Unable to compile URL regex\n"));
+    LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
+    return NULL;
+  }
+
   /* Configure plugin */
   if (GNUNET_SYSERR == server_configure_plugin (plugin))
   {




reply via email to

[Prev in Thread] Current Thread [Next in Thread]