aboutsummaryrefslogtreecommitdiff
path: root/src/gns/gnunet-service-gns.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-20 15:50:09 +0000
committerChristian Grothoff <christian@grothoff.org>2013-10-20 15:50:09 +0000
commite9496ec9ae3115baf1701f50b9438094dfece97f (patch)
tree8fbc20580c5aa50c05704bce5f4d4947d18fb90e /src/gns/gnunet-service-gns.c
parent09f4417022e2bfa68751b8ec67347c4ad3a40034 (diff)
downloadgnunet-e9496ec9ae3115baf1701f50b9438094dfece97f.tar.gz
gnunet-e9496ec9ae3115baf1701f50b9438094dfece97f.zip
-towards implementing #3051
Diffstat (limited to 'src/gns/gnunet-service-gns.c')
-rw-r--r--src/gns/gnunet-service-gns.c350
1 files changed, 269 insertions, 81 deletions
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
index 53f065037..ca2e80fd0 100644
--- a/src/gns/gnunet-service-gns.c
+++ b/src/gns/gnunet-service-gns.c
@@ -107,6 +107,28 @@ struct ClientLookupHandle
107 107
108 108
109/** 109/**
110 * Handle for DHT PUT activity triggered from the namestore monitor.
111 */
112struct MonitorActivity
113{
114 /**
115 * Kept in a DLL.
116 */
117 struct MonitorActivity *next;
118
119 /**
120 * Kept in a DLL.
121 */
122 struct MonitorActivity *prev;
123
124 /**
125 * Handle for the DHT PUT operation.
126 */
127 struct GNUNET_DHT_PutHandle *ph;
128};
129
130
131/**
110 * Our handle to the DHT 132 * Our handle to the DHT
111 */ 133 */
112static struct GNUNET_DHT_Handle *dht_handle; 134static struct GNUNET_DHT_Handle *dht_handle;
@@ -132,6 +154,11 @@ static struct GNUNET_NAMECACHE_Handle *namecache_handle;
132static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter; 154static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
133 155
134/** 156/**
157 * Handle to monitor namestore changes to instant propagation.
158 */
159static struct GNUNET_NAMESTORE_ZoneMonitor *zmon;
160
161/**
135 * Our notification context. 162 * Our notification context.
136 */ 163 */
137static struct GNUNET_SERVER_NotificationContext *nc; 164static struct GNUNET_SERVER_NotificationContext *nc;
@@ -147,6 +174,16 @@ static struct ClientLookupHandle *clh_head;
147static struct ClientLookupHandle *clh_tail; 174static struct ClientLookupHandle *clh_tail;
148 175
149/** 176/**
177 * Head of monitor activities; kept in a DLL.
178 */
179static struct MonitorActivity *ma_head;
180
181/**
182 * Tail of monitor activities; kept in a DLL.
183 */
184static struct MonitorActivity *ma_tail;
185
186/**
150 * Useful for zone update for DHT put 187 * Useful for zone update for DHT put
151 */ 188 */
152static unsigned long long num_public_records; 189static unsigned long long num_public_records;
@@ -199,6 +236,15 @@ static int v6_enabled;
199static int v4_enabled; 236static int v4_enabled;
200 237
201/** 238/**
239 * Did we finish the initial iteration over the namestore?
240 * (while we do the initial iteration, we do not generate
241 * DHT PUTs as there might be WAY too many of those).
242 * TODO: expand namestore monitor API with a way to
243 * suppress this initial iteration.
244 */
245static int sync_finished;
246
247/**
202 * Handle to the statistics service 248 * Handle to the statistics service
203 */ 249 */
204static struct GNUNET_STATISTICS_Handle *statistics; 250static struct GNUNET_STATISTICS_Handle *statistics;
@@ -211,9 +257,11 @@ static struct GNUNET_STATISTICS_Handle *statistics;
211 * @param tc unused 257 * @param tc unused
212 */ 258 */
213static void 259static void
214shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 260shutdown_task (void *cls,
261 const struct GNUNET_SCHEDULER_TaskContext *tc)
215{ 262{
216 struct ClientLookupHandle *clh; 263 struct ClientLookupHandle *clh;
264 struct MonitorActivity *ma;
217 265
218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
219 "Shutting down!\n"); 267 "Shutting down!\n");
@@ -229,6 +277,14 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
229 GNS_interceptor_done (); 277 GNS_interceptor_done ();
230 GNS_resolver_done (); 278 GNS_resolver_done ();
231 GNS_shorten_done (); 279 GNS_shorten_done ();
280 while (NULL != (ma = ma_head))
281 {
282 GNUNET_DHT_put_cancel (ma->ph);
283 GNUNET_CONTAINER_DLL_remove (ma_head,
284 ma_tail,
285 ma);
286 GNUNET_free (ma);
287 }
232 if (NULL != statistics) 288 if (NULL != statistics)
233 { 289 {
234 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); 290 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
@@ -244,6 +300,11 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
244 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter); 300 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
245 namestore_iter = NULL; 301 namestore_iter = NULL;
246 } 302 }
303 if (NULL != zmon)
304 {
305 GNUNET_NAMESTORE_zone_monitor_stop (zmon);
306 zmon = NULL;
307 }
247 if (NULL != namestore_handle) 308 if (NULL != namestore_handle)
248 { 309 {
249 GNUNET_NAMESTORE_disconnect (namestore_handle); 310 GNUNET_NAMESTORE_disconnect (namestore_handle);
@@ -296,37 +357,148 @@ publish_zone_dht_start (void *cls,
296/** 357/**
297 * Continuation called from DHT once the PUT operation is done. 358 * Continuation called from DHT once the PUT operation is done.
298 * 359 *
299 * @param cls closure, NULL 360 * @param cls closure, NULL if called from regular iteration,
361 * `struct MonitorActivity` if called from #handle_monitor_event.
300 * @param success #GNUNET_OK on success 362 * @param success #GNUNET_OK on success
301 */ 363 */
302static void 364static void
303dht_put_continuation (void *cls, 365dht_put_continuation (void *cls,
304 int success) 366 int success)
305{ 367{
368 struct MonitorActivity *ma = cls;
306 struct GNUNET_TIME_Relative next_put_interval; 369 struct GNUNET_TIME_Relative next_put_interval;
307 370
308 active_put = NULL;
309 num_public_records++; 371 num_public_records++;
310 if ( (num_public_records > last_num_public_records) && 372 if (NULL == ma)
311 (GNUNET_NO == first_zone_iteration) )
312 { 373 {
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 374 active_put = NULL;
314 "Last record count was lower than current record count. Reducing interval.\n"); 375 if ( (num_public_records > last_num_public_records) &&
315 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window, 376 (GNUNET_NO == first_zone_iteration) )
316 num_public_records); 377 {
317 next_put_interval = GNUNET_TIME_relative_divide (put_interval, 378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
318 LATE_ITERATION_SPEEDUP_FACTOR); 379 "Last record count was lower than current record count. Reducing interval.\n");
380 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
381 num_public_records);
382 next_put_interval = GNUNET_TIME_relative_divide (put_interval,
383 LATE_ITERATION_SPEEDUP_FACTOR);
384 }
385 else
386 next_put_interval = put_interval;
387
388 GNUNET_STATISTICS_set (statistics,
389 "Current zone iteration interval (ms)",
390 next_put_interval.rel_value_us / 1000LL,
391 GNUNET_NO);
392 zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval,
393 &publish_zone_dht_next,
394 NULL);
319 } 395 }
320 else 396 else
321 next_put_interval = put_interval; 397 {
322 398 GNUNET_CONTAINER_DLL_remove (ma_head,
323 GNUNET_STATISTICS_set (statistics, 399 ma_tail,
324 "Current zone iteration interval (ms)", 400 ma);
325 next_put_interval.rel_value_us / 1000LL, 401 GNUNET_free (ma);
326 GNUNET_NO); 402 }
327 zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval, 403}
328 &publish_zone_dht_next, 404
329 NULL); 405
406/**
407 * Convert namestore records from the internal format to that
408 * suitable for publication (removes private records, converts
409 * to absolute expiration time).
410 *
411 * @param rd input records
412 * @param rd_count size of the @a rd and @a rd_public arrays
413 * @param rd_public where to write the converted records
414 * @return number of records written to @a rd_public
415 */
416static unsigned int
417convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
418 unsigned int rd_count,
419 struct GNUNET_GNSRECORD_Data *rd_public)
420{
421 struct GNUNET_TIME_Absolute now;
422 unsigned int rd_public_count;
423 unsigned int i;
424
425 rd_public_count = 0;
426 now = GNUNET_TIME_absolute_get ();
427 for (i=0;i<rd_count;i++)
428 if (0 == (rd[i].flags & (GNUNET_GNSRECORD_RF_PRIVATE |
429 GNUNET_GNSRECORD_RF_PENDING)))
430 {
431 rd_public[rd_public_count] = rd[i];
432 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
433 {
434 /* GNUNET_GNSRECORD_block_create will convert to absolute time;
435 we just need to adjust our iteration frequency */
436 min_relative_record_time.rel_value_us =
437 GNUNET_MIN (rd_public[rd_public_count].expiration_time,
438 min_relative_record_time.rel_value_us);
439 }
440 else if (rd_public[rd_public_count].expiration_time < now.abs_value_us)
441 {
442 /* record already expired, skip it */
443 continue;
444 }
445 rd_public_count++;
446 }
447 return rd_public_count;
448}
449
450
451/**
452 * Store GNS records in the DHT.
453 *
454 * @param key key of the zone
455 * @param label label to store under
456 * @param rd_public public record data
457 * @param rd_public_count number of records in @a rd_public
458 * @param pc_arg closure argument to pass to the #dht_put_continuation
459 * @return DHT PUT handle, NULL on error
460 */
461static struct GNUNET_DHT_PutHandle *
462perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
463 const char *label,
464 const struct GNUNET_GNSRECORD_Data *rd_public,
465 unsigned int rd_public_count,
466 void *pc_arg)
467{
468 struct GNUNET_GNSRECORD_Block *block;
469 struct GNUNET_HashCode query;
470 struct GNUNET_TIME_Absolute expire;
471 size_t block_size;
472 struct GNUNET_DHT_PutHandle *ret;
473
474 expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
475 rd_public);
476 block = GNUNET_GNSRECORD_block_create (key,
477 expire,
478 label,
479 rd_public,
480 rd_public_count);
481 block_size = ntohl (block->purpose.size)
482 + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
483 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
484 GNUNET_GNSRECORD_query_from_private_key (key,
485 label,
486 &query);
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488 "Storing record in DHT with expiration `%s'\n",
489 GNUNET_STRINGS_absolute_time_to_string (expire));
490 ret = GNUNET_DHT_put (dht_handle, &query,
491 DHT_GNS_REPLICATION_LEVEL,
492 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
493 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
494 block_size,
495 block,
496 expire,
497 DHT_OPERATION_TIMEOUT,
498 &dht_put_continuation,
499 pc_arg);
500 GNUNET_free (block);
501 return ret;
330} 502}
331 503
332 504
@@ -346,14 +518,8 @@ put_gns_record (void *cls,
346 unsigned int rd_count, 518 unsigned int rd_count,
347 const struct GNUNET_GNSRECORD_Data *rd) 519 const struct GNUNET_GNSRECORD_Data *rd)
348{ 520{
349 struct GNUNET_GNSRECORD_Block *block;
350 struct GNUNET_HashCode query;
351 struct GNUNET_TIME_Absolute expire;
352 struct GNUNET_TIME_Absolute now;
353 size_t block_size;
354 struct GNUNET_GNSRECORD_Data rd_public[rd_count]; 521 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
355 unsigned int rd_public_count; 522 unsigned int rd_public_count;
356 unsigned int i;
357 523
358 if (NULL == name) 524 if (NULL == name)
359 { 525 {
@@ -411,30 +577,9 @@ put_gns_record (void *cls,
411 return; 577 return;
412 } 578 }
413 579
414 /* filter out records that are not public, and convert to 580 rd_public_count = convert_records_for_export (rd,
415 absolute expiration time. */ 581 rd_count,
416 rd_public_count = 0; 582 rd_public);
417 now = GNUNET_TIME_absolute_get ();
418 for (i=0;i<rd_count;i++)
419 if (0 == (rd[i].flags & (GNUNET_GNSRECORD_RF_PRIVATE |
420 GNUNET_GNSRECORD_RF_PENDING)))
421 {
422 rd_public[rd_public_count] = rd[i];
423 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
424 {
425 /* GNUNET_GNSRECORD_block_create will convert to absolute time;
426 we just need to adjust our iteration frequency */
427 min_relative_record_time.rel_value_us =
428 GNUNET_MIN (rd_public[rd_public_count].expiration_time,
429 min_relative_record_time.rel_value_us);
430 }
431 else if (rd_public[rd_public_count].expiration_time < now.abs_value_us)
432 {
433 /* record already expired, skip it */
434 continue;
435 }
436 rd_public_count++;
437 }
438 583
439 /* We got a set of records to publish */ 584 /* We got a set of records to publish */
440 if (0 == rd_public_count) 585 if (0 == rd_public_count)
@@ -443,38 +588,17 @@ put_gns_record (void *cls,
443 NULL); 588 NULL);
444 return; 589 return;
445 } 590 }
446 expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count, 591
447 rd_public); 592 active_put = perform_dht_put (key,
448 block = GNUNET_GNSRECORD_block_create (key, 593 name,
449 expire, 594 rd_public,
450 name, 595 rd_public_count,
451 rd_public, 596 NULL);
452 rd_public_count);
453 block_size = ntohl (block->purpose.size)
454 + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
455 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
456 GNUNET_GNSRECORD_query_from_private_key (key,
457 name,
458 &query);
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Storing record in DHT with expiration `%s'\n",
461 GNUNET_STRINGS_absolute_time_to_string (expire));
462 active_put = GNUNET_DHT_put (dht_handle, &query,
463 DHT_GNS_REPLICATION_LEVEL,
464 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
465 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
466 block_size,
467 block,
468 expire,
469 DHT_OPERATION_TIMEOUT,
470 &dht_put_continuation,
471 NULL);
472 if (NULL == active_put) 597 if (NULL == active_put)
473 { 598 {
474 GNUNET_break (0); 599 GNUNET_break (0);
475 dht_put_continuation (NULL, GNUNET_NO); 600 dht_put_continuation (NULL, GNUNET_NO);
476 } 601 }
477 GNUNET_free (block);
478} 602}
479 603
480 604
@@ -501,6 +625,52 @@ publish_zone_dht_start (void *cls,
501} 625}
502 626
503 627
628/**
629 * Process a record that was stored in the namestore
630 * (invoked by the monitor).
631 *
632 * @param cls closure, NULL
633 * @param zone private key of the zone; NULL on disconnect
634 * @param label label of the records; NULL on disconnect
635 * @param rd_count number of entries in @a rd array, 0 if label was deleted
636 * @param rd array of records with data to store
637 */
638static void
639handle_monitor_event (void *cls,
640 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
641 const char *label,
642 unsigned int rd_count,
643 const struct GNUNET_GNSRECORD_Data *rd)
644{
645 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
646 unsigned int rd_public_count;
647 struct MonitorActivity *ma;
648
649 if (GNUNET_YES != sync_finished)
650 return; /* do not do DHT PUTs on initial sync, as that may
651 create far too many PUTs on startup */
652 /* filter out records that are not public, and convert to
653 absolute expiration time. */
654 rd_public_count = convert_records_for_export (rd, rd_count,
655 rd_public);
656 if (0 == rd_public_count)
657 return; /* nothing to do */
658 ma = GNUNET_new (struct MonitorActivity);
659 ma->ph = perform_dht_put (zone, label,
660 rd, rd_count,
661 ma);
662 if (NULL == ma->ph)
663 {
664 /* PUT failed, do not remember operation */
665 GNUNET_free (ma);
666 return;
667 }
668 GNUNET_CONTAINER_DLL_insert (ma_head,
669 ma_tail,
670 ma);
671}
672
673
504/* END DHT ZONE PROPAGATION */ 674/* END DHT ZONE PROPAGATION */
505 675
506 676
@@ -655,6 +825,21 @@ notify_client_disconnect (void *cls,
655 825
656 826
657/** 827/**
828 * The zone monitor is now in SYNC with the current state of the
829 * name store. Start to perform periodic iterations.
830 *
831 * @param cls NULL
832 */
833static void
834monitor_sync_event (void *cls)
835{
836 sync_finished = GNUNET_YES;
837 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
838 NULL);
839}
840
841
842/**
658 * Process GNS requests. 843 * Process GNS requests.
659 * 844 *
660 * @param cls closure 845 * @param cls closure
@@ -732,8 +917,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
732 { 917 {
733 if (GNUNET_OK != 918 if (GNUNET_OK !=
734 GNUNET_CRYPTO_ecdsa_public_key_from_string (dns_root_name, 919 GNUNET_CRYPTO_ecdsa_public_key_from_string (dns_root_name,
735 strlen (dns_root_name), 920 strlen (dns_root_name),
736 &dns_root)) 921 &dns_root))
737 { 922 {
738 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 923 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
739 "gns", "DNS_ROOT", 924 "gns", "DNS_ROOT",
@@ -768,8 +953,11 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
768 GNUNET_SERVER_add_handlers (server, handlers); 953 GNUNET_SERVER_add_handlers (server, handlers);
769 statistics = GNUNET_STATISTICS_create ("gns", c); 954 statistics = GNUNET_STATISTICS_create ("gns", c);
770 nc = GNUNET_SERVER_notification_context_create (server, 1); 955 nc = GNUNET_SERVER_notification_context_create (server, 1);
771 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start, 956 zmon = GNUNET_NAMESTORE_zone_monitor_start (c,
772 NULL); 957 NULL,
958 &handle_monitor_event,
959 &monitor_sync_event,
960 NULL);
773 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 961 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
774 &shutdown_task, NULL); 962 &shutdown_task, NULL);
775} 963}