gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r27813 - in gnunet/src: core mesh nse transport


From: gnunet
Subject: [GNUnet-SVN] r27813 - in gnunet/src: core mesh nse transport
Date: Tue, 9 Jul 2013 09:35:46 +0200

Author: grothoff
Date: 2013-07-09 09:35:46 +0200 (Tue, 09 Jul 2013)
New Revision: 27813

Modified:
   gnunet/src/core/gnunet-service-core.c
   gnunet/src/mesh/gnunet-service-mesh.c
   gnunet/src/nse/gnunet-service-nse.c
   gnunet/src/transport/gnunet-service-transport.c
Log:
-simplify zone key loading by using synchronous ECC key API

Modified: gnunet/src/core/gnunet-service-core.c
===================================================================
--- gnunet/src/core/gnunet-service-core.c       2013-07-09 07:28:27 UTC (rev 
27812)
+++ gnunet/src/core/gnunet-service-core.c       2013-07-09 07:35:46 UTC (rev 
27813)
@@ -54,12 +54,7 @@
  */
 static struct GNUNET_SERVER_Handle *GSC_server;
 
-/**
- * Hostkey generation context
- */
-static struct GNUNET_CRYPTO_EccKeyGenerationContext *keygen;
 
-
 /**
  * Last task run during shutdown.  Disconnects us from
  * the transport.
@@ -71,11 +66,6 @@
 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n");
-  if (NULL != keygen)
-  {
-    GNUNET_CRYPTO_ecc_key_create_stop (keygen);
-    keygen = NULL;
-  }
   GSC_CLIENTS_done ();
   GSC_NEIGHBOURS_done ();
   GSC_SESSIONS_done ();
@@ -90,43 +80,7 @@
 }
 
 
-
 /**
- * Callback for hostkey read/generation
- *
- * @param cls NULL
- * @param pk the private key
- * @param emsg error message
- */
-static void
-key_generation_cb (void *cls,
-                   struct GNUNET_CRYPTO_EccPrivateKey *pk,
-                   const char *emsg)
-{
-  keygen = NULL;
-  if (NULL == pk)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               _("Failed to read or generate private key: %s\n"),
-               emsg);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  if ((GNUNET_OK != GSC_KX_init (pk)) || 
-      (GNUNET_OK != GSC_NEIGHBOURS_init ()))
-  {
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  GSC_SESSIONS_init ();
-  GSC_CLIENTS_init (GSC_server);
-  GNUNET_SERVER_resume (GSC_server);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Core service of `%4s' ready.\n"),
-              GNUNET_i2s (&GSC_my_identity));
-}
-
-
-/**
  * Initiate core service.
  *
  * @param cls closure
@@ -137,6 +91,7 @@
 run (void *cls, struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
+  struct GNUNET_CRYPTO_EccPrivateKey *pk;
   char *keyfile;
 
   GSC_cfg = c;
@@ -156,14 +111,20 @@
                                 NULL);
   GNUNET_SERVER_suspend (server);
   GSC_TYPEMAP_init ();
-  keygen = GNUNET_CRYPTO_ecc_key_create_start (keyfile, &key_generation_cb, 
NULL);
+  pk = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
   GNUNET_free (keyfile);
-  if (NULL == keygen)
+  GNUNET_assert (NULL != pk);
+  if ((GNUNET_OK != GSC_KX_init (pk)) || 
+      (GNUNET_OK != GSC_NEIGHBOURS_init ()))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Transport service is unable to access hostkey. 
Exiting.\n"));
     GNUNET_SCHEDULER_shutdown ();
+    return;
   }
+  GSC_SESSIONS_init ();
+  GSC_CLIENTS_init (GSC_server);
+  GNUNET_SERVER_resume (GSC_server);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Core service of `%4s' ready.\n"),
+              GNUNET_i2s (&GSC_my_identity));
 }
 
 

Modified: gnunet/src/mesh/gnunet-service-mesh.c
===================================================================
--- gnunet/src/mesh/gnunet-service-mesh.c       2013-07-09 07:28:27 UTC (rev 
27812)
+++ gnunet/src/mesh/gnunet-service-mesh.c       2013-07-09 07:35:46 UTC (rev 
27813)
@@ -586,11 +586,6 @@
 /*************************** Static global variables 
**************************/
 
 /**
- * Hostkey generation context
- */
-static struct GNUNET_CRYPTO_EccKeyGenerationContext *keygen;
-
-/**
  * DLL with all the clients, head.
  */
 static struct MeshClient *clients_head;
@@ -5177,11 +5172,6 @@
     GNUNET_CORE_disconnect (core_handle);
     core_handle = NULL;
   }
-  if (NULL != keygen)
-  {
-    GNUNET_CRYPTO_ecc_key_create_stop (keygen);
-    keygen = NULL;
-  }
   GNUNET_CONTAINER_multihashmap_iterate (tunnels, &shutdown_tunnel, NULL);
   GNUNET_CONTAINER_multihashmap_iterate (peers, &shutdown_peer, NULL);
   if (dht_handle != NULL)
@@ -5204,64 +5194,6 @@
 
 
 /**
- * Callback for hostkey read/generation.
- *
- * @param cls Closure (Configuration handle).
- * @param pk The ECC private key.
- * @param emsg Error message, if any.
- */
-static void
-key_generation_cb (void *cls,
-                   struct GNUNET_CRYPTO_EccPrivateKey *pk,
-                   const char *emsg)
-{
-  const struct GNUNET_CONFIGURATION_Handle *c = cls;
-
-  keygen = NULL;
-  if (NULL == pk)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                _("Could not access hostkey: %s. Exiting.\n"),
-                emsg);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  my_private_key = pk;
-  GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key);
-  GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
-                      &my_full_id.hashPubKey);
-  myid = GNUNET_PEER_intern (&my_full_id);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Mesh for peer [%s] starting\n",
-              GNUNET_i2s(&my_full_id));
-
-  core_handle = GNUNET_CORE_connect (c, /* Main configuration */
-                                     NULL,      /* Closure passed to MESH 
functions */
-                                     &core_init,        /* Call core_init once 
connected */
-                                     &core_connect,     /* Handle connects */
-                                     &core_disconnect,  /* remove peers on 
disconnects */
-                                     NULL,      /* Don't notify about all 
incoming messages */
-                                     GNUNET_NO, /* For header only in 
notification */
-                                     NULL,      /* Don't notify about all 
outbound messages */
-                                     GNUNET_NO, /* For header-only out 
notification */
-                                     core_handlers);    /* Register these 
handlers */
-  if (core_handle == NULL)
-  {
-    GNUNET_break (0);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-
-  next_tid = 0;
-  next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
-
-  announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh service running\n");
-}
-
-
-/**
  * Process mesh requests.
  *
  * @param cls closure
@@ -5273,6 +5205,7 @@
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
   char *keyfile;
+  struct GNUNET_CRYPTO_EccPrivateKey *pk;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
   server_handle = server;
@@ -5411,10 +5344,38 @@
   /* Scheduled the task to clean up when shutdown is called */
   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
                                 NULL);
-  keygen = GNUNET_CRYPTO_ecc_key_create_start (keyfile,
-                                               &key_generation_cb,
-                                               (void *) c);
+  pk = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
   GNUNET_free (keyfile);
+  GNUNET_assert (NULL != pk);
+  my_private_key = pk;
+  GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key);
+  GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
+                      &my_full_id.hashPubKey);
+  myid = GNUNET_PEER_intern (&my_full_id);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Mesh for peer [%s] starting\n",
+              GNUNET_i2s(&my_full_id));
+
+  core_handle = GNUNET_CORE_connect (c, /* Main configuration */
+                                     NULL,      /* Closure passed to MESH 
functions */
+                                     &core_init,        /* Call core_init once 
connected */
+                                     &core_connect,     /* Handle connects */
+                                     &core_disconnect,  /* remove peers on 
disconnects */
+                                     NULL,      /* Don't notify about all 
incoming messages */
+                                     GNUNET_NO, /* For header only in 
notification */
+                                     NULL,      /* Don't notify about all 
outbound messages */
+                                     GNUNET_NO, /* For header-only out 
notification */
+                                     core_handlers);    /* Register these 
handlers */
+  if (NULL == core_handle)
+  {
+    GNUNET_break (0);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  next_tid = 0;
+  next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
+  announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh service running\n");
 }
 
 

Modified: gnunet/src/nse/gnunet-service-nse.c
===================================================================
--- gnunet/src/nse/gnunet-service-nse.c 2013-07-09 07:28:27 UTC (rev 27812)
+++ gnunet/src/nse/gnunet-service-nse.c 2013-07-09 07:35:46 UTC (rev 27813)
@@ -306,12 +306,7 @@
  */
 static struct GNUNET_SERVER_Handle *srv;
 
-/**
- * Hostkey generation context
- */
-static struct GNUNET_CRYPTO_EccKeyGenerationContext *keygen;
 
-
 /**
  * Initialize a message to clients with the current network
  * size estimate.
@@ -1303,11 +1298,6 @@
     proof_task = GNUNET_SCHEDULER_NO_TASK;
     write_proof ();             /* remember progress */
   }
-  if (NULL != keygen)
-  {
-    GNUNET_CRYPTO_ecc_key_create_stop (keygen);
-    keygen = NULL;
-  }
   if (NULL != nc)
   {
     GNUNET_SERVER_notification_context_destroy (nc);
@@ -1389,16 +1379,16 @@
 
 
 /**
- * Callback for hostkey read/generation
+ * Handle network size estimate clients.
  *
- * @param cls NULL
- * @param pk the private key
- * @param emsg error message
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
  */
 static void
-key_generation_cb (void *cls,
-                   struct GNUNET_CRYPTO_EccPrivateKey *pk,
-                   const char *emsg)
+run (void *cls, 
+     struct GNUNET_SERVER_Handle *server,
+     const struct GNUNET_CONFIGURATION_Handle *c)
 {
   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
@@ -1411,77 +1401,8 @@
     {NULL, 0, 0}
   };
   char *proof;
-
-  keygen = NULL;
-  if (NULL == pk)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                _("Could not access hostkey: %s. Exiting.\n"),
-               emsg);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  my_private_key = pk;
-  GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key);
-  GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
-                      &my_identity.hashPubKey);
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", 
&proof))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _
-                ("NSE service is lacking key configuration settings.  
Exiting.\n"));
-    GNUNET_CRYPTO_ecc_key_free (my_private_key);
-    my_private_key = NULL;    
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
-      (sizeof (my_proof) !=
-       GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
-    my_proof = 0;
-  GNUNET_free (proof);
-  proof_task =
-      GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                          &find_proof, NULL);
-
-  peers = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
-  GNUNET_SERVER_add_handlers (srv, handlers);
-  nc = GNUNET_SERVER_notification_context_create (srv, 1);
-  /* Connect to core service and register core handlers */
-  coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
-                                 NULL,       /* Closure passed to functions */
-                                 &core_init,    /* Call core_init once 
connected */
-                                 &handle_core_connect,  /* Handle connects */
-                                 &handle_core_disconnect,       /* Handle 
disconnects */
-                                 NULL,  /* Don't want notified about all 
incoming messages */
-                                 GNUNET_NO,     /* For header only inbound 
notification */
-                                 NULL,  /* Don't want notified about all 
outbound messages */
-                                 GNUNET_NO,     /* For header only outbound 
notification */
-                                 core_handlers);        /* Register these 
handlers */
-  if (NULL == coreAPI)
-  {
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  stats = GNUNET_STATISTICS_create ("nse", cfg);
-  GNUNET_SERVER_resume (srv);
-}
-
-
-/**
- * Handle network size estimate clients.
- *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
- */
-static void
-run (void *cls, 
-     struct GNUNET_SERVER_Handle *server,
-     const struct GNUNET_CONFIGURATION_Handle *c)
-{
   char *keyfile;
+  struct GNUNET_CRYPTO_EccPrivateKey *pk;
 
   cfg = c;
   srv = server;  
@@ -1533,8 +1454,56 @@
   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
                                 NULL);
   GNUNET_SERVER_suspend (srv);
-  keygen = GNUNET_CRYPTO_ecc_key_create_start (keyfile, &key_generation_cb, 
NULL);
+
+
+  pk = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
   GNUNET_free (keyfile);
+  GNUNET_assert (NULL != pk);
+  my_private_key = pk;
+  GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key);
+  GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
+                      &my_identity.hashPubKey);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", 
&proof))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _
+                ("NSE service is lacking key configuration settings.  
Exiting.\n"));
+    GNUNET_CRYPTO_ecc_key_free (my_private_key);
+    my_private_key = NULL;    
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
+      (sizeof (my_proof) !=
+       GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
+    my_proof = 0;
+  GNUNET_free (proof);
+  proof_task =
+      GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                          &find_proof, NULL);
+
+  peers = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
+  GNUNET_SERVER_add_handlers (srv, handlers);
+  nc = GNUNET_SERVER_notification_context_create (srv, 1);
+  /* Connect to core service and register core handlers */
+  coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
+                                 NULL,       /* Closure passed to functions */
+                                 &core_init,    /* Call core_init once 
connected */
+                                 &handle_core_connect,  /* Handle connects */
+                                 &handle_core_disconnect,       /* Handle 
disconnects */
+                                 NULL,  /* Don't want notified about all 
incoming messages */
+                                 GNUNET_NO,     /* For header only inbound 
notification */
+                                 NULL,  /* Don't want notified about all 
outbound messages */
+                                 GNUNET_NO,     /* For header only outbound 
notification */
+                                 core_handlers);        /* Register these 
handlers */
+  if (NULL == coreAPI)
+  {
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  stats = GNUNET_STATISTICS_create ("nse", cfg);
+  GNUNET_SERVER_resume (srv);
 }
 
 

Modified: gnunet/src/transport/gnunet-service-transport.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport.c     2013-07-09 07:28:27 UTC 
(rev 27812)
+++ gnunet/src/transport/gnunet-service-transport.c     2013-07-09 07:35:46 UTC 
(rev 27813)
@@ -63,11 +63,6 @@
 struct GNUNET_PEERINFO_Handle *GST_peerinfo;
 
 /**
- * Hostkey generation context
- */
-struct GNUNET_CRYPTO_EccKeyGenerationContext *GST_keygen;
-
-/**
  * Handle to our service's server.
  */
 static struct GNUNET_SERVER_Handle *GST_server;
@@ -584,11 +579,6 @@
 static void
 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  if (NULL != GST_keygen)
-  {
-    GNUNET_CRYPTO_ecc_key_create_stop (GST_keygen);
-    GST_keygen = NULL;
-  }
   GST_neighbours_stop ();
   GST_validation_stop ();
   GST_plugins_unload ();
@@ -620,31 +610,45 @@
 
 
 /**
- * Callback for hostkey read/generation
+ * Initiate transport service.
  *
- * @param cls NULL
- * @param pk the private key
- * @param emsg error message
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
  */
 static void
-key_generation_cb (void *cls,
-                   struct GNUNET_CRYPTO_EccPrivateKey *pk,
-                   const char *emsg)
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+     const struct GNUNET_CONFIGURATION_Handle *c)
 {
+  char *keyfile;
+  struct GNUNET_CRYPTO_EccPrivateKey *pk;
   long long unsigned int max_fd_cfg;
   int max_fd_rlimit;
   int max_fd;
   int friend_only;
 
-  GST_keygen = NULL;
-  if (NULL == pk)
+  /* setup globals */
+  GST_cfg = c;
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (c, "PEER", "PRIVATE_KEY",
+                                               &keyfile))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                _("Could not access hostkey: %s. Exiting.\n"),
-                emsg);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _
+                ("Transport service is lacking key configuration settings.  
Exiting.\n"));
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (c, "transport", "HELLO_EXPIRATION",
+                                           &hello_expiration))
+  {
+    hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
+  }
+  GST_server = server;
+  pk = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
+  GNUNET_free (keyfile);
+  GNUNET_assert (NULL != pk);
   GST_my_private_key = pk;
 
   GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
@@ -671,10 +675,10 @@
   struct rlimit r_file;
   if (0 == getrlimit (RLIMIT_NOFILE, &r_file))
   {
-               max_fd_rlimit = r_file.rlim_cur;
-               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                                                               "Maximum number 
of open files was: %u/%u\n", r_file.rlim_cur,
-                                                               
r_file.rlim_max);
+    max_fd_rlimit = r_file.rlim_cur;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Maximum number of open files was: %u/%u\n", r_file.rlim_cur,
+               r_file.rlim_max);
   }
   max_fd_rlimit = (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport 
*/
 #endif
@@ -713,56 +717,10 @@
                         (max_fd / 3) * 2);
   GST_clients_start (GST_server);
   GST_validation_start ((max_fd / 3));
-  if (NULL != GST_server)
-    GNUNET_SERVER_resume (GST_server);
 }
 
 
 /**
- * Initiate transport service.
- *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
- */
-static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
-     const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  char *keyfile;
-
-  /* setup globals */
-  GST_cfg = c;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (c, "PEER", "PRIVATE_KEY",
-                                               &keyfile))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _
-                ("Transport service is lacking key configuration settings.  
Exiting.\n"));
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c, "transport", "HELLO_EXPIRATION",
-                                           &hello_expiration))
-  {
-    hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
-  }
-  GST_server = server;
-  GNUNET_SERVER_suspend (server);
-  GST_keygen = GNUNET_CRYPTO_ecc_key_create_start (keyfile, 
&key_generation_cb, NULL);
-  GNUNET_free (keyfile);
-  if (NULL == GST_keygen)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Transport service is unable to access hostkey. 
Exiting.\n"));
-    GNUNET_SCHEDULER_shutdown ();
-  }
-}
-
-
-/**
  * The main function for the transport service.
  *
  * @param argc number of arguments from the command line




reply via email to

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