-help seaspider some more
[oweals/gnunet.git] / src / hostlist / gnunet-daemon-hostlist.c
index e8c9bc8c798fa0c411d739d16703c39cfec8e6cb..0eedb56b16e8f81b54b172d6a6f184e0629e773f 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
  * @file hostlist/gnunet-daemon-hostlist.c
  * @brief code for bootstrapping via hostlist servers
  * @author Christian Grothoff
  * @file hostlist/gnunet-daemon-hostlist.c
  * @brief code for bootstrapping via hostlist servers
  * @author Christian Grothoff
- *
- * TODO:
- * - implement -a and -e switches (send P2P messages about our hostlist URL,
- *   receive such messages and automatically update our hostlist URL config
- *   value).
  */
 
 #include <stdlib.h>
 #include "platform.h"
 #include "hostlist-client.h"
  */
 
 #include <stdlib.h>
 #include "platform.h"
 #include "hostlist-client.h"
-#include "hostlist-server.h"
 #include "gnunet_core_service.h"
 #include "gnunet_getopt_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_core_service.h"
 #include "gnunet_getopt_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_time_lib.h"
 #include "gnunet_util_lib.h"
 
 #include "gnunet_time_lib.h"
 #include "gnunet_util_lib.h"
 
+#if HAVE_MHD
+
+#include "hostlist-server.h"
 
 /**
  * Set if we are allowed to advertise our hostlist to others.
  */
 static int advertising;
 
 
 /**
  * Set if we are allowed to advertise our hostlist to others.
  */
 static int advertising;
 
+/**
+ * Set if the user wants us to run a hostlist server.
+ */
+static int provide_hostlist;
+
+/**
+ * Handle to hostlist server's connect handler
+ */
+static GNUNET_CORE_ConnectEventHandler server_ch;
+
+/**
+ * Handle to hostlist server's disconnect handler
+ */
+static GNUNET_CORE_DisconnectEventHandler server_dh;
+
+#endif
+
 /**
  * Set if we are allowed to learn about peers by accessing
  * hostlist servers.
 /**
  * Set if we are allowed to learn about peers by accessing
  * hostlist servers.
@@ -60,11 +74,6 @@ static int bootstrapping;
  */
 static int learning;
 
  */
 static int learning;
 
-/**
- * Set if the user wants us to run a hostlist server.
- */
-static int provide_hostlist;
-
 /**
  * Statistics handle.
  */
 /**
  * Statistics handle.
  */
@@ -73,44 +82,127 @@ static struct GNUNET_STATISTICS_Handle *stats;
 /**
  * Handle to the core service (NULL until we've connected to it).
  */
 /**
  * Handle to the core service (NULL until we've connected to it).
  */
-struct GNUNET_CORE_Handle *core;
-
-/**
- * gnunet-daemon-hostlist command line options.
- */
-static struct GNUNET_GETOPT_CommandLineOption options[] = {
-  { 'a', "advertise", NULL, 
-    gettext_noop ("advertise our hostlist to other peers"),
-    GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising },
-  { 'b', "bootstrap", NULL, 
-    gettext_noop ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
-    GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping },
-  { 'e', "enable-learning", NULL,
-    gettext_noop ("enable learning about hostlist servers from other peers"),
-    GNUNET_NO, &GNUNET_GETOPT_set_one, &learning},
-  { 'p', "provide-hostlist", NULL, 
-    gettext_noop ("provide a hostlist server"),
-    GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist},
-  GNUNET_GETOPT_OPTION_END
+static struct GNUNET_CORE_Handle *core;
+
+/**
+ * Handle to the hostlist client's advertisement handler
+ */
+static GNUNET_CORE_MessageCallback client_adv_handler;
+
+/**
+ * Handle to hostlist client's connect handler
+ */
+static GNUNET_CORE_ConnectEventHandler client_ch;
+
+/**
+ * Handle to hostlist client's disconnect handler
+ */
+static GNUNET_CORE_DisconnectEventHandler client_dh;
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * A HOSTLIST_ADV message is used to exchange information about
+ * hostlist advertisements.  This struct is always
+ * followed by the actual url under which the hostlist can be obtained:
+ *
+ * 1) transport-name (0-terminated)
+ * 2) address-length (uint32_t, network byte order; possibly
+ *    unaligned!)
+ * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
+ *    unaligned!)
+ * 4) address (address-length bytes; possibly unaligned!)
+ */
+struct GNUNET_HOSTLIST_ADV_Message
+{
+  /**
+   * Type will be GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT.
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Always zero (for alignment).
+   */
+  uint32_t reserved GNUNET_PACKED;
 };
 };
+GNUNET_NETWORK_STRUCT_END
 
 
+static struct GNUNET_PeerIdentity me;
 
 static void
 
 static void
-core_init (void *cls,
-          struct GNUNET_CORE_Handle * server,
-          const struct GNUNET_PeerIdentity *
-          my_identity,
-          const struct
-          GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
-          publicKey)
+core_init (void *cls, struct GNUNET_CORE_Handle *server,
+           const struct GNUNET_PeerIdentity *my_identity)
+{
+  me = *my_identity;
+}
+
+/**
+ * Core handler for p2p hostlist advertisements
+ *
+ * @param cls closure
+ * @param peer identity of the sender
+ * @param message advertisement message we got
+ * @param atsi performance information
+ * @param atsi_count number of records in 'atsi'
+ * @return GNUNET_OK on success
+ */
+static int
+advertisement_handler (void *cls, const struct GNUNET_PeerIdentity *peer,
+                       const struct GNUNET_MessageHeader *message,
+                       const struct GNUNET_ATS_Information *atsi,
+                       unsigned int atsi_count)
 {
 {
-  if (advertising && (NULL != server))
-    {    
-      /* FIXME: provide "server" to 'hostlist' module */
-    }
+  GNUNET_assert (NULL != client_adv_handler);
+  return (*client_adv_handler) (cls, peer, message, atsi, atsi_count);
 }
 
 
 }
 
 
+/**
+ * Method called whenever a given peer connects.  Wrapper to call both client's and server's functions
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ * @param atsi performance data
+ * @param atsi_count number of records in 'atsi'
+ */
+static void
+connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer,
+                 const struct GNUNET_ATS_Information *atsi,
+                 unsigned int atsi_count)
+{
+  if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity)))
+    return;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "A new peer connected, notifying client and server\n");
+  if (NULL != client_ch)
+    (*client_ch) (cls, peer, atsi, atsi_count);
+#if HAVE_MHD
+  if (NULL != server_ch)
+    (*server_ch) (cls, peer, atsi, atsi_count);
+#endif
+}
+
+/**
+ * Method called whenever a given peer disconnects. Wrapper to call both client's and server's functions
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+  if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity)))
+    return;
+  /* call hostlist client disconnect handler */
+  if (NULL != client_dh)
+    (*client_dh) (cls, peer);
+#if HAVE_MHD
+  /* call hostlist server disconnect handler */
+  if (NULL != server_dh)
+    (*server_dh) (cls, peer);
+#endif
+}
+
 /**
  * Last task run during shutdown.  Disconnects us from
  * the other services.
 /**
  * Last task run during shutdown.  Disconnects us from
  * the other services.
@@ -118,21 +210,27 @@ core_init (void *cls,
 static void
 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 static void
 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist daemon is shutting down\n");
+  if (core != NULL)
+  {
+    GNUNET_CORE_disconnect (core);
+    core = NULL;
+  }
   if (bootstrapping)
   if (bootstrapping)
-    {
-      GNUNET_HOSTLIST_client_stop ();
-    }
+  {
+    GNUNET_HOSTLIST_client_stop ();
+  }
+#if HAVE_MHD
   if (provide_hostlist)
   if (provide_hostlist)
-    {      
-      GNUNET_HOSTLIST_server_stop ();
-    }
-  GNUNET_CORE_disconnect (core);
+  {
+    GNUNET_HOSTLIST_server_stop ();
+  }
+#endif
   if (stats != NULL)
   if (stats != NULL)
-    {
-      GNUNET_STATISTICS_destroy (stats,
-                                GNUNET_NO);
-      stats = NULL;
-    }
+  {
+    GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
+    stats = NULL;
+  }
 }
 
 
 }
 
 
@@ -140,67 +238,66 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * Main function that will be run.
  *
  * @param cls closure
  * Main function that will be run.
  *
  * @param cls closure
- * @param sched the scheduler to use
  * @param args remaining command-line arguments
  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  * @param cfg configuration
  */
  * @param args remaining command-line arguments
  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  * @param cfg configuration
  */
-static void 
-run (void *cls,
-     struct GNUNET_SCHEDULER_Handle * sched,
-     char *const *args,
-     const char *cfgfile,
-     const struct GNUNET_CONFIGURATION_Handle * cfg)
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
 {
-  GNUNET_CORE_ClientEventHandler ch = NULL;
-  GNUNET_CORE_ClientEventHandler dh = NULL;
-  struct GNUNET_CORE_MessageHandler handlers[] = 
-    {
-      { NULL, 0, 0 }
-    };
-
-  if ( (! bootstrapping) &&
-       (! learning) &&
-       (! provide_hostlist) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("None of the functions for the hostlist daemon were enabled.  I have no reason to run!\n"));
-      return;
-    }
-  stats = GNUNET_STATISTICS_create (sched, "hostlist", cfg);
-  if (learning)
-    {
-      /* FIXME (register handler with core for hostlist ads) */
-    }
+  static const struct GNUNET_CORE_MessageHandler learn_handlers[] = {
+    {&advertisement_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0},
+    {NULL, 0, 0}
+  };
+  static const struct GNUNET_CORE_MessageHandler no_learn_handlers[] = {
+    {NULL, 0, 0}
+  };
+  if ((!bootstrapping) && (!learning)
+#if HAVE_MHD
+      && (!provide_hostlist)
+#endif
+      )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _
+                ("None of the functions for the hostlist daemon were enabled.  I have no reason to run!\n"));
+    return;
+  }
+
+
+
+  stats = GNUNET_STATISTICS_create ("hostlist", cfg);
+
+  core =
+      GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_handler,
+                           &disconnect_handler, NULL, GNUNET_NO, NULL,
+                           GNUNET_NO,
+                           learning ? learn_handlers : no_learn_handlers);
+
   if (bootstrapping)
   if (bootstrapping)
-    {
-      GNUNET_HOSTLIST_client_start (cfg, sched, stats,
-                                   &ch, &dh);
-    }
+  {
+    GNUNET_HOSTLIST_client_start (cfg, stats, &client_ch, &client_dh,
+                                  &client_adv_handler, learning);
+  }
+
+#if HAVE_MHD
   if (provide_hostlist)
   if (provide_hostlist)
-    {      
-      GNUNET_HOSTLIST_server_start (cfg, sched, stats);
-    }
-  core = GNUNET_CORE_connect (sched, cfg,
-                             GNUNET_TIME_UNIT_FOREVER_REL,
-                             NULL,
-                             &core_init,
-                             ch, dh,
-                             NULL,
-                             NULL, GNUNET_NO,
-                             NULL, GNUNET_NO,
-                             handlers);
-  GNUNET_SCHEDULER_add_delayed (sched,
-                                GNUNET_TIME_UNIT_FOREVER_REL,
-                                &cleaning_task, NULL);
+  {
+    GNUNET_HOSTLIST_server_start (cfg, stats, core, &server_ch, &server_dh,
+                                  advertising);
+  }
+#endif
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task,
+                                NULL);
+
   if (NULL == core)
   if (NULL == core)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Failed to connect to `%s' service.\n"),
-                 "core");
-      GNUNET_SCHEDULER_shutdown (sched);
-      return;     
-    }
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Failed to connect to `%s' service.\n"), "core");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
 }
 
 
 }
 
 
@@ -214,15 +311,36 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
 int
 main (int argc, char *const *argv)
 {
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+#if HAVE_MHD
+    {'a', "advertise", NULL,
+     gettext_noop ("advertise our hostlist to other peers"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising},
+#endif
+    {'b', "bootstrap", NULL,
+     gettext_noop
+     ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping},
+    {'e', "enable-learning", NULL,
+     gettext_noop ("enable learning about hostlist servers from other peers"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &learning},
+#if HAVE_MHD
+    {'p', "provide-hostlist", NULL,
+     gettext_noop ("provide a hostlist server"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist},
+#endif
+    GNUNET_GETOPT_OPTION_END
+  };
+
   int ret;
 
   int ret;
 
-  ret = (GNUNET_OK ==
-         GNUNET_PROGRAM_run (argc,
-                             argv,
-                             "hostlist", 
-                            _("GNUnet hostlist server and client"),
-                            options,
-                            &run, NULL)) ? 0 : 1;
+  GNUNET_log_setup ("hostlist", "WARNING", NULL);
+  ret =
+      (GNUNET_OK ==
+       GNUNET_PROGRAM_run (argc, argv, "hostlist",
+                           _("GNUnet hostlist server and client"), options,
+                           &run, NULL)) ? 0 : 1;
+
   return ret;
 }
 
   return ret;
 }