fix
[oweals/gnunet.git] / src / transport / plugin_transport_http_server.c
index cd539a86114df0534c25fe24c5fe0a07350ff3cf..2ce844307eb1e14c5d026866055984270579dd04 100644 (file)
 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_server_done
 #endif
 
-#define TESTING GNUNET_NO
-
-#if TESTING
-#define TIMEOUT_LOG GNUNET_ERROR_TYPE_ERROR
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
-#define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
-#else
-#define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
-#define TIMEOUT_LOG GNUNET_ERROR_TYPE_DEBUG
-#define TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
-#endif
-
 #define HTTP_ERROR_RESPONSE "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>"
 #define _RECEIVE 0
 #define _SEND 1
@@ -123,7 +111,6 @@ struct Session
    */
   void *addr;
 
-
   /**
    * Address length
    */
@@ -258,15 +245,6 @@ struct HTTP_Server_Plugin
    */
   struct GNUNET_NAT_Handle *nat;
 
-  /**
-   * Server semi connections
-   * A full session consists of 2 semi-connections: send and receive
-   * If not both directions are established the server keeps this sessions here
-   */
-  //struct Session *server_semi_head;
-
-  //struct Session *server_semi_tail;
-
   /**
    * List of own addresses
    */
@@ -498,6 +476,9 @@ http_server_plugin_send (void *cls,
   }
   GNUNET_assert (NULL != session->server_send);
 
+  if (GNUNET_YES == session->server_send->disconnect)
+    return GNUNET_SYSERR;
+
   /* create new message and schedule */
   bytes_sent = sizeof (struct HTTP_Message) + msgbuf_size;
   msg = GNUNET_malloc (bytes_sent);
@@ -622,6 +603,9 @@ server_delete_session (struct Session *s)
   struct HTTP_Server_Plugin *plugin = s->plugin;
   server_stop_session_timeout(s);
 
+  if (GNUNET_YES == s->session_passed)
+    plugin->env->session_end (plugin->env->cls, &s->target, s);
+
   GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
   struct HTTP_Message *msg = s->msg_head;
   struct HTTP_Message *tmp = NULL;
@@ -648,6 +632,9 @@ server_delete_session (struct Session *s)
   GNUNET_free_non_null (s->server_recv);
   GNUNET_free_non_null (s->server_send);
   GNUNET_free (s);
+
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   "Session %p destroyed\n", s);
 }
 
 
@@ -845,7 +832,11 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
 
   hash_end = strrchr (hash_start, ';');
   if (NULL == hash_end)
+  {
+    GNUNET_break (0);
     goto error; /* ';' delimiter not found */
+  }
+
   if (hash_end >= url_end)
   {
       GNUNET_break (0);
@@ -885,14 +876,17 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
   tag = strtoul (tag_start, &tag_end, 10);
   if (tag == 0)
   {
+      GNUNET_break (0);
     goto error; /* mal formed */
   }
   if (tag_end == NULL)
   {
+      GNUNET_break (0);
     goto error; /* mal formed */
   }
   if (tag_end != url_end)
   {
+      GNUNET_break (0);
     goto error; /* mal formed */
   }
 
@@ -996,7 +990,7 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
 #if MHD_VERSION >= 0x00090E00
   if ((NULL == s->server_recv) || (NULL == s->server_send))
   {
-    to = (HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000);
+    to = (HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value / 1000);
     MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to);
     server_reschedule (plugin, sc->mhd_daemon, GNUNET_NO);
   }
@@ -1005,7 +999,7 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                      "Session %p for peer `%s' fully connected\n",
                      s, GNUNET_i2s (&target));
-    to = (TIMEOUT.rel_value / 1000);
+    to = (SERVER_SESSION_TIMEOUT.rel_value / 1000);
     server_mhd_connection_timeout (plugin, s, to);
   }
 
@@ -1087,7 +1081,7 @@ server_send_callback (void *cls, uint64_t pos, char *buf, size_t max)
     }
   }
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
-                   "Sent %u bytes\n", s, bytes_read);
+                   "Sent %u bytes to peer `%s' with session %p \n", bytes_read, GNUNET_i2s (&s->target), s);
 
 
 
@@ -1240,7 +1234,7 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
       if ((s->next_receive.abs_value <= now.abs_value))
       {
         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
-                         "PUT with %u bytes forwarded to MST\n", s,
+                         "PUT with %u bytes forwarded to MST\n",
                          *upload_data_size);
         if (s->msg_tk == NULL)
         {
@@ -1343,20 +1337,8 @@ server_disconnect_cb (void *cls, struct MHD_Connection *connection,
                      "Peer `%s' on address `%s' disconnected\n",
                      GNUNET_i2s (&s->target),
                      http_common_plugin_address_to_string (NULL, s->addr, s->addrlen));
-    if (s->msg_tk != NULL)
-    {
-      GNUNET_SERVER_mst_destroy (s->msg_tk);
-      s->msg_tk = NULL;
-    }
 
-    GNUNET_CONTAINER_DLL_remove(plugin->head, plugin->tail, s);
-    server_stop_session_timeout (s);
-    if (GNUNET_YES == s->session_passed)
-      plugin->env->session_end (plugin->env->cls, &s->target, s);
-    GNUNET_free (s->addr);
-    GNUNET_free (s);
-    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
-                     "Session %p destroyed\n", s);
+    server_delete_session (s);
   }
 }
 
@@ -1707,12 +1689,12 @@ server_start (struct HTTP_Server_Plugin *plugin)
 
 
 #if MHD_VERSION >= 0x00090E00
-  timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000;
+  timeout = HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value / 1000;
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                    "MHD can set timeout per connection! Default time out %u sec.\n",
                    timeout);
 #else
-  timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000;
+  timeout = SERVER_SESSION_TIMEOUT.rel_value / 1000;
   GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
                    "MHD cannot set timeout per connection! Default time out %u sec.\n",
                    timeout);
@@ -1820,12 +1802,6 @@ server_start (struct HTTP_Server_Plugin *plugin)
 void
 server_stop (struct HTTP_Server_Plugin *plugin)
 {
-  struct MHD_Daemon *server_v4_tmp = plugin->server_v4;
-  plugin->server_v4 = NULL;
-
-  struct MHD_Daemon *server_v6_tmp = plugin->server_v6;
-  plugin->server_v6 = NULL;
-
   if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
   {
     GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
@@ -1838,13 +1814,15 @@ server_stop (struct HTTP_Server_Plugin *plugin)
     plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
   }
 
-  if (server_v6_tmp != NULL)
+  if (plugin->server_v4 != NULL)
   {
-    MHD_stop_daemon (server_v4_tmp);
+    MHD_stop_daemon (plugin->server_v4);
+    plugin->server_v4 = NULL;
   }
-  if (server_v6_tmp != NULL)
+  if ( plugin->server_v6 != NULL)
   {
-    MHD_stop_daemon (server_v6_tmp);
+    MHD_stop_daemon (plugin->server_v6);
+    plugin->server_v6 = NULL;
   }
 
   p = NULL;
@@ -1866,12 +1844,6 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr,
   struct HTTP_Server_Plugin *plugin = cls;
   struct HttpAddressWrapper *w = NULL;
 
-  if ((AF_INET == addr->sa_family) && (GNUNET_NO == plugin->use_ipv4))
-    return;
-
-  if ((AF_INET6 == addr->sa_family) && (GNUNET_NO == plugin->use_ipv6))
-    return;
-
   w = GNUNET_malloc (sizeof (struct HttpAddressWrapper));
   w->addr = http_common_address_from_socket (plugin->protocol, addr, addrlen);
   if (NULL == w->addr)
@@ -1886,7 +1858,7 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr,
                    "Notifying transport to add address `%s'\n",
                    http_common_plugin_address_to_string(NULL, w->addr, w->addrlen));
 
-  plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, w->addrlen);
+  plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, w->addrlen, "http_client");
 }
 
 
@@ -1917,7 +1889,7 @@ server_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
                    "Notifying transport to remove address `%s'\n",
                    http_common_plugin_address_to_string (NULL, w->addr, w->addrlen));
   GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
-  plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, w->addrlen);
+  plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, w->addrlen, "http_client");
   GNUNET_free (w->addr);
   GNUNET_free (w);
 }
@@ -1941,10 +1913,45 @@ server_nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *
   struct HTTP_Server_Plugin *plugin = cls;
 
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
-                   "NPMC called %s to address `%s'\n",
+                   "NAT called to %s address `%s'\n",
                    (add_remove == GNUNET_NO) ? "remove" : "add",
                    GNUNET_a2s (addr, addrlen));
 
+  if (AF_INET == addr->sa_family)
+  {
+    struct sockaddr_in *s4 = (struct sockaddr_in *) addr;
+
+    if (GNUNET_NO == plugin->use_ipv4)
+      return;
+
+    if ((NULL != plugin->server_addr_v4) &&
+        (0 != memcmp (&plugin->server_addr_v4->sin_addr,
+                      &s4->sin_addr, sizeof (struct in_addr))))
+    {
+        GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                         "Skipping address `%s' (not bindto address)\n",
+                         GNUNET_a2s (addr, addrlen));
+      return;
+    }
+  }
+
+  if (AF_INET6 == addr->sa_family)
+  {
+    struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) addr;
+    if (GNUNET_NO == plugin->use_ipv6)
+      return;
+
+    if ((NULL != plugin->server_addr_v6) &&
+        (0 != memcmp (&plugin->server_addr_v6->sin6_addr,
+                      &s6->sin6_addr, sizeof (struct in6_addr))))
+    {
+        GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                         "Skipping address `%s' (not bindto address)\n",
+                         GNUNET_a2s (addr, addrlen));
+        return;
+    }
+  }
+
   switch (add_remove)
   {
   case GNUNET_YES:
@@ -2246,7 +2253,9 @@ server_notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskCo
   plugin->ext_addr_len = strlen (plugin->ext_addr) + 1;
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                    "Notifying transport about external hostname address `%s'\n", plugin->ext_addr);
-  plugin->env->notify_address (plugin->env->cls, GNUNET_YES, plugin->ext_addr, plugin->ext_addr_len );
+  plugin->env->notify_address (plugin->env->cls, GNUNET_YES,
+                               plugin->ext_addr, plugin->ext_addr_len,
+                               "http_client");
 }
 
 
@@ -2409,7 +2418,7 @@ server_session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc
   s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_log (TIMEOUT_LOG,
               "Session %p was idle for %llu ms, disconnecting\n",
-              s, (unsigned long long) TIMEOUT.rel_value);
+              s, (unsigned long long) SERVER_SESSION_TIMEOUT.rel_value);
 
   /* call session destroy function */
  GNUNET_assert (GNUNET_OK == server_disconnect (s));
@@ -2423,12 +2432,12 @@ server_start_session_timeout (struct Session *s)
 {
  GNUNET_assert (NULL != s);
  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
- s->timeout_task =  GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ s->timeout_task =  GNUNET_SCHEDULER_add_delayed (SERVER_SESSION_TIMEOUT,
                                                   &server_session_timeout,
                                                   s);
  GNUNET_log (TIMEOUT_LOG,
              "Timeout for session %p set to %llu ms\n",
-             s,  (unsigned long long) TIMEOUT.rel_value);
+             s,  (unsigned long long) SERVER_SESSION_TIMEOUT.rel_value);
 }
 
 
@@ -2442,12 +2451,12 @@ server_reschedule_session_timeout (struct Session *s)
  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
 
  GNUNET_SCHEDULER_cancel (s->timeout_task);
- s->timeout_task =  GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ s->timeout_task =  GNUNET_SCHEDULER_add_delayed (SERVER_SESSION_TIMEOUT,
                                                   &server_session_timeout,
                                                   s);
  GNUNET_log (TIMEOUT_LOG,
              "Timeout rescheduled for session %p set to %llu ms\n",
-             s, (unsigned long long) TIMEOUT.rel_value);
+             s, (unsigned long long) SERVER_SESSION_TIMEOUT.rel_value);
 }
 
 /**
@@ -2458,6 +2467,19 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
   struct HTTP_Server_Plugin *plugin = api->cls;
+  struct Session *pos;
+  struct Session *next;
+
+  if (NULL == api->cls)
+  {
+    /* Free for stub mode */
+    GNUNET_free (api);
+    return NULL;
+  }
+
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   _("Shutting down plugin `%s'\n"),
+                   plugin->name);
 
   if (GNUNET_SCHEDULER_NO_TASK != plugin->notify_ext_task)
   {
@@ -2475,7 +2497,8 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
       plugin->env->notify_address (plugin->env->cls,
                                    GNUNET_NO,
                                    plugin->ext_addr,
-                                   plugin->ext_addr_len);
+                                   plugin->ext_addr_len,
+                                   "http_client");
   }
 
   /* Stop to report addresses to transport service */
@@ -2483,12 +2506,24 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
 
   server_stop (plugin);
 
+  next = plugin->head;
+  while (NULL != (pos = next))
+  {
+      next = pos->next;
+      GNUNET_CONTAINER_DLL_remove( plugin->head, plugin->tail, pos);
+      server_delete_session (pos);
+  }
+
   /* Clean up */
   GNUNET_free_non_null (plugin->external_hostname);
   GNUNET_free_non_null (plugin->ext_addr);
   GNUNET_free_non_null (plugin->server_addr_v4);
   GNUNET_free_non_null (plugin->server_addr_v6);
 
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   _("Shutdown for plugin `%s' complete\n"),
+                   plugin->name);
+
   GNUNET_free (plugin);
   GNUNET_free (api);
   return NULL;
@@ -2508,6 +2543,19 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
   plugin = GNUNET_malloc (sizeof (struct HTTP_Server_Plugin));
   plugin->env = env;
   p = plugin;
+
+  if (NULL == env->receive)
+  {
+    /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
+       initialze the plugin or the API */
+    api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+    api->cls = NULL;
+    api->address_to_string = &http_common_plugin_address_to_string;
+    api->string_to_address = &http_common_plugin_string_to_address;
+    api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
+    return api;
+  }
+
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
   api->send = &http_server_plugin_send;