aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-06-18 10:30:08 +0200
committerChristian Grothoff <christian@grothoff.org>2019-06-18 10:30:08 +0200
commit9ae7f13f17e3d04d3ba88862299c8e42541eab47 (patch)
tree167259c402cd199bcbce49f14d6aae20f41425d8 /src/util
parent93c332be89c4c65f10b7c4c49b6ed15d91b91884 (diff)
downloadgnunet-9ae7f13f17e3d04d3ba88862299c8e42541eab47.tar.gz
gnunet-9ae7f13f17e3d04d3ba88862299c8e42541eab47.zip
Introducing GNUNET_Uuid and matching hash map for 128 bit values.
TNG: reducing size of AcknowledgementUUIDPs from 256 bits to 128 bits.
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am1
-rw-r--r--src/util/common_logging.c393
-rw-r--r--src/util/container_multiuuidmap.c1015
3 files changed, 1192 insertions, 217 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 8a99197f8..fe5cc6e72 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -78,6 +78,7 @@ libgnunetutil_la_SOURCES = \
78 container_meta_data.c \ 78 container_meta_data.c \
79 container_multihashmap.c \ 79 container_multihashmap.c \
80 container_multishortmap.c \ 80 container_multishortmap.c \
81 container_multiuuidmap.c \
81 container_multipeermap.c \ 82 container_multipeermap.c \
82 container_multihashmap32.c \ 83 container_multihashmap32.c \
83 crypto_symmetric.c \ 84 crypto_symmetric.c \
diff --git a/src/util/common_logging.c b/src/util/common_logging.c
index 5052134f8..b5678e5be 100644
--- a/src/util/common_logging.c
+++ b/src/util/common_logging.c
@@ -107,7 +107,8 @@ static __thread struct GNUNET_AsyncScopeSave current_async_scope;
107 * Note that this message maybe truncated to the first BULK_TRACK_SIZE 107 * Note that this message maybe truncated to the first BULK_TRACK_SIZE
108 * characters, in which case it is NOT 0-terminated! 108 * characters, in which case it is NOT 0-terminated!
109 */ 109 */
110static GNUNET_THREAD_LOCAL char last_bulk[BULK_TRACK_SIZE] __attribute__ ((nonstring)); 110static GNUNET_THREAD_LOCAL char last_bulk[BULK_TRACK_SIZE]
111 __attribute__ ((nonstring));
111 112
112/** 113/**
113 * Type of the last bulk message. 114 * Type of the last bulk message.
@@ -211,7 +212,7 @@ struct LogDef
211}; 212};
212 213
213 214
214#if !defined(GNUNET_CULL_LOGGING) 215#if ! defined(GNUNET_CULL_LOGGING)
215/** 216/**
216 * Dynamic array of logging definitions 217 * Dynamic array of logging definitions
217 */ 218 */
@@ -263,17 +264,17 @@ get_type (const char *log)
263{ 264{
264 if (NULL == log) 265 if (NULL == log)
265 return GNUNET_ERROR_TYPE_UNSPECIFIED; 266 return GNUNET_ERROR_TYPE_UNSPECIFIED;
266 if (0 == strcasecmp (log, _("DEBUG"))) 267 if (0 == strcasecmp (log, _ ("DEBUG")))
267 return GNUNET_ERROR_TYPE_DEBUG; 268 return GNUNET_ERROR_TYPE_DEBUG;
268 if (0 == strcasecmp (log, _("INFO"))) 269 if (0 == strcasecmp (log, _ ("INFO")))
269 return GNUNET_ERROR_TYPE_INFO; 270 return GNUNET_ERROR_TYPE_INFO;
270 if (0 == strcasecmp (log, _("MESSAGE"))) 271 if (0 == strcasecmp (log, _ ("MESSAGE")))
271 return GNUNET_ERROR_TYPE_MESSAGE; 272 return GNUNET_ERROR_TYPE_MESSAGE;
272 if (0 == strcasecmp (log, _("WARNING"))) 273 if (0 == strcasecmp (log, _ ("WARNING")))
273 return GNUNET_ERROR_TYPE_WARNING; 274 return GNUNET_ERROR_TYPE_WARNING;
274 if (0 == strcasecmp (log, _("ERROR"))) 275 if (0 == strcasecmp (log, _ ("ERROR")))
275 return GNUNET_ERROR_TYPE_ERROR; 276 return GNUNET_ERROR_TYPE_ERROR;
276 if (0 == strcasecmp (log, _("NONE"))) 277 if (0 == strcasecmp (log, _ ("NONE")))
277 return GNUNET_ERROR_TYPE_NONE; 278 return GNUNET_ERROR_TYPE_NONE;
278 return GNUNET_ERROR_TYPE_INVALID; 279 return GNUNET_ERROR_TYPE_INVALID;
279} 280}
@@ -292,7 +293,7 @@ GNUNET_abort_ ()
292} 293}
293 294
294 295
295#if !defined(GNUNET_CULL_LOGGING) 296#if ! defined(GNUNET_CULL_LOGGING)
296/** 297/**
297 * Utility function - reallocates logdefs array to be twice as large. 298 * Utility function - reallocates logdefs array to be twice as large.
298 */ 299 */
@@ -353,7 +354,7 @@ setup_log_file (const struct tm *tm)
353 if (0 == strftime (fn, sizeof (fn), log_file_name, tm)) 354 if (0 == strftime (fn, sizeof (fn), log_file_name, tm))
354 return GNUNET_SYSERR; 355 return GNUNET_SYSERR;
355 leftsquare = strrchr (fn, '['); 356 leftsquare = strrchr (fn, '[');
356 if ( (NULL != leftsquare) && (']' == leftsquare[1]) ) 357 if ((NULL != leftsquare) && (']' == leftsquare[1]))
357 { 358 {
358 char *logfile_copy = GNUNET_strdup (fn); 359 char *logfile_copy = GNUNET_strdup (fn);
359 360
@@ -371,8 +372,7 @@ setup_log_file (const struct tm *tm)
371 return GNUNET_OK; /* no change */ 372 return GNUNET_OK; /* no change */
372 log_rotate (last_fn); 373 log_rotate (last_fn);
373 strcpy (last_fn, fn); 374 strcpy (last_fn, fn);
374 if (GNUNET_SYSERR == 375 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (fn))
375 GNUNET_DISK_directory_create_for_file (fn))
376 { 376 {
377 fprintf (stderr, 377 fprintf (stderr,
378 "Failed to create directory for `%s': %s\n", 378 "Failed to create directory for `%s': %s\n",
@@ -381,14 +381,12 @@ setup_log_file (const struct tm *tm)
381 return GNUNET_SYSERR; 381 return GNUNET_SYSERR;
382 } 382 }
383#if WINDOWS 383#if WINDOWS
384 altlog_fd = OPEN (fn, O_APPEND | 384 altlog_fd =
385 O_BINARY | 385 OPEN (fn, O_APPEND | O_BINARY | O_WRONLY | O_CREAT, _S_IREAD | _S_IWRITE);
386 O_WRONLY | O_CREAT,
387 _S_IREAD | _S_IWRITE);
388#else 386#else
389 altlog_fd = OPEN (fn, O_APPEND | 387 altlog_fd = OPEN (fn,
390 O_WRONLY | O_CREAT, 388 O_APPEND | O_WRONLY | O_CREAT,
391 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 389 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
392#endif 390#endif
393 if (-1 != altlog_fd) 391 if (-1 != altlog_fd)
394 { 392 {
@@ -512,7 +510,7 @@ GNUNET_get_log_call_status (int caller_level,
512 /* We have no definitions to override globally configured log level, 510 /* We have no definitions to override globally configured log level,
513 * so just use it right away. 511 * so just use it right away.
514 */ 512 */
515 if ( (min_level >= 0) && (GNUNET_NO == gnunet_force_log_present) ) 513 if ((min_level >= 0) && (GNUNET_NO == gnunet_force_log_present))
516 return caller_level <= min_level; 514 return caller_level <= min_level;
517 515
518 /* Only look for forced definitions? */ 516 /* Only look for forced definitions? */
@@ -520,7 +518,7 @@ GNUNET_get_log_call_status (int caller_level,
520 for (i = 0; i < logdefs_len; i++) 518 for (i = 0; i < logdefs_len; i++)
521 { 519 {
522 ld = &logdefs[i]; 520 ld = &logdefs[i];
523 if (( (!force_only) || ld->force) && 521 if (((! force_only) || ld->force) &&
524 (line >= ld->from_line && line <= ld->to_line) && 522 (line >= ld->from_line && line <= ld->to_line) &&
525 (0 == regexec (&ld->component_regex, comp, 0, NULL, 0)) && 523 (0 == regexec (&ld->component_regex, comp, 0, NULL, 0)) &&
526 (0 == regexec (&ld->file_regex, file, 0, NULL, 0)) && 524 (0 == regexec (&ld->file_regex, file, 0, NULL, 0)) &&
@@ -591,73 +589,79 @@ parse_definitions (const char *constname, int force)
591 { 589 {
592 switch (p[0]) 590 switch (p[0])
593 { 591 {
594 case ';': /* found a field separator */ 592 case ';': /* found a field separator */
595 p[0] = '\0'; 593 p[0] = '\0';
596 switch (state) 594 switch (state)
597 { 595 {
598 case 0: /* within a component name */ 596 case 0: /* within a component name */
599 comp = start; 597 comp = start;
600 break; 598 break;
601 case 1: /* within a file name */ 599 case 1: /* within a file name */
602 file = start; 600 file = start;
603 break; 601 break;
604 case 2: /* within a function name */ 602 case 2: /* within a function name */
605 /* after a file name there must be a function name */ 603 /* after a file name there must be a function name */
606 function = start; 604 function = start;
607 break; 605 break;
608 case 3: /* within a from-to line range */ 606 case 3: /* within a from-to line range */
609 if (strlen (start) > 0) 607 if (strlen (start) > 0)
610 { 608 {
611 errno = 0; 609 errno = 0;
612 from_line = strtol (start, &t, 10); 610 from_line = strtol (start, &t, 10);
613 if ( (0 != errno) || (from_line < 0) ) 611 if ((0 != errno) || (from_line < 0))
614 { 612 {
615 GNUNET_free (def); 613 GNUNET_free (def);
616 return counter; 614 return counter;
617 } 615 }
618 if ( (t < p) && ('-' == t[0]) ) 616 if ((t < p) && ('-' == t[0]))
619 { 617 {
620 errno = 0; 618 errno = 0;
621 start = t + 1; 619 start = t + 1;
622 to_line = strtol (start, &t, 10); 620 to_line = strtol (start, &t, 10);
623 if ( (0 != errno) || (to_line < 0) || (t != p) ) 621 if ((0 != errno) || (to_line < 0) || (t != p))
624 { 622 {
625 GNUNET_free (def); 623 GNUNET_free (def);
626 return counter; 624 return counter;
627 } 625 }
628 } 626 }
629 else /* one number means "match this line only" */ 627 else /* one number means "match this line only" */
630 to_line = from_line; 628 to_line = from_line;
631 } 629 }
632 else /* default to 0-max */ 630 else /* default to 0-max */
633 { 631 {
634 from_line = 0; 632 from_line = 0;
635 to_line = INT_MAX; 633 to_line = INT_MAX;
636 } 634 }
637 break; 635 break;
638 default: 636 default:
639 fprintf(stderr, 637 fprintf (
640 _("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"), 638 stderr,
641 p); 639 _ ("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
640 p);
642 break; 641 break;
643 } 642 }
644 start = p + 1; 643 start = p + 1;
645 state++; 644 state++;
646 break; 645 break;
647 case '\0': /* found EOL */ 646 case '\0': /* found EOL */
648 keep_looking = 0; 647 keep_looking = 0;
649 /* fall through to '/' */ 648 /* fall through to '/' */
650 case '/': /* found a definition separator */ 649 case '/': /* found a definition separator */
651 switch (state) 650 switch (state)
652 { 651 {
653 case 4: /* within a log level */ 652 case 4: /* within a log level */
654 p[0] = '\0'; 653 p[0] = '\0';
655 state = 0; 654 state = 0;
656 level = get_type ((const char *) start); 655 level = get_type ((const char *) start);
657 if ( (GNUNET_ERROR_TYPE_INVALID == level) || 656 if ((GNUNET_ERROR_TYPE_INVALID == level) ||
658 (GNUNET_ERROR_TYPE_UNSPECIFIED == level) || 657 (GNUNET_ERROR_TYPE_UNSPECIFIED == level) ||
659 (0 != add_definition (comp, file, function, from_line, to_line, 658 (0 != add_definition (comp,
660 level, force)) ) 659 file,
660 function,
661 from_line,
662 to_line,
663 level,
664 force)))
661 { 665 {
662 GNUNET_free (def); 666 GNUNET_free (def);
663 return counter; 667 return counter;
@@ -666,9 +670,10 @@ parse_definitions (const char *constname, int force)
666 start = p + 1; 670 start = p + 1;
667 break; 671 break;
668 default: 672 default:
669 fprintf(stderr, 673 fprintf (
670 _("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"), 674 stderr,
671 p); 675 _ ("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
676 p);
672 break; 677 break;
673 } 678 }
674 default: 679 default:
@@ -688,7 +693,7 @@ parse_all_definitions ()
688{ 693{
689 if (GNUNET_NO == gnunet_force_log_parsed) 694 if (GNUNET_NO == gnunet_force_log_parsed)
690 gnunet_force_log_present = 695 gnunet_force_log_present =
691 parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO; 696 parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO;
692 gnunet_force_log_parsed = GNUNET_YES; 697 gnunet_force_log_parsed = GNUNET_YES;
693 698
694 if (GNUNET_NO == gnunet_log_parsed) 699 if (GNUNET_NO == gnunet_log_parsed)
@@ -707,14 +712,12 @@ parse_all_definitions ()
707 * @return #GNUNET_OK on success 712 * @return #GNUNET_OK on success
708 */ 713 */
709int 714int
710GNUNET_log_setup (const char *comp, 715GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile)
711 const char *loglevel,
712 const char *logfile)
713{ 716{
714 const char *env_logfile; 717 const char *env_logfile;
715 718
716 min_level = get_type (loglevel); 719 min_level = get_type (loglevel);
717#if !defined(GNUNET_CULL_LOGGING) 720#if ! defined(GNUNET_CULL_LOGGING)
718 parse_all_definitions (); 721 parse_all_definitions ();
719#endif 722#endif
720#ifdef WINDOWS 723#ifdef WINDOWS
@@ -761,8 +764,7 @@ GNUNET_log_setup (const char *comp,
761 * @param logger_cls closure for @a logger 764 * @param logger_cls closure for @a logger
762 */ 765 */
763void 766void
764GNUNET_logger_add (GNUNET_Logger logger, 767GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls)
765 void *logger_cls)
766{ 768{
767 struct CustomLogger *entry; 769 struct CustomLogger *entry;
768 770
@@ -781,8 +783,7 @@ GNUNET_logger_add (GNUNET_Logger logger,
781 * @param logger_cls closure for @a logger 783 * @param logger_cls closure for @a logger
782 */ 784 */
783void 785void
784GNUNET_logger_remove (GNUNET_Logger logger, 786GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls)
785 void *logger_cls)
786{ 787{
787 struct CustomLogger *pos; 788 struct CustomLogger *pos;
788 struct CustomLogger *prev; 789 struct CustomLogger *prev;
@@ -828,8 +829,7 @@ output_message (enum GNUNET_ErrorType kind,
828 EnterCriticalSection (&output_message_cs); 829 EnterCriticalSection (&output_message_cs);
829#endif 830#endif
830 /* only use the standard logger if no custom loggers are present */ 831 /* only use the standard logger if no custom loggers are present */
831 if ( (NULL != GNUNET_stderr) && 832 if ((NULL != GNUNET_stderr) && (NULL == loggers))
832 (NULL == loggers) )
833 { 833 {
834 if (kind == GNUNET_ERROR_TYPE_MESSAGE) 834 if (kind == GNUNET_ERROR_TYPE_MESSAGE)
835 { 835 {
@@ -841,9 +841,7 @@ output_message (enum GNUNET_ErrorType kind,
841 * this way if the output is going to logfiles or robots 841 * this way if the output is going to logfiles or robots
842 * instead. 842 * instead.
843 */ 843 */
844 FPRINTF (GNUNET_stderr, 844 FPRINTF (GNUNET_stderr, "* %s", msg);
845 "* %s",
846 msg);
847 } 845 }
848 else if (GNUNET_YES == current_async_scope.have_scope) 846 else if (GNUNET_YES == current_async_scope.have_scope)
849 { 847 {
@@ -881,11 +879,7 @@ output_message (enum GNUNET_ErrorType kind,
881 pos = loggers; 879 pos = loggers;
882 while (NULL != pos) 880 while (NULL != pos)
883 { 881 {
884 pos->logger (pos->logger_cls, 882 pos->logger (pos->logger_cls, kind, comp, datestr, msg);
885 kind,
886 comp,
887 datestr,
888 msg);
889 pos = pos->next; 883 pos = pos->next;
890 } 884 }
891#if WINDOWS 885#if WINDOWS
@@ -907,8 +901,7 @@ flush_bulk (const char *datestr)
907 char *last; 901 char *last;
908 const char *ft; 902 const char *ft;
909 903
910 if ( (0 == last_bulk_time.abs_value_us) || 904 if ((0 == last_bulk_time.abs_value_us) || (0 == last_bulk_repeat))
911 (0 == last_bulk_repeat) )
912 return; 905 return;
913 rev = 0; 906 rev = 0;
914 last = memchr (last_bulk, '\0', BULK_TRACK_SIZE); 907 last = memchr (last_bulk, '\0', BULK_TRACK_SIZE);
@@ -921,11 +914,17 @@ flush_bulk (const char *datestr)
921 rev = 1; 914 rev = 1;
922 last[0] = '\0'; 915 last[0] = '\0';
923 } 916 }
924 ft = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration 917 ft =
925 (last_bulk_time), GNUNET_YES); 918 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (
926 snprintf (msg, sizeof (msg), 919 last_bulk_time),
927 _("Message `%.*s' repeated %u times in the last %s\n"), 920 GNUNET_YES);
928 BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft); 921 snprintf (msg,
922 sizeof (msg),
923 _ ("Message `%.*s' repeated %u times in the last %s\n"),
924 BULK_TRACK_SIZE,
925 last_bulk,
926 last_bulk_repeat,
927 ft);
929 if (rev == 1) 928 if (rev == 1)
930 last[0] = '\n'; 929 last[0] = '\n';
931 output_message (last_bulk_kind, last_bulk_comp, datestr, msg); 930 output_message (last_bulk_kind, last_bulk_comp, datestr, msg);
@@ -941,8 +940,7 @@ flush_bulk (const char *datestr)
941 * @param check_reset #GNUNET_YES to assert that the log skip counter is currently zero 940 * @param check_reset #GNUNET_YES to assert that the log skip counter is currently zero
942 */ 941 */
943void 942void
944GNUNET_log_skip (int n, 943GNUNET_log_skip (int n, int check_reset)
945 int check_reset)
946{ 944{
947 int ok; 945 int ok;
948 946
@@ -993,15 +991,10 @@ mylog (enum GNUNET_ErrorType kind,
993 va_list vacp; 991 va_list vacp;
994 992
995 va_copy (vacp, va); 993 va_copy (vacp, va);
996 size = VSNPRINTF (NULL, 994 size = VSNPRINTF (NULL, 0, message, vacp) + 1;
997 0,
998 message,
999 vacp) + 1;
1000 GNUNET_assert (0 != size); 995 GNUNET_assert (0 != size);
1001 va_end (vacp); 996 va_end (vacp);
1002 memset (date, 997 memset (date, 0, DATE_STR_SIZE);
1003 0,
1004 DATE_STR_SIZE);
1005 { 998 {
1006 char buf[size]; 999 char buf[size];
1007 long long offset; 1000 long long offset;
@@ -1022,24 +1015,19 @@ mylog (enum GNUNET_ErrorType kind,
1022 else 1015 else
1023 { 1016 {
1024 if (0 == 1017 if (0 ==
1025 strftime (date2, 1018 strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr))
1026 DATE_STR_SIZE, 1019 abort ();
1027 "%b %d %H:%M:%S-%%020llu", 1020 if (0 > snprintf (date,
1028 tmptr)) 1021 sizeof (date),
1029 abort (); 1022 date2,
1030 if (0 > 1023 (long long) (pc.QuadPart /
1031 snprintf (date, 1024 (performance_frequency.QuadPart / 1000))))
1032 sizeof (date), 1025 abort ();
1033 date2,
1034 (long long) (pc.QuadPart /
1035 (performance_frequency.QuadPart / 1000))))
1036 abort ();
1037 } 1026 }
1038#else 1027#else
1039 struct timeval timeofday; 1028 struct timeval timeofday;
1040 1029
1041 gettimeofday (&timeofday, 1030 gettimeofday (&timeofday, NULL);
1042 NULL);
1043 offset = GNUNET_TIME_get_offset (); 1031 offset = GNUNET_TIME_get_offset ();
1044 if (offset > 0) 1032 if (offset > 0)
1045 { 1033 {
@@ -1047,80 +1035,59 @@ mylog (enum GNUNET_ErrorType kind,
1047 timeofday.tv_usec += (offset % 1000LL) * 1000LL; 1035 timeofday.tv_usec += (offset % 1000LL) * 1000LL;
1048 if (timeofday.tv_usec > 1000000LL) 1036 if (timeofday.tv_usec > 1000000LL)
1049 { 1037 {
1050 timeofday.tv_usec -= 1000000LL; 1038 timeofday.tv_usec -= 1000000LL;
1051 timeofday.tv_sec++; 1039 timeofday.tv_sec++;
1052 } 1040 }
1053 } 1041 }
1054 else 1042 else
1055 { 1043 {
1056 timeofday.tv_sec += offset / 1000LL; 1044 timeofday.tv_sec += offset / 1000LL;
1057 if (timeofday.tv_usec > - (offset % 1000LL) * 1000LL) 1045 if (timeofday.tv_usec > -(offset % 1000LL) * 1000LL)
1058 { 1046 {
1059 timeofday.tv_usec += (offset % 1000LL) * 1000LL; 1047 timeofday.tv_usec += (offset % 1000LL) * 1000LL;
1060 } 1048 }
1061 else 1049 else
1062 { 1050 {
1063 timeofday.tv_usec += 1000000LL + (offset % 1000LL) * 1000LL; 1051 timeofday.tv_usec += 1000000LL + (offset % 1000LL) * 1000LL;
1064 timeofday.tv_sec--; 1052 timeofday.tv_sec--;
1065 } 1053 }
1066 } 1054 }
1067 tmptr = localtime (&timeofday.tv_sec); 1055 tmptr = localtime (&timeofday.tv_sec);
1068 if (NULL == tmptr) 1056 if (NULL == tmptr)
1069 { 1057 {
1070 strcpy (date, 1058 strcpy (date, "localtime error");
1071 "localtime error");
1072 } 1059 }
1073 else 1060 else
1074 { 1061 {
1075 if (0 == 1062 if (0 == strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr))
1076 strftime (date2, 1063 abort ();
1077 DATE_STR_SIZE, 1064 if (0 > snprintf (date, sizeof (date), date2, timeofday.tv_usec))
1078 "%b %d %H:%M:%S-%%06u", 1065 abort ();
1079 tmptr))
1080 abort ();
1081 if (0 >
1082 snprintf (date,
1083 sizeof (date),
1084 date2,
1085 timeofday.tv_usec))
1086 abort ();
1087 } 1066 }
1088#endif 1067#endif
1089 VSNPRINTF (buf, 1068 VSNPRINTF (buf, size, message, va);
1090 size,
1091 message,
1092 va);
1093#if ! (defined(GNUNET_CULL_LOGGING) || TALER_WALLET_ONLY) 1069#if ! (defined(GNUNET_CULL_LOGGING) || TALER_WALLET_ONLY)
1094 if (NULL != tmptr) 1070 if (NULL != tmptr)
1095 (void) setup_log_file (tmptr); 1071 (void) setup_log_file (tmptr);
1096#endif 1072#endif
1097 if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) && 1073 if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
1098 (0 != last_bulk_time.abs_value_us) && 1074 (0 != last_bulk_time.abs_value_us) &&
1099 (0 == strncmp (buf, 1075 (0 == strncmp (buf, last_bulk, sizeof (last_bulk))))
1100 last_bulk,
1101 sizeof (last_bulk))))
1102 { 1076 {
1103 last_bulk_repeat++; 1077 last_bulk_repeat++;
1104 if ( (GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value_us > 1078 if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value_us >
1105 BULK_DELAY_THRESHOLD) || 1079 BULK_DELAY_THRESHOLD) ||
1106 (last_bulk_repeat > BULK_REPEAT_THRESHOLD) ) 1080 (last_bulk_repeat > BULK_REPEAT_THRESHOLD))
1107 flush_bulk (date); 1081 flush_bulk (date);
1108 return; 1082 return;
1109 } 1083 }
1110 flush_bulk (date); 1084 flush_bulk (date);
1111 strncpy (last_bulk, 1085 strncpy (last_bulk, buf, sizeof (last_bulk));
1112 buf,
1113 sizeof (last_bulk));
1114 last_bulk_repeat = 0; 1086 last_bulk_repeat = 0;
1115 last_bulk_kind = kind; 1087 last_bulk_kind = kind;
1116 last_bulk_time = GNUNET_TIME_absolute_get (); 1088 last_bulk_time = GNUNET_TIME_absolute_get ();
1117 strncpy (last_bulk_comp, 1089 strncpy (last_bulk_comp, comp, COMP_TRACK_SIZE);
1118 comp, 1090 output_message (kind, comp, date, buf);
1119 COMP_TRACK_SIZE);
1120 output_message (kind,
1121 comp,
1122 date,
1123 buf);
1124 } 1091 }
1125} 1092}
1126 1093
@@ -1133,8 +1100,7 @@ mylog (enum GNUNET_ErrorType kind,
1133 * @param ... arguments for format string 1100 * @param ... arguments for format string
1134 */ 1101 */
1135void 1102void
1136GNUNET_log_nocheck (enum GNUNET_ErrorType kind, 1103GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
1137 const char *message, ...)
1138{ 1104{
1139 va_list va; 1105 va_list va;
1140 1106
@@ -1154,8 +1120,10 @@ GNUNET_log_nocheck (enum GNUNET_ErrorType kind,
1154 * @param ... arguments for format string 1120 * @param ... arguments for format string
1155 */ 1121 */
1156void 1122void
1157GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind, const char *comp, 1123GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind,
1158 const char *message, ...) 1124 const char *comp,
1125 const char *message,
1126 ...)
1159{ 1127{
1160 va_list va; 1128 va_list va;
1161 char comp_w_pid[128]; 1129 char comp_w_pid[128];
@@ -1180,18 +1148,18 @@ const char *
1180GNUNET_error_type_to_string (enum GNUNET_ErrorType kind) 1148GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
1181{ 1149{
1182 if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0) 1150 if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0)
1183 return _("ERROR"); 1151 return _ ("ERROR");
1184 if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0) 1152 if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0)
1185 return _("WARNING"); 1153 return _ ("WARNING");
1186 if ((kind & GNUNET_ERROR_TYPE_MESSAGE) > 0) 1154 if ((kind & GNUNET_ERROR_TYPE_MESSAGE) > 0)
1187 return _("MESSAGE"); 1155 return _ ("MESSAGE");
1188 if ((kind & GNUNET_ERROR_TYPE_INFO) > 0) 1156 if ((kind & GNUNET_ERROR_TYPE_INFO) > 0)
1189 return _("INFO"); 1157 return _ ("INFO");
1190 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0) 1158 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0)
1191 return _("DEBUG"); 1159 return _ ("DEBUG");
1192 if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0) 1160 if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0)
1193 return _("NONE"); 1161 return _ ("NONE");
1194 return _("INVALID"); 1162 return _ ("INVALID");
1195} 1163}
1196 1164
1197 1165
@@ -1202,7 +1170,7 @@ GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
1202 * @return string form; will be overwritten by next call to GNUNET_h2s. 1170 * @return string form; will be overwritten by next call to GNUNET_h2s.
1203 */ 1171 */
1204const char * 1172const char *
1205GNUNET_h2s (const struct GNUNET_HashCode * hc) 1173GNUNET_h2s (const struct GNUNET_HashCode *hc)
1206{ 1174{
1207 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret; 1175 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1208 1176
@@ -1223,7 +1191,7 @@ GNUNET_h2s (const struct GNUNET_HashCode * hc)
1223 * @return string form; will be overwritten by next call to GNUNET_h2s. 1191 * @return string form; will be overwritten by next call to GNUNET_h2s.
1224 */ 1192 */
1225const char * 1193const char *
1226GNUNET_h2s2 (const struct GNUNET_HashCode * hc) 1194GNUNET_h2s2 (const struct GNUNET_HashCode *hc)
1227{ 1195{
1228 static struct GNUNET_CRYPTO_HashAsciiEncoded ret; 1196 static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1229 1197
@@ -1248,11 +1216,8 @@ GNUNET_p2s (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1248 static struct GNUNET_CRYPTO_HashAsciiEncoded ret; 1216 static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1249 struct GNUNET_HashCode hc; 1217 struct GNUNET_HashCode hc;
1250 1218
1251 GNUNET_CRYPTO_hash (p, 1219 GNUNET_CRYPTO_hash (p, sizeof (*p), &hc);
1252 sizeof (*p), 1220 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1253 &hc);
1254 GNUNET_CRYPTO_hash_to_enc (&hc,
1255 &ret);
1256 ret.encoding[6] = '\0'; 1221 ret.encoding[6] = '\0';
1257 return (const char *) ret.encoding; 1222 return (const char *) ret.encoding;
1258} 1223}
@@ -1273,11 +1238,8 @@ GNUNET_p2s2 (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1273 static struct GNUNET_CRYPTO_HashAsciiEncoded ret; 1238 static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1274 struct GNUNET_HashCode hc; 1239 struct GNUNET_HashCode hc;
1275 1240
1276 GNUNET_CRYPTO_hash (p, 1241 GNUNET_CRYPTO_hash (p, sizeof (*p), &hc);
1277 sizeof (*p), 1242 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1278 &hc);
1279 GNUNET_CRYPTO_hash_to_enc (&hc,
1280 &ret);
1281 ret.encoding[6] = '\0'; 1243 ret.encoding[6] = '\0';
1282 return (const char *) ret.encoding; 1244 return (const char *) ret.encoding;
1283} 1245}
@@ -1298,11 +1260,8 @@ GNUNET_e2s (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1298 static struct GNUNET_CRYPTO_HashAsciiEncoded ret; 1260 static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1299 struct GNUNET_HashCode hc; 1261 struct GNUNET_HashCode hc;
1300 1262
1301 GNUNET_CRYPTO_hash (p, 1263 GNUNET_CRYPTO_hash (p, sizeof (*p), &hc);
1302 sizeof (*p), 1264 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1303 &hc);
1304 GNUNET_CRYPTO_hash_to_enc (&hc,
1305 &ret);
1306 ret.encoding[6] = '\0'; 1265 ret.encoding[6] = '\0';
1307 return (const char *) ret.encoding; 1266 return (const char *) ret.encoding;
1308} 1267}
@@ -1323,11 +1282,8 @@ GNUNET_e2s2 (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1323 static struct GNUNET_CRYPTO_HashAsciiEncoded ret; 1282 static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1324 struct GNUNET_HashCode hc; 1283 struct GNUNET_HashCode hc;
1325 1284
1326 GNUNET_CRYPTO_hash (p, 1285 GNUNET_CRYPTO_hash (p, sizeof (*p), &hc);
1327 sizeof (*p), 1286 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1328 &hc);
1329 GNUNET_CRYPTO_hash_to_enc (&hc,
1330 &ret);
1331 ret.encoding[6] = '\0'; 1287 ret.encoding[6] = '\0';
1332 return (const char *) ret.encoding; 1288 return (const char *) ret.encoding;
1333} 1289}
@@ -1347,10 +1303,27 @@ GNUNET_sh2s (const struct GNUNET_ShortHashCode *shc)
1347{ 1303{
1348 static char buf[64]; 1304 static char buf[64];
1349 1305
1350 GNUNET_STRINGS_data_to_string (shc, 1306 GNUNET_STRINGS_data_to_string (shc, sizeof (*shc), buf, sizeof (buf));
1351 sizeof (*shc), 1307 buf[6] = '\0';
1352 buf, 1308 return (const char *) buf;
1353 sizeof (buf)); 1309}
1310
1311
1312/**
1313 * @ingroup logging
1314 * Convert a UUID to a string (for printing debug messages).
1315 * This is one of the very few calls in the entire API that is
1316 * NOT reentrant!
1317 *
1318 * @param uuid the UUID
1319 * @return string
1320 */
1321const char *
1322GNUNET_uuid2s (const struct GNUNET_Uuid *uuid)
1323{
1324 static char buf[32];
1325
1326 GNUNET_STRINGS_data_to_string (uuid, sizeof (*uuid), buf, sizeof (buf));
1354 buf[6] = '\0'; 1327 buf[6] = '\0';
1355 return (const char *) buf; 1328 return (const char *) buf;
1356} 1329}
@@ -1365,7 +1338,7 @@ GNUNET_sh2s (const struct GNUNET_ShortHashCode *shc)
1365 * @return string form; will be overwritten by next call to GNUNET_h2s_full. 1338 * @return string form; will be overwritten by next call to GNUNET_h2s_full.
1366 */ 1339 */
1367const char * 1340const char *
1368GNUNET_h2s_full (const struct GNUNET_HashCode * hc) 1341GNUNET_h2s_full (const struct GNUNET_HashCode *hc)
1369{ 1342{
1370 static struct GNUNET_CRYPTO_HashAsciiEncoded ret; 1343 static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1371 1344
@@ -1391,9 +1364,7 @@ GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
1391 if (NULL == pid) 1364 if (NULL == pid)
1392 return "NULL"; 1365 return "NULL";
1393 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key); 1366 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1394 strncpy (buf, 1367 strncpy (buf, ret, sizeof (buf) - 1);
1395 ret,
1396 sizeof (buf) - 1);
1397 GNUNET_free (ret); 1368 GNUNET_free (ret);
1398 buf[4] = '\0'; 1369 buf[4] = '\0';
1399 return buf; 1370 return buf;
@@ -1419,9 +1390,7 @@ GNUNET_i2s2 (const struct GNUNET_PeerIdentity *pid)
1419 if (NULL == pid) 1390 if (NULL == pid)
1420 return "NULL"; 1391 return "NULL";
1421 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key); 1392 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1422 strncpy (buf, 1393 strncpy (buf, ret, sizeof (buf) - 1);
1423 ret,
1424 sizeof (buf) - 1);
1425 GNUNET_free (ret); 1394 GNUNET_free (ret);
1426 buf[4] = '\0'; 1395 buf[4] = '\0';
1427 return buf; 1396 return buf;
@@ -1459,12 +1428,12 @@ GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid)
1459 * will be overwritten by next call to #GNUNET_a2s. 1428 * will be overwritten by next call to #GNUNET_a2s.
1460 */ 1429 */
1461const char * 1430const char *
1462GNUNET_a2s (const struct sockaddr *addr, 1431GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
1463 socklen_t addrlen)
1464{ 1432{
1465#ifndef WINDOWS 1433#ifndef WINDOWS
1466#define LEN GNUNET_MAX ((INET6_ADDRSTRLEN + 8), \ 1434#define LEN \
1467 (1 + sizeof (struct sockaddr_un) - sizeof (sa_family_t))) 1435 GNUNET_MAX ((INET6_ADDRSTRLEN + 8), \
1436 (1 + sizeof (struct sockaddr_un) - sizeof (sa_family_t)))
1468#else 1437#else
1469#define LEN (INET6_ADDRSTRLEN + 8) 1438#define LEN (INET6_ADDRSTRLEN + 8)
1470#endif 1439#endif
@@ -1477,24 +1446,18 @@ GNUNET_a2s (const struct sockaddr *addr,
1477 unsigned int off; 1446 unsigned int off;
1478 1447
1479 if (addr == NULL) 1448 if (addr == NULL)
1480 return _("unknown address"); 1449 return _ ("unknown address");
1481 switch (addr->sa_family) 1450 switch (addr->sa_family)
1482 { 1451 {
1483 case AF_INET: 1452 case AF_INET:
1484 if (addrlen != sizeof (struct sockaddr_in)) 1453 if (addrlen != sizeof (struct sockaddr_in))
1485 return "<invalid v4 address>"; 1454 return "<invalid v4 address>";
1486 v4 = (const struct sockaddr_in *) addr; 1455 v4 = (const struct sockaddr_in *) addr;
1487 inet_ntop (AF_INET, 1456 inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN);
1488 &v4->sin_addr,
1489 buf,
1490 INET_ADDRSTRLEN);
1491 if (0 == ntohs (v4->sin_port)) 1457 if (0 == ntohs (v4->sin_port))
1492 return buf; 1458 return buf;
1493 strcat (buf, ":"); 1459 strcat (buf, ":");
1494 GNUNET_snprintf (b2, 1460 GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v4->sin_port));
1495 sizeof (b2),
1496 "%u",
1497 ntohs (v4->sin_port));
1498 strcat (buf, b2); 1461 strcat (buf, b2);
1499 return buf; 1462 return buf;
1500 case AF_INET6: 1463 case AF_INET6:
@@ -1502,19 +1465,12 @@ GNUNET_a2s (const struct sockaddr *addr,
1502 return "<invalid v4 address>"; 1465 return "<invalid v4 address>";
1503 v6 = (const struct sockaddr_in6 *) addr; 1466 v6 = (const struct sockaddr_in6 *) addr;
1504 buf[0] = '['; 1467 buf[0] = '[';
1505 inet_ntop (AF_INET6, 1468 inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN);
1506 &v6->sin6_addr,
1507 &buf[1],
1508 INET6_ADDRSTRLEN);
1509 if (0 == ntohs (v6->sin6_port)) 1469 if (0 == ntohs (v6->sin6_port))
1510 return &buf[1]; 1470 return &buf[1];
1511 strcat (buf, "]:"); 1471 strcat (buf, "]:");
1512 GNUNET_snprintf (b2, 1472 GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v6->sin6_port));
1513 sizeof (b2), 1473 strcat (buf, b2);
1514 "%u",
1515 ntohs (v6->sin6_port));
1516 strcat (buf,
1517 b2);
1518 return buf; 1474 return buf;
1519 case AF_UNIX: 1475 case AF_UNIX:
1520 if (addrlen <= sizeof (sa_family_t)) 1476 if (addrlen <= sizeof (sa_family_t))
@@ -1532,7 +1488,7 @@ GNUNET_a2s (const struct sockaddr *addr,
1532 &un->sun_path[off]); 1488 &un->sun_path[off]);
1533 return buf; 1489 return buf;
1534 default: 1490 default:
1535 return _("invalid address"); 1491 return _ ("invalid address");
1536 } 1492 }
1537} 1493}
1538 1494
@@ -1546,13 +1502,14 @@ GNUNET_a2s (const struct sockaddr *addr,
1546 */ 1502 */
1547void 1503void
1548GNUNET_log_config_missing (enum GNUNET_ErrorType kind, 1504GNUNET_log_config_missing (enum GNUNET_ErrorType kind,
1549 const char *section, 1505 const char *section,
1550 const char *option) 1506 const char *option)
1551{ 1507{
1552 GNUNET_log (kind, 1508 GNUNET_log (kind,
1553 _("Configuration fails to specify option `%s' in section `%s'!\n"), 1509 _ (
1554 option, 1510 "Configuration fails to specify option `%s' in section `%s'!\n"),
1555 section); 1511 option,
1512 section);
1556} 1513}
1557 1514
1558 1515
@@ -1566,13 +1523,17 @@ GNUNET_log_config_missing (enum GNUNET_ErrorType kind,
1566 */ 1523 */
1567void 1524void
1568GNUNET_log_config_invalid (enum GNUNET_ErrorType kind, 1525GNUNET_log_config_invalid (enum GNUNET_ErrorType kind,
1569 const char *section, 1526 const char *section,
1570 const char *option, 1527 const char *option,
1571 const char *required) 1528 const char *required)
1572{ 1529{
1573 GNUNET_log (kind, 1530 GNUNET_log (
1574 _("Configuration specifies invalid value for option `%s' in section `%s': %s\n"), 1531 kind,
1575 option, section, required); 1532 _ (
1533 "Configuration specifies invalid value for option `%s' in section `%s': %s\n"),
1534 option,
1535 section,
1536 required);
1576} 1537}
1577 1538
1578 1539
@@ -1633,15 +1594,14 @@ GNUNET_async_scope_get (struct GNUNET_AsyncScopeSave *scope_ret)
1633/** 1594/**
1634 * Initializer 1595 * Initializer
1635 */ 1596 */
1636void __attribute__ ((constructor)) 1597void __attribute__ ((constructor)) GNUNET_util_cl_init ()
1637GNUNET_util_cl_init ()
1638{ 1598{
1639 GNUNET_stderr = stderr; 1599 GNUNET_stderr = stderr;
1640#ifdef MINGW 1600#ifdef MINGW
1641 GNInitWinEnv (NULL); 1601 GNInitWinEnv (NULL);
1642#endif 1602#endif
1643#if WINDOWS 1603#if WINDOWS
1644 if (!InitializeCriticalSectionAndSpinCount (&output_message_cs, 0x00000400)) 1604 if (! InitializeCriticalSectionAndSpinCount (&output_message_cs, 0x00000400))
1645 GNUNET_abort_ (); 1605 GNUNET_abort_ ();
1646#endif 1606#endif
1647} 1607}
@@ -1650,8 +1610,7 @@ GNUNET_util_cl_init ()
1650/** 1610/**
1651 * Destructor 1611 * Destructor
1652 */ 1612 */
1653void __attribute__ ((destructor)) 1613void __attribute__ ((destructor)) GNUNET_util_cl_fini ()
1654GNUNET_util_cl_fini ()
1655{ 1614{
1656#if WINDOWS 1615#if WINDOWS
1657 DeleteCriticalSection (&output_message_cs); 1616 DeleteCriticalSection (&output_message_cs);
diff --git a/src/util/container_multiuuidmap.c b/src/util/container_multiuuidmap.c
new file mode 100644
index 000000000..49eb64cfe
--- /dev/null
+++ b/src/util/container_multiuuidmap.c
@@ -0,0 +1,1015 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008, 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20/**
21 * @file util/container_multiuuidmap.c
22 * @brief hash map for UUIDs where the same key may be present multiple times
23 * @author Christian Grothoff
24 */
25
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define LOG(kind, ...) \
30 GNUNET_log_from (kind, "util-container-multiuuidmap", __VA_ARGS__)
31
32/**
33 * Maximum recursion depth for callbacks of
34 * #GNUNET_CONTAINER_multihashmap_get_multiple() themselve s
35 * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
36 * Should be totally excessive, but if violated we die.
37 */
38#define NEXT_CACHE_SIZE 16
39
40
41/**
42 * An entry in the hash map with the full key.
43 */
44struct BigMapEntry
45{
46
47 /**
48 * Value of the entry.
49 */
50 void *value;
51
52 /**
53 * If there is a hash collision, we create a linked list.
54 */
55 struct BigMapEntry *next;
56
57 /**
58 * Key for the entry.
59 */
60 struct GNUNET_Uuid key;
61};
62
63
64/**
65 * An entry in the hash map with just a pointer to the key.
66 */
67struct SmallMapEntry
68{
69
70 /**
71 * Value of the entry.
72 */
73 void *value;
74
75 /**
76 * If there is a hash collision, we create a linked list.
77 */
78 struct SmallMapEntry *next;
79
80 /**
81 * Key for the entry.
82 */
83 const struct GNUNET_Uuid *key;
84};
85
86
87/**
88 * Entry in the map.
89 */
90union MapEntry
91{
92 /**
93 * Variant used if map entries only contain a pointer to the key.
94 */
95 struct SmallMapEntry *sme;
96
97 /**
98 * Variant used if map entries contain the full key.
99 */
100 struct BigMapEntry *bme;
101};
102
103
104/**
105 * Internal representation of the hash map.
106 */
107struct GNUNET_CONTAINER_MultiUuidmap
108{
109 /**
110 * All of our buckets.
111 */
112 union MapEntry *map;
113
114 /**
115 * Number of entries in the map.
116 */
117 unsigned int size;
118
119 /**
120 * Length of the "map" array.
121 */
122 unsigned int map_length;
123
124 /**
125 * #GNUNET_NO if the map entries are of type 'struct BigMapEntry',
126 * #GNUNET_YES if the map entries are of type 'struct SmallMapEntry'.
127 */
128 int use_small_entries;
129
130 /**
131 * Counts the destructive modifications (grow, remove)
132 * to the map, so that iterators can check if they are still valid.
133 */
134 unsigned int modification_counter;
135
136 /**
137 * Map entries indicating iteration positions currently
138 * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
139 * Only used up to @e next_cache_off.
140 */
141 union MapEntry next_cache[NEXT_CACHE_SIZE];
142
143 /**
144 * Offset of @e next_cache entries in use, must be smaller
145 * than #NEXT_CACHE_SIZE.
146 */
147 unsigned int next_cache_off;
148};
149
150
151/**
152 * Cursor into a multiuuidmap.
153 * Allows to enumerate elements asynchronously.
154 */
155struct GNUNET_CONTAINER_MultiUuidmapIterator
156{
157 /**
158 * Position in the bucket 'idx'
159 */
160 union MapEntry me;
161
162 /**
163 * Current bucket index.
164 */
165 unsigned int idx;
166
167 /**
168 * Modification counter as observed on the map when the iterator
169 * was created.
170 */
171 unsigned int modification_counter;
172
173 /**
174 * Map that we are iterating over.
175 */
176 const struct GNUNET_CONTAINER_MultiUuidmap *map;
177};
178
179
180/**
181 * Create a multi hash map.
182 *
183 * @param len initial size (map will grow as needed)
184 * @param do_not_copy_keys #GNUNET_NO is always safe and should be used by default;
185 * #GNUNET_YES means that on 'put', the 'key' does not have
186 * to be copied as the destination of the pointer is
187 * guaranteed to be life as long as the value is stored in
188 * the hashmap. This can significantly reduce memory
189 * consumption, but of course is also a recipie for
190 * heap corruption if the assumption is not true. Only
191 * use this if (1) memory use is important in this case and
192 * (2) you have triple-checked that the invariant holds
193 * @return NULL on error
194 */
195struct GNUNET_CONTAINER_MultiUuidmap *
196GNUNET_CONTAINER_multiuuidmap_create (unsigned int len, int do_not_copy_keys)
197{
198 struct GNUNET_CONTAINER_MultiUuidmap *map;
199
200 GNUNET_assert (len > 0);
201 map = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmap);
202 map->map = GNUNET_malloc_large (len * sizeof (union MapEntry));
203 if (NULL == map->map)
204 {
205 GNUNET_free (map);
206 return NULL;
207 }
208 map->map_length = len;
209 map->use_small_entries = do_not_copy_keys;
210 return map;
211}
212
213
214/**
215 * Destroy a hash map. Will not free any values
216 * stored in the hash map!
217 *
218 * @param map the map
219 */
220void
221GNUNET_CONTAINER_multiuuidmap_destroy (
222 struct GNUNET_CONTAINER_MultiUuidmap *map)
223{
224 GNUNET_assert (0 == map->next_cache_off);
225 for (unsigned int i = 0; i < map->map_length; i++)
226 {
227 union MapEntry me;
228
229 me = map->map[i];
230 if (map->use_small_entries)
231 {
232 struct SmallMapEntry *sme;
233 struct SmallMapEntry *nxt;
234
235 nxt = me.sme;
236 while (NULL != (sme = nxt))
237 {
238 nxt = sme->next;
239 GNUNET_free (sme);
240 }
241 me.sme = NULL;
242 }
243 else
244 {
245 struct BigMapEntry *bme;
246 struct BigMapEntry *nxt;
247
248 nxt = me.bme;
249 while (NULL != (bme = nxt))
250 {
251 nxt = bme->next;
252 GNUNET_free (bme);
253 }
254 me.bme = NULL;
255 }
256 }
257 GNUNET_free (map->map);
258 GNUNET_free (map);
259}
260
261
262/**
263 * Compute the index of the bucket for the given key.
264 *
265 * @param map hash map for which to compute the index
266 * @param key what key should the index be computed for
267 * @return offset into the "map" array of "map"
268 */
269static unsigned int
270idx_of (const struct GNUNET_CONTAINER_MultiUuidmap *map,
271 const struct GNUNET_Uuid *key)
272{
273 unsigned int kx;
274
275 GNUNET_assert (NULL != map);
276 GNUNET_memcpy (&kx, key, sizeof (kx));
277 return kx % map->map_length;
278}
279
280
281/**
282 * Get the number of key-value pairs in the map.
283 *
284 * @param map the map
285 * @return the number of key value pairs
286 */
287unsigned int
288GNUNET_CONTAINER_multiuuidmap_size (
289 const struct GNUNET_CONTAINER_MultiUuidmap *map)
290{
291 return map->size;
292}
293
294
295/**
296 * Given a key find a value in the map matching the key.
297 *
298 * @param map the map
299 * @param key what to look for
300 * @return NULL if no value was found; note that
301 * this is indistinguishable from values that just
302 * happen to be NULL; use "contains" to test for
303 * key-value pairs with value NULL
304 */
305void *
306GNUNET_CONTAINER_multiuuidmap_get (
307 const struct GNUNET_CONTAINER_MultiUuidmap *map,
308 const struct GNUNET_Uuid *key)
309{
310 union MapEntry me;
311
312 me = map->map[idx_of (map, key)];
313 if (map->use_small_entries)
314 {
315 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
316 if (0 == GNUNET_memcmp (key, sme->key))
317 return sme->value;
318 }
319 else
320 {
321 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
322 if (0 == GNUNET_memcmp (key, &bme->key))
323 return bme->value;
324 }
325 return NULL;
326}
327
328
329/**
330 * Iterate over all entries in the map.
331 *
332 * @param map the map
333 * @param it function to call on each entry
334 * @param it_cls extra argument to @a it
335 * @return the number of key value pairs processed,
336 * #GNUNET_SYSERR if it aborted iteration
337 */
338int
339GNUNET_CONTAINER_multiuuidmap_iterate (
340 struct GNUNET_CONTAINER_MultiUuidmap *map,
341 GNUNET_CONTAINER_MultiUuidmapIterator it,
342 void *it_cls)
343{
344 int count;
345 union MapEntry me;
346 union MapEntry *ce;
347 struct GNUNET_Uuid kc;
348
349 count = 0;
350 GNUNET_assert (NULL != map);
351 ce = &map->next_cache[map->next_cache_off];
352 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
353 for (unsigned int i = 0; i < map->map_length; i++)
354 {
355 me = map->map[i];
356 if (map->use_small_entries)
357 {
358 struct SmallMapEntry *sme;
359
360 ce->sme = me.sme;
361 while (NULL != (sme = ce->sme))
362 {
363 ce->sme = sme->next;
364 if ((NULL != it) && (GNUNET_OK != it (it_cls, sme->key, sme->value)))
365 {
366 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
367 return GNUNET_SYSERR;
368 }
369 count++;
370 }
371 }
372 else
373 {
374 struct BigMapEntry *bme;
375
376 ce->bme = me.bme;
377 while (NULL != (bme = ce->bme))
378 {
379 ce->bme = bme->next;
380 if (NULL != it)
381 {
382 kc = bme->key;
383 if (GNUNET_OK != it (it_cls, &kc, bme->value))
384 {
385 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
386 return GNUNET_SYSERR;
387 }
388 }
389 count++;
390 }
391 }
392 }
393 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
394 return count;
395}
396
397
398/**
399 * We are about to free() the @a bme, make sure it is not in
400 * the list of next values for any iterator in the @a map's next_cache.
401 *
402 * @param map the map to check
403 * @param bme the entry that is about to be free'd
404 */
405static void
406update_next_cache_bme (struct GNUNET_CONTAINER_MultiUuidmap *map,
407 const struct BigMapEntry *bme)
408{
409 for (unsigned int i = 0; i < map->next_cache_off; i++)
410 if (map->next_cache[i].bme == bme)
411 map->next_cache[i].bme = bme->next;
412}
413
414
415/**
416 * We are about to free() the @a sme, make sure it is not in
417 * the list of next values for any iterator in the @a map's next_cache.
418 *
419 * @param map the map to check
420 * @param sme the entry that is about to be free'd
421 */
422static void
423update_next_cache_sme (struct GNUNET_CONTAINER_MultiUuidmap *map,
424 const struct SmallMapEntry *sme)
425{
426 for (unsigned int i = 0; i < map->next_cache_off; i++)
427 if (map->next_cache[i].sme == sme)
428 map->next_cache[i].sme = sme->next;
429}
430
431
432/**
433 * Remove the given key-value pair from the map. Note that if the
434 * key-value pair is in the map multiple times, only one of the pairs
435 * will be removed.
436 *
437 * @param map the map
438 * @param key key of the key-value pair
439 * @param value value of the key-value pair
440 * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
441 * is not in the map
442 */
443int
444GNUNET_CONTAINER_multiuuidmap_remove (struct GNUNET_CONTAINER_MultiUuidmap *map,
445 const struct GNUNET_Uuid *key,
446 const void *value)
447{
448 union MapEntry me;
449 unsigned int i;
450
451 map->modification_counter++;
452 i = idx_of (map, key);
453 me = map->map[i];
454 if (map->use_small_entries)
455 {
456 struct SmallMapEntry *p = NULL;
457
458 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
459 {
460 if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
461 {
462 if (NULL == p)
463 map->map[i].sme = sme->next;
464 else
465 p->next = sme->next;
466 update_next_cache_sme (map, sme);
467 GNUNET_free (sme);
468 map->size--;
469 return GNUNET_YES;
470 }
471 p = sme;
472 }
473 }
474 else
475 {
476 struct BigMapEntry *p = NULL;
477
478 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
479 {
480 if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
481 {
482 if (NULL == p)
483 map->map[i].bme = bme->next;
484 else
485 p->next = bme->next;
486 update_next_cache_bme (map, bme);
487 GNUNET_free (bme);
488 map->size--;
489 return GNUNET_YES;
490 }
491 p = bme;
492 }
493 }
494 return GNUNET_NO;
495}
496
497
498/**
499 * Remove all entries for the given key from the map.
500 * Note that the values would not be "freed".
501 *
502 * @param map the map
503 * @param key identifies values to be removed
504 * @return number of values removed
505 */
506int
507GNUNET_CONTAINER_multiuuidmap_remove_all (
508 struct GNUNET_CONTAINER_MultiUuidmap *map,
509 const struct GNUNET_Uuid *key)
510{
511 union MapEntry me;
512 unsigned int i;
513 int ret;
514
515 map->modification_counter++;
516
517 ret = 0;
518 i = idx_of (map, key);
519 me = map->map[i];
520 if (map->use_small_entries)
521 {
522 struct SmallMapEntry *sme;
523 struct SmallMapEntry *p;
524
525 p = NULL;
526 sme = me.sme;
527 while (NULL != sme)
528 {
529 if (0 == GNUNET_memcmp (key, sme->key))
530 {
531 if (NULL == p)
532 map->map[i].sme = sme->next;
533 else
534 p->next = sme->next;
535 update_next_cache_sme (map, sme);
536 GNUNET_free (sme);
537 map->size--;
538 if (NULL == p)
539 sme = map->map[i].sme;
540 else
541 sme = p->next;
542 ret++;
543 }
544 else
545 {
546 p = sme;
547 sme = sme->next;
548 }
549 }
550 }
551 else
552 {
553 struct BigMapEntry *bme;
554 struct BigMapEntry *p;
555
556 p = NULL;
557 bme = me.bme;
558 while (NULL != bme)
559 {
560 if (0 == GNUNET_memcmp (key, &bme->key))
561 {
562 if (NULL == p)
563 map->map[i].bme = bme->next;
564 else
565 p->next = bme->next;
566 update_next_cache_bme (map, bme);
567 GNUNET_free (bme);
568 map->size--;
569 if (NULL == p)
570 bme = map->map[i].bme;
571 else
572 bme = p->next;
573 ret++;
574 }
575 else
576 {
577 p = bme;
578 bme = bme->next;
579 }
580 }
581 }
582 return ret;
583}
584
585
586/**
587 * Check if the map contains any value under the given
588 * key (including values that are NULL).
589 *
590 * @param map the map
591 * @param key the key to test if a value exists for it
592 * @return #GNUNET_YES if such a value exists,
593 * #GNUNET_NO if not
594 */
595int
596GNUNET_CONTAINER_multiuuidmap_contains (
597 const struct GNUNET_CONTAINER_MultiUuidmap *map,
598 const struct GNUNET_Uuid *key)
599{
600 union MapEntry me;
601
602 me = map->map[idx_of (map, key)];
603 if (map->use_small_entries)
604 {
605 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
606 if (0 == GNUNET_memcmp (key, sme->key))
607 return GNUNET_YES;
608 }
609 else
610 {
611 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
612 if (0 == GNUNET_memcmp (key, &bme->key))
613 return GNUNET_YES;
614 }
615 return GNUNET_NO;
616}
617
618
619/**
620 * Check if the map contains the given value under the given
621 * key.
622 *
623 * @param map the map
624 * @param key the key to test if a value exists for it
625 * @param value value to test for
626 * @return #GNUNET_YES if such a value exists,
627 * #GNUNET_NO if not
628 */
629int
630GNUNET_CONTAINER_multiuuidmap_contains_value (
631 const struct GNUNET_CONTAINER_MultiUuidmap *map,
632 const struct GNUNET_Uuid *key,
633 const void *value)
634{
635 union MapEntry me;
636
637 me = map->map[idx_of (map, key)];
638 if (map->use_small_entries)
639 {
640 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
641 if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
642 return GNUNET_YES;
643 }
644 else
645 {
646 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
647 if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
648 return GNUNET_YES;
649 }
650 return GNUNET_NO;
651}
652
653
654/**
655 * Grow the given map to a more appropriate size.
656 *
657 * @param map the hash map to grow
658 */
659static void
660grow (struct GNUNET_CONTAINER_MultiUuidmap *map)
661{
662 union MapEntry *old_map;
663 union MapEntry *new_map;
664 unsigned int old_len;
665 unsigned int new_len;
666 unsigned int idx;
667
668 old_map = map->map;
669 old_len = map->map_length;
670 new_len = old_len * 2;
671 if (0 == new_len) /* 2^31 * 2 == 0 */
672 new_len = old_len; /* never use 0 */
673 if (new_len == old_len)
674 return; /* nothing changed */
675 new_map = GNUNET_malloc_large (new_len * sizeof (union MapEntry));
676 if (NULL == new_map)
677 return; /* grow not possible */
678 map->modification_counter++;
679 map->map_length = new_len;
680 map->map = new_map;
681 for (unsigned int i = 0; i < old_len; i++)
682 {
683 if (map->use_small_entries)
684 {
685 struct SmallMapEntry *sme;
686
687 while (NULL != (sme = old_map[i].sme))
688 {
689 old_map[i].sme = sme->next;
690 idx = idx_of (map, sme->key);
691 sme->next = new_map[idx].sme;
692 new_map[idx].sme = sme;
693 }
694 }
695 else
696 {
697 struct BigMapEntry *bme;
698
699 while (NULL != (bme = old_map[i].bme))
700 {
701 old_map[i].bme = bme->next;
702 idx = idx_of (map, &bme->key);
703 bme->next = new_map[idx].bme;
704 new_map[idx].bme = bme;
705 }
706 }
707 }
708 GNUNET_free (old_map);
709}
710
711
712/**
713 * Store a key-value pair in the map.
714 *
715 * @param map the map
716 * @param key key to use
717 * @param value value to use
718 * @param opt options for put
719 * @return #GNUNET_OK on success,
720 * #GNUNET_NO if a value was replaced (with REPLACE)
721 * #GNUNET_SYSERR if #GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
722 * value already exists
723 */
724int
725GNUNET_CONTAINER_multiuuidmap_put (struct GNUNET_CONTAINER_MultiUuidmap *map,
726 const struct GNUNET_Uuid *key,
727 void *value,
728 enum GNUNET_CONTAINER_MultiHashMapOption opt)
729{
730 union MapEntry me;
731 unsigned int i;
732
733 i = idx_of (map, key);
734 if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
735 (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
736 {
737 me = map->map[i];
738 if (map->use_small_entries)
739 {
740 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
741 if (0 == GNUNET_memcmp (key, sme->key))
742 {
743 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
744 return GNUNET_SYSERR;
745 sme->value = value;
746 return GNUNET_NO;
747 }
748 }
749 else
750 {
751 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
752 if (0 == GNUNET_memcmp (key, &bme->key))
753 {
754 if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
755 return GNUNET_SYSERR;
756 bme->value = value;
757 return GNUNET_NO;
758 }
759 }
760 }
761 if (map->size / 3 >= map->map_length / 4)
762 {
763 grow (map);
764 i = idx_of (map, key);
765 }
766 if (map->use_small_entries)
767 {
768 struct SmallMapEntry *sme;
769
770 sme = GNUNET_new (struct SmallMapEntry);
771 sme->key = key;
772 sme->value = value;
773 sme->next = map->map[i].sme;
774 map->map[i].sme = sme;
775 }
776 else
777 {
778 struct BigMapEntry *bme;
779
780 bme = GNUNET_new (struct BigMapEntry);
781 bme->key = *key;
782 bme->value = value;
783 bme->next = map->map[i].bme;
784 map->map[i].bme = bme;
785 }
786 map->size++;
787 return GNUNET_OK;
788}
789
790
791/**
792 * Iterate over all entries in the map that match a particular key.
793 *
794 * @param map the map
795 * @param key key that the entries must correspond to
796 * @param it function to call on each entry
797 * @param it_cls extra argument to @a it
798 * @return the number of key value pairs processed,
799 * #GNUNET_SYSERR if it aborted iteration
800 */
801int
802GNUNET_CONTAINER_multiuuidmap_get_multiple (
803 struct GNUNET_CONTAINER_MultiUuidmap *map,
804 const struct GNUNET_Uuid *key,
805 GNUNET_CONTAINER_MultiUuidmapIterator it,
806 void *it_cls)
807{
808 int count;
809 union MapEntry me;
810 union MapEntry *ce;
811
812 ce = &map->next_cache[map->next_cache_off];
813 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
814 count = 0;
815 me = map->map[idx_of (map, key)];
816 if (map->use_small_entries)
817 {
818 struct SmallMapEntry *sme;
819
820 ce->sme = me.sme;
821 while (NULL != (sme = ce->sme))
822 {
823 ce->sme = sme->next;
824 if (0 != GNUNET_memcmp (key, sme->key))
825 continue;
826 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
827 {
828 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
829 return GNUNET_SYSERR;
830 }
831 count++;
832 }
833 }
834 else
835 {
836 struct BigMapEntry *bme;
837
838 ce->bme = me.bme;
839 while (NULL != (bme = ce->bme))
840 {
841 ce->bme = bme->next;
842 if (0 != GNUNET_memcmp (key, &bme->key))
843 continue;
844 if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
845 {
846 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
847 return GNUNET_SYSERR;
848 }
849 count++;
850 }
851 }
852 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
853 return count;
854}
855
856
857/**
858 * @ingroup hashmap
859 * Call @a it on a random value from the map, or not at all
860 * if the map is empty. Note that this function has linear
861 * complexity (in the size of the map).
862 *
863 * @param map the map
864 * @param it function to call on a random entry
865 * @param it_cls extra argument to @a it
866 * @return the number of key value pairs processed, zero or one.
867 */
868unsigned int
869GNUNET_CONTAINER_multiuuidmap_get_random (
870 const struct GNUNET_CONTAINER_MultiUuidmap *map,
871 GNUNET_CONTAINER_MultiUuidmapIterator it,
872 void *it_cls)
873{
874 unsigned int off;
875 union MapEntry me;
876
877 if (0 == map->size)
878 return 0;
879 if (NULL == it)
880 return 1;
881 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
882 for (unsigned int idx = 0; idx < map->map_length; idx++)
883 {
884 me = map->map[idx];
885 if (map->use_small_entries)
886 {
887 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
888 {
889 if (0 == off)
890 {
891 if (GNUNET_OK != it (it_cls, sme->key, sme->value))
892 return GNUNET_SYSERR;
893 return 1;
894 }
895 off--;
896 }
897 }
898 else
899 {
900 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
901 {
902 if (0 == off)
903 {
904 if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
905 return GNUNET_SYSERR;
906 return 1;
907 }
908 off--;
909 }
910 }
911 }
912 GNUNET_break (0);
913 return GNUNET_SYSERR;
914}
915
916
917/**
918 * Create an iterator for a multiuuidmap.
919 * The iterator can be used to retrieve all the elements in the multiuuidmap
920 * one by one, without having to handle all elements at once (in contrast to
921 * #GNUNET_CONTAINER_multiuuidmap_iterate). Note that the iterator can not be
922 * used anymore if elements have been removed from 'map' after the creation of
923 * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
924 * result in skipped or repeated elements.
925 *
926 * @param map the map to create an iterator for
927 * @return an iterator over the given multiuuidmap 'map'
928 */
929struct GNUNET_CONTAINER_MultiUuidmapIterator *
930GNUNET_CONTAINER_multiuuidmap_iterator_create (
931 const struct GNUNET_CONTAINER_MultiUuidmap *map)
932{
933 struct GNUNET_CONTAINER_MultiUuidmapIterator *iter;
934
935 iter = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmapIterator);
936 iter->map = map;
937 iter->modification_counter = map->modification_counter;
938 iter->me = map->map[0];
939 return iter;
940}
941
942
943/**
944 * Retrieve the next element from the hash map at the iterator's position.
945 * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
946 * are not modified.
947 * This operation is only allowed if no elements have been removed from the
948 * multiuuidmap since the creation of 'iter', and the map has not been destroyed.
949 * Adding elements may result in repeating or skipping elements.
950 *
951 * @param iter the iterator to get the next element from
952 * @param key pointer to store the key in, can be NULL
953 * @param value pointer to store the value in, can be NULL
954 * @return #GNUNET_YES we returned an element,
955 * #GNUNET_NO if we are out of elements
956 */
957int
958GNUNET_CONTAINER_multiuuidmap_iterator_next (
959 struct GNUNET_CONTAINER_MultiUuidmapIterator *iter,
960 struct GNUNET_Uuid *key,
961 const void **value)
962{
963 /* make sure the map has not been modified */
964 GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
965
966 /* look for the next entry, skipping empty buckets */
967 while (1)
968 {
969 if (iter->idx >= iter->map->map_length)
970 return GNUNET_NO;
971 if (GNUNET_YES == iter->map->use_small_entries)
972 {
973 if (NULL != iter->me.sme)
974 {
975 if (NULL != key)
976 *key = *iter->me.sme->key;
977 if (NULL != value)
978 *value = iter->me.sme->value;
979 iter->me.sme = iter->me.sme->next;
980 return GNUNET_YES;
981 }
982 }
983 else
984 {
985 if (NULL != iter->me.bme)
986 {
987 if (NULL != key)
988 *key = iter->me.bme->key;
989 if (NULL != value)
990 *value = iter->me.bme->value;
991 iter->me.bme = iter->me.bme->next;
992 return GNUNET_YES;
993 }
994 }
995 iter->idx += 1;
996 if (iter->idx < iter->map->map_length)
997 iter->me = iter->map->map[iter->idx];
998 }
999}
1000
1001
1002/**
1003 * Destroy a multiuuidmap iterator.
1004 *
1005 * @param iter the iterator to destroy
1006 */
1007void
1008GNUNET_CONTAINER_multiuuidmap_iterator_destroy (
1009 struct GNUNET_CONTAINER_MultiUuidmapIterator *iter)
1010{
1011 GNUNET_free (iter);
1012}
1013
1014
1015/* end of container_multiuuidmap.c */