gnunet-svn
[Top][All Lists]
Advanced

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

[gnunet] 01/02: PEERSTORE: Fix hello_add API


From: gnunet
Subject: [gnunet] 01/02: PEERSTORE: Fix hello_add API
Date: Sun, 25 Feb 2024 10:57:35 +0100

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a commit to branch master
in repository gnunet.

commit 2de3ca3a659f731aa9e533991db5fd46e7e90860
Author: Martin Schanzenbach <schanzen@gnunet.org>
AuthorDate: Sun Feb 25 10:53:16 2024 +0100

    PEERSTORE: Fix hello_add API
    
    The new UPSERT API does not work as indended.
    Instead, we now iterate over all entries and check if we have a newer
    hello to add/replace.
    This also fixes some handle/closure oddities exposed in the peerstore
    API.
---
 src/include/gnunet_peerstore_service.h             |  54 +---------
 .../hostlist/gnunet-daemon-hostlist_client.c       |  88 ++++++++++-----
 src/service/peerstore/peerstore_api.c              | 119 ++++++++++++++++-----
 src/service/topology/gnunet-daemon-topology.c      |  60 +++++++----
 4 files changed, 197 insertions(+), 124 deletions(-)

diff --git a/src/include/gnunet_peerstore_service.h 
b/src/include/gnunet_peerstore_service.h
index 0284d46dd..319946e1d 100644
--- a/src/include/gnunet_peerstore_service.h
+++ b/src/include/gnunet_peerstore_service.h
@@ -181,60 +181,8 @@ typedef void (*GNUNET_PEERSTORE_Continuation) (void *cls, 
int success);
 /**
  * Context for a add hello uri request.
  */
-struct GNUNET_PEERSTORE_StoreHelloContext
-{
-  /**
-   * Kept (also) in a DLL.
-   */
-  struct GNUNET_PEERSTORE_StoreHelloContext *prev;
-
-  /**
-   * Kept (also) in a DLL.
-   */
-  struct GNUNET_PEERSTORE_StoreHelloContext *next;
-
-  /**
-   * Peerstore handle.
-   */
-  struct GNUNET_PEERSTORE_Handle *h;
-
-  /**
-   * Function to call with information.
-   */
-  GNUNET_PEERSTORE_Continuation cont;
-
-  /**
-   * Closure for @e callback.
-   */
-  void *cont_cls;
-
-  /**
-   * Hello uri which was request for storing.
-   */
-  struct GNUNET_MessageHeader *hello;
-
-  /**
-   * The peer id for the hello.
-   */
-  struct GNUNET_PeerIdentity *pid;
-
-  /**
-   * The iteration for the merge
-   */
-  struct GNUNET_PEERSTORE_StoreContext *sc;
+struct GNUNET_PEERSTORE_StoreHelloContext;
 
-};
-
-/**
- * Closure to hold a GNUNET_PEERSTORE_StoreHelloContext.
- */
-struct GNUNET_PEERSTORE_StoreHelloContextClosure
-{
-  /**
-   * The GNUNET_PEERSTORE_StoreHelloContext to hold.
-   */
-  struct GNUNET_PEERSTORE_StoreHelloContext *shc;
-};
 
 /**
  * Function called by PEERSTORE for each matching record.
diff --git a/src/service/hostlist/gnunet-daemon-hostlist_client.c 
b/src/service/hostlist/gnunet-daemon-hostlist_client.c
index 9388c8940..95891a1ad 100644
--- a/src/service/hostlist/gnunet-daemon-hostlist_client.c
+++ b/src/service/hostlist/gnunet-daemon-hostlist_client.c
@@ -138,6 +138,26 @@ struct Hostlist
   uint32_t times_used;
 };
 
+/**
+* Context for a add hello uri request.
+*/
+struct StoreHelloEntry
+{
+  /**
+   * Kept (also) in a DLL.
+   */
+  struct StoreHelloEntry *prev;
+
+  /**
+   * Kept (also) in a DLL.
+   */
+  struct StoreHelloEntry *next;
+
+  /**
+   * Store hello ctx
+   */
+  struct GNUNET_PEERSTORE_StoreHelloContext *sc;
+};
 
 /**
  * Our configuration.
@@ -232,12 +252,12 @@ static struct GNUNET_TIME_Absolute end_time;
 /**
  * Head of the linkd list to store the store context for hellos.
  */
-static struct GNUNET_PEERSTORE_StoreHelloContext *shc_head;
+static struct StoreHelloEntry *she_head;
 
 /**
  * Tail of the linkd list to store the store context for hellos.
  */
-static struct GNUNET_PEERSTORE_StoreHelloContext *shc_tail;
+static struct StoreHelloEntry *she_tail;
 
 /**
  * Head of the linked list used to store hostlists
@@ -323,16 +343,17 @@ static struct GNUNET_PEERSTORE_Handle *peerstore;
 static void
 shc_cont (void *cls, int success)
 {
-  struct GNUNET_PEERSTORE_StoreHelloContextClosure *shc_cls =  cls;
+  struct StoreHelloEntry *she =  cls;
 
+  she->sc = NULL;
   if (GNUNET_YES == success)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Hostlist entry stored successfully!\n");
   else
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Error storing hostlist entry!\n");
-  GNUNET_CONTAINER_DLL_remove (shc_head, shc_tail, shc_cls->shc);
-  GNUNET_free (shc_cls);
+  GNUNET_CONTAINER_DLL_remove (she_head, she_tail, she);
+  GNUNET_free (she);
 }
 
 
@@ -349,8 +370,7 @@ static size_t
 callback_download (void *ptr, size_t size, size_t nmemb, void *ctx)
 {
   static char download_buffer[GNUNET_MAX_MESSAGE_SIZE - 1];
-  struct GNUNET_PEERSTORE_StoreHelloContext *shc;
-  struct GNUNET_PEERSTORE_StoreHelloContextClosure *shc_cls;
+  struct StoreHelloEntry *she;
   const char *cbuf = ptr;
   const struct GNUNET_MessageHeader *msg;
   size_t total;
@@ -414,18 +434,17 @@ callback_download (void *ptr, size_t size, size_t nmemb, 
void *ctx)
       1,
       GNUNET_NO);
     stat_hellos_obtained++;
-    shc_cls = GNUNET_new (struct GNUNET_PEERSTORE_StoreHelloContextClosure);
-    shc = GNUNET_PEERSTORE_hello_add (peerstore,
-                                      msg,
-                                      shc_cont,
-                                      shc_cls);
-    if (NULL != shc)
+    she = GNUNET_new (struct StoreHelloEntry);
+    she->sc = GNUNET_PEERSTORE_hello_add (peerstore,
+                                           msg,
+                                           shc_cont,
+                                           she);
+    if (NULL != she->sc)
     {
-      shc_cls->shc = shc;
-      GNUNET_CONTAINER_DLL_insert (shc_head, shc_tail, shc);
+      GNUNET_CONTAINER_DLL_insert (she_head, she_tail, she);
     }
     else
-      GNUNET_free (shc_cls);
+      GNUNET_free (she);
     memmove (download_buffer, &download_buffer[msize], download_pos - msize);
     download_pos -= msize;
   }
@@ -1042,28 +1061,40 @@ download_hostlist ()
   CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1);
 #ifdef CURLOPT_REDIR_PROTOCOLS_STR
   if (0 == strncasecmp (current_url, "https://";, strlen ("https://";)))
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, 
CURLOPT_REDIR_PROTOCOLS_STR, "https"));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl,
+                                                 CURLOPT_REDIR_PROTOCOLS_STR,
+                                                 "https"));
   else
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, 
CURLOPT_REDIR_PROTOCOLS_STR, "http,https"));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl,
+                                                 CURLOPT_REDIR_PROTOCOLS_STR,
+                                                 "http,https"));
 #else
 #ifdef CURLOPT_REDIR_PROTOCOLS
   if (0 == strncasecmp (current_url, "https://";, strlen ("https://";)))
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, 
CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS,
+                                                 CURLPROTO_HTTPS));
   else
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, 
CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS,
+                                                 CURLPROTO_HTTP
+                                                 | CURLPROTO_HTTPS));
 #endif
 #endif
 #ifdef CURLOPT_PROTOCOLS_STR
   if (0 == strncasecmp (current_url, "https://";, strlen ("https://";)))
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS_STR, 
"https"));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS_STR,
+                                                 "https"));
   else
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS_STR, 
"http,https"));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS_STR,
+                                                 "http,https"));
 #else
 #ifdef CURLOPT_PROTOCOLS
   if (0 == strncasecmp (current_url, "https://";, strlen ("https://";)))
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS, 
CURLPROTO_HTTPS));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS,
+                                                 CURLPROTO_HTTPS));
   else
-    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS, 
CURLPROTO_HTTP | CURLPROTO_HTTPS));
+    GNUNET_assert (CURLE_OK == curl_easy_setopt (curl, CURLOPT_PROTOCOLS,
+                                                 CURLPROTO_HTTP
+                                                 | CURLPROTO_HTTPS));
 #endif
 #endif
   CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4);
@@ -1784,13 +1815,14 @@ GNUNET_HOSTLIST_client_start (const struct 
GNUNET_CONFIGURATION_Handle *c,
 void
 GNUNET_HOSTLIST_client_stop ()
 {
-  struct GNUNET_PEERSTORE_StoreHelloContext *pos;
+  struct StoreHelloEntry *pos;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n");
-  while (NULL != (pos = shc_head))
+  while (NULL != (pos = she_head))
   {
-    GNUNET_CONTAINER_DLL_remove (shc_head, shc_tail, pos);
-    GNUNET_PEERSTORE_hello_add_cancel (pos);
+    GNUNET_CONTAINER_DLL_remove (she_head, she_tail, pos);
+    GNUNET_PEERSTORE_hello_add_cancel (pos->sc);
+    GNUNET_free (pos);
   }
   if (NULL != sget)
   {
diff --git a/src/service/peerstore/peerstore_api.c 
b/src/service/peerstore/peerstore_api.c
index 6272ebdff..bf8b990e5 100644
--- a/src/service/peerstore/peerstore_api.c
+++ b/src/service/peerstore/peerstore_api.c
@@ -23,6 +23,7 @@
  * @author Omar Tarabai
  * @author Christian Grothoff
  */
+#include "gnunet_time_lib.h"
 #include "platform.h"
 #include "gnunet_common.h"
 #include "gnunet_protocols.h"
@@ -95,6 +96,47 @@ struct GNUNET_PEERSTORE_Handle
 
 };
 
+/**
+* Context for a add hello uri request.
+*/
+struct GNUNET_PEERSTORE_StoreHelloContext
+{
+  /**
+   * Peerstore handle.
+   */
+  struct GNUNET_PEERSTORE_Handle *h;
+
+  /**
+   * Function to call with information.
+   */
+  GNUNET_PEERSTORE_Continuation cont;
+
+  /**
+   * Closure for @e callback.
+   */
+  void *cont_cls;
+
+  /**
+   * Hello uri which was request for storing.
+   */
+  struct GNUNET_MessageHeader *hello;
+
+  /**
+   * The peer id for the hello.
+   */
+  struct GNUNET_PeerIdentity pid;
+
+  /**
+   * Store operation for the merge
+   */
+  struct GNUNET_PEERSTORE_StoreContext *sc;
+
+  /**
+   * The iteration for the merge
+   */
+  struct GNUNET_PEERSTORE_IterateContext *ic;
+};
+
 /**
  * Context for a store request
  */
@@ -635,7 +677,7 @@ handle_iterate_result (void *cls, const struct 
PeerstoreRecordMessage *msg)
  */
 void
 GNUNET_PEERSTORE_iteration_next (struct GNUNET_PEERSTORE_IterateContext *ic,
-                               uint64_t limit)
+                                 uint64_t limit)
 {
   struct GNUNET_MQ_Envelope *ev;
   struct PeerstoreIterationNextMessage *inm;
@@ -686,11 +728,11 @@ GNUNET_PEERSTORE_iteration_stop (struct 
GNUNET_PEERSTORE_IterateContext *ic)
 
 struct GNUNET_PEERSTORE_IterateContext *
 GNUNET_PEERSTORE_iteration_start (struct GNUNET_PEERSTORE_Handle *h,
-                                const char *sub_system,
-                                const struct GNUNET_PeerIdentity *peer,
-                                const char *key,
-                                GNUNET_PEERSTORE_Processor callback,
-                                void *callback_cls)
+                                  const char *sub_system,
+                                  const struct GNUNET_PeerIdentity *peer,
+                                  const char *key,
+                                  GNUNET_PEERSTORE_Processor callback,
+                                  void *callback_cls)
 {
   struct GNUNET_MQ_Envelope *ev;
   struct PeerstoreIterationStartMessage *srm;
@@ -806,17 +848,50 @@ hello_store_success (void *cls, int success)
          "Storing hello uri failed\n");
     huc->cont (huc->cont_cls, success);
     GNUNET_free (huc->hello);
-    GNUNET_free (huc->pid);
     GNUNET_free (huc);
     return;
   }
   huc->cont (huc->cont_cls, GNUNET_OK);
   GNUNET_free (huc->hello);
-  GNUNET_free (huc->pid);
   GNUNET_free (huc);
 }
 
 
+static void
+hello_add_iter (void *cls, const struct GNUNET_PEERSTORE_Record *record,
+                const char *emsg)
+{
+  struct GNUNET_PEERSTORE_StoreHelloContext *huc = cls;
+  struct GNUNET_TIME_Absolute hello_exp =
+    GNUNET_HELLO_builder_get_expiration_time (huc->hello);
+  if (NULL == record)
+  {
+    /** If we ever get here, we are newer than the existing record
+     *  or the only/first record.
+     */
+    huc->sc = GNUNET_PEERSTORE_store (huc->h,
+                                      "peerstore",
+                                      &huc->pid,
+                                      GNUNET_PEERSTORE_HELLO_KEY,
+                                      huc->hello,
+                                      ntohs (huc->hello->size),
+                                      hello_exp,
+                                      
GNUNET_PEERSTORE_STOREOPTION_UPSERT_LATER_EXPIRY,
+                                      &hello_store_success,
+                                      huc);
+    return;
+  }
+  if (GNUNET_TIME_absolute_cmp (record->expiry, >, hello_exp))
+  {
+    huc->cont (huc->cont_cls, GNUNET_OK);
+    GNUNET_PEERSTORE_iteration_stop (huc->ic);
+    GNUNET_free (huc->hello);
+    GNUNET_free (huc);
+    return;
+  }
+}
+
+
 struct GNUNET_PEERSTORE_StoreHelloContext *
 GNUNET_PEERSTORE_hello_add (struct GNUNET_PEERSTORE_Handle *h,
                             const struct GNUNET_MessageHeader *msg,
@@ -830,7 +905,6 @@ GNUNET_PEERSTORE_hello_add (struct GNUNET_PEERSTORE_Handle 
*h,
   struct GNUNET_TIME_Absolute hello_exp =
     GNUNET_HELLO_builder_get_expiration_time (msg);
   struct GNUNET_TIME_Absolute huc_exp;
-  uint16_t pid_size;
   uint16_t size_msg = ntohs (msg->size);
 
   if (NULL == builder)
@@ -847,24 +921,17 @@ GNUNET_PEERSTORE_hello_add (struct 
GNUNET_PEERSTORE_Handle *h,
   huc_exp =
     GNUNET_HELLO_builder_get_expiration_time (huc->hello);
   pid = GNUNET_HELLO_builder_get_id (builder);
-  pid_size = sizeof (struct GNUNET_PeerIdentity);
-  huc->pid = GNUNET_malloc (pid_size);
-  GNUNET_memcpy (huc->pid, pid, pid_size);
+  huc->pid = *pid;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Adding hello for peer %s with expiration %s msg size %u\n",
-       GNUNET_i2s (huc->pid),
+       GNUNET_i2s (&huc->pid),
        GNUNET_STRINGS_absolute_time_to_string (huc_exp),
        size_msg);
-  huc->sc = GNUNET_PEERSTORE_store (h,
-                                    "peerstore",
-                                    huc->pid,
-                                    GNUNET_PEERSTORE_HELLO_KEY,
-                                    huc->hello,
-                                    ntohs (huc->hello->size),
-                                    hello_exp,
-                                    
GNUNET_PEERSTORE_STOREOPTION_UPSERT_LATER_EXPIRY,
-                                    &hello_store_success,
-                                    huc);
+
+  huc->ic = GNUNET_PEERSTORE_iteration_start (h, "peerstore", &huc->pid,
+                                              GNUNET_PEERSTORE_HELLO_KEY,
+                                              &hello_add_iter,
+                                              huc);
   GNUNET_HELLO_builder_free (builder);
   return huc;
 }
@@ -874,9 +941,11 @@ void
 GNUNET_PEERSTORE_hello_add_cancel (struct
                                    GNUNET_PEERSTORE_StoreHelloContext *huc)
 {
-  GNUNET_PEERSTORE_store_cancel (huc->sc);
+  if (NULL != huc->sc)
+    GNUNET_PEERSTORE_store_cancel (huc->sc);
+  if (NULL != huc->ic)
+    GNUNET_PEERSTORE_iteration_stop (huc->ic);
   GNUNET_free (huc->hello);
-  GNUNET_free (huc->pid);
   GNUNET_free (huc);
 }
 
diff --git a/src/service/topology/gnunet-daemon-topology.c 
b/src/service/topology/gnunet-daemon-topology.c
index 588000358..c59610014 100644
--- a/src/service/topology/gnunet-daemon-topology.c
+++ b/src/service/topology/gnunet-daemon-topology.c
@@ -107,6 +107,26 @@ struct Peer
 
 };
 
+/**
+* Context for a add hello uri request.
+*/
+struct StoreHelloEntry
+{
+  /**
+   * Kept (also) in a DLL.
+   */
+  struct StoreHelloEntry *prev;
+
+  /**
+   * Kept (also) in a DLL.
+   */
+  struct StoreHelloEntry *next;
+
+  /**
+   * Store hello ctx
+   */
+  struct GNUNET_PEERSTORE_StoreHelloContext *sc;
+};
 
 /**
  * The task to delayed start the notification process intially.
@@ -182,12 +202,12 @@ static unsigned int target_connection_count;
 /**
  * Head of the linkd list to store the store context for hellos.
  */
-static struct GNUNET_PEERSTORE_StoreHelloContext *shc_head;
+static struct StoreHelloEntry *she_head;
 
 /**
  * Tail of the linkd list to store the store context for hellos.
  */
-static struct GNUNET_PEERSTORE_StoreHelloContext *shc_tail;
+static struct StoreHelloEntry *she_tail;
 
 /**
  * Free all resources associated with the given peer.
@@ -730,10 +750,12 @@ static void
 error_cb (void *cls)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              _ ("Error in communication with PEERSTORE service to 
monitor.\n"));
+              _ (
+                "Error in communication with PEERSTORE service to 
monitor.\n"));
   return;
 }
 
+
 static void
 sync_cb (void *cls)
 {
@@ -742,6 +764,7 @@ sync_cb (void *cls)
   return;
 }
 
+
 /**
  * PEERSTORE calls this function to let us know about a possible peer
  * that we might want to connect to.
@@ -886,16 +909,17 @@ check_hello (void *cls, const struct GNUNET_MessageHeader 
*message)
 static void
 shc_cont (void *cls, int success)
 {
-  struct GNUNET_PEERSTORE_StoreHelloContextClosure *shc_cls =  cls;
+  struct StoreHelloEntry *she =  cls;
 
+  she->sc = NULL;
   if (GNUNET_YES == success)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Hello stored successfully!\n");
   else
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Error storing hello!\n");
-  GNUNET_CONTAINER_DLL_remove (shc_head, shc_tail, shc_cls->shc);
-  GNUNET_free (shc_cls);
+  GNUNET_CONTAINER_DLL_remove (she_head, she_tail, she);
+  GNUNET_free (she);
 }
 
 
@@ -909,8 +933,7 @@ shc_cont (void *cls, int success)
 static void
 handle_hello (void *cls, const struct GNUNET_MessageHeader *message)
 {
-  struct GNUNET_PEERSTORE_StoreHelloContext *shc;
-  struct GNUNET_PEERSTORE_StoreHelloContextClosure *shc_cls;
+  struct StoreHelloEntry *she;
   const struct GNUNET_PeerIdentity *other = cls;
   struct GNUNET_HELLO_Builder *builder = GNUNET_HELLO_builder_from_msg (
     message);
@@ -923,15 +946,14 @@ handle_hello (void *cls, const struct 
GNUNET_MessageHeader *message)
                             1,
                             GNUNET_NO);
   GNUNET_HELLO_builder_from_msg (message);
-  shc_cls = GNUNET_new (struct GNUNET_PEERSTORE_StoreHelloContextClosure);
-  shc = GNUNET_PEERSTORE_hello_add (ps, message, &shc_cont, shc_cls);
-  if (NULL != shc)
+  she = GNUNET_new (struct StoreHelloEntry);
+  she->sc = GNUNET_PEERSTORE_hello_add (ps, message, &shc_cont, she);
+  if (NULL != she->sc)
   {
-    shc_cls->shc = shc;
-    GNUNET_CONTAINER_DLL_insert (shc_head, shc_tail, shc);
+    GNUNET_CONTAINER_DLL_insert (she_head, she_tail, she);
   }
   else
-    GNUNET_free (shc_cls);
+    GNUNET_free (she);
   GNUNET_HELLO_builder_free (builder);
 }
 
@@ -945,13 +967,15 @@ handle_hello (void *cls, const struct 
GNUNET_MessageHeader *message)
 static void
 cleaning_task (void *cls)
 {
-  struct GNUNET_PEERSTORE_StoreHelloContext *pos;
+  struct StoreHelloEntry *pos;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Topology shutdown\n");
-  while (NULL != (pos = shc_head))
+  while (NULL != (pos = she_head))
   {
-    GNUNET_CONTAINER_DLL_remove (shc_head, shc_tail, pos);
-    GNUNET_PEERSTORE_hello_add_cancel (pos);
+    GNUNET_CONTAINER_DLL_remove (she_head, she_tail, pos);
+    if (NULL != pos->sc)
+      GNUNET_PEERSTORE_hello_add_cancel (pos->sc);
+    GNUNET_free (pos);
   }
   if (NULL != peerstore_notify)
   {

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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