summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-01-04 22:11:55 +0100
committerChristian Grothoff <christian@grothoff.org>2017-01-04 22:11:55 +0100
commit5672e0e27b671fa878143e5eed8a9b677588b178 (patch)
tree91a9a5bbeac95a3a65b08484d3295ee3cd03e8b8
parent60c6dfd1fe22a01a3f7723e7e2bb18d52895c527 (diff)
move functionality of publishing namestore zone in DHT from GNS service to new zonemaster service
-rw-r--r--configure.ac2
-rw-r--r--doc/man/gnunet-nat.110
-rw-r--r--doc/structure.dot5
-rw-r--r--po/POTFILES.in2
-rw-r--r--src/gns/gns.conf.in4
-rw-r--r--src/gns/gnunet-service-gns.c647
-rw-r--r--src/gns/gnunet-service-gns_reverser.c5
-rw-r--r--src/vpn/vpn.conf.in2
-rw-r--r--src/zonemaster/Makefile.am35
-rw-r--r--src/zonemaster/gnunet-service-zonemaster.c773
-rw-r--r--src/zonemaster/zonemaster.conf.in25
11 files changed, 857 insertions, 653 deletions
diff --git a/configure.ac b/configure.ac
index faf058849..c41bcc4b5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1641,6 +1641,8 @@ src/util/Makefile
src/util/resolver.conf
src/vpn/Makefile
src/vpn/vpn.conf
+src/zonemaster/Makefile
+src/zonemaster/zonemaster.conf
src/rest/Makefile
src/identity-provider/Makefile
pkgconfig/Makefile
diff --git a/doc/man/gnunet-nat.1 b/doc/man/gnunet-nat.1
index 5bdbb21eb..a834a1d96 100644
--- a/doc/man/gnunet-nat.1
+++ b/doc/man/gnunet-nat.1
@@ -81,13 +81,15 @@ We are bound to "127.0.0.1:8080" on UDP and want to obtain all applicable IP add
\fBICMP-based NAT traversal:\fR
-Watch for connection reversal request:
+Watch for connection reversal request (you must be bound to NAT range or to wildcard, 0.0.0.0), only works for IPv4:
- # gnunet-nat FIXME
+ # gnunet-nat -Wt -i 192.168.178.12:8080
-Initiate connection reversal request:
+Initiate connection reversal request from peer at external IPv4 address 1.2.3.4 while we are running ourselves at 2.3.4.5:8080 (must use IPv4 addresses):
- # gnunet-nat FIXME
+ # gnunet-nat -t -r 1.2.3.4:8080 -i 2.3.4.5:8080
+
+ # gnunet-nat -t -r 1.2.3.4:8080 -i 0.0.0.0:8080 ### TEST THIS!
\fBManual hole punching:\fR
diff --git a/doc/structure.dot b/doc/structure.dot
index 2a30c7c17..e244d20b8 100644
--- a/doc/structure.dot
+++ b/doc/structure.dot
@@ -41,8 +41,9 @@ splines = true;
dv -> ats;
dns -> tun;
dns -> dnsstub;
- gns [shape=house];
- gns -> namestore;
+ zonemaster [shape=house];
+ zonemaster -> namestore;
+ zonemaster -> dht;
gns -> dns;
gns -> dht;
gns -> block [style=dotted,color=blue];
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 80aab7123..56af200ff 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -245,6 +245,7 @@ src/nat/gnunet-nat.c
src/nat/gnunet-nat-server.c
src/nat/gnunet-service-nat.c
src/nat/gnunet-service-nat_helper.c
+src/nat/gnunet-service-nat_mini.c
src/nat/gnunet-service-nat_stun.c
src/nat/nat_api.c
src/nat/nat_api_stun.c
@@ -489,6 +490,7 @@ src/vpn/gnunet-helper-vpn-windows.c
src/vpn/gnunet-service-vpn.c
src/vpn/gnunet-vpn.c
src/vpn/vpn_api.c
+src/zonemaster/gnunet-service-zonemaster.c
src/fs/fs_api.h
src/include/gnunet_common.h
src/include/gnunet_mq_lib.h
diff --git a/src/gns/gns.conf.in b/src/gns/gns.conf.in
index bf59cac15..b34246cef 100644
--- a/src/gns/gns.conf.in
+++ b/src/gns/gns.conf.in
@@ -5,7 +5,6 @@ HOSTNAME = localhost
BINARY = gnunet-service-gns
UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-gns.sock
@JAVAPORT@PORT = 2102
-USER_SERVICE = YES
# Do we require users that want to access GNS to run this process
# (usually not a good idea)
@@ -17,9 +16,6 @@ UNIX_MATCH_GID = YES
# How many queries is GNS allowed to perform in the background at the same time?
MAX_PARALLEL_BACKGROUND_QUERIES = 1000
-# How frequently do we try to publish our full zone?
-ZONE_PUBLISH_TIME_WINDOW = 4 h
-
# Using caching or always ask DHT
# USE_CACHE = YES
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
index 3e718dac8..7c1dfaba2 100644
--- a/src/gns/gnunet-service-gns.c
+++ b/src/gns/gnunet-service-gns.c
@@ -40,43 +40,6 @@
#include "gnunet-service-gns_interceptor.h"
#include "gnunet_protocols.h"
-/**
- * The initial interval in milliseconds btween puts in
- * a zone iteration
- */
-#define INITIAL_PUT_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
-
-/**
- * The lower bound for the zone iteration interval
- */
-#define MINIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_SECONDS
-
-/**
- * The upper bound for the zone iteration interval
- */
-#define MAXIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
-
-/**
- * The default put interval for the zone iteration. In case
- * no option is found
- */
-#define DEFAULT_ZONE_PUBLISH_TIME_WINDOW GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
-
-/**
- * The factor the current zone iteration interval is divided by for each
- * additional new record
- */
-#define LATE_ITERATION_SPEEDUP_FACTOR 2
-
-/**
- * How long until a DHT PUT attempt should time out?
- */
-#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
-
-/**
- * What replication level do we use for DHT PUT operations?
- */
-#define DHT_GNS_REPLICATION_LEVEL 5
/**
* GnsClient prototype
@@ -146,36 +109,14 @@ struct GnsClient
/**
- * Handle for DHT PUT activity triggered from the namestore monitor.
- */
-struct MonitorActivity
-{
- /**
- * Kept in a DLL.
- */
- struct MonitorActivity *next;
-
- /**
- * Kept in a DLL.
- */
- struct MonitorActivity *prev;
-
- /**
- * Handle for the DHT PUT operation.
- */
- struct GNUNET_DHT_PutHandle *ph;
-};
-
-
-/**
* Our handle to the DHT
*/
static struct GNUNET_DHT_Handle *dht_handle;
/**
- * Active DHT put operation (or NULL)
+ * Our handle to the namecache service
*/
-static struct GNUNET_DHT_PutHandle *active_put;
+static struct GNUNET_NAMECACHE_Handle *namecache_handle;
/**
* Our handle to the namestore service
@@ -183,11 +124,6 @@ static struct GNUNET_DHT_PutHandle *active_put;
static struct GNUNET_NAMESTORE_Handle *namestore_handle;
/**
- * Our handle to the namecache service
- */
-static struct GNUNET_NAMECACHE_Handle *namecache_handle;
-
-/**
* Our handle to the identity service
*/
static struct GNUNET_IDENTITY_Handle *identity_handle;
@@ -199,68 +135,6 @@ static struct GNUNET_IDENTITY_Handle *identity_handle;
static struct GNUNET_IDENTITY_Operation *identity_op;
/**
- * Handle to iterate over our authoritative zone in namestore
- */
-static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
-
-/**
- * Handle to monitor namestore changes to instant propagation.
- */
-static struct GNUNET_NAMESTORE_ZoneMonitor *zmon;
-
-/**
- * Head of monitor activities; kept in a DLL.
- */
-static struct MonitorActivity *ma_head;
-
-/**
- * Tail of monitor activities; kept in a DLL.
- */
-static struct MonitorActivity *ma_tail;
-
-/**
- * Useful for zone update for DHT put
- */
-static unsigned long long num_public_records;
-
-/**
- * Last seen record count
- */
-static unsigned long long last_num_public_records;
-
-/**
- * Minimum relative expiration time of records seem during the current
- * zone iteration.
- */
-static struct GNUNET_TIME_Relative min_relative_record_time;
-
-/**
- * Zone iteration PUT interval.
- */
-static struct GNUNET_TIME_Relative put_interval;
-
-/**
- * Default time window for zone iteration
- */
-static struct GNUNET_TIME_Relative zone_publish_time_window_default;
-
-/**
- * Time window for zone iteration, adjusted based on relative record
- * expiration times in our zone.
- */
-static struct GNUNET_TIME_Relative zone_publish_time_window;
-
-/**
- * zone publish task
- */
-static struct GNUNET_SCHEDULER_Task *zone_publish_task;
-
-/**
- * #GNUNET_YES if zone has never been published before
- */
-static int first_zone_iteration;
-
-/**
* #GNUNET_YES if ipv6 is supported
*/
static int v6_enabled;
@@ -285,8 +159,6 @@ static struct GNUNET_STATISTICS_Handle *statistics;
static void
shutdown_task (void *cls)
{
- struct MonitorActivity *ma;
-
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Shutting down!\n");
GNS_interceptor_done ();
@@ -303,35 +175,12 @@ shutdown_task (void *cls)
GNS_resolver_done ();
GNS_reverse_done ();
GNS_shorten_done ();
- while (NULL != (ma = ma_head))
- {
- GNUNET_DHT_put_cancel (ma->ph);
- GNUNET_CONTAINER_DLL_remove (ma_head,
- ma_tail,
- ma);
- GNUNET_free (ma);
- }
if (NULL != statistics)
{
GNUNET_STATISTICS_destroy (statistics,
GNUNET_NO);
statistics = NULL;
}
- if (NULL != zone_publish_task)
- {
- GNUNET_SCHEDULER_cancel (zone_publish_task);
- zone_publish_task = NULL;
- }
- if (NULL != namestore_iter)
- {
- GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
- namestore_iter = NULL;
- }
- if (NULL != zmon)
- {
- GNUNET_NAMESTORE_zone_monitor_stop (zmon);
- zmon = NULL;
- }
if (NULL != namestore_handle)
{
GNUNET_NAMESTORE_disconnect (namestore_handle);
@@ -342,11 +191,6 @@ shutdown_task (void *cls)
GNUNET_NAMECACHE_disconnect (namecache_handle);
namecache_handle = NULL;
}
- if (NULL != active_put)
- {
- GNUNET_DHT_put_cancel (active_put);
- active_put = NULL;
- }
if (NULL != dht_handle)
{
GNUNET_DHT_disconnect (dht_handle);
@@ -354,6 +198,7 @@ shutdown_task (void *cls)
}
}
+
/**
* Called whenever a client is disconnected.
*
@@ -413,408 +258,6 @@ client_connect_cb (void *cls,
/**
- * Method called periodically that triggers iteration over authoritative records
- *
- * @param cls closure
- */
-static void
-publish_zone_dht_next (void *cls)
-{
- zone_publish_task = NULL;
- GNUNET_assert (NULL != namestore_iter);
- GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
-}
-
-
-/**
- * Periodically iterate over our zone and store everything in dht
- *
- * @param cls NULL
- */
-static void
-publish_zone_dht_start (void *cls);
-
-
-/**
- * Continuation called from DHT once the PUT operation is done.
- *
- * @param cls closure, NULL if called from regular iteration,
- * `struct MonitorActivity` if called from #handle_monitor_event.
- * @param success #GNUNET_OK on success
- */
-static void
-dht_put_continuation (void *cls,
- int success)
-{
- struct MonitorActivity *ma = cls;
- struct GNUNET_TIME_Relative next_put_interval;
-
- num_public_records++;
- if (NULL == ma)
- {
- active_put = NULL;
- if ( (num_public_records > last_num_public_records) &&
- (GNUNET_NO == first_zone_iteration) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Last record count was lower than current record count. Reducing interval.\n");
- put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
- num_public_records);
- next_put_interval = GNUNET_TIME_relative_divide (put_interval,
- LATE_ITERATION_SPEEDUP_FACTOR);
- }
- else
- next_put_interval = put_interval;
- next_put_interval = GNUNET_TIME_relative_min (next_put_interval,
- MAXIMUM_ZONE_ITERATION_INTERVAL);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "PUT complete, next PUT in %s!\n",
- GNUNET_STRINGS_relative_time_to_string (next_put_interval,
- GNUNET_YES));
-
- GNUNET_STATISTICS_set (statistics,
- "Current zone iteration interval (ms)",
- next_put_interval.rel_value_us / 1000LL,
- GNUNET_NO);
- GNUNET_assert (NULL == zone_publish_task);
- zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval,
- &publish_zone_dht_next,
- NULL);
- }
- else
- {
- GNUNET_CONTAINER_DLL_remove (ma_head,
- ma_tail,
- ma);
- GNUNET_free (ma);
- }
-}
-
-
-/**
- * Convert namestore records from the internal format to that
- * suitable for publication (removes private records, converts
- * to absolute expiration time).
- *
- * @param rd input records
- * @param rd_count size of the @a rd and @a rd_public arrays
- * @param rd_public where to write the converted records
- * @return number of records written to @a rd_public
- */
-static unsigned int
-convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
- unsigned int rd_count,
- struct GNUNET_GNSRECORD_Data *rd_public)
-{
- struct GNUNET_TIME_Absolute now;
- unsigned int rd_public_count;
- unsigned int i;
-
- rd_public_count = 0;
- now = GNUNET_TIME_absolute_get ();
- for (i=0;i<rd_count;i++)
- if (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))
- {
- rd_public[rd_public_count] = rd[i];
- if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
- {
- /* GNUNET_GNSRECORD_block_create will convert to absolute time;
- we just need to adjust our iteration frequency */
- min_relative_record_time.rel_value_us =
- GNUNET_MIN (rd_public[rd_public_count].expiration_time,
- min_relative_record_time.rel_value_us);
- }
- else if (rd_public[rd_public_count].expiration_time < now.abs_value_us)
- {
- /* record already expired, skip it */
- continue;
- }
- rd_public_count++;
- }
- return rd_public_count;
-}
-
-
-/**
- * Store GNS records in the DHT.
- *
- * @param key key of the zone
- * @param label label to store under
- * @param rd_public public record data
- * @param rd_public_count number of records in @a rd_public
- * @param pc_arg closure argument to pass to the #dht_put_continuation
- * @return DHT PUT handle, NULL on error
- */
-static struct GNUNET_DHT_PutHandle *
-perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
- const char *label,
- const struct GNUNET_GNSRECORD_Data *rd_public,
- unsigned int rd_public_count,
- void *pc_arg)
-{
- struct GNUNET_GNSRECORD_Block *block;
- struct GNUNET_HashCode query;
- struct GNUNET_TIME_Absolute expire;
- size_t block_size;
- struct GNUNET_DHT_PutHandle *ret;
-
- expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
- rd_public);
- block = GNUNET_GNSRECORD_block_create (key,
- expire,
- label,
- rd_public,
- rd_public_count);
- if (NULL == block)
- return NULL; /* whoops */
- block_size = ntohl (block->purpose.size)
- + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
- + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
- GNUNET_GNSRECORD_query_from_private_key (key,
- label,
- &query);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Storing %u record(s) for label `%s' in DHT with expiration `%s' under key %s\n",
- rd_public_count,
- label,
- GNUNET_STRINGS_absolute_time_to_string (expire),
- GNUNET_h2s (&query));
- ret = GNUNET_DHT_put (dht_handle,
- &query,
- DHT_GNS_REPLICATION_LEVEL,
- GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
- GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
- block_size,
- block,
- expire,
- &dht_put_continuation,
- pc_arg);
- GNUNET_free (block);
- return ret;
-}
-
-
-/**
- * We encountered an error in our zone iteration.
- */
-static void
-zone_iteration_error (void *cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got disconnected from namestore database, retrying.\n");
- namestore_iter = NULL;
- /* We end up here on error/disconnect/shutdown, so potentially
- while a zone publish task or a DHT put is still running; hence
- we need to cancel those. */
- if (NULL != zone_publish_task)
- {
- GNUNET_SCHEDULER_cancel (zone_publish_task);
- zone_publish_task = NULL;
- }
- if (NULL != active_put)
- {
- GNUNET_DHT_put_cancel (active_put);
- active_put = NULL;
- }
- zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
- NULL);
-}
-
-
-/**
- * Zone iteration is completed.
- */
-static void
-zone_iteration_finished (void *cls)
-{
- /* we're done with one iteration, calculate when to do the next one */
- namestore_iter = NULL;
- last_num_public_records = num_public_records;
- first_zone_iteration = GNUNET_NO;
- if (0 == num_public_records)
- {
- /**
- * If no records are known (startup) or none present
- * we can safely set the interval to the value for a single
- * record
- */
- put_interval = zone_publish_time_window;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "No records in namestore database.\n");
- }
- else
- {
- /* If records are present, next publication is based on the minimum
- * relative expiration time of the records published divided by 4
- */
- zone_publish_time_window
- = GNUNET_TIME_relative_min (GNUNET_TIME_relative_divide (min_relative_record_time, 4),
- zone_publish_time_window_default);
- put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
- num_public_records);
- }
- /* reset for next iteration */
- min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
- put_interval = GNUNET_TIME_relative_max (MINIMUM_ZONE_ITERATION_INTERVAL,
- put_interval);
- put_interval = GNUNET_TIME_relative_min (put_interval,
- MAXIMUM_ZONE_ITERATION_INTERVAL);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Zone iteration finished. Adjusted zone iteration interval to %s\n",
- GNUNET_STRINGS_relative_time_to_string (put_interval,
- GNUNET_YES));
- GNUNET_STATISTICS_set (statistics,
- "Current zone iteration interval (in ms)",
- put_interval.rel_value_us / 1000LL,
- GNUNET_NO);
- GNUNET_STATISTICS_update (statistics,
- "Number of zone iterations",
- 1,
- GNUNET_NO);
- GNUNET_STATISTICS_set (statistics,
- "Number of public records in DHT",
- last_num_public_records,
- GNUNET_NO);
- GNUNET_assert (NULL == zone_publish_task);
- if (0 == num_public_records)
- zone_publish_task = GNUNET_SCHEDULER_add_delayed (put_interval,
- &publish_zone_dht_start,
- NULL);
- else
- zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
- NULL);
-}
-
-
-/**
- * Function used to put all records successively into the DHT.
- *
- * @param cls the closure (NULL)
- * @param key the private key of the authority (ours)
- * @param label the name of the records, NULL once the iteration is done
- * @param rd_count the number of records in @a rd
- * @param rd the record data
- */
-static void
-put_gns_record (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
- const char *label,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct GNUNET_GNSRECORD_Data rd_public[rd_count];
- unsigned int rd_public_count;
-
- rd_public_count = convert_records_for_export (rd,
- rd_count,
- rd_public);
-
- if (0 == rd_public_count)
- {
- GNUNET_assert (NULL == zone_publish_task);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Record set empty, moving to next record set\n");
- zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
- NULL);
- return;
- }
- /* We got a set of records to publish */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Starting DHT PUT\n");
- active_put = perform_dht_put (key,
- label,
- rd_public,
- rd_public_count,
- NULL);
- if (NULL == active_put)
- {
- GNUNET_break (0);
- dht_put_continuation (NULL, GNUNET_NO);
- }
-}
-
-
-/**
- * Periodically iterate over all zones and store everything in DHT
- *
- * @param cls NULL
- */
-static void
-publish_zone_dht_start (void *cls)
-{
- zone_publish_task = NULL;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Starting DHT zone update!\n");
- /* start counting again */
- num_public_records = 0;
- GNUNET_assert (NULL == namestore_iter);
- namestore_iter
- = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
- NULL, /* All zones */
- &zone_iteration_error,
- NULL,
- &put_gns_record,
- NULL,
- &zone_iteration_finished,
- NULL);
-}
-
-
-/**
- * Process a record that was stored in the namestore
- * (invoked by the monitor).
- *
- * @param cls closure, NULL
- * @param zone private key of the zone; NULL on disconnect
- * @param label label of the records; NULL on disconnect
- * @param rd_count number of entries in @a rd array, 0 if label was deleted
- * @param rd array of records with data to store
- */
-static void
-handle_monitor_event (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const char *label,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct GNUNET_GNSRECORD_Data rd_public[rd_count];
- unsigned int rd_public_count;
- struct MonitorActivity *ma;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received %u records for label `%s' via namestore monitor\n",
- rd_count,
- label);
- /* filter out records that are not public, and convert to
- absolute expiration time. */
- rd_public_count = convert_records_for_export (rd,
- rd_count,
- rd_public);
- if (0 == rd_public_count)
- return; /* nothing to do */
- ma = GNUNET_new (struct MonitorActivity);
- ma->ph = perform_dht_put (zone,
- label,
- rd,
- rd_count,
- ma);
- if (NULL == ma->ph)
- {
- /* PUT failed, do not remember operation */
- GNUNET_free (ma);
- return;
- }
- GNUNET_CONTAINER_DLL_insert (ma_head,
- ma_tail,
- ma);
-}
-
-
-/* END DHT ZONE PROPAGATION */
-
-
-/**
* Reply to client with the result from our lookup.
*
* @param cls the closure (our client lookup handle)
@@ -1020,49 +463,6 @@ handle_rev_lookup (void *cls,
/**
- * The zone monitor is now in SYNC with the current state of the
- * name store. Start to perform periodic iterations.
- *
- * @param cls NULL
- */
-static void
-monitor_sync_event (void *cls)
-{
- GNUNET_assert (NULL == zone_publish_task);
- zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
- NULL);
-}
-
-
-/**
- * The zone monitor is now in SYNC with the current state of the
- * name store. Start to perform periodic iterations.
- *
- * @param cls NULL
- */
-static void
-handle_monitor_error (void *cls)
-{
- if (NULL != zone_publish_task)
- {
- GNUNET_SCHEDULER_cancel (zone_publish_task);
- zone_publish_task = NULL;
- }
- if (NULL != namestore_iter)
- {
- GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
- namestore_iter = NULL;
- }
- if (NULL != active_put)
- {
- GNUNET_DHT_put_cancel (active_put);
- active_put = NULL;
- }
- zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
- NULL);
-}
-
-/**
* Method called to inform about the ego to be used for the master zone
* for DNS interceptions.
*
@@ -1107,7 +507,6 @@ identity_reverse_cb (void *cls,
}
-
/**
* Method called to inform about the ego to be used for the master zone
* for DNS interceptions.
@@ -1178,8 +577,7 @@ run (void *cls,
unsigned long long max_parallel_bg_queries = 0;
v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
- v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
- min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
+ v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
namestore_handle = GNUNET_NAMESTORE_connect (c);
if (NULL == namestore_handle)
{
@@ -1188,7 +586,7 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- namecache_handle = GNUNET_NAMECACHE_connect (c);
+ namecache_handle = GNUNET_NAMECACHE_connect (c);
if (NULL == namecache_handle)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1197,29 +595,6 @@ run (void *cls,
return;
}
- put_interval = INITIAL_PUT_INTERVAL;
- zone_publish_time_window_default = DEFAULT_ZONE_PUBLISH_TIME_WINDOW;
- if (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_time (c, "gns",
- "ZONE_PUBLISH_TIME_WINDOW",
- &zone_publish_time_window_default))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Time window for zone iteration: %s\n",
- GNUNET_STRINGS_relative_time_to_string (zone_publish_time_window,
- GNUNET_YES));
- }
- zone_publish_time_window = zone_publish_time_window_default;
- if (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (c, "gns",
- "MAX_PARALLEL_BACKGROUND_QUERIES",
- &max_parallel_bg_queries))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Number of allowed parallel background queries: %llu\n",
- max_parallel_bg_queries);
- }
-
dht_handle = GNUNET_DHT_connect (c,
(unsigned int) max_parallel_bg_queries);
if (NULL == dht_handle)
@@ -1254,19 +629,7 @@ run (void *cls,
GNS_shorten_init (namestore_handle,
namecache_handle,
dht_handle);
- /* Schedule periodic put for our records. */
- first_zone_iteration = GNUNET_YES;
statistics = GNUNET_STATISTICS_create ("gns", c);
- zmon = GNUNET_NAMESTORE_zone_monitor_start (c,
- NULL,
- GNUNET_NO,
- &handle_monitor_error,
- NULL,
- &handle_monitor_event,
- NULL,
- &monitor_sync_event,
- NULL);
- GNUNET_break (NULL != zmon);
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
}
diff --git a/src/gns/gnunet-service-gns_reverser.c b/src/gns/gnunet-service-gns_reverser.c
index 931dc6809..b5b8b31b7 100644
--- a/src/gns/gnunet-service-gns_reverser.c
+++ b/src/gns/gnunet-service-gns_reverser.c
@@ -394,6 +394,7 @@ handle_gns_result_iter (void *cls,
it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
}
+
static void
next_it (void *cls)
{
@@ -402,6 +403,7 @@ next_it (void *cls)
GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
}
+
static void
iterator_cb (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
@@ -487,6 +489,7 @@ store_reverse (void *cls,
GNUNET_free (ith);
}
+
static void
finished_cb (void *cls)
{
@@ -522,6 +525,7 @@ finished_cb (void *cls)
}
+
static void
it_error (void *cls)
{
@@ -529,6 +533,7 @@ it_error (void *cls)
"Error iterating for REVERSE\n");
}
+
static void
check_reverse_records (void *cls)
{
diff --git a/src/vpn/vpn.conf.in b/src/vpn/vpn.conf.in
index 000300084..585131554 100644
--- a/src/vpn/vpn.conf.in
+++ b/src/vpn/vpn.conf.in
@@ -6,7 +6,7 @@ BINARY = gnunet-service-vpn
ACCEPT_FROM = 127.0.0.1;
ACCEPT_FROM6 = ::1;
UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-vpn.sock
-UNIX_MATCH_UID = YES
+UNIX_MATCH_UID = NO
UNIX_MATCH_GID = YES
IPV6ADDR = 1234::1
diff --git a/src/zonemaster/Makefile.am b/src/zonemaster/Makefile.am
new file mode 100644
index 000000000..21f986498
--- /dev/null
+++ b/src/zonemaster/Makefile.am
@@ -0,0 +1,35 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+plugindir = $(libdir)/gnunet
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfg_DATA = \
+ zonemaster.conf
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIBS = -lgcov
+endif
+
+libexec_PROGRAMS = \
+ gnunet-service-zonemaster
+
+gnunet_service_zonemaster_SOURCES = \
+ gnunet-service-zonemaster.c
+
+gnunet_service_zonemaster_LDADD = \
+ $(top_builddir)/src/dht/libgnunetdht.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/namestore/libgnunetnamestore.la \
+ $(GN_LIBINTL)
+
diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c
new file mode 100644
index 000000000..d61eb723f
--- /dev/null
+++ b/src/zonemaster/gnunet-service-zonemaster.c
@@ -0,0 +1,773 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012, 2013, 2014, 2017 GNUnet e.V.
+
+ 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 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file zonemaster/gnunet-service-zonemaster.c
+ * @brief publish records from namestore to GNUnet name system
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dnsparser_lib.h"
+#include "gnunet_dht_service.h"
+#include "gnunet_namestore_service.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_namestore_plugin.h"
+#include "gnunet_signatures.h"
+
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+
+
+/**
+ * The initial interval in milliseconds btween puts in
+ * a zone iteration
+ */
+#define INITIAL_PUT_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
+
+/**
+ * The lower bound for the zone iteration interval
+ */
+#define MINIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_SECONDS
+
+/**
+ * The upper bound for the zone iteration interval
+ */
+#define MAXIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
+
+/**
+ * The default put interval for the zone iteration. In case
+ * no option is found
+ */
+#define DEFAULT_ZONE_PUBLISH_TIME_WINDOW GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
+
+/**
+ * The factor the current zone iteration interval is divided by for each
+ * additional new record
+ */
+#define LATE_ITERATION_SPEEDUP_FACTOR 2
+
+/**
+ * How long until a DHT PUT attempt should time out?
+ */
+#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+/**
+ * What replication level do we use for DHT PUT operations?
+ */
+#define DHT_GNS_REPLICATION_LEVEL 5
+
+
+/**
+ * Handle for DHT PUT activity triggered from the namestore monitor.
+ */
+struct MonitorActivity
+{
+ /**
+ * Kept in a DLL.
+ */
+ struct MonitorActivity *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct MonitorActivity *prev;
+
+ /**
+ * Handle for the DHT PUT operation.
+ */
+ struct GNUNET_DHT_PutHandle *ph;
+};
+
+
+/**
+ * Handle to the statistics service
+ */
+static struct GNUNET_STATISTICS_Handle *statistics;
+
+/**
+ * Our handle to the DHT
+ */
+static struct GNUNET_DHT_Handle *dht_handle;
+
+/**
+ * Active DHT put operation (or NULL)
+ */
+static struct GNUNET_DHT_PutHandle *active_put;
+
+/**
+ * Our handle to the namestore service
+ */
+static struct GNUNET_NAMESTORE_Handle *namestore_handle;
+
+/**
+ * Handle to iterate over our authoritative zone in namestore
+ */
+static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
+
+/**
+ * Handle to monitor namestore changes to instant propagation.
+ */
+static struct GNUNET_NAMESTORE_ZoneMonitor *zmon;
+
+/**
+ * Head of monitor activities; kept in a DLL.
+ */
+static struct MonitorActivity *ma_head;
+
+/**
+ * Tail of monitor activities; kept in a DLL.
+ */
+static struct MonitorActivity *ma_tail;
+
+/**
+ * Useful for zone update for DHT put
+ */
+static unsigned long long num_public_records;
+
+/**
+ * Last seen record count
+ */
+static unsigned long long last_num_public_records;
+
+/**
+ * Minimum relative expiration time of records seem during the current
+ * zone iteration.
+ */
+static struct GNUNET_TIME_Relative min_relative_record_time;
+
+/**
+ * Zone iteration PUT interval.
+ */
+static struct GNUNET_TIME_Relative put_interval;
+
+/**
+ * Default time window for zone iteration
+ */
+static struct GNUNET_TIME_Relative zone_publish_time_window_default;
+
+/**
+ * Time window for zone iteration, adjusted based on relative record
+ * expiration times in our zone.
+ */
+static struct GNUNET_TIME_Relative zone_publish_time_window;
+
+/**
+ * zone publish task
+ */
+static struct GNUNET_SCHEDULER_Task *zone_publish_task;
+
+/**
+ * #GNUNET_YES if zone has never been published before
+ */
+static int first_zone_iteration;
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls)
+{
+ struct MonitorActivity *ma;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Shutting down!\n");
+ while (NULL != (ma = ma_head))
+ {
+ GNUNET_DHT_put_cancel (ma->ph);
+ GNUNET_CONTAINER_DLL_remove (ma_head,
+ ma_tail,
+ ma);
+ GNUNET_free (ma);
+ }
+ if (NULL != statistics)
+ {
+ GNUNET_STATISTICS_destroy (statistics,
+ GNUNET_NO);
+ statistics = NULL;
+ }
+ if (NULL != zone_publish_task)
+ {
+ GNUNET_SCHEDULER_cancel (zone_publish_task);
+ zone_publish_task = NULL;
+ }
+ if (NULL != namestore_iter)
+ {
+ GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
+ namestore_iter = NULL;
+ }
+ if (NULL != zmon)
+ {
+ GNUNET_NAMESTORE_zone_monitor_stop (zmon);
+ zmon = NULL;
+ }
+ if (NULL != namestore_handle)
+ {
+ GNUNET_NAMESTORE_disconnect (namestore_handle);
+ namestore_handle = NULL;
+ }
+ if (NULL != active_put)
+ {
+ GNUNET_DHT_put_cancel (active_put);
+ active_put = NULL;
+ }
+ if (NULL != dht_handle)
+ {
+ GNUNET_DHT_disconnect (dht_handle);
+ dht_handle = NULL;
+ }
+}
+
+
+/**
+ * Method called periodically that triggers iteration over authoritative records
+ *
+ * @param cls closure
+ */
+static void
+publish_zone_dht_next (void *cls)
+{
+ zone_publish_task = NULL;
+ GNUNET_assert (NULL != namestore_iter);
+ GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
+}
+
+
+/**
+ * Periodically iterate over our zone and store everything in dht
+ *
+ * @param cls NULL
+ */
+static void
+publish_zone_dht_start (void *cls);
+
+
+/**
+ * Continuation called from DHT once the PUT operation is done.
+ *
+ * @param cls closure, NULL if called from regular iteration,
+ * `struct MonitorActivity` if called from #handle_monitor_event.
+ * @param success #GNUNET_OK on success
+ */
+static void
+dht_put_continuation (void *cls,
+ int success)
+{
+ struct MonitorActivity *ma = cls;
+ struct GNUNET_TIME_Relative next_put_interval;
+
+ num_public_records++;
+ if (NULL == ma)
+ {
+ active_put = NULL;
+ if ( (num_public_records > last_num_public_records) &&
+ (GNUNET_NO == first_zone_iteration) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Last record count was lower than current record count. Reducing interval.\n");
+ put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
+ num_public_records);
+ next_put_interval = GNUNET_TIME_relative_divide (put_interval,
+ LATE_ITERATION_SPEEDUP_FACTOR);
+ }
+ else
+ next_put_interval = put_interval;
+ next_put_interval = GNUNET_TIME_relative_min (next_put_interval,
+ MAXIMUM_ZONE_ITERATION_INTERVAL);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "PUT complete, next PUT in %s!\n",
+ GNUNET_STRINGS_relative_time_to_string (next_put_interval,
+ GNUNET_YES));
+
+ GNUNET_STATISTICS_set (statistics,
+ "Current zone iteration interval (ms)",
+ next_put_interval.rel_value_us / 1000LL,
+ GNUNET_NO);
+ GNUNET_assert (NULL == zone_publish_task);
+ zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval,
+ &publish_zone_dht_next,
+ NULL);
+ }
+ else
+ {
+ GNUNET_CONTAINER_DLL_remove (ma_head,
+ ma_tail,
+ ma);
+ GNUNET_free (ma);
+ }
+}
+
+
+/**
+ * Convert namestore records from the internal format to that
+ * suitable for publication (removes private records, converts
+ * to absolute expiration time).
+ *
+ * @param rd input records
+ * @param rd_count size of the @a rd and @a rd_public arrays
+ * @param rd_public where to write the converted records
+ * @return number of records written to @a rd_public
+ */
+static unsigned int
+convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
+ unsigned int rd_count,
+ struct GNUNET_GNSRECORD_Data *rd_public)
+{
+ struct GNUNET_TIME_Absolute now;
+ unsigned int rd_public_count;
+ unsigned int i;
+
+ rd_public_count = 0;
+ now = GNUNET_TIME_absolute_get ();
+ for (i=0;i<rd_count;i++)
+ if (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))
+ {
+ rd_public[rd_public_count] = rd[i];
+ if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
+ {
+ /* GNUNET_GNSRECORD_block_create will convert to absolute time;
+ we just need to adjust our iteration frequency */
+ min_relative_record_time.rel_value_us =
+ GNUNET_MIN (rd_public[rd_public_count].expiration_time,
+ min_relative_record_time.rel_value_us);
+ }
+ else if (rd_public[rd_public_count].expiration_time < now.abs_value_us)
+ {
+ /* record already expired, skip it */
+ continue;
+ }
+ rd_public_count++;
+ }
+ return rd_public_count;
+}
+
+
+/**
+ * Store GNS records in the DHT.
+ *
+ * @param key key of the zone
+ * @param label label to store under
+ * @param rd_public public record data
+ * @param rd_public_count number of records in @a rd_public
+ * @param pc_arg closure argument to pass to the #dht_put_continuation
+ * @return DHT PUT handle, NULL on error
+ */
+static struct GNUNET_DHT_PutHandle *
+perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+ const char *label,
+ const struct GNUNET_GNSRECORD_Data *rd_public,
+ unsigned int rd_public_count,
+ void *pc_arg)
+{
+ struct GNUNET_GNSRECORD_Block *block;
+ struct GNUNET_HashCode query;
+ struct GNUNET_TIME_Absolute expire;
+ size_t block_size;
+ struct GNUNET_DHT_PutHandle *ret;
+
+ expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
+ rd_public);
+ block = GNUNET_GNSRECORD_block_create (key,
+ expire,
+ label,
+ rd_public,
+ rd_public_count);
+ if (NULL == block)
+ return NULL; /* whoops */
+ block_size = ntohl (block->purpose.size)
+ + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
+ + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
+ GNUNET_GNSRECORD_query_from_private_key (key,
+ label,
+ &query);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Storing %u record(s) for label `%s' in DHT with expiration `%s' under key %s\n",
+ rd_public_count,
+ label,
+ GNUNET_STRINGS_absolute_time_to_string (expire),
+ GNUNET_h2s (&query));
+ ret = GNUNET_DHT_put (dht_handle,
+ &query,
+ DHT_GNS_REPLICATION_LEVEL,
+ GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
+ GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
+ block_size,
+ block,
+ expire,
+ &dht_put_continuation,
+ pc_arg);
+ GNUNET_free (block);
+ return ret;
+}
+
+
+/**
+ * We encountered an error in our zone iteration.
+ */
+static void
+zone_iteration_error (void *cls)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got disconnected from namestore database, retrying.\n");
+ namestore_iter = NULL;
+ /* We end up here on error/disconnect/shutdown, so potentially
+ while a zone publish task or a DHT put is still running; hence
+ we need to cancel those. */
+ if (NULL != zone_publish_task)
+ {
+ GNUNET_SCHEDULER_cancel (zone_publish_task);
+ zone_publish_task = NULL;
+ }
+ if (NULL != active_put)
+ {
+ GNUNET_DHT_put_cancel (active_put);
+ active_put = NULL;
+ }
+ zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
+ NULL);
+}
+
+
+/**
+ * Zone iteration is completed.
+ */
+static void
+zone_iteration_finished (void *cls)
+{
+ /* we're done with one iteration, calculate when to do the next one */
+ namestore_iter = NULL;
+ last_num_public_records = num_public_records;
+ first_zone_iteration = GNUNET_NO;
+ if (0 == num_public_records)
+ {
+ /**
+ * If no records are known (startup) or none present
+ * we can safely set the interval to the value for a single
+ * record
+ */
+ put_interval = zone_publish_time_window;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "No records in namestore database.\n");
+ }
+ else
+ {
+ /* If records are present, next publication is based on the minimum
+ * relative expiration time of the records published divided by 4
+ */
+ zone_publish_time_window
+ = GNUNET_TIME_relative_min (GNUNET_TIME_relative_divide (min_relative_record_time, 4),
+ zone_publish_time_window_default);
+ put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
+ num_public_records);
+ }
+ /* reset for next iteration */
+ min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
+ put_interval = GNUNET_TIME_relative_max (MINIMUM_ZONE_ITERATION_INTERVAL,
+ put_interval);
+ put_interval = GNUNET_TIME_relative_min (put_interval,
+ MAXIMUM_ZONE_ITERATION_INTERVAL);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Zone iteration finished. Adjusted zone iteration interval to %s\n",
+ GNUNET_STRINGS_relative_time_to_string (put_interval,
+ GNUNET_YES));
+ GNUNET_STATISTICS_set (statistics,
+ "Current zone iteration interval (in ms)",
+ put_interval.rel_value_us / 1000LL,
+ GNUNET_NO);
+ GNUNET_STATISTICS_update (statistics,
+ "Number of zone iterations",
+ 1,
+ GNUNET_NO);
+ GNUNET_STATISTICS_set (statistics,
+ "Number of public records in DHT",
+ last_num_public_records,
+ GNUNET_NO);
+ GNUNET_assert (NULL == zone_publish_task);
+ if (0 == num_public_records)
+ zone_publish_task = GNUNET_SCHEDULER_add_delayed (put_interval,
+ &publish_zone_dht_start,
+ NULL);
+ else
+ zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
+ NULL);
+}
+
+
+/**
+ * Function used to put all records successively into the DHT.
+ *
+ * @param cls the closure (NULL)
+ * @param key the private key of the authority (ours)
+ * @param label the name of the records, NULL once the iteration is done
+ * @param rd_count the number of records in @a rd
+ * @param rd the record data
+ */
+static void
+put_gns_record (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+ const char *label,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct GNUNET_GNSRECORD_Data rd_public[rd_count];
+ unsigned int rd_public_count;
+
+ rd_public_count = convert_records_for_export (rd,
+ rd_count,
+ rd_public);
+
+ if (0 == rd_public_count)
+ {
+ GNUNET_assert (NULL == zone_publish_task);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Record set empty, moving to next record set\n");
+ zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
+ NULL);
+ return;
+ }
+ /* We got a set of records to publish */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Starting DHT PUT\n");
+ active_put = perform_dht_put (key,
+ label,
+ rd_public,
+ rd_public_count,
+ NULL);
+ if (NULL == active_put)
+ {
+ GNUNET_break (0);
+ dht_put_continuation (NULL, GNUNET_NO);
+ }
+}
+
+
+/**
+ * Periodically iterate over all zones and store everything in DHT
+ *
+ * @param cls NULL
+ */
+static void
+publish_zone_dht_start (void *cls)
+{
+ zone_publish_task = NULL;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Starting DHT zone update!\n");
+ /* start counting again */
+ num_public_records = 0;
+ GNUNET_assert (NULL == namestore_iter);
+ namestore_iter
+ = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
+ NULL, /* All zones */
+ &zone_iteration_error,
+ NULL,
+ &put_gns_record,
+ NULL,
+ &zone_iteration_finished,
+ NULL);
+}
+
+
+/**
+ * Process a record that was stored in the namestore
+ * (invoked by the monitor).
+ *
+ * @param cls closure, NULL
+ * @param zone private key of the zone; NULL on disconnect
+ * @param label label of the records; NULL on disconnect
+ * @param rd_count number of entries in @a rd array, 0 if label was deleted
+ * @param rd array of records with data to store
+ */
+static void
+handle_monitor_event (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *label,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct GNUNET_GNSRECORD_Data rd_public[rd_count];
+ unsigned int rd_public_count;
+ struct MonitorActivity *ma;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u records for label `%s' via namestore monitor\n",
+ rd_count,
+ label);
+ /* filter out records that are not public, and convert to
+ absolute expiration time. */
+ rd_public_count = convert_records_for_export (rd,
+ rd_count,
+ rd_public);
+ if (0 == rd_public_count)
+ return; /* nothing to do */
+ ma = GNUNET_new (struct MonitorActivity);
+ ma->ph = perform_dht_put (zone,
+ label,
+ rd,
+ rd_count,
+ ma);
+ if (NULL == ma->ph)
+ {
+ /* PUT failed, do not remember operation */
+ GNUNET_free (ma);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_insert (ma_head,
+ ma_tail,
+ ma);
+}
+
+
+/**
+ * The zone monitor is now in SYNC with the current state of the
+ * name store. Start to perform periodic iterations.
+ *
+ * @param cls NULL
+ */
+static void
+monitor_sync_event (void *cls)
+{
+ GNUNET_assert (NULL == zone_publish_task);
+ zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
+ NULL);
+}
+
+
+/**
+ * The zone monitor is now in SYNC with the current state of the
+ * name store. Start to perform periodic iterations.
+ *
+ * @param cls NULL
+ */
+static void
+handle_monitor_error (void *cls)
+{
+ if (NULL != zone_publish_task)
+ {
+ GNUNET_SCHEDULER_cancel (zone_publish_task);
+ zone_publish_task = NULL;
+ }
+ if (NULL != namestore_iter)
+ {
+ GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
+ namestore_iter = NULL;
+ }
+ if (NULL != active_put)
+ {
+ GNUNET_DHT_put_cancel (active_put);
+ active_put = NULL;
+ }
+ zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
+ NULL);
+}
+
+
+/**
+ * Performe zonemaster duties: watch namestore, publish records.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_SERVICE_Handle *service)
+{
+ unsigned long long max_parallel_bg_queries = 0;
+
+ min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
+ namestore_handle = GNUNET_NAMESTORE_connect (c);
+ if (NULL == namestore_handle)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to connect to the namestore!\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ put_interval = INITIAL_PUT_INTERVAL;
+ zone_publish_time_window_default = DEFAULT_ZONE_PUBLISH_TIME_WINDOW;
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_time (c, "gns",
+ "ZONE_PUBLISH_TIME_WINDOW",
+ &zone_publish_time_window_default))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Time window for zone iteration: %s\n",
+ GNUNET_STRINGS_relative_time_to_string (zone_publish_time_window,
+ GNUNET_YES));
+ }
+ zone_publish_time_window = zone_publish_time_window_default;
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (c, "gns",
+ "MAX_PARALLEL_BACKGROUND_QUERIES",
+ &max_parallel_bg_queries))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Number of allowed parallel background queries: %llu\n",
+ max_parallel_bg_queries);
+ }
+
+ dht_handle = GNUNET_DHT_connect (c,
+ (unsigned int) max_parallel_bg_queries);
+ if (NULL == dht_handle)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not connect to DHT!\n"));
+ GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
+ return;
+ }
+
+ /* Schedule periodic put for our records. */
+ first_zone_iteration = GNUNET_YES;\
+ statistics = GNUNET_STATISTICS_create ("zonemaster", c);
+ zmon = GNUNET_NAMESTORE_zone_monitor_start (c,
+ NULL,
+ GNUNET_NO,
+ &handle_monitor_error,
+ NULL,
+ &handle_monitor_event,
+ NULL,
+ &monitor_sync_event,
+ NULL);
+ GNUNET_break (NULL != zmon);
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("zonemaster",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ NULL,
+ NULL,
+ NULL,
+ GNUNET_MQ_handler_end());
+
+
+/* end of gnunet-service-zonemaster.c */
diff --git a/src/zonemaster/zonemaster.conf.in b/src/zonemaster/zonemaster.conf.in
new file mode 100644
index 000000000..dda0c7ec4
--- /dev/null
+++ b/src/zonemaster/zonemaster.conf.in
@@ -0,0 +1,25 @@
+[gns]
+AUTOSTART = @AUTOSTART@
+FORCESTART = YES
+HOSTNAME = localhost
+BINARY = gnunet-service-zonemaster
+UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-zonemaster.sock
+@JAVAPORT@PORT = 2123
+
+# Do we require users that want to access GNS to run this process
+# (usually not a good idea)
+UNIX_MATCH_UID = NO
+
+# Do we require users that want to access GNS to be in the 'gnunet' group?
+UNIX_MATCH_GID = NO
+
+# How many queries is GNS allowed to perform in the background at the same time?
+MAX_PARALLEL_BACKGROUND_QUERIES = 1000
+
+# How frequently do we try to publish our full zone?
+ZONE_PUBLISH_TIME_WINDOW = 4 h
+
+# Using caching or always ask DHT
+# USE_CACHE = YES
+
+# PREFIX = valgrind --leak-check=full --track-origins=yes