diff options
Diffstat (limited to 'src/util')
64 files changed, 3935 insertions, 2642 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am index cded34d..8414ef2 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -37,6 +37,7 @@ noinst_PROGRAMS = \ gnunet-config-diff \ test_common_logging_dummy + gnunet_config_diff_SOURCES = \ gnunet-config-diff.c gnunet_config_diff_LDADD = \ @@ -98,23 +99,26 @@ libgnunetutil_la_SOURCES = \ service.c \ signal.c \ strings.c \ - time.c + time.c \ + speedup.c libgnunetutil_la_LIBADD = \ $(GCLIBADD) $(WINLIB) \ $(LIBGCRYPT_LIBS) \ $(LTLIBICONV) \ - -lltdl -lz $(XLIB) + -lltdl -lz -lunistring $(XLIB) libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ - -version-info 7:0:0 + -version-info 8:0:0 bin_PROGRAMS = \ gnunet-service-resolver \ - gnunet-resolver + gnunet-resolver \ + gnunet-rsa + gnunet_service_resolver_SOURCES = \ gnunet-service-resolver.c @@ -133,6 +137,15 @@ gnunet_resolver_LDADD = \ gnunet_resolver_DEPENDENCIES = \ libgnunetutil.la + +gnunet_rsa_SOURCES = \ + gnunet-rsa.c +gnunet_rsa_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_rsa_DEPENDENCIES = \ + libgnunetutil.la + plugin_LTLIBRARIES = \ libgnunet_plugin_test.la @@ -183,6 +196,7 @@ check_PROGRAMS = \ test_resolver_api \ test_scheduler \ test_scheduler_delay \ + test_server_mst_interrupt \ test_server \ test_server_disconnect \ test_server_with_client \ @@ -190,6 +204,7 @@ check_PROGRAMS = \ test_service \ test_strings \ test_time \ + test_speedup \ $(BENCHMARKS) \ test_os_start_process \ test_common_logging_runtime_loglevels @@ -390,6 +405,11 @@ test_scheduler_delay_SOURCES = \ test_scheduler_delay_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la +test_server_mst_interrupt_SOURCES = \ + test_server_mst_interrupt.c +test_server_mst_interrupt_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + test_server_SOURCES = \ test_server.c test_server_LDADD = \ @@ -426,6 +446,11 @@ test_time_SOURCES = \ test_time_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la +test_speedup_SOURCES = \ + test_speedup.c +test_speedup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + perf_crypto_hash_SOURCES = \ perf_crypto_hash.c perf_crypto_hash_LDADD = \ @@ -437,4 +462,5 @@ EXTRA_DIST = \ test_program_data.conf \ test_pseudonym_data.conf \ test_resolver_api_data.conf \ - test_service_data.conf + test_service_data.conf \ + test_speedup_data.conf diff --git a/src/util/Makefile.in b/src/util/Makefile.in index 3c82fbf..5ea0157 100644 --- a/src/util/Makefile.in +++ b/src/util/Makefile.in @@ -40,7 +40,7 @@ target_triplet = @target@ noinst_PROGRAMS = gnunet-config-diff$(EXEEXT) \ test_common_logging_dummy$(EXEEXT) bin_PROGRAMS = gnunet-service-resolver$(EXEEXT) \ - gnunet-resolver$(EXEEXT) + gnunet-resolver$(EXEEXT) gnunet-rsa$(EXEEXT) check_PROGRAMS = test_bio$(EXEEXT) test_client$(EXEEXT) \ test_common_allocation$(EXEEXT) test_common_endian$(EXEEXT) \ test_common_logging$(EXEEXT) test_configuration$(EXEEXT) \ @@ -62,10 +62,12 @@ check_PROGRAMS = test_bio$(EXEEXT) test_client$(EXEEXT) \ test_peer$(EXEEXT) test_plugin$(EXEEXT) test_program$(EXEEXT) \ test_pseudonym$(EXEEXT) test_resolver_api$(EXEEXT) \ test_scheduler$(EXEEXT) test_scheduler_delay$(EXEEXT) \ - test_server$(EXEEXT) test_server_disconnect$(EXEEXT) \ + test_server_mst_interrupt$(EXEEXT) test_server$(EXEEXT) \ + test_server_disconnect$(EXEEXT) \ test_server_with_client$(EXEEXT) $(am__EXEEXT_1) \ test_service$(EXEEXT) test_strings$(EXEEXT) test_time$(EXEEXT) \ - $(am__EXEEXT_2) test_os_start_process$(EXEEXT) \ + test_speedup$(EXEEXT) $(am__EXEEXT_2) \ + test_os_start_process$(EXEEXT) \ test_common_logging_runtime_loglevels$(EXEEXT) subdir = src/util DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ @@ -140,7 +142,7 @@ am_libgnunetutil_la_OBJECTS = bandwidth.lo bio.lo client.lo \ os_installation.lo os_network.lo os_priority.lo peer.lo \ plugin.lo program.lo pseudonym.lo resolver_api.lo scheduler.lo \ server.lo server_mst.lo server_nc.lo server_tc.lo service.lo \ - signal.lo strings.lo time.lo + signal.lo strings.lo time.lo speedup.lo libgnunetutil_la_OBJECTS = $(am_libgnunetutil_la_OBJECTS) libgnunetutil_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ @@ -162,6 +164,8 @@ am_gnunet_config_diff_OBJECTS = gnunet-config-diff.$(OBJEXT) gnunet_config_diff_OBJECTS = $(am_gnunet_config_diff_OBJECTS) am_gnunet_resolver_OBJECTS = gnunet-resolver.$(OBJEXT) gnunet_resolver_OBJECTS = $(am_gnunet_resolver_OBJECTS) +am_gnunet_rsa_OBJECTS = gnunet-rsa.$(OBJEXT) +gnunet_rsa_OBJECTS = $(am_gnunet_rsa_OBJECTS) am_gnunet_service_resolver_OBJECTS = \ gnunet-service-resolver.$(OBJEXT) gnunet_service_resolver_OBJECTS = \ @@ -345,6 +349,12 @@ am_test_server_disconnect_OBJECTS = test_server_disconnect.$(OBJEXT) test_server_disconnect_OBJECTS = $(am_test_server_disconnect_OBJECTS) test_server_disconnect_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la +am_test_server_mst_interrupt_OBJECTS = \ + test_server_mst_interrupt.$(OBJEXT) +test_server_mst_interrupt_OBJECTS = \ + $(am_test_server_mst_interrupt_OBJECTS) +test_server_mst_interrupt_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la am_test_server_with_client_OBJECTS = \ test_server_with_client.$(OBJEXT) test_server_with_client_OBJECTS = \ @@ -360,6 +370,9 @@ test_server_with_client_unix_DEPENDENCIES = \ am_test_service_OBJECTS = test_service.$(OBJEXT) test_service_OBJECTS = $(am_test_service_OBJECTS) test_service_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_speedup_OBJECTS = test_speedup.$(OBJEXT) +test_speedup_OBJECTS = $(am_test_speedup_OBJECTS) +test_speedup_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_strings_OBJECTS = test_strings.$(OBJEXT) test_strings_OBJECTS = $(am_test_strings_OBJECTS) test_strings_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la @@ -411,9 +424,9 @@ am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ $(libgnunetutil_la_SOURCES) $(libgnunetutilwin_la_SOURCES) \ $(gnunet_config_diff_SOURCES) $(gnunet_resolver_SOURCES) \ - $(gnunet_service_resolver_SOURCES) $(perf_crypto_hash_SOURCES) \ - $(test_bio_SOURCES) $(test_client_SOURCES) \ - $(test_common_allocation_SOURCES) \ + $(gnunet_rsa_SOURCES) $(gnunet_service_resolver_SOURCES) \ + $(perf_crypto_hash_SOURCES) $(test_bio_SOURCES) \ + $(test_client_SOURCES) $(test_common_allocation_SOURCES) \ $(test_common_endian_SOURCES) $(test_common_logging_SOURCES) \ $(test_common_logging_dummy_SOURCES) \ $(test_common_logging_runtime_loglevels_SOURCES) \ @@ -439,17 +452,18 @@ SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ $(test_resolver_api_SOURCES) $(test_scheduler_SOURCES) \ $(test_scheduler_delay_SOURCES) $(test_server_SOURCES) \ $(test_server_disconnect_SOURCES) \ + $(test_server_mst_interrupt_SOURCES) \ $(test_server_with_client_SOURCES) \ $(test_server_with_client_unix_SOURCES) \ - $(test_service_SOURCES) $(test_strings_SOURCES) \ - $(test_time_SOURCES) + $(test_service_SOURCES) $(test_speedup_SOURCES) \ + $(test_strings_SOURCES) $(test_time_SOURCES) DIST_SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ $(libgnunetutil_la_SOURCES) \ $(am__libgnunetutilwin_la_SOURCES_DIST) \ $(gnunet_config_diff_SOURCES) $(gnunet_resolver_SOURCES) \ - $(gnunet_service_resolver_SOURCES) $(perf_crypto_hash_SOURCES) \ - $(test_bio_SOURCES) $(test_client_SOURCES) \ - $(test_common_allocation_SOURCES) \ + $(gnunet_rsa_SOURCES) $(gnunet_service_resolver_SOURCES) \ + $(perf_crypto_hash_SOURCES) $(test_bio_SOURCES) \ + $(test_client_SOURCES) $(test_common_allocation_SOURCES) \ $(test_common_endian_SOURCES) $(test_common_logging_SOURCES) \ $(test_common_logging_dummy_SOURCES) \ $(test_common_logging_runtime_loglevels_SOURCES) \ @@ -475,10 +489,11 @@ DIST_SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ $(test_resolver_api_SOURCES) $(test_scheduler_SOURCES) \ $(test_scheduler_delay_SOURCES) $(test_server_SOURCES) \ $(test_server_disconnect_SOURCES) \ + $(test_server_mst_interrupt_SOURCES) \ $(test_server_with_client_SOURCES) \ $(test_server_with_client_unix_SOURCES) \ - $(test_service_SOURCES) $(test_strings_SOURCES) \ - $(test_time_SOURCES) + $(test_service_SOURCES) $(test_speedup_SOURCES) \ + $(test_strings_SOURCES) $(test_time_SOURCES) DATA = $(dist_pkgcfg_DATA) $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags @@ -540,6 +555,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ @@ -573,6 +589,7 @@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ +MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ @@ -780,17 +797,18 @@ libgnunetutil_la_SOURCES = \ service.c \ signal.c \ strings.c \ - time.c + time.c \ + speedup.c libgnunetutil_la_LIBADD = \ $(GCLIBADD) $(WINLIB) \ $(LIBGCRYPT_LIBS) \ $(LTLIBICONV) \ - -lltdl -lz $(XLIB) + -lltdl -lz -lunistring $(XLIB) libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ - -version-info 7:0:0 + -version-info 8:0:0 gnunet_service_resolver_SOURCES = \ gnunet-service-resolver.c @@ -812,6 +830,16 @@ gnunet_resolver_LDADD = \ gnunet_resolver_DEPENDENCIES = \ libgnunetutil.la +gnunet_rsa_SOURCES = \ + gnunet-rsa.c + +gnunet_rsa_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_rsa_DEPENDENCIES = \ + libgnunetutil.la + plugin_LTLIBRARIES = \ libgnunet_plugin_test.la @@ -1054,6 +1082,12 @@ test_scheduler_delay_SOURCES = \ test_scheduler_delay_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la +test_server_mst_interrupt_SOURCES = \ + test_server_mst_interrupt.c + +test_server_mst_interrupt_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + test_server_SOURCES = \ test_server.c @@ -1096,6 +1130,12 @@ test_time_SOURCES = \ test_time_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la +test_speedup_SOURCES = \ + test_speedup.c + +test_speedup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + perf_crypto_hash_SOURCES = \ perf_crypto_hash.c @@ -1107,7 +1147,8 @@ EXTRA_DIST = \ test_program_data.conf \ test_pseudonym_data.conf \ test_resolver_api_data.conf \ - test_service_data.conf + test_service_data.conf \ + test_speedup_data.conf all: all-am @@ -1289,6 +1330,9 @@ gnunet-config-diff$(EXEEXT): $(gnunet_config_diff_OBJECTS) $(gnunet_config_diff_ gnunet-resolver$(EXEEXT): $(gnunet_resolver_OBJECTS) $(gnunet_resolver_DEPENDENCIES) @rm -f gnunet-resolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_resolver_OBJECTS) $(gnunet_resolver_LDADD) $(LIBS) +gnunet-rsa$(EXEEXT): $(gnunet_rsa_OBJECTS) $(gnunet_rsa_DEPENDENCIES) + @rm -f gnunet-rsa$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_rsa_OBJECTS) $(gnunet_rsa_LDADD) $(LIBS) gnunet-service-resolver$(EXEEXT): $(gnunet_service_resolver_OBJECTS) $(gnunet_service_resolver_DEPENDENCIES) @rm -f gnunet-service-resolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_resolver_OBJECTS) $(gnunet_service_resolver_LDADD) $(LIBS) @@ -1418,6 +1462,9 @@ test_server$(EXEEXT): $(test_server_OBJECTS) $(test_server_DEPENDENCIES) test_server_disconnect$(EXEEXT): $(test_server_disconnect_OBJECTS) $(test_server_disconnect_DEPENDENCIES) @rm -f test_server_disconnect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_server_disconnect_OBJECTS) $(test_server_disconnect_LDADD) $(LIBS) +test_server_mst_interrupt$(EXEEXT): $(test_server_mst_interrupt_OBJECTS) $(test_server_mst_interrupt_DEPENDENCIES) + @rm -f test_server_mst_interrupt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_server_mst_interrupt_OBJECTS) $(test_server_mst_interrupt_LDADD) $(LIBS) test_server_with_client$(EXEEXT): $(test_server_with_client_OBJECTS) $(test_server_with_client_DEPENDENCIES) @rm -f test_server_with_client$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_server_with_client_OBJECTS) $(test_server_with_client_LDADD) $(LIBS) @@ -1427,6 +1474,9 @@ test_server_with_client_unix$(EXEEXT): $(test_server_with_client_unix_OBJECTS) $ test_service$(EXEEXT): $(test_service_OBJECTS) $(test_service_DEPENDENCIES) @rm -f test_service$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_service_OBJECTS) $(test_service_LDADD) $(LIBS) +test_speedup$(EXEEXT): $(test_speedup_OBJECTS) $(test_speedup_DEPENDENCIES) + @rm -f test_speedup$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_speedup_OBJECTS) $(test_speedup_LDADD) $(LIBS) test_strings$(EXEEXT): $(test_strings_OBJECTS) $(test_strings_DEPENDENCIES) @rm -f test_strings$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_strings_OBJECTS) $(test_strings_LDADD) $(LIBS) @@ -1466,6 +1516,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt_helpers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-config-diff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-resolver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-rsa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-resolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load.Plo@am__quote@ @@ -1486,6 +1537,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_tc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/service.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speedup.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_bio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_client.Po@am__quote@ @@ -1529,9 +1581,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_scheduler_delay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_disconnect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_mst_interrupt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_with_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_with_client_unix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_service.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_speedup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_strings.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@ diff --git a/src/util/client.c b/src/util/client.c index 2f09a90..c29b48e 100644 --- a/src/util/client.c +++ b/src/util/client.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2006, 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -26,7 +26,6 @@ * Generic TCP code for reliable, record-oriented TCP * connections between clients and service providers. */ - #include "platform.h" #include "gnunet_common.h" #include "gnunet_client_lib.h" @@ -34,7 +33,6 @@ #include "gnunet_server_lib.h" #include "gnunet_scheduler_lib.h" -#define DEBUG_CLIENT GNUNET_EXTRA_LOGGING /** * How often do we re-try tranmsitting requests before giving up? @@ -53,7 +51,7 @@ struct GNUNET_CLIENT_TransmitHandle /** * Connection state. */ - struct GNUNET_CLIENT_Connection *sock; + struct GNUNET_CLIENT_Connection *client; /** * Function to call to get the data for transmission. @@ -113,7 +111,7 @@ struct TransmitGetResponseContext /** * Client handle. */ - struct GNUNET_CLIENT_Connection *sock; + struct GNUNET_CLIENT_Connection *client; /** * Message to transmit; do not free, allocated @@ -147,9 +145,9 @@ struct GNUNET_CLIENT_Connection { /** - * the socket handle, NULL if not live + * The connection handle, NULL if not live */ - struct GNUNET_CONNECTION_Handle *sock; + struct GNUNET_CONNECTION_Handle *connection; /** * Our configuration. @@ -250,6 +248,79 @@ struct GNUNET_CLIENT_Connection /** + * Try connecting to the server using UNIX domain sockets. + * + * @param service_name name of service to connect to + * @param cfg configuration to use + * @return NULL on error, connection to UNIX otherwise + */ +static struct GNUNET_CONNECTION_Handle * +try_unixpath (const char *service_name, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ +#if AF_UNIX + struct GNUNET_CONNECTION_Handle *connection; + char *unixpath; + + unixpath = NULL; + if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && + (0 < strlen (unixpath))) + { + /* We have a non-NULL unixpath, need to validate it */ + connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath); + if (NULL != connection) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n", + unixpath); + GNUNET_free (unixpath); + return connection; + } + } + GNUNET_free_non_null (unixpath); +#endif + return NULL; +} + + +/** + * Try connecting to the server using UNIX domain sockets. + * + * @param service_name name of service to connect to + * @param cfg configuration to use + * @return GNUNET_OK if the configuration is valid, GNUNET_SYSERR if not + */ +static int +test_service_configuration (const char *service_name, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + int ret = GNUNET_SYSERR; + char *hostname = NULL; + unsigned long long port; +#if AF_UNIX + char *unixpath = NULL; + + if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && + (0 < strlen (unixpath))) + ret = GNUNET_OK; + GNUNET_free_non_null (unixpath); +#endif + + if ( (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) && + (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)) && + (port <= 65535) && (0 != port) && + (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", + &hostname)) && + (0 != strlen (hostname)) ) + ret = GNUNET_OK; + GNUNET_free_non_null (hostname); + return ret; +} + + +/** * Try to connect to the service. * * @param service_name name of service to connect to @@ -261,34 +332,18 @@ static struct GNUNET_CONNECTION_Handle * do_connect (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int attempt) { - struct GNUNET_CONNECTION_Handle *sock; + struct GNUNET_CONNECTION_Handle *connection; char *hostname; - char *unixpath; unsigned long long port; - sock = NULL; -#if AF_UNIX + connection = NULL; if (0 == (attempt % 2)) { - /* on even rounds, try UNIX */ - unixpath = NULL; - if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) /* We have a non-NULL unixpath, does that mean it's valid? */ - { - sock = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath); - if (sock != NULL) - { -#if DEBUG_CLIENT - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n", - unixpath); -#endif - GNUNET_free (unixpath); - return sock; - } - } - GNUNET_free_non_null (unixpath); + /* on even rounds, try UNIX first */ + connection = try_unixpath (service_name, cfg); + if (NULL != connection) + return connection; } -#endif - if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) { @@ -319,42 +374,21 @@ do_connect (const char *service_name, port = 0; hostname = NULL; } - if (port == 0) + if (0 == port) { -#if AF_UNIX - if (0 != (attempt % 2)) - { - /* try UNIX */ - unixpath = NULL; - if ((GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", - &unixpath)) && - (0 < strlen (unixpath))) - { - sock = - GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath); - if (sock != NULL) - { - GNUNET_free (unixpath); - GNUNET_free_non_null (hostname); - return sock; - } - } - GNUNET_free_non_null (unixpath); - } -#endif -#if DEBUG_CLIENT + /* if port is 0, try UNIX */ + connection = try_unixpath (service_name, cfg); + if (NULL != connection) + return connection; LOG (GNUNET_ERROR_TYPE_DEBUG, "Port is 0 for service `%s', UNIXPATH did not work, returning NULL!\n", service_name); -#endif GNUNET_free_non_null (hostname); return NULL; } - - sock = GNUNET_CONNECTION_create_from_connect (cfg, hostname, port); + connection = GNUNET_CONNECTION_create_from_connect (cfg, hostname, port); GNUNET_free (hostname); - return sock; + return connection; } @@ -369,17 +403,21 @@ struct GNUNET_CLIENT_Connection * GNUNET_CLIENT_connect (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg) { - struct GNUNET_CLIENT_Connection *ret; - struct GNUNET_CONNECTION_Handle *sock; - - sock = do_connect (service_name, cfg, 0); - ret = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection)); - ret->attempts = 1; - ret->sock = sock; - ret->service_name = GNUNET_strdup (service_name); - ret->cfg = cfg; - ret->back_off = GNUNET_TIME_UNIT_MILLISECONDS; - return ret; + struct GNUNET_CLIENT_Connection *client; + struct GNUNET_CONNECTION_Handle *connection; + + if (GNUNET_OK != + test_service_configuration (service_name, + cfg)) + return NULL; + connection = do_connect (service_name, cfg, 0); + client = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection)); + client->attempts = 1; + client->connection = connection; + client->service_name = GNUNET_strdup (service_name); + client->cfg = cfg; + client->back_off = GNUNET_TIME_UNIT_MILLISECONDS; + return client; } @@ -394,57 +432,57 @@ GNUNET_CLIENT_connect (const char *service_name, * destroyed (unless, of course, there is an error with the server in * which case the message may still be lost). * - * @param finish_pending_write should a transmission already passed to the - * handle be completed? - * @param sock handle to the service connection + * @param client handle to the service connection */ void -GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock, - int finish_pending_write) +GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client) { - if (sock->in_receive == GNUNET_YES) + if (GNUNET_YES == client->in_receive) { - GNUNET_CONNECTION_receive_cancel (sock->sock); - sock->in_receive = GNUNET_NO; + GNUNET_CONNECTION_receive_cancel (client->connection); + client->in_receive = GNUNET_NO; } - if (sock->th != NULL) + if (NULL != client->th) { - GNUNET_CLIENT_notify_transmit_ready_cancel (sock->th); - sock->th = NULL; + GNUNET_CLIENT_notify_transmit_ready_cancel (client->th); + client->th = NULL; } - if (NULL != sock->sock) + if (NULL != client->connection) { - GNUNET_CONNECTION_destroy (sock->sock, finish_pending_write); - sock->sock = NULL; + GNUNET_CONNECTION_destroy (client->connection); + client->connection = NULL; } - if (sock->receive_task != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != client->receive_task) { - GNUNET_SCHEDULER_cancel (sock->receive_task); - sock->receive_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel (client->receive_task); + client->receive_task = GNUNET_SCHEDULER_NO_TASK; } - if (sock->tag != NULL) + if (NULL != client->tag) { - GNUNET_free (sock->tag); - sock->tag = NULL; + GNUNET_free (client->tag); + client->tag = NULL; } - sock->receiver_handler = NULL; - GNUNET_array_grow (sock->received_buf, sock->received_size, 0); - GNUNET_free (sock->service_name); - GNUNET_free (sock); + client->receiver_handler = NULL; + GNUNET_array_grow (client->received_buf, client->received_size, 0); + GNUNET_free (client->service_name); + GNUNET_free (client); } /** - * Check if message is complete + * Check if message is complete. Sets the "msg_complete" member + * in the client struct. + * + * @param client connection with the buffer to check */ static void -check_complete (struct GNUNET_CLIENT_Connection *conn) +check_complete (struct GNUNET_CLIENT_Connection *client) { - if ((conn->received_pos >= sizeof (struct GNUNET_MessageHeader)) && - (conn->received_pos >= - ntohs (((const struct GNUNET_MessageHeader *) conn->received_buf)-> + if ((client->received_pos >= sizeof (struct GNUNET_MessageHeader)) && + (client->received_pos >= + ntohs (((const struct GNUNET_MessageHeader *) client->received_buf)-> size))) - conn->msg_complete = GNUNET_YES; + client->msg_complete = GNUNET_YES; } @@ -464,54 +502,51 @@ static void receive_helper (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode) { - struct GNUNET_CLIENT_Connection *conn = cls; + struct GNUNET_CLIENT_Connection *client = cls; struct GNUNET_TIME_Relative remaining; GNUNET_CLIENT_MessageHandler receive_handler; void *receive_handler_cls; - GNUNET_assert (conn->msg_complete == GNUNET_NO); - conn->in_receive = GNUNET_NO; - if ((available == 0) || (conn->sock == NULL) || (errCode != 0)) + GNUNET_assert (GNUNET_NO == client->msg_complete); + GNUNET_assert (GNUNET_YES == client->in_receive); + client->in_receive = GNUNET_NO; + if ((0 == available) || (NULL == client->connection) || (0 != errCode)) { /* signal timeout! */ -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, - "Timeout in receive_helper, available %u, conn->sock %s, errCode `%s'\n", - (unsigned int) available, conn->sock == NULL ? "NULL" : "non-NULL", + "Timeout in receive_helper, available %u, client->connection %s, errCode `%s'\n", + (unsigned int) available, NULL == client->connection ? "NULL" : "non-NULL", STRERROR (errCode)); -#endif - if (NULL != (receive_handler = conn->receiver_handler)) + if (NULL != (receive_handler = client->receiver_handler)) { - receive_handler_cls = conn->receiver_handler_cls; - conn->receiver_handler = NULL; + receive_handler_cls = client->receiver_handler_cls; + client->receiver_handler = NULL; receive_handler (receive_handler_cls, NULL); } return; } - /* FIXME: optimize for common fast case where buf contains the * entire message and we need no copying... */ - /* slow path: append to array */ - if (conn->received_size < conn->received_pos + available) - GNUNET_array_grow (conn->received_buf, conn->received_size, - conn->received_pos + available); - memcpy (&conn->received_buf[conn->received_pos], buf, available); - conn->received_pos += available; - check_complete (conn); + if (client->received_size < client->received_pos + available) + GNUNET_array_grow (client->received_buf, client->received_size, + client->received_pos + available); + memcpy (&client->received_buf[client->received_pos], buf, available); + client->received_pos += available; + check_complete (client); /* check for timeout */ - remaining = GNUNET_TIME_absolute_get_remaining (conn->receive_timeout); - if (remaining.rel_value == 0) + remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout); + if (0 == remaining.rel_value) { /* signal timeout! */ - if (NULL != conn->receiver_handler) - conn->receiver_handler (conn->receiver_handler_cls, NULL); + if (NULL != client->receiver_handler) + client->receiver_handler (client->receiver_handler_cls, NULL); return; } /* back to receive -- either for more data or to call callback! */ - GNUNET_CLIENT_receive (conn, conn->receiver_handler, - conn->receiver_handler_cls, remaining); + GNUNET_CLIENT_receive (client, client->receiver_handler, + client->receiver_handler_cls, remaining); } @@ -524,30 +559,28 @@ receive_helper (void *cls, const void *buf, size_t available, static void receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_CLIENT_Connection *sock = cls; - GNUNET_CLIENT_MessageHandler handler = sock->receiver_handler; + struct GNUNET_CLIENT_Connection *client = cls; + GNUNET_CLIENT_MessageHandler handler = client->receiver_handler; const struct GNUNET_MessageHeader *cmsg = - (const struct GNUNET_MessageHeader *) sock->received_buf; - void *handler_cls = sock->receiver_handler_cls; + (const struct GNUNET_MessageHeader *) client->received_buf; + void *handler_cls = client->receiver_handler_cls; uint16_t msize = ntohs (cmsg->size); char mbuf[msize]; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf; -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u and size %u\n", ntohs (cmsg->type), msize); -#endif - sock->receive_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_assert (GNUNET_YES == sock->msg_complete); - GNUNET_assert (sock->received_pos >= msize); + client->receive_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (GNUNET_YES == client->msg_complete); + GNUNET_assert (client->received_pos >= msize); memcpy (msg, cmsg, msize); - memmove (sock->received_buf, &sock->received_buf[msize], - sock->received_pos - msize); - sock->received_pos -= msize; - sock->msg_complete = GNUNET_NO; - sock->receiver_handler = NULL; - check_complete (sock); - if (handler != NULL) + memmove (client->received_buf, &client->received_buf[msize], + client->received_pos - msize); + client->received_pos -= msize; + client->msg_complete = GNUNET_NO; + client->receiver_handler = NULL; + check_complete (client); + if (NULL != handler) handler (handler_cls, msg); } @@ -555,17 +588,17 @@ receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) /** * Read from the service. * - * @param sock the service + * @param client the service * @param handler function to call with the message * @param handler_cls closure for handler * @param timeout how long to wait until timing out */ void -GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *sock, +GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client, GNUNET_CLIENT_MessageHandler handler, void *handler_cls, struct GNUNET_TIME_Relative timeout) { - if (sock->sock == NULL) + if (NULL == client->connection) { /* already disconnected, fail instantly! */ GNUNET_break (0); /* this should not happen in well-written code! */ @@ -573,23 +606,21 @@ GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *sock, handler (handler_cls, NULL); return; } - sock->receiver_handler = handler; - sock->receiver_handler_cls = handler_cls; - sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); - if (GNUNET_YES == sock->msg_complete) + client->receiver_handler = handler; + client->receiver_handler_cls = handler_cls; + client->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (GNUNET_YES == client->msg_complete) { - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->receive_task); - sock->receive_task = GNUNET_SCHEDULER_add_now (&receive_task, sock); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->receive_task); + client->receive_task = GNUNET_SCHEDULER_add_now (&receive_task, client); } else { - GNUNET_assert (sock->in_receive == GNUNET_NO); - sock->in_receive = GNUNET_YES; -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "calling GNUNET_CONNECTION_receive\n"); -#endif - GNUNET_CONNECTION_receive (sock->sock, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, - timeout, &receive_helper, sock); + GNUNET_assert (GNUNET_NO == client->in_receive); + client->in_receive = GNUNET_YES; + GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, + timeout, &receive_helper, client); } } @@ -614,25 +645,23 @@ service_test_error (GNUNET_SCHEDULER_Task task, void *task_cls) static void confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg) { - struct GNUNET_CLIENT_Connection *conn = cls; + struct GNUNET_CLIENT_Connection *client = cls; /* We may want to consider looking at the reply in more * detail in the future, for example, is this the * correct service? FIXME! */ - if (msg != NULL) + if (NULL != msg) { -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Received confirmation that service is running.\n"); -#endif - GNUNET_SCHEDULER_add_continuation (conn->test_cb, conn->test_cb_cls, + GNUNET_SCHEDULER_add_continuation (client->test_cb, client->test_cb_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } else { - service_test_error (conn->test_cb, conn->test_cb_cls); + service_test_error (client->test_cb, client->test_cb_cls); } - GNUNET_CLIENT_disconnect (conn, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); } @@ -648,27 +677,23 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg) static size_t write_test (void *cls, size_t size, void *buf) { - struct GNUNET_CLIENT_Connection *conn = cls; + struct GNUNET_CLIENT_Connection *client = cls; struct GNUNET_MessageHeader *msg; if (size < sizeof (struct GNUNET_MessageHeader)) { -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failure to transmit TEST request.\n")); -#endif - service_test_error (conn->test_cb, conn->test_cb_cls); - GNUNET_CLIENT_disconnect (conn, GNUNET_NO); + service_test_error (client->test_cb, client->test_cb_cls); + GNUNET_CLIENT_disconnect (client); return 0; /* client disconnected */ } -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "TEST"); -#endif msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); - GNUNET_CLIENT_receive (conn, &confirm_handler, conn, + GNUNET_CLIENT_receive (client, &confirm_handler, client, GNUNET_TIME_absolute_get_remaining - (conn->test_deadline)); + (client->test_deadline)); return sizeof (struct GNUNET_MessageHeader); } @@ -695,12 +720,10 @@ GNUNET_CLIENT_service_test (const char *service, char *hostname; unsigned long long port; struct GNUNET_NETWORK_Handle *sock; - struct GNUNET_CLIENT_Connection *conn; + struct GNUNET_CLIENT_Connection *client; -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n", service); -#endif #ifdef AF_UNIX { /* probe UNIX support */ @@ -720,7 +743,7 @@ GNUNET_CLIENT_service_test (const char *service, else { sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); - if (sock != NULL) + if (NULL != sock) { memset (&s_un, 0, sizeof (s_un)); s_un.sun_family = AF_UNIX; @@ -786,7 +809,7 @@ GNUNET_CLIENT_service_test (const char *service, s_in.sin_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); - if (sock != NULL) + if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in, @@ -820,7 +843,7 @@ GNUNET_CLIENT_service_test (const char *service, s_in6.sin6_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0); - if (sock != NULL) + if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in6, @@ -852,8 +875,8 @@ GNUNET_CLIENT_service_test (const char *service, GNUNET_free_non_null (hostname); /* non-localhost, try 'connect' method */ - conn = GNUNET_CLIENT_connect (service, cfg); - if (conn == NULL) + client = GNUNET_CLIENT_connect (service, cfg); + if (NULL == client) { LOG (GNUNET_ERROR_TYPE_INFO, _("Could not connect to service `%s', must not be running.\n"), @@ -861,20 +884,18 @@ GNUNET_CLIENT_service_test (const char *service, service_test_error (task, task_cls); return; } - conn->test_cb = task; - conn->test_cb_cls = task_cls; - conn->test_deadline = GNUNET_TIME_relative_to_absolute (timeout); - - if (NULL == - GNUNET_CLIENT_notify_transmit_ready (conn, - sizeof (struct GNUNET_MessageHeader), - timeout, GNUNET_YES, &write_test, - conn)) + client->test_cb = task; + client->test_cb_cls = task_cls; + client->test_deadline = GNUNET_TIME_relative_to_absolute (timeout); + if (NULL == GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + timeout, GNUNET_YES, &write_test, + client)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failure to transmit request to service `%s'\n"), service); service_test_error (task, task_cls); - GNUNET_CLIENT_disconnect (conn, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); return; } } @@ -908,47 +929,35 @@ client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct GNUNET_TIME_Relative delay; th->reconnect_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { -#if DEBUG_CLIENT - LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed due to shutdown.\n"); -#endif - th->sock->th = NULL; - th->notify (th->notify_cls, 0, NULL); - GNUNET_free (th); - return; - } - th->sock->sock = - do_connect (th->sock->service_name, th->sock->cfg, th->sock->attempts++); - if (NULL == th->sock->sock) + th->client->connection = + do_connect (th->client->service_name, th->client->cfg, th->client->attempts++); + if (NULL == th->client->connection) { /* could happen if we're out of sockets */ delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining - (th->timeout), th->sock->back_off); - th->sock->back_off = + (th->timeout), th->client->back_off); + th->client->back_off = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply - (th->sock->back_off, 2), + (th->client->back_off, 2), GNUNET_TIME_UNIT_SECONDS); -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, trying again in %llums.\n", MAX_ATTEMPTS - th->attempts_left, (unsigned long long) delay.rel_value); -#endif th->reconnect_task = GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); return; } th->th = - GNUNET_CONNECTION_notify_transmit_ready (th->sock->sock, th->size, + GNUNET_CONNECTION_notify_transmit_ready (th->client->connection, th->size, GNUNET_TIME_absolute_get_remaining (th->timeout), &client_notify, th); - if (th->th == NULL) + if (NULL == th->th) { GNUNET_break (0); - th->sock->th = NULL; + th->client->th = NULL; th->notify (th->notify_cls, 0, NULL); GNUNET_free (th); return; @@ -969,49 +978,47 @@ static size_t client_notify (void *cls, size_t size, void *buf) { struct GNUNET_CLIENT_TransmitHandle *th = cls; + struct GNUNET_CLIENT_Connection *client = th->client; size_t ret; struct GNUNET_TIME_Relative delay; th->th = NULL; - th->sock->th = NULL; - if (buf == NULL) + client->th = NULL; + if (NULL == buf) { delay = GNUNET_TIME_absolute_get_remaining (th->timeout); delay.rel_value /= 2; - if ((0 != - (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) || - (GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) || + if ((GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) || (delay.rel_value < 1)) { -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, giving up.\n", MAX_ATTEMPTS - th->attempts_left); -#endif GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL)); GNUNET_free (th); return 0; } /* auto-retry */ -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect to `%s', automatically trying again.\n", - th->sock->service_name); -#endif - GNUNET_CONNECTION_destroy (th->sock->sock, GNUNET_NO); - th->sock->sock = NULL; - delay = GNUNET_TIME_relative_min (delay, th->sock->back_off); - th->sock->back_off = + client->service_name); + if (GNUNET_YES == client->in_receive) + { + GNUNET_CONNECTION_receive_cancel (client->connection); + client->in_receive = GNUNET_NO; + } + GNUNET_CONNECTION_destroy (client->connection); + client->connection = NULL; + delay = GNUNET_TIME_relative_min (delay, client->back_off); + client->back_off = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply - (th->sock->back_off, 2), + (client->back_off, 2), GNUNET_TIME_UNIT_SECONDS); -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, trying again in %llums.\n", MAX_ATTEMPTS - th->attempts_left, (unsigned long long) delay.rel_value); -#endif - th->sock->th = th; + client->th = th; th->reconnect_task = GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); return 0; @@ -1028,7 +1035,7 @@ client_notify (void *cls, size_t size, void *buf) * are free in the transmission buffer. May call the notify * method immediately if enough space is available. * - * @param sock connection to the service + * @param client connection to the service * @param size number of bytes to send * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? @@ -1043,7 +1050,7 @@ client_notify (void *cls, size_t size, void *buf) * a handle if the notify callback was queued (can be used to cancel) */ struct GNUNET_CLIENT_TransmitHandle * -GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock, +GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client, size_t size, struct GNUNET_TIME_Relative timeout, int auto_retry, @@ -1052,7 +1059,7 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock, { struct GNUNET_CLIENT_TransmitHandle *th; - if (NULL != sock->th) + if (NULL != client->th) { /* If this breaks, you most likley called this function twice without waiting * for completion or canceling the request */ @@ -1060,31 +1067,31 @@ GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock, return NULL; } th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle)); - th->sock = sock; + th->client = client; th->size = size; th->timeout = GNUNET_TIME_relative_to_absolute (timeout); th->auto_retry = auto_retry; th->notify = notify; th->notify_cls = notify_cls; th->attempts_left = MAX_ATTEMPTS; - sock->th = th; - if (sock->sock == NULL) + client->th = th; + if (NULL == client->connection) { th->reconnect_task = - GNUNET_SCHEDULER_add_delayed (sock->back_off, &client_delayed_retry, + GNUNET_SCHEDULER_add_delayed (client->back_off, &client_delayed_retry, th); } else { th->th = - GNUNET_CONNECTION_notify_transmit_ready (sock->sock, size, timeout, + GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, timeout, &client_notify, th); if (NULL == th->th) { GNUNET_break (0); GNUNET_free (th); - sock->th = NULL; + client->th = NULL; return NULL; } } @@ -1101,7 +1108,7 @@ void GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle *th) { - if (th->reconnect_task != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != th->reconnect_task) { GNUNET_assert (NULL == th->th); GNUNET_SCHEDULER_cancel (th->reconnect_task); @@ -1112,7 +1119,7 @@ GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle GNUNET_assert (NULL != th->th); GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th); } - th->sock->th = NULL; + th->client->th = NULL; GNUNET_free (th); } @@ -1134,14 +1141,12 @@ transmit_for_response (void *cls, size_t size, void *buf) struct TransmitGetResponseContext *tc = cls; uint16_t msize; - tc->sock->tag = NULL; + tc->client->tag = NULL; msize = ntohs (tc->hdr->size); if (NULL == buf) { -#if DEBUG_CLIENT LOG (GNUNET_ERROR_TYPE_DEBUG, _("Could not submit request, not expecting to receive a response.\n")); -#endif if (NULL != tc->rn) tc->rn (tc->rn_cls, NULL); GNUNET_free (tc); @@ -1149,7 +1154,7 @@ transmit_for_response (void *cls, size_t size, void *buf) } GNUNET_assert (size >= msize); memcpy (buf, tc->hdr, msize); - GNUNET_CLIENT_receive (tc->sock, tc->rn, tc->rn_cls, + GNUNET_CLIENT_receive (tc->client, tc->rn, tc->rn_cls, GNUNET_TIME_absolute_get_remaining (tc->timeout)); GNUNET_free (tc); return msize; @@ -1163,7 +1168,7 @@ transmit_for_response (void *cls, size_t size, void *buf) * will be called with a "NULL" response (in which * case the connection should probably be destroyed). * - * @param sock connection to use + * @param client connection to use * @param hdr message to transmit * @param timeout when to give up (for both transmission * and for waiting for a response) @@ -1178,7 +1183,7 @@ transmit_for_response (void *cls, size_t size, void *buf) * is already pending */ int -GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *sock, +GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *client, const struct GNUNET_MessageHeader *hdr, struct GNUNET_TIME_Relative timeout, int auto_retry, @@ -1188,26 +1193,26 @@ GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *sock, struct TransmitGetResponseContext *tc; uint16_t msize; - if (NULL != sock->th) + if (NULL != client->th) return GNUNET_SYSERR; - GNUNET_assert (sock->tag == NULL); + GNUNET_assert (NULL == client->tag); msize = ntohs (hdr->size); tc = GNUNET_malloc (sizeof (struct TransmitGetResponseContext) + msize); - tc->sock = sock; + tc->client = client; tc->hdr = (const struct GNUNET_MessageHeader *) &tc[1]; memcpy (&tc[1], hdr, msize); tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); tc->rn = rn; tc->rn_cls = rn_cls; if (NULL == - GNUNET_CLIENT_notify_transmit_ready (sock, msize, timeout, auto_retry, + GNUNET_CLIENT_notify_transmit_ready (client, msize, timeout, auto_retry, &transmit_for_response, tc)) { GNUNET_break (0); GNUNET_free (tc); return GNUNET_SYSERR; } - sock->tag = tc; + client->tag = tc; return GNUNET_OK; } diff --git a/src/util/common_logging.c b/src/util/common_logging.c index e19aa8c..2c0fd57 100644 --- a/src/util/common_logging.c +++ b/src/util/common_logging.c @@ -530,6 +530,8 @@ parse_all_definitions () gnunet_force_log_parsed = GNUNET_YES; } #endif + + /** * Setup logging. * @@ -569,30 +571,29 @@ GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile) if (NULL == fn) return GNUNET_SYSERR; dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)); - altlog_fd = OPEN (fn, O_APPEND | #if WINDOWS + altlog_fd = OPEN (fn, O_APPEND | O_BINARY | -#endif O_WRONLY | O_CREAT, -#if WINDOWS - _S_IREAD | _S_IWRITE + _S_IREAD | _S_IWRITE); #else - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH + altlog_fd = OPEN (fn, O_APPEND | + O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); #endif - ); if (altlog_fd != -1) { int dup_return; if (GNUNET_stderr != NULL) fclose (GNUNET_stderr); dup_return = dup2 (altlog_fd, 2); - close (altlog_fd); + (void) close (altlog_fd); if (dup_return != -1) { altlog = fdopen (2, "ab"); if (altlog == NULL) { - close (2); + (void) close (2); altlog_fd = -1; } } diff --git a/src/util/configuration.c b/src/util/configuration.c index f24b2c2..308672f 100644 --- a/src/util/configuration.c +++ b/src/util/configuration.c @@ -21,7 +21,6 @@ /** * @file src/util/configuration.c * @brief configuration management - * * @author Christian Grothoff */ @@ -197,19 +196,19 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, for (i = strlen (line) - 1; (i >= 0) && (isspace ((unsigned char) line[i])); i--) line[i] = '\0'; - if (1 == sscanf (line, "@INLINE@ %191[^\n]", value)) + if (1 == SSCANF (line, "@INLINE@ %191[^\n]", value)) { /* @INLINE@ value */ if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, value)) ret = GNUNET_SYSERR; /* failed to parse included config */ } - else if (1 == sscanf (line, "[%99[^]]]", value)) + else if (1 == SSCANF (line, "[%99[^]]]", value)) { /* [value] */ GNUNET_free (section); section = GNUNET_strdup (value); } - else if (2 == sscanf (line, " %63[^= ] = %191[^\n]", tag, value)) + else if (2 == SSCANF (line, " %63[^= ] = %191[^\n]", tag, value)) { /* tag = value */ /* Strip LF */ @@ -233,7 +232,7 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, } GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]); } - else if (1 == sscanf (line, " %63[^= ] =[^\n]", tag)) + else if (1 == SSCANF (line, " %63[^= ] =[^\n]", tag)) { /* tag = */ GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, ""); @@ -1228,14 +1227,42 @@ static int parse_configuration_file (void *cls, const char *filename) { struct GNUNET_CONFIGURATION_Handle *cfg = cls; + char * ext; int ret; + /* Examine file extension */ + ext = strrchr (filename, '.'); + if ((NULL == ext) || (0 != strcmp (ext, ".conf"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename); + return GNUNET_OK; + } + ret = GNUNET_CONFIGURATION_parse (cfg, filename); return ret; } /** + * Load default configuration. This function will parse the + * defaults from the given defaults_d directory. + * + * @param cfg configuration to update + * @param defaults_d directory with the defaults + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *defaults_d) +{ + if (GNUNET_SYSERR == + GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg)) + return GNUNET_SYSERR; /* no configuration at all found */ + return GNUNET_OK; +} + + +/** * Load configuration (starts with defaults, then loads * system-specific configuration). * diff --git a/src/util/connection.c b/src/util/connection.c index 8224479..31e6399 100644 --- a/src/util/connection.c +++ b/src/util/connection.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) + (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -44,32 +44,6 @@ #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) -/** - * Possible functions to call after connect failed or succeeded. - */ -enum ConnectContinuations -{ - /** - * Call nothing. - */ - COCO_NONE = 0, - - /** - * Call "receive_again". - */ - COCO_RECEIVE_AGAIN = 1, - - /** - * Call "transmit_ready". - */ - COCO_TRANSMIT_READY = 2, - - /** - * Call "destroy_continuation". - */ - COCO_DESTROY_CONTINUATION = 4 -}; - /** * Transmission handle. There can only be one for each connection. @@ -89,9 +63,9 @@ struct GNUNET_CONNECTION_TransmitHandle void *notify_ready_cls; /** - * Our socket handle. + * Our connection handle. */ - struct GNUNET_CONNECTION_Handle *sh; + struct GNUNET_CONNECTION_Handle *connection; /** * Timeout for receiving (in absolute time). @@ -142,7 +116,7 @@ struct AddressProbe /** * Connection for which we are probing. */ - struct GNUNET_CONNECTION_Handle *h; + struct GNUNET_CONNECTION_Handle *connection; /** * Lenth of addr. @@ -150,14 +124,14 @@ struct AddressProbe socklen_t addrlen; /** - * Task waiting for the socket to finish connecting. + * Task waiting for the connection to finish connecting. */ GNUNET_SCHEDULER_TaskIdentifier task; }; /** - * @brief handle for a network socket + * @brief handle for a network connection */ struct GNUNET_CONNECTION_Handle { @@ -185,7 +159,7 @@ struct GNUNET_CONNECTION_Handle struct sockaddr *addr; /** - * Pointer to the hostname if socket was + * Pointer to the hostname if connection was * created using DNS lookup, otherwise NULL. */ char *hostname; @@ -243,11 +217,6 @@ struct GNUNET_CONNECTION_Handle GNUNET_SCHEDULER_TaskIdentifier write_task; /** - * Destroy task (if already scheduled). - */ - GNUNET_SCHEDULER_TaskIdentifier destroy_task; - - /** * Handle to a pending DNS lookup request. */ struct GNUNET_RESOLVER_RequestHandle *dns_active; @@ -263,21 +232,11 @@ struct GNUNET_CONNECTION_Handle struct GNUNET_TIME_Absolute receive_timeout; /** - * Functions to call after connect failed or succeeded. - */ - enum ConnectContinuations ccs; - - /** * Maximum number of bytes to read (for receiving). */ size_t max; /** - * Ignore GNUNET_SCHEDULER_REASON_SHUTDOWN for this socket. - */ - int ignore_shutdown; - - /** * Port to connect to. */ uint16_t port; @@ -292,73 +251,75 @@ struct GNUNET_CONNECTION_Handle }; + /** * Set the persist option on this connection handle. Indicates * that the underlying socket or fd should never really be closed. * Used for indicating process death. * - * @param sock the connection to set persistent + * @param connection the connection to set persistent */ void -GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *sock) +GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection) { - sock->persist = GNUNET_YES; + connection->persist = GNUNET_YES; } /** - * Disable the "CORK" feature for communication with the given socket, + * Disable the "CORK" feature for communication with the given connection, * forcing the OS to immediately flush the buffer on transmission * instead of potentially buffering multiple messages. Essentially * reduces the OS send buffers to zero. * Used to make sure that the last messages sent through the connection * reach the other side before the process is terminated. * - * @param sock the connection to make flushing and blocking + * @param connection the connection to make flushing and blocking * @return GNUNET_OK on success */ int -GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *sock) +GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection) { - return GNUNET_NETWORK_socket_disable_corking (sock->sock); + return GNUNET_NETWORK_socket_disable_corking (connection->sock); } + /** - * Create a socket handle by boxing an existing OS socket. The OS + * Create a connection handle by boxing an existing OS socket. The OS * socket should henceforth be no longer used directly. - * GNUNET_socket_destroy will close it. + * GNUNET_connection_destroy will close it. * * @param osSocket existing socket to box - * @return the boxed socket handle + * @return the boxed connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket) { - struct GNUNET_CONNECTION_Handle *ret; + struct GNUNET_CONNECTION_Handle *connection; - ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); - ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; - ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); - ret->sock = osSocket; - return ret; + connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); + connection->sock = osSocket; + return connection; } /** - * Create a socket handle by accepting on a listen socket. This + * Create a connection handle by accepting on a listen socket. This * function may block if the listen socket has no connection ready. * * @param access function to use to check if access is allowed * @param access_cls closure for access * @param lsock listen socket - * @return the socket handle, NULL on error + * @return the connection handle, NULL on error */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle *lsock) { - struct GNUNET_CONNECTION_Handle *ret; + struct GNUNET_CONNECTION_Handle *connection; char addr[128]; socklen_t addrlen; struct GNUNET_NETWORK_Handle *sock; @@ -369,7 +330,6 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, void *uaddr; struct GNUNET_CONNECTION_Credentials *gcp; struct GNUNET_CONNECTION_Credentials gc; - #ifdef SO_PEERCRED struct ucred uc; socklen_t olen; @@ -392,7 +352,7 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, sa = (struct sockaddr *) addr; v6 = (struct sockaddr_in6 *) addr; - if ((sa->sa_family == AF_INET6) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr))) + if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr))) { /* convert to V4 address */ v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); @@ -417,7 +377,7 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, gcp = NULL; gc.uid = 0; gc.gid = 0; - if (sa->sa_family == AF_UNIX) + if (AF_UNIX == sa->sa_family) { #if HAVE_GETPEEREID /* most BSDs */ @@ -453,10 +413,10 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, #endif } - if ((access != NULL) && + if ((NULL != access) && (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen)))) { - if (aret == GNUNET_NO) + if (GNUNET_NO == aret) LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"), GNUNET_a2s (uaddr, addrlen)); GNUNET_break (GNUNET_OK == @@ -465,147 +425,151 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, GNUNET_free (uaddr); return NULL; } - ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); - ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; - ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); - ret->addr = uaddr; - ret->addrlen = addrlen; - ret->sock = sock; + connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); + connection->addr = uaddr; + connection->addrlen = addrlen; + connection->sock = sock; LOG (GNUNET_ERROR_TYPE_INFO, _("Accepting connection from `%s': %p\n"), - GNUNET_a2s (uaddr, addrlen), ret); - return ret; + GNUNET_a2s (uaddr, addrlen), connection); + return connection; } + /** * Obtain the network address of the other party. * - * @param sock the client to get the address for + * @param connection the client to get the address for * @param addr where to store the address * @param addrlen where to store the length of the address * @return GNUNET_OK on success */ int -GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *sock, +GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection, void **addr, size_t * addrlen) { - if ((sock->addr == NULL) || (sock->addrlen == 0)) + if ((NULL == connection->addr) || (0 == connection->addrlen)) return GNUNET_NO; - *addr = GNUNET_malloc (sock->addrlen); - memcpy (*addr, sock->addr, sock->addrlen); - *addrlen = sock->addrlen; + *addr = GNUNET_malloc (connection->addrlen); + memcpy (*addr, connection->addr, connection->addrlen); + *addrlen = connection->addrlen; return GNUNET_OK; } /** - * This function is called after establishing a connection either has - * succeeded or timed out. Note that it is possible that the attempt - * timed out and that we're immediately retrying. If we are retrying, - * we need to wait again (or timeout); if we succeeded, we need to - * wait for data (or timeout). + * Tell the receiver callback that we had an IO error. * - * @param cls our connection handle - * @param tc task context describing why we are here + * @param connection connection to signal error + * @param errcode error code to send */ static void -receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); +signal_receive_error (struct GNUNET_CONNECTION_Handle *connection, int errcode) +{ + GNUNET_CONNECTION_Receiver receiver; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receive encounters error (%s), connection closed (%p)\n", + STRERROR (errcode), + connection); + GNUNET_assert (NULL != (receiver = connection->receiver)); + connection->receiver = NULL; + receiver (connection->receiver_cls, NULL, 0, connection->addr, connection->addrlen, errcode); +} /** - * Scheduler let us know that the connect task is finished (or was - * cancelled due to shutdown). Now really clean up. + * Tell the receiver callback that a timeout was reached. * - * @param cls our "struct GNUNET_CONNECTION_Handle *" - * @param tc unused + * @param connection connection to signal for + */ +static void +signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection) +{ + GNUNET_CONNECTION_Receiver receiver; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection signals timeout to receiver (%p)!\n", + connection); + GNUNET_assert (NULL != (receiver = connection->receiver)); + connection->receiver = NULL; + receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0); +} + + +/** + * We failed to transmit data to the service, signal the error. + * + * @param connection handle that had trouble + * @param ecode error code (errno) */ static void -destroy_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection, + int ecode) { - struct GNUNET_CONNECTION_Handle *sock = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; - struct AddressProbe *pos; - sock->destroy_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_assert (sock->dns_active == NULL); - if (0 != (sock->ccs & COCO_TRANSMIT_READY)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroy waits for CCS-TR to be done (%p)\n", - sock); - sock->ccs |= COCO_DESTROY_CONTINUATION; - return; - } - if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Destroy waits for write_task to be done (%p)\n", sock); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); - sock->destroy_task = - GNUNET_SCHEDULER_add_after (sock->write_task, &destroy_continuation, - sock); - return; - } - if (0 != (sock->ccs & COCO_RECEIVE_AGAIN)) - { - sock->ccs |= COCO_DESTROY_CONTINUATION; - return; - } - if (sock->sock != NULL) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission encounterd error (%s), connection closed (%p)\n", + STRERROR (ecode), + connection); + if (NULL != connection->sock) { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down socket (%p)\n", sock); - if (sock->persist != GNUNET_YES) - { - if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR)) - && (errno != ENOTCONN) && (errno != ECONNRESET)) - LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown"); - } + GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); + connection->sock = NULL; + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); } - if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); - sock->destroy_task = - GNUNET_SCHEDULER_add_after (sock->read_task, &destroy_continuation, - sock); + /* send errors trigger read errors... */ + GNUNET_SCHEDULER_cancel (connection->read_task); + connection->read_task = GNUNET_SCHEDULER_NO_TASK; + signal_receive_timeout (connection); return; } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroy actually runs (%p)!\n", sock); - while (NULL != (pos = sock->ap_head)) - { - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); - GNUNET_SCHEDULER_cancel (pos->task); - GNUNET_CONTAINER_DLL_remove (sock->ap_head, sock->ap_tail, pos); - GNUNET_free (pos); - } - GNUNET_assert (sock->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK); - GNUNET_assert (sock->ccs == COCO_NONE); - if (NULL != (notify = sock->nth.notify_ready)) - { - sock->nth.notify_ready = NULL; - notify (sock->nth.notify_ready_cls, 0, NULL); - } + if (NULL == connection->nth.notify_ready) + return; /* nobody to tell about it */ + notify = connection->nth.notify_ready; + connection->nth.notify_ready = NULL; + notify (connection->nth.notify_ready_cls, 0, NULL); +} - if (sock->sock != NULL) + +/** + * We've failed for good to establish a connection (timeout or + * no more addresses to try). + * + * @param connection the connection we tried to establish + */ +static void +connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection) +{ + LOG (GNUNET_ERROR_TYPE_INFO, + _("Failed to establish TCP connection to `%s:%u', no further addresses to try.\n"), + connection->hostname, connection->port); + GNUNET_break (NULL == connection->ap_head); + GNUNET_break (NULL == connection->ap_tail); + GNUNET_break (GNUNET_NO == connection->dns_active); + GNUNET_break (NULL == connection->sock); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); + + /* signal errors for jobs that used to wait on the connection */ + if (NULL != connection->receiver) + signal_receive_error (connection, ECONNREFUSED); + if (NULL != connection->nth.notify_ready) { - if (sock->persist != GNUNET_YES) - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock)); - else - GNUNET_free (sock->sock); /* at least no memory leak (we deliberately - * leak the socket in this special case) ... */ + GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); + connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; + signal_transmit_error (connection, ECONNREFUSED); } - GNUNET_free_non_null (sock->addr); - GNUNET_free_non_null (sock->hostname); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing memory of connection %p.\n", sock); - GNUNET_free (sock->write_buffer); - GNUNET_free (sock); } - /** - * See if we are now connected. If not, wait longer for - * connect to succeed. If connected, we should be able - * to write now as well, unless we timed out. + * We are ready to transmit (or got a timeout). * * @param cls our connection handle * @param tc task context describing why we are here @@ -615,98 +579,52 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** - * We've failed for good to establish a connection. + * This function is called once we either timeout or have data ready + * to read. * - * @param h the connection we tried to establish + * @param cls connection to read from + * @param tc scheduler context */ static void -connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h) -{ - LOG ((0 != - strncmp (h->hostname, "localhost:", - 10)) ? GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING, - _ - ("Failed to establish TCP connection to `%s:%u', no further addresses to try.\n"), - h->hostname, h->port); - /* connect failed / timed out */ - GNUNET_break (h->ap_head == NULL); - GNUNET_break (h->ap_tail == NULL); - GNUNET_break (h->dns_active == GNUNET_NO); - GNUNET_break (h->sock == NULL); - - /* trigger jobs that used to wait on "connect_task" */ - if (0 != (h->ccs & COCO_RECEIVE_AGAIN)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "connect_fail_continuation triggers receive_again (%p)\n", h); - h->ccs -= COCO_RECEIVE_AGAIN; - h->read_task = GNUNET_SCHEDULER_add_now (&receive_again, h); - } - if (0 != (h->ccs & COCO_TRANSMIT_READY)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "connect_fail_continuation cancels timeout_task, triggers transmit_ready (%p)\n", - h); - GNUNET_assert (h->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); - GNUNET_SCHEDULER_cancel (h->nth.timeout_task); - h->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; - h->ccs -= COCO_TRANSMIT_READY; - GNUNET_assert (h->nth.notify_ready != NULL); - GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK); - h->write_task = GNUNET_SCHEDULER_add_now (&transmit_ready, h); - } - if (0 != (h->ccs & COCO_DESTROY_CONTINUATION)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "connect_fail_continuation runs destroy_continuation (%p)\n", h); - h->ccs -= COCO_DESTROY_CONTINUATION; - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task); - h->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, h); - } -} +receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * We've succeeded in establishing a connection. * - * @param h the connection we tried to establish + * @param connection the connection we tried to establish */ static void -connect_success_continuation (struct GNUNET_CONNECTION_Handle *h) +connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection) { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' succeeded! (%p)\n", - GNUNET_a2s (h->addr, h->addrlen), h); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Connection to `%s' succeeded! (%p)\n", + GNUNET_a2s (connection->addr, connection->addrlen), connection); /* trigger jobs that waited for the connection */ - if (0 != (h->ccs & COCO_RECEIVE_AGAIN)) + if (NULL != connection->receiver) { LOG (GNUNET_ERROR_TYPE_DEBUG, - "connect_success_continuation runs receive_again (%p)\n", h); - h->ccs -= COCO_RECEIVE_AGAIN; - h->read_task = GNUNET_SCHEDULER_add_now (&receive_again, h); + "Connection succeeded, starting with receiving data (%p)\n", + connection); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->read_task); + connection->read_task = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining + (connection->receive_timeout), connection->sock, + &receive_ready, connection); } - if (0 != (h->ccs & COCO_TRANSMIT_READY)) + if (NULL != connection->nth.notify_ready) { LOG (GNUNET_ERROR_TYPE_DEBUG, - "connect_success_continuation runs transmit_ready, cancels timeout_task (%p)\n", - h); - GNUNET_assert (h->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); - GNUNET_SCHEDULER_cancel (h->nth.timeout_task); - h->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; - h->ccs -= COCO_TRANSMIT_READY; - GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK); - GNUNET_assert (h->nth.notify_ready != NULL); - h->write_task = + "Connection succeeded, starting with sending data (%p)\n", + connection); + GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); + connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (connection->write_task == GNUNET_SCHEDULER_NO_TASK); + connection->write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining - (h->nth.transmit_timeout), h->sock, - &transmit_ready, h); - } - if (0 != (h->ccs & COCO_DESTROY_CONTINUATION)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "connect_success_continuation runs destroy_continuation (%p)\n", h); - h->ccs -= COCO_DESTROY_CONTINUATION; - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task); - h->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, h); + (connection->nth.transmit_timeout), connection->sock, + &transmit_ready, connection); } } @@ -723,48 +641,48 @@ connect_probe_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct AddressProbe *ap = cls; - struct GNUNET_CONNECTION_Handle *h = ap->h; + struct GNUNET_CONNECTION_Handle *connection = ap->connection; struct AddressProbe *pos; int error; socklen_t len; - GNUNET_assert (ap->sock != NULL); - GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, ap); + GNUNET_assert (NULL != ap->sock); + GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, ap); len = sizeof (error); errno = 0; error = 0; if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error, - &len)) || (error != 0)) + &len)) || (0 != error)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); GNUNET_free (ap); - if ((NULL == h->ap_head) && (h->dns_active == GNUNET_NO)) - connect_fail_continuation (h); + if ((NULL == connection->ap_head) && (GNUNET_NO == connection->dns_active)) + connect_fail_continuation (connection); return; } - GNUNET_assert (h->sock == NULL); - h->sock = ap->sock; - GNUNET_assert (h->addr == NULL); - h->addr = GNUNET_malloc (ap->addrlen); - memcpy (h->addr, ap->addr, ap->addrlen); - h->addrlen = ap->addrlen; + GNUNET_assert (NULL == connection->sock); + connection->sock = ap->sock; + GNUNET_assert (NULL == connection->addr); + connection->addr = GNUNET_malloc (ap->addrlen); + memcpy (connection->addr, ap->addr, ap->addrlen); + connection->addrlen = ap->addrlen; GNUNET_free (ap); /* cancel all other attempts */ - while (NULL != (pos = h->ap_head)) + while (NULL != (pos = connection->ap_head)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); GNUNET_SCHEDULER_cancel (pos->task); - GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, pos); + GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos); GNUNET_free (pos); } - connect_success_continuation (h); + connect_success_continuation (connection); } /** - * Try to establish a socket connection given the specified address. + * Try to establish a connection given the specified address. * This function is called by the resolver once we have a DNS reply. * * @param cls our "struct GNUNET_CONNECTION_Handle *" @@ -775,37 +693,37 @@ static void try_connect_using_address (void *cls, const struct sockaddr *addr, socklen_t addrlen) { - struct GNUNET_CONNECTION_Handle *h = cls; + struct GNUNET_CONNECTION_Handle *connection = cls; struct AddressProbe *ap; struct GNUNET_TIME_Relative delay; - if (addr == NULL) + if (NULL == addr) { - h->dns_active = NULL; - if ((NULL == h->ap_head) && (NULL == h->sock)) - connect_fail_continuation (h); + connection->dns_active = NULL; + if ((NULL == connection->ap_head) && (NULL == connection->sock)) + connect_fail_continuation (connection); return; } - if (h->sock != NULL) + if (NULL != connection->sock) return; /* already connected */ - GNUNET_assert (h->addr == NULL); + GNUNET_assert (NULL == connection->addr); /* try to connect */ LOG (GNUNET_ERROR_TYPE_DEBUG, - "Trying to connect using address `%s:%u/%s:%u'\n", h->hostname, h->port, - GNUNET_a2s (addr, addrlen), h->port); + "Trying to connect using address `%s:%u/%s:%u'\n", connection->hostname, connection->port, + GNUNET_a2s (addr, addrlen), connection->port); ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); ap->addr = (const struct sockaddr *) &ap[1]; memcpy (&ap[1], addr, addrlen); ap->addrlen = addrlen; - ap->h = h; + ap->connection = connection; switch (ap->addr->sa_family) { case AF_INET: - ((struct sockaddr_in *) ap->addr)->sin_port = htons (h->port); + ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port); break; case AF_INET6: - ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (h->port); + ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port); break; default: GNUNET_break (0); @@ -813,39 +731,39 @@ try_connect_using_address (void *cls, const struct sockaddr *addr, return; /* not supported by us */ } ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0); - if (ap->sock == NULL) + if (NULL == ap->sock) { GNUNET_free (ap); return; /* not supported by OS */ } LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), - GNUNET_a2s (ap->addr, ap->addrlen), h); + GNUNET_a2s (ap->addr, ap->addrlen), connection); if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) && - (errno != EINPROGRESS)) + (EINPROGRESS != errno)) { /* maybe refused / unsupported address, try next */ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); #if 0 LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"), - GNUNET_a2s (ap->addr, ap->addrlen), h); + GNUNET_a2s (ap->addr, ap->addrlen), connection); #endif GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); GNUNET_free (ap); return; } - GNUNET_CONTAINER_DLL_insert (h->ap_head, h->ap_tail, ap); + GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap); delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; - if (h->nth.notify_ready != NULL) + if (NULL != connection->nth.notify_ready) delay = GNUNET_TIME_relative_min (delay, - GNUNET_TIME_absolute_get_remaining (h-> + GNUNET_TIME_absolute_get_remaining (connection-> nth.transmit_timeout)); - if (h->receiver != NULL) + if (NULL != connection->receiver) delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_absolute_get_remaining - (h->receive_timeout)); + (connection->receive_timeout)); ap->task = GNUNET_SCHEDULER_add_write_net (delay, ap->sock, &connect_probe_continuation, ap); @@ -853,45 +771,45 @@ try_connect_using_address (void *cls, const struct sockaddr *addr, /** - * Create a socket handle by (asynchronously) connecting to a host. + * Create a connection handle by (asynchronously) connecting to a host. * This function returns immediately, even if the connection has not * yet been established. This function only creates TCP connections. * * @param cfg configuration to use * @param hostname name of the host to connect to * @param port port to connect to - * @return the socket handle + * @return the connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *hostname, uint16_t port) { - struct GNUNET_CONNECTION_Handle *ret; + struct GNUNET_CONNECTION_Handle *connection; GNUNET_assert (0 < strlen (hostname)); /* sanity check */ - ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); - ret->cfg = cfg; - ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; - ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); - ret->port = port; - ret->hostname = GNUNET_strdup (hostname); - ret->dns_active = - GNUNET_RESOLVER_ip_get (ret->hostname, AF_UNSPEC, + connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + connection->cfg = cfg; + connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); + connection->port = port; + connection->hostname = GNUNET_strdup (hostname); + connection->dns_active = + GNUNET_RESOLVER_ip_get (connection->hostname, AF_UNSPEC, GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, - &try_connect_using_address, ret); - return ret; + &try_connect_using_address, connection); + return connection; } /** - * Create a socket handle by connecting to a UNIX domain service. + * Create a connection handle by connecting to a UNIX domain service. * This function returns immediately, even if the connection has not * yet been established. This function only creates UNIX connections. * * @param cfg configuration to use * @param unixpath path to connect to - * @return the socket handle, NULL on systems without UNIX support + * @return the connection handle, NULL on systems without UNIX support */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct @@ -899,7 +817,7 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct *cfg, const char *unixpath) { #ifdef AF_UNIX - struct GNUNET_CONNECTION_Handle *ret; + struct GNUNET_CONNECTION_Handle *connection; struct sockaddr_un *un; size_t slen; @@ -918,32 +836,32 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct #if LINUX un->sun_path[0] = '\0'; #endif - ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); - ret->cfg = cfg; - ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; - ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); - ret->port = 0; - ret->hostname = NULL; - ret->addr = (struct sockaddr *) un; - ret->addrlen = slen; - ret->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); - if (NULL == ret->sock) + connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + connection->cfg = cfg; + connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); + connection->port = 0; + connection->hostname = NULL; + connection->addr = (struct sockaddr *) un; + connection->addrlen = slen; + connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); + if (NULL == connection->sock) { - GNUNET_free (ret->addr); - GNUNET_free (ret->write_buffer); - GNUNET_free (ret); + GNUNET_free (connection->addr); + GNUNET_free (connection->write_buffer); + GNUNET_free (connection); return NULL; } if (GNUNET_OK != - GNUNET_NETWORK_socket_connect (ret->sock, ret->addr, ret->addrlen)) + GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen)) { /* Just return; we expect everything to work eventually so don't fail HARD */ - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret->sock)); - ret->sock = NULL; - return ret; + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); + connection->sock = NULL; + return connection; } - connect_success_continuation (ret); - return ret; + connect_success_continuation (connection); + return connection; #else return NULL; #endif @@ -951,14 +869,14 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct /** - * Create a socket handle by (asynchronously) connecting to a host. + * Create a connection handle by (asynchronously) connecting to a host. * This function returns immediately, even if the connection has not * yet been established. This function only creates TCP connections. * * @param af_family address family to use * @param serv_addr server address * @param addrlen length of server address - * @return the socket handle + * @return the connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_sockaddr (int af_family, @@ -966,17 +884,16 @@ GNUNET_CONNECTION_create_from_sockaddr (int af_family, socklen_t addrlen) { struct GNUNET_NETWORK_Handle *s; - struct GNUNET_CONNECTION_Handle *ret; - + struct GNUNET_CONNECTION_Handle *connection; s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0); - if (s == NULL) + if (NULL == s) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket"); return NULL; } if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) && - (errno != EINPROGRESS)) + (EINPROGRESS != errno)) { /* maybe refused / unsupported address, try next */ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); @@ -985,293 +902,221 @@ GNUNET_CONNECTION_create_from_sockaddr (int af_family, GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); return NULL; } - ret = GNUNET_CONNECTION_create_from_existing (s); - ret->addr = GNUNET_malloc (addrlen); - memcpy (ret->addr, serv_addr, addrlen); - ret->addrlen = addrlen; + connection = GNUNET_CONNECTION_create_from_existing (s); + connection->addr = GNUNET_malloc (addrlen); + memcpy (connection->addr, serv_addr, addrlen); + connection->addrlen = addrlen; LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), - GNUNET_a2s (serv_addr, addrlen), ret); - return ret; + GNUNET_a2s (serv_addr, addrlen), connection); + return connection; } /** - * Check if socket is valid (no fatal errors have happened so far). - * Note that a socket that is still trying to connect is considered + * Check if connection is valid (no fatal errors have happened so far). + * Note that a connection that is still trying to connect is considered * valid. * - * @param sock socket to check + * @param connection connection to check * @return GNUNET_YES if valid, GNUNET_NO otherwise */ int -GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock) +GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection) { - if ((sock->ap_head != NULL) || (sock->dns_active != NULL)) + if ((NULL != connection->ap_head) || (NULL != connection->dns_active)) return GNUNET_YES; /* still trying to connect */ - return (sock->sock == NULL) ? GNUNET_NO : GNUNET_YES; + return (NULL == connection->sock) ? GNUNET_NO : GNUNET_YES; } /** - * Close the socket and free associated resources. Pending - * transmissions may be completed or dropped depending on the - * arguments. If a receive call is pending and should - * NOT be completed, 'GNUNET_CONNECTION_receive_cancel' - * should be called explicitly first. + * Close the connection and free associated resources. There must + * not be any pending requests for reading or writing to the + * connection at this time. * - * @param sock socket to destroy - * @param finish_pending_write should pending writes be completed or aborted? - * (this applies to transmissions where the data has already been - * read from the application; all other transmissions should be - * aborted using 'GNUNET_CONNECTION_notify_transmit_ready_cancel'). + * @param connection connection to destroy */ void -GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock, - int finish_pending_write) +GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection) { - if (GNUNET_NO == finish_pending_write) + struct AddressProbe *pos; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection); + GNUNET_assert (NULL == connection->nth.notify_ready); + GNUNET_assert (NULL == connection->receiver); + if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { - if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (sock->write_task); - sock->write_task = GNUNET_SCHEDULER_NO_TASK; - sock->write_buffer_off = 0; - } - sock->nth.notify_ready = NULL; + GNUNET_SCHEDULER_cancel (connection->write_task); + connection->write_task = GNUNET_SCHEDULER_NO_TASK; + connection->write_buffer_off = 0; } - if ((sock->write_buffer_off == 0) && (sock->dns_active != NULL)) + if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { - GNUNET_RESOLVER_request_cancel (sock->dns_active); - sock->dns_active = NULL; + GNUNET_SCHEDULER_cancel (connection->read_task); + connection->read_task = GNUNET_SCHEDULER_NO_TASK; } - - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); - sock->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, sock); -} - - -/** - * Tell the receiver callback that a timeout was reached. - */ -static void -signal_timeout (struct GNUNET_CONNECTION_Handle *sh) -{ - GNUNET_CONNECTION_Receiver receiver; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Network signals time out to receiver (%p)!\n", - sh); - GNUNET_assert (NULL != (receiver = sh->receiver)); - sh->receiver = NULL; - receiver (sh->receiver_cls, NULL, 0, NULL, 0, 0); -} - - -/** - * Tell the receiver callback that we had an IO error. - */ -static void -signal_error (struct GNUNET_CONNECTION_Handle *sh, int errcode) -{ - GNUNET_CONNECTION_Receiver receiver; - - GNUNET_assert (NULL != (receiver = sh->receiver)); - sh->receiver = NULL; - receiver (sh->receiver_cls, NULL, 0, sh->addr, sh->addrlen, errcode); + if (GNUNET_SCHEDULER_NO_TASK != connection->nth.timeout_task) + { + GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); + connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + connection->nth.notify_ready = NULL; + if (NULL != connection->dns_active) + { + GNUNET_RESOLVER_request_cancel (connection->dns_active); + connection->dns_active = NULL; + } + while (NULL != (pos = connection->ap_head)) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); + GNUNET_SCHEDULER_cancel (pos->task); + GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos); + GNUNET_free (pos); + } + if ( (NULL != connection->sock) && + (GNUNET_YES != connection->persist) ) + { + if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) && + (ENOTCONN != errno) && + (ECONNRESET != errno) ) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown"); + } + if (NULL != connection->sock) + { + if (GNUNET_YES != connection->persist) + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); + else + GNUNET_free (connection->sock); /* at least no memory leak (we deliberately + * leak the socket in this special case) ... */ + } + GNUNET_free_non_null (connection->addr); + GNUNET_free_non_null (connection->hostname); + GNUNET_free (connection->write_buffer); + GNUNET_free (connection); } /** * This function is called once we either timeout * or have data ready to read. + * + * @param cls connection to read from + * @param tc scheduler context */ static void receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_CONNECTION_Handle *sh = cls; - struct GNUNET_TIME_Absolute now; - char buffer[sh->max]; + struct GNUNET_CONNECTION_Handle *connection = cls; + char buffer[connection->max]; ssize_t ret; GNUNET_CONNECTION_Receiver receiver; - sh->read_task = GNUNET_SCHEDULER_NO_TASK; - if ((GNUNET_YES == sh->ignore_shutdown) && - (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))) + connection->read_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { /* ignore shutdown request, go again immediately */ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Ignoring shutdown signal per configuration\n"); - sh->read_task = + connection->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining - (sh->receive_timeout), sh->sock, - &receive_ready, sh); + (connection->receive_timeout), connection->sock, + &receive_ready, connection); return; } - now = GNUNET_TIME_absolute_get (); - if ((now.abs_value > sh->receive_timeout.abs_value) || - (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) || - (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))) + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { - if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Receive from `%s' encounters error: time out by %llums... (%p)\n", - GNUNET_a2s (sh->addr, sh->addrlen), - GNUNET_TIME_absolute_get_duration (sh->receive_timeout).rel_value, - sh); - signal_timeout (sh); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receive from `%s' encounters error: timeout (%p)\n", + GNUNET_a2s (connection->addr, connection->addrlen), + GNUNET_TIME_absolute_get_duration (connection->receive_timeout).rel_value, + connection); + signal_receive_timeout (connection); return; } - if (sh->sock == NULL) + if (NULL == connection->sock) { /* connect failed for good */ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Receive encounters error, socket closed... (%p)\n", sh); - signal_error (sh, ECONNREFUSED); + signal_receive_error (connection, ECONNREFUSED); return; } - GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, sh->sock)); + GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock)); RETRY: - ret = GNUNET_NETWORK_socket_recv (sh->sock, buffer, sh->max); - if (ret == -1) + ret = GNUNET_NETWORK_socket_recv (connection->sock, buffer, connection->max); + if (-1 == ret) { - if (errno == EINTR) + if (EINTR == errno) goto RETRY; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Error receiving: %s\n", STRERROR (errno)); - signal_error (sh, errno); + signal_receive_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "receive_ready read %u/%u bytes from `%s' (%p)!\n", (unsigned int) ret, - sh->max, GNUNET_a2s (sh->addr, sh->addrlen), sh); - GNUNET_assert (NULL != (receiver = sh->receiver)); - sh->receiver = NULL; - receiver (sh->receiver_cls, buffer, ret, sh->addr, sh->addrlen, 0); + connection->max, GNUNET_a2s (connection->addr, connection->addrlen), connection); + GNUNET_assert (NULL != (receiver = connection->receiver)); + connection->receiver = NULL; + receiver (connection->receiver_cls, buffer, ret, connection->addr, connection->addrlen, 0); } /** - * This function is called after establishing a connection either has - * succeeded or timed out. Note that it is possible that the attempt - * timed out and that we're immediately retrying. If we are retrying, - * we need to wait again (or timeout); if we succeeded, we need to - * wait for data (or timeout). - * - * @param cls our connection handle - * @param tc task context describing why we are here - */ -static void -receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_CONNECTION_Handle *sh = cls; - struct GNUNET_TIME_Absolute now; - - sh->read_task = GNUNET_SCHEDULER_NO_TASK; - if (sh->sock == NULL) - { - /* not connected and no longer trying */ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Receive encounters error, socket closed (%p)...\n", sh); - signal_error (sh, ECONNREFUSED); - return; - } - now = GNUNET_TIME_absolute_get (); - if ((now.abs_value > sh->receive_timeout.abs_value) || - (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Receive encounters error: time out (%p)...\n", sh); - signal_timeout (sh); - return; - } - GNUNET_assert (sh->sock != NULL); - /* connect succeeded, wait for data! */ - sh->read_task = - GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining - (sh->receive_timeout), sh->sock, - &receive_ready, sh); -} - - -/** - * Receive data from the given socket. Note that this function will + * Receive data from the given connection. Note that this function will * call "receiver" asynchronously using the scheduler. It will * "immediately" return. Note that there MUST only be one active - * receive call per socket at any given point in time (so do not + * receive call per connection at any given point in time (so do not * call receive again until the receiver callback has been invoked). * - * @param sock socket handle + * @param connection connection handle * @param max maximum number of bytes to read - * @param timeout maximum amount of time to wait (use -1 for "forever") + * @param timeout maximum amount of time to wait * @param receiver function to call with received data * @param receiver_cls closure for receiver */ void -GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, size_t max, +GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, size_t max, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_Receiver receiver, void *receiver_cls) { - struct GNUNET_SCHEDULER_TaskContext tc; - - GNUNET_assert ((sock->read_task == GNUNET_SCHEDULER_NO_TASK) && - (0 == (sock->ccs & COCO_RECEIVE_AGAIN)) && - (sock->receiver == NULL)); - sock->receiver = receiver; - sock->receiver_cls = receiver_cls; - sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); - sock->max = max; - if (sock->sock != NULL) + GNUNET_assert ((GNUNET_SCHEDULER_NO_TASK == connection->read_task) && + (NULL == connection->receiver)); + GNUNET_assert (NULL != receiver); + connection->receiver = receiver; + connection->receiver_cls = receiver_cls; + connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); + connection->max = max; + if (NULL != connection->sock) { - memset (&tc, 0, sizeof (tc)); - tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE; - receive_again (sock, &tc); + connection->read_task = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining + (connection->receive_timeout), connection->sock, + &receive_ready, connection); return; } - if ((sock->dns_active == NULL) && (sock->ap_head == NULL)) + if ((NULL == connection->dns_active) && (NULL == connection->ap_head)) { + connection->receiver = NULL; receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT); return; } - sock->ccs += COCO_RECEIVE_AGAIN; -} - - -/** - * Configure this connection to ignore shutdown signals. - * - * @param sock socket handle - * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default - */ -void -GNUNET_CONNECTION_ignore_shutdown (struct GNUNET_CONNECTION_Handle *sock, - int do_ignore) -{ - sock->ignore_shutdown = do_ignore; } /** - * Cancel receive job on the given socket. Note that the + * Cancel receive job on the given connection. Note that the * receiver callback must not have been called yet in order * for the cancellation to be valid. * - * @param sock socket handle + * @param connection connection handle * @return closure of the original receiver callback closure */ void * -GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock) +GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection) { - if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_assert (sock == GNUNET_SCHEDULER_cancel (sock->read_task)); - sock->read_task = GNUNET_SCHEDULER_NO_TASK; - } - else + if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { - GNUNET_assert (0 != (sock->ccs & COCO_RECEIVE_AGAIN)); - sock->ccs -= COCO_RECEIVE_AGAIN; + GNUNET_assert (connection == GNUNET_SCHEDULER_cancel (connection->read_task)); + connection->read_task = GNUNET_SCHEDULER_NO_TASK; } - sock->receiver = NULL; - return sock->receiver_cls; + connection->receiver = NULL; + return connection->receiver_cls; } @@ -1279,41 +1124,42 @@ GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock) * Try to call the transmit notify method (check if we do * have enough space available first)! * - * @param sock socket for which we should do this processing + * @param connection connection for which we should do this processing * @return GNUNET_YES if we were able to call notify */ static int -process_notify (struct GNUNET_CONNECTION_Handle *sock) +process_notify (struct GNUNET_CONNECTION_Handle *connection) { size_t used; size_t avail; size_t size; GNUNET_CONNECTION_TransmitReadyNotify notify; - GNUNET_assert (sock->write_task == GNUNET_SCHEDULER_NO_TASK); - if (NULL == (notify = sock->nth.notify_ready)) + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); + if (NULL == (notify = connection->nth.notify_ready)) return GNUNET_NO; - used = sock->write_buffer_off - sock->write_buffer_pos; - avail = sock->write_buffer_size - used; - size = sock->nth.notify_size; + used = connection->write_buffer_off - connection->write_buffer_pos; + avail = connection->write_buffer_size - used; + size = connection->nth.notify_size; if (size > avail) return GNUNET_NO; - sock->nth.notify_ready = NULL; - if (sock->write_buffer_size - sock->write_buffer_off < size) + connection->nth.notify_ready = NULL; + if (connection->write_buffer_size - connection->write_buffer_off < size) { /* need to compact */ - memmove (sock->write_buffer, &sock->write_buffer[sock->write_buffer_pos], + memmove (connection->write_buffer, &connection->write_buffer[connection->write_buffer_pos], used); - sock->write_buffer_off -= sock->write_buffer_pos; - sock->write_buffer_pos = 0; + connection->write_buffer_off -= connection->write_buffer_pos; + connection->write_buffer_pos = 0; } - avail = sock->write_buffer_size - sock->write_buffer_off; + avail = connection->write_buffer_size - connection->write_buffer_off; GNUNET_assert (avail >= size); size = - notify (sock->nth.notify_ready_cls, avail, - &sock->write_buffer[sock->write_buffer_off]); + notify (connection->nth.notify_ready_cls, avail, + &connection->write_buffer[connection->write_buffer_off]); GNUNET_assert (size <= avail); - sock->write_buffer_off += size; + if (0 != size) + connection->write_buffer_off += size; return GNUNET_YES; } @@ -1332,19 +1178,18 @@ process_notify (struct GNUNET_CONNECTION_Handle *sock) static void transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_CONNECTION_Handle *sock = cls; + struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; - sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; + connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s:%u/%s' fails, time out reached (%p).\n", - sock->hostname, - sock->port, GNUNET_a2s (sock->addr, sock->addrlen), sock); - GNUNET_assert (0 != (sock->ccs & COCO_TRANSMIT_READY)); - sock->ccs -= COCO_TRANSMIT_READY; /* remove request */ - notify = sock->nth.notify_ready; - sock->nth.notify_ready = NULL; - notify (sock->nth.notify_ready_cls, 0, NULL); + connection->hostname, + connection->port, GNUNET_a2s (connection->addr, connection->addrlen), connection); + notify = connection->nth.notify_ready; + GNUNET_assert (NULL != notify); + connection->nth.notify_ready = NULL; + notify (connection->nth.notify_ready_cls, 0, NULL); } @@ -1360,54 +1205,21 @@ transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void connect_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_CONNECTION_Handle *sock = cls; + struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission request of size %u fails (%s/%u), connection failed (%p).\n", - sock->nth.notify_size, sock->hostname, sock->port, sock); - sock->write_task = GNUNET_SCHEDULER_NO_TASK; - notify = sock->nth.notify_ready; - sock->nth.notify_ready = NULL; - notify (sock->nth.notify_ready_cls, 0, NULL); -} - - -/** - * FIXME - * - * @param sock FIXME - */ -static void -transmit_error (struct GNUNET_CONNECTION_Handle *sock) -{ - GNUNET_CONNECTION_TransmitReadyNotify notify; - - if (NULL != sock->sock) - { - GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR); - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock)); - sock->sock = NULL; - } - if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (sock->read_task); - sock->read_task = GNUNET_SCHEDULER_NO_TASK; - signal_timeout (sock); - return; - } - if (sock->nth.notify_ready == NULL) - return; /* nobody to tell about it */ - notify = sock->nth.notify_ready; - sock->nth.notify_ready = NULL; - notify (sock->nth.notify_ready_cls, 0, NULL); + connection->nth.notify_size, connection->hostname, connection->port, connection); + connection->write_task = GNUNET_SCHEDULER_NO_TASK; + notify = connection->nth.notify_ready; + connection->nth.notify_ready = NULL; + notify (connection->nth.notify_ready_cls, 0, NULL); } /** - * See if we are now connected. If not, wait longer for - * connect to succeed. If connected, we should be able - * to write now as well, unless we timed out. + * We are ready to transmit (or got a timeout). * * @param cls our connection handle * @param tc task context describing why we are here @@ -1415,27 +1227,27 @@ transmit_error (struct GNUNET_CONNECTION_Handle *sock) static void transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_CONNECTION_Handle *sock = cls; + struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; ssize_t ret; size_t have; - LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", sock); - GNUNET_assert (sock->write_task != GNUNET_SCHEDULER_NO_TASK); - sock->write_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_assert (sock->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK); + LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", connection); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != connection->write_task); + connection->write_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task); if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { - if ((sock->ignore_shutdown == GNUNET_YES) && (NULL != sock->sock)) + if (NULL != connection->sock) goto SCHEDULE_WRITE; /* ignore shutdown, go again immediately */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, shutdown happened (%p).\n", - GNUNET_a2s (sock->addr, sock->addrlen), sock); - notify = sock->nth.notify_ready; + GNUNET_a2s (connection->addr, connection->addrlen), connection); + notify = connection->nth.notify_ready; if (NULL != notify) { - sock->nth.notify_ready = NULL; - notify (sock->nth.notify_ready_cls, 0, NULL); + connection->nth.notify_ready = NULL; + notify (connection->nth.notify_ready_cls, 0, NULL); } return; } @@ -1443,95 +1255,97 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, time out reached (%p).\n", - GNUNET_a2s (sock->addr, sock->addrlen), sock); - notify = sock->nth.notify_ready; + GNUNET_a2s (connection->addr, connection->addrlen), connection); + notify = connection->nth.notify_ready; GNUNET_assert (NULL != notify); - sock->nth.notify_ready = NULL; - notify (sock->nth.notify_ready_cls, 0, NULL); + connection->nth.notify_ready = NULL; + notify (connection->nth.notify_ready_cls, 0, NULL); return; } - GNUNET_assert (NULL != sock->sock); - if (tc->write_ready == NULL) + GNUNET_assert (NULL != connection->sock); + if (NULL == tc->write_ready) { - /* special circumstances (in particular, - * PREREQ_DONE after connect): not yet ready to write, - * but no "fatal" error either. Hence retry. */ + /* special circumstances (in particular, PREREQ_DONE after + * connect): not yet ready to write, but no "fatal" error either. + * Hence retry. */ goto SCHEDULE_WRITE; } - if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, sock->sock)) + if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock)) { - LOG (GNUNET_ERROR_TYPE_INFO, - _ - ("Could not satisfy pending transmission request, socket closed or connect failed (%p).\n"), - sock); - transmit_error (sock); - return; /* connect failed for good, we're finished */ + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); + /* special circumstances (in particular, shutdown): not yet ready + * to write, but no "fatal" error either. Hence retry. */ + goto SCHEDULE_WRITE; } - GNUNET_assert (sock->write_buffer_off >= sock->write_buffer_pos); - if ((sock->nth.notify_ready != NULL) && - (sock->write_buffer_size < sock->nth.notify_size)) + GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos); + if ((NULL != connection->nth.notify_ready) && + (connection->write_buffer_size < connection->nth.notify_size)) { - sock->write_buffer = - GNUNET_realloc (sock->write_buffer, sock->nth.notify_size); - sock->write_buffer_size = sock->nth.notify_size; + connection->write_buffer = + GNUNET_realloc (connection->write_buffer, connection->nth.notify_size); + connection->write_buffer_size = connection->nth.notify_size; } - process_notify (sock); - have = sock->write_buffer_off - sock->write_buffer_pos; - if (have == 0) + process_notify (connection); + have = connection->write_buffer_off - connection->write_buffer_pos; + if (0 == have) { /* no data ready for writing, terminate write loop */ return; } - GNUNET_assert (have <= sock->write_buffer_size); - GNUNET_assert (have + sock->write_buffer_pos <= sock->write_buffer_size); - GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_size); + GNUNET_assert (have <= connection->write_buffer_size); + GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size); + GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); RETRY: ret = - GNUNET_NETWORK_socket_send (sock->sock, - &sock->write_buffer[sock->write_buffer_pos], - have); - if (ret == -1) + GNUNET_NETWORK_socket_send (connection->sock, + &connection->write_buffer[connection->write_buffer_pos], + have); + if (-1 == ret) { - if (errno == EINTR) + if (EINTR == errno) goto RETRY; - LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "send"); - transmit_error (sock); + if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) + { + GNUNET_SCHEDULER_cancel (connection->write_task); + connection->write_task = GNUNET_SCHEDULER_NO_TASK; + } + signal_transmit_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, - "transmit_ready transmitted %u/%u bytes to `%s' (%p)\n", - (unsigned int) ret, have, GNUNET_a2s (sock->addr, sock->addrlen), sock); - sock->write_buffer_pos += ret; - if (sock->write_buffer_pos == sock->write_buffer_off) + "Connection transmitted %u/%u bytes to `%s' (%p)\n", + (unsigned int) ret, have, GNUNET_a2s (connection->addr, connection->addrlen), connection); + connection->write_buffer_pos += ret; + if (connection->write_buffer_pos == connection->write_buffer_off) { /* transmitted all pending data */ - sock->write_buffer_pos = 0; - sock->write_buffer_off = 0; + connection->write_buffer_pos = 0; + connection->write_buffer_off = 0; } - if ((sock->write_buffer_off == 0) && (NULL == sock->nth.notify_ready)) + if ((0 == connection->write_buffer_off) && (NULL == connection->nth.notify_ready)) return; /* all data sent! */ /* not done writing, schedule more */ SCHEDULE_WRITE: LOG (GNUNET_ERROR_TYPE_DEBUG, - "Re-scheduling transmit_ready (more to do) (%p).\n", sock); - have = sock->write_buffer_off - sock->write_buffer_pos; - GNUNET_assert ((sock->nth.notify_ready != NULL) || (have > 0)); - if (sock->write_task == GNUNET_SCHEDULER_NO_TASK) - sock->write_task = - GNUNET_SCHEDULER_add_write_net ((sock->nth.notify_ready == + "Re-scheduling transmit_ready (more to do) (%p).\n", connection); + have = connection->write_buffer_off - connection->write_buffer_pos; + GNUNET_assert ((NULL != connection->nth.notify_ready) || (have > 0)); + if (GNUNET_SCHEDULER_NO_TASK == connection->write_task) + connection->write_task = + GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready == NULL) ? GNUNET_TIME_UNIT_FOREVER_REL : GNUNET_TIME_absolute_get_remaining - (sock->nth.transmit_timeout), - sock->sock, &transmit_ready, sock); + (connection->nth.transmit_timeout), + connection->sock, &transmit_ready, connection); } /** - * Ask the socket to call us once the specified number of bytes + * Ask the connection to call us once the specified number of bytes * are free in the transmission buffer. May call the notify * method immediately if enough space is available. * - * @param sock socket + * @param connection connection * @param size number of bytes to send * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? @@ -1541,55 +1355,55 @@ SCHEDULE_WRITE: * NULL if we are already going to notify someone else (busy) */ struct GNUNET_CONNECTION_TransmitHandle * -GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *sock, +GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { - if (sock->nth.notify_ready != NULL) + if (NULL != connection->nth.notify_ready) { GNUNET_assert (0); return NULL; } - GNUNET_assert (notify != NULL); + GNUNET_assert (NULL != notify); GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); - GNUNET_assert (sock->write_buffer_off <= sock->write_buffer_size); - GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_size); - GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_off); - sock->nth.notify_ready = notify; - sock->nth.notify_ready_cls = notify_cls; - sock->nth.sh = sock; - sock->nth.notify_size = size; - sock->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->nth.timeout_task); - if ((sock->sock == NULL) && (sock->ap_head == NULL) && - (sock->dns_active == NULL)) + GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size); + GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); + GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off); + connection->nth.notify_ready = notify; + connection->nth.notify_ready_cls = notify_cls; + connection->nth.connection = connection; + connection->nth.notify_size = size; + connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task); + if ((NULL == connection->sock) && + (NULL == connection->ap_head) && + (NULL == connection->dns_active)) { - if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (sock->write_task); - sock->write_task = GNUNET_SCHEDULER_add_now (&connect_error, sock); - return &sock->nth; + if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) + GNUNET_SCHEDULER_cancel (connection->write_task); + connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error, connection); + return &connection->nth; } - if (GNUNET_SCHEDULER_NO_TASK != sock->write_task) - return &sock->nth; - if (sock->sock != NULL) + if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) + return &connection->nth; /* previous transmission still in progress */ + if (NULL != connection->sock) { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling transmit_ready (%p).\n", sock); - sock->write_task = + /* connected, try to transmit now */ + LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling transmission (%p).\n", connection); + connection->write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining - (sock->nth.transmit_timeout), - sock->sock, &transmit_ready, sock); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "CCS-Scheduling transmit_ready, adding timeout task (%p).\n", sock); - sock->ccs |= COCO_TRANSMIT_READY; - sock->nth.timeout_task = - GNUNET_SCHEDULER_add_delayed (timeout, &transmit_timeout, sock); + (connection->nth.transmit_timeout), + connection->sock, &transmit_ready, connection); + return &connection->nth; } - return &sock->nth; + /* not yet connected, wait for connection */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Need to wait to schedule transmission for connection, adding timeout task (%p).\n", connection); + connection->nth.timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &transmit_timeout, connection); + return &connection->nth; } @@ -1603,24 +1417,18 @@ GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th) { - GNUNET_assert (th->notify_ready != NULL); - if (0 != (th->sh->ccs & COCO_TRANSMIT_READY)) + GNUNET_assert (NULL != th->notify_ready); + th->notify_ready = NULL; + if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task) { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "notify_transmit_ready_cancel cancels timeout_task (%p)\n", th); GNUNET_SCHEDULER_cancel (th->timeout_task); th->timeout_task = GNUNET_SCHEDULER_NO_TASK; - th->sh->ccs -= COCO_TRANSMIT_READY; } - else + if (GNUNET_SCHEDULER_NO_TASK != th->connection->write_task) { - if (th->sh->write_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (th->sh->write_task); - th->sh->write_task = GNUNET_SCHEDULER_NO_TASK; - } + GNUNET_SCHEDULER_cancel (th->connection->write_task); + th->connection->write_task = GNUNET_SCHEDULER_NO_TASK; } - th->notify_ready = NULL; } /* end of connection.c */ diff --git a/src/util/container_bloomfilter.c b/src/util/container_bloomfilter.c index 84aab6b..8c226f6 100644 --- a/src/util/container_bloomfilter.c +++ b/src/util/container_bloomfilter.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2006, 2008, 2011 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2003, 2004, 2006, 2008, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -350,14 +350,16 @@ iterateBits (const struct GNUNET_CONTAINER_BloomFilter *bf, bitCount = bf->addressesPerElement; tmp[0] = *key; round = 0; + GNUNET_assert (bf->bitArraySize > 0); + GNUNET_assert (bf->bitArraySize * 8LL > bf->bitArraySize); while (bitCount > 0) { while (slot < (sizeof (GNUNET_HashCode) / sizeof (uint32_t))) { if (GNUNET_YES != callback (arg, bf, - (((uint32_t *) & tmp[round & 1])[slot]) & - ((bf->bitArraySize * 8) - 1))) + (((uint32_t *) & tmp[round & 1])[slot]) % + ((bf->bitArraySize * 8LL)))) return; slot++; bitCount--; @@ -442,7 +444,8 @@ testBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, * * @param filename the name of the file (or the prefix) * @param size the size of the bloom-filter (number of - * bytes of storage space to use) + * bytes of storage space to use); will be rounded up + * to next power of 2 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per * element (number of bits set per element in the set) * @return the bloomfilter @@ -549,8 +552,6 @@ GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size, } bf->bitArraySize = size; bf->addressesPerElement = k; - memset (bf->bitArray, 0, bf->bitArraySize); - if (GNUNET_YES != must_read) return bf; /* already done! */ /* Read from the file what bits we can */ @@ -606,33 +607,22 @@ GNUNET_CONTAINER_bloomfilter_init (const char *data, size_t size, unsigned int k) { struct GNUNET_CONTAINER_BloomFilter *bf; - size_t ui; - if ((k == 0) || (size == 0)) - return NULL; - ui = 1; - while (ui < size) - ui *= 2; - if (size != ui) - { - GNUNET_break (0); + if ((0 == k) || (0 == size)) return NULL; - } bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); bf->filename = NULL; bf->fh = NULL; bf->bitArray = GNUNET_malloc_large (size); - if (bf->bitArray == NULL) + if (NULL == bf->bitArray) { GNUNET_free (bf); return NULL; } bf->bitArraySize = size; bf->addressesPerElement = k; - if (data != NULL) + if (NULL != data) memcpy (bf->bitArray, data, size); - else - memset (bf->bitArray, 0, bf->bitArraySize); return bf; } @@ -848,7 +838,6 @@ GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, bf->bitArraySize = size; bf->bitArray = GNUNET_malloc (size); - memset (bf->bitArray, 0, bf->bitArraySize); if (bf->filename != NULL) make_empty_file (bf->fh, bf->bitArraySize * 4LL); while (GNUNET_YES == iterator (iterator_cls, &hc)) diff --git a/src/util/container_heap.c b/src/util/container_heap.c index c34e220..b9cab1e 100644 --- a/src/util/container_heap.c +++ b/src/util/container_heap.c @@ -30,7 +30,7 @@ #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) -#define DEBUG 0 +#define EXTRA_CHECKS 0 /** * Node in the heap. @@ -104,7 +104,7 @@ struct GNUNET_CONTAINER_Heap }; -#if DEBUG +#if EXTRA_CHECKS /** * Check if internal invariants hold for the given node. * @@ -401,7 +401,7 @@ GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap) insert_node (heap, heap->root, root->right_child); } GNUNET_free (root); -#if DEBUG +#if EXTRA_CHECKS GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); CHECK (heap->root); @@ -502,7 +502,7 @@ GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node) if (heap->walk_pos == node) heap->walk_pos = NULL; GNUNET_free (node); -#if DEBUG +#if EXTRA_CHECKS CHECK (heap->root); GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); @@ -523,13 +523,13 @@ GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapCostType new_cost) { -#if DEBUG +#if EXTRA_CHECKS GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); CHECK (heap->root); #endif remove_node (node); -#if DEBUG +#if EXTRA_CHECKS CHECK (heap->root); GNUNET_assert (((heap->size == 1) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 2)); @@ -539,7 +539,7 @@ GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, heap->root = node; else insert_node (heap, heap->root, node); -#if DEBUG +#if EXTRA_CHECKS CHECK (heap->root); GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); diff --git a/src/util/container_slist.c b/src/util/container_slist.c index 7b85dc8..6b58325 100644 --- a/src/util/container_slist.c +++ b/src/util/container_slist.c @@ -250,10 +250,11 @@ GNUNET_CONTAINER_slist_clear (struct GNUNET_CONTAINER_SList *l) /** * Check if a list contains a certain element - * * @param l list * @param buf payload buffer to find * @param len length of the payload (number of bytes in buf) + * + * @return GNUNET_YES if found, GNUNET_NO otherwise */ int GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, @@ -267,6 +268,32 @@ GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, return GNUNET_NO; } +typedef int (*Comparator)(const void *, size_t, const void *, size_t); + +/** + * Check if a list contains a certain element + * + * @param l list + * @param buf payload buffer to find + * @param len length of the payload (number of bytes in buf) + * @param compare comparison function, should return 0 if compared elements match + * + * @return NULL if the 'buf' could not be found, pointer to the + * list element, if found + */ +void * +GNUNET_CONTAINER_slist_contains2 (const struct GNUNET_CONTAINER_SList *l, + const void *buf, size_t len, + Comparator compare) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + for (e = l->head; e != NULL; e = e->next) + if ((e->len == len) && (*compare)(buf, len, e->elem, e->len) == 0) + return e->elem; + return NULL; +} + /** * Count the elements of a list diff --git a/src/util/crypto_aes.c b/src/util/crypto_aes.c index 8b031f3..d5c36d7 100644 --- a/src/util/crypto_aes.c +++ b/src/util/crypto_aes.c @@ -34,6 +34,8 @@ /** * Create a new SessionKey (for AES-256). + * + * @param key session key to initialize */ void GNUNET_CRYPTO_aes_create_session_key (struct GNUNET_CRYPTO_AesSessionKey *key) @@ -44,6 +46,7 @@ GNUNET_CRYPTO_aes_create_session_key (struct GNUNET_CRYPTO_AesSessionKey *key) htonl (GNUNET_CRYPTO_crc32_n (key, GNUNET_CRYPTO_AES_KEY_LENGTH)); } + /** * Check that a new session key is well-formed. * @@ -56,16 +59,55 @@ GNUNET_CRYPTO_aes_check_session_key (const struct GNUNET_CRYPTO_AesSessionKey uint32_t crc; crc = GNUNET_CRYPTO_crc32_n (key, GNUNET_CRYPTO_AES_KEY_LENGTH); - if (ntohl (key->crc32) == crc) - return GNUNET_OK; - GNUNET_break_op (0); - return GNUNET_SYSERR; + if (ntohl (key->crc32) != crc) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Initialize AES cipher. + * + * @param handle handle to initialize + * @param sessionkey session key to use + * @param iv initialization vector to use + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +setup_cipher (gcry_cipher_hd_t *handle, + const struct GNUNET_CRYPTO_AesSessionKey * + sessionkey, + const struct GNUNET_CRYPTO_AesInitializationVector * + iv) +{ + int rc; + + if (GNUNET_OK != + GNUNET_CRYPTO_aes_check_session_key (sessionkey)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_assert (0 == + gcry_cipher_open (handle, GCRY_CIPHER_AES256, + GCRY_CIPHER_MODE_CFB, 0)); + rc = gcry_cipher_setkey (*handle, sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + rc = gcry_cipher_setiv (*handle, iv, + sizeof (struct + GNUNET_CRYPTO_AesInitializationVector)); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + return GNUNET_OK; } /** * Encrypt a block with the public key of another * host that uses the same cyper. + * * @param block the block to encrypt * @param len the size of the block * @param sessionkey the key used to encrypt @@ -82,28 +124,15 @@ GNUNET_CRYPTO_aes_encrypt (const void *block, size_t len, iv, void *result) { gcry_cipher_hd_t handle; - int rc; - if (sessionkey->crc32 != - htonl (GNUNET_CRYPTO_crc32_n (sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH))) - { - GNUNET_break (0); + if (GNUNET_OK != setup_cipher (&handle, sessionkey, iv)) return -1; - } - GNUNET_assert (0 == - gcry_cipher_open (&handle, GCRY_CIPHER_AES256, - GCRY_CIPHER_MODE_CFB, 0)); - rc = gcry_cipher_setkey (handle, sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); - GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); - rc = gcry_cipher_setiv (handle, iv, - sizeof (struct - GNUNET_CRYPTO_AesInitializationVector)); - GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, len, block, len)); gcry_cipher_close (handle); return len; } + /** * Decrypt a given block with the sessionkey. * @@ -123,30 +152,18 @@ GNUNET_CRYPTO_aes_decrypt (const void *block, size_t size, iv, void *result) { gcry_cipher_hd_t handle; - int rc; - if (sessionkey->crc32 != - htonl (GNUNET_CRYPTO_crc32_n (sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH))) - { - GNUNET_break (0); + if (GNUNET_OK != setup_cipher (&handle, sessionkey, iv)) return -1; - } - GNUNET_assert (0 == - gcry_cipher_open (&handle, GCRY_CIPHER_AES256, - GCRY_CIPHER_MODE_CFB, 0)); - rc = gcry_cipher_setkey (handle, sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); - GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); - rc = gcry_cipher_setiv (handle, iv, - sizeof (struct - GNUNET_CRYPTO_AesInitializationVector)); - GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, block, size)); gcry_cipher_close (handle); return size; } + /** * @brief Derive an IV + * * @param iv initialization vector * @param skey session key * @param salt salt for the derivation @@ -165,8 +182,10 @@ GNUNET_CRYPTO_aes_derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, va_end (argp); } + /** * @brief Derive an IV + * * @param iv initialization vector * @param skey session key * @param salt salt for the derivation diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c index 63d9654..4d957c0 100644 --- a/src/util/crypto_hash.c +++ b/src/util/crypto_hash.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -34,6 +34,7 @@ #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" +#include "gnunet_strings_lib.h" #include <gcrypt.h> #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) @@ -55,6 +56,21 @@ GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret) /** + * Compute short (256-bit) hash of a given block. + * + * @param block the data to GNUNET_CRYPTO_hash, length is given as a second argument + * @param size the length of the data to GNUNET_CRYPTO_hash + * @param ret pointer to where to write the hashcode + */ +void +GNUNET_CRYPTO_short_hash (const void *block, size_t size, + struct GNUNET_CRYPTO_ShortHashCode * ret) +{ + gcry_md_hash_buffer (GCRY_MD_SHA256, ret, block, size); +} + + +/** * Context used when hashing a file. */ struct GNUNET_CRYPTO_FileHashContext @@ -204,7 +220,7 @@ GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority, return NULL; } fhc->bsize = blocksize; - if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO)) + if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO, GNUNET_YES)) { GNUNET_free (fhc->filename); GNUNET_free (fhc); @@ -241,25 +257,8 @@ GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc) } - /* ***************** binary-ASCII encoding *************** */ -/** - * Get the numeric value corresponding to a character. - * - * @param a a character - * @return corresponding numeric value - */ -static unsigned int -getValue__ (unsigned char a) -{ - if ((a >= '0') && (a <= '9')) - return a - '0'; - if ((a >= 'A') && (a <= 'V')) - return (a - 'A' + 10); - return -1; -} - /** * Convert GNUNET_CRYPTO_hash to ASCII encoding. The ASCII encoding is rather @@ -276,88 +275,37 @@ void GNUNET_CRYPTO_hash_to_enc (const GNUNET_HashCode * block, struct GNUNET_CRYPTO_HashAsciiEncoded *result) { - /** - * 32 characters for encoding (GNUNET_CRYPTO_hash => 32 characters) - */ - static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; - unsigned int wpos; - unsigned int rpos; - unsigned int bits; - unsigned int vbit; - - GNUNET_assert (block != NULL); - GNUNET_assert (result != NULL); - vbit = 0; - wpos = 0; - rpos = 0; - bits = 0; - while ((rpos < sizeof (GNUNET_HashCode)) || (vbit > 0)) - { - if ((rpos < sizeof (GNUNET_HashCode)) && (vbit < 5)) - { - bits = (bits << 8) | ((unsigned char *) block)[rpos++]; /* eat 8 more bits */ - vbit += 8; - } - if (vbit < 5) - { - bits <<= (5 - vbit); /* zero-padding */ - GNUNET_assert (vbit == 2); /* padding by 3: 512+3 mod 5 == 0 */ - vbit = 5; - } - GNUNET_assert (wpos < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); - result->encoding[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; - vbit -= 5; - } - GNUNET_assert (wpos == sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); - GNUNET_assert (vbit == 0); - result->encoding[wpos] = '\0'; + char *np; + + np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block, + sizeof (struct GNUNET_HashCode), + (char*) result, + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); + GNUNET_assert (NULL != np); + *np = '\0'; } /** - * Convert ASCII encoding back to GNUNET_CRYPTO_hash + * Convert ASCII encoding back to hash code. * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) - * @param result where to store the GNUNET_CRYPTO_hash code + * @param result where to store the hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_CRYPTO_hash_from_string2 (const char *enc, size_t enclen, GNUNET_HashCode * result) { - unsigned int rpos; - unsigned int wpos; - unsigned int bits; - unsigned int vbit; - int ret; + char upper_enc[enclen]; + char* up_ptr = upper_enc; - if (enclen != sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1) - return GNUNET_SYSERR; + GNUNET_STRINGS_utf8_toupper(enc, &up_ptr); - vbit = 2; /* padding! */ - wpos = sizeof (GNUNET_HashCode); - rpos = sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1; - bits = (ret = getValue__ (enc[--rpos])) >> 3; - if (-1 == ret) - return GNUNET_SYSERR; - while (wpos > 0) - { - GNUNET_assert (rpos > 0); - bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; - if (-1 == ret) - return GNUNET_SYSERR; - vbit += 5; - if (vbit >= 8) - { - ((unsigned char *) result)[--wpos] = (unsigned char) bits; - bits >>= 8; - vbit -= 8; - } - } - GNUNET_assert (rpos == 0); - GNUNET_assert (vbit == 0); - return GNUNET_OK; + return GNUNET_STRINGS_string_to_data (upper_enc, enclen, + (unsigned char*) result, + sizeof (struct GNUNET_HashCode)); } @@ -644,4 +592,119 @@ GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, } + +/** + * Double short (256-bit) hash to create a long hash. + * + * @param sh short hash to double + * @param dh where to store the (doubled) long hash (not really a hash) + */ +void +GNUNET_CRYPTO_short_hash_double (const struct GNUNET_CRYPTO_ShortHashCode *sh, + struct GNUNET_HashCode *dh) +{ + char *ptr; + + ptr = (char*) dh; + memcpy (ptr, sh, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); + memcpy (&ptr[sizeof (struct GNUNET_CRYPTO_ShortHashCode)], sh, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); +} + + +/** + * Truncate doubled short hash back to a short hash. + * + * @param dh doubled short hash to reduce again + * @param sh where to store the short hash + * @return GNUNET_OK on success, GNUNET_SYSERR if this was not a + * doubled short hash + */ +int +GNUNET_CRYPTO_short_hash_from_truncation (const struct GNUNET_HashCode *dh, + struct GNUNET_CRYPTO_ShortHashCode *sh) +{ + const struct GNUNET_CRYPTO_ShortHashCode *s; + + s = (const struct GNUNET_CRYPTO_ShortHashCode *) dh; + if (0 != memcmp (&s[0], + &s[1], + sizeof (struct GNUNET_CRYPTO_ShortHashCode))) + return GNUNET_SYSERR; + *sh = *s; + return GNUNET_OK; +} + + +/** + * Convert ASCII encoding back to a 'struct GNUNET_CRYPTO_ShortHash' + * + * @param enc the encoding + * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) + * @param result where to store the GNUNET_CRYPTO_hash code + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ +int +GNUNET_CRYPTO_short_hash_from_string2 (const char *enc, size_t enclen, + struct GNUNET_CRYPTO_ShortHashCode * result) +{ + + char upper_enc[enclen]; + char* up_ptr = upper_enc; + + GNUNET_STRINGS_utf8_toupper(enc, &up_ptr); + return GNUNET_STRINGS_string_to_data (upper_enc, enclen, + (unsigned char*) result, + sizeof (struct GNUNET_CRYPTO_ShortHashCode)); +} + + +/** + * Convert short hash to ASCII encoding. + * + * @param block the hash code + * @param result where to store the encoding (struct GNUNET_CRYPTO_ShortHashAsciiEncoded can be + * safely cast to char*, a '\\0' termination is set). + */ +void +GNUNET_CRYPTO_short_hash_to_enc (const struct GNUNET_CRYPTO_ShortHashCode * block, + struct GNUNET_CRYPTO_ShortHashAsciiEncoded *result) +{ + char *np; + + np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block, + sizeof (struct GNUNET_CRYPTO_ShortHashCode), + (char*) result, + sizeof (struct GNUNET_CRYPTO_ShortHashAsciiEncoded) - 1); + GNUNET_assert (NULL != np); + *np = '\0'; +} + +/** + * Compare function for ShortHashCodes, producing a total ordering + * of all hashcodes. + * + * @param h1 some hash code + * @param h2 some hash code + * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. + */ +int +GNUNET_CRYPTO_short_hash_cmp (const struct GNUNET_CRYPTO_ShortHashCode * h1, + const struct GNUNET_CRYPTO_ShortHashCode * h2) +{ + unsigned int *i1; + unsigned int *i2; + int i; + + i1 = (unsigned int *) h1; + i2 = (unsigned int *) h2; + for (i = (sizeof (struct GNUNET_CRYPTO_ShortHashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) + { + if (i1[i] > i2[i]) + return 1; + if (i1[i] < i2[i]) + return -1; + } + return 0; +} + /* end of crypto_hash.c */ diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c index 40bfa67..c2b9677 100644 --- a/src/util/crypto_hkdf.c +++ b/src/util/crypto_hkdf.c @@ -49,6 +49,7 @@ #define DEBUG_HKDF 0 + #if GNUNET_BUILD #include "platform.h" #include "gnunet_crypto_lib.h" diff --git a/src/util/crypto_ksk.c b/src/util/crypto_ksk.c index 0f5a295..274457b 100644 --- a/src/util/crypto_ksk.c +++ b/src/util/crypto_ksk.c @@ -557,202 +557,65 @@ makeKblockKeyInternal (const GNUNET_HashCode * hc) /** - * Decode the internal format into the format used - * by libgcrypt. + * Entry in the KSK cache. */ -static struct GNUNET_CRYPTO_RsaPrivateKey * -ksk_decode_key (const struct KskRsaPrivateKeyBinaryEncoded *encoding) -{ - struct GNUNET_CRYPTO_RsaPrivateKey *ret; - gcry_sexp_t res; - gcry_mpi_t n, e, d, p, q, u; - int rc; - size_t size; - int pos; - - pos = 0; - size = ntohs (encoding->sizen); - rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, - &((const unsigned char *) (&encoding[1]))[pos], size, - &size); - pos += ntohs (encoding->sizen); - if (rc) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - return NULL; - } - size = ntohs (encoding->sizee); - rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, - &((const unsigned char *) (&encoding[1]))[pos], size, - &size); - pos += ntohs (encoding->sizee); - if (rc) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (n); - return NULL; - } - size = ntohs (encoding->sized); - rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG, - &((const unsigned char *) (&encoding[1]))[pos], size, - &size); - pos += ntohs (encoding->sized); - if (rc) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (n); - gcry_mpi_release (e); - return NULL; - } - /* swap p and q! */ - size = ntohs (encoding->sizep); - if (size > 0) - { - rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, - &((const unsigned char *) (&encoding[1]))[pos], size, - &size); - pos += ntohs (encoding->sizep); - if (rc) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (n); - gcry_mpi_release (e); - gcry_mpi_release (d); - return NULL; - } - } - else - q = NULL; - size = ntohs (encoding->sizeq); - if (size > 0) - { - rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG, - &((const unsigned char *) (&encoding[1]))[pos], size, - &size); - pos += ntohs (encoding->sizeq); - if (rc) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (n); - gcry_mpi_release (e); - gcry_mpi_release (d); - if (q != NULL) - gcry_mpi_release (q); - return NULL; - } - } - else - p = NULL; - pos += ntohs (encoding->sizedmp1); - pos += ntohs (encoding->sizedmq1); - size = - ntohs (encoding->len) - sizeof (struct KskRsaPrivateKeyBinaryEncoded) - - pos; - if (size > 0) - { - rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG, - &((const unsigned char *) (&encoding[1]))[pos], size, - &size); - if (rc) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (n); - gcry_mpi_release (e); - gcry_mpi_release (d); - if (p != NULL) - gcry_mpi_release (p); - if (q != NULL) - gcry_mpi_release (q); - return NULL; - } - } - else - u = NULL; - - if ((p != NULL) && (q != NULL) && (u != NULL)) - { - rc = gcry_sexp_build (&res, &size, /* erroff */ - "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))", - n, e, d, p, q, u); - } - else - { - if ((p != NULL) && (q != NULL)) - { - rc = gcry_sexp_build (&res, &size, /* erroff */ - "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))", - n, e, d, p, q); - } - else - { - rc = gcry_sexp_build (&res, &size, /* erroff */ - "(private-key(rsa(n %m)(e %m)(d %m)))", n, e, d); - } - } - gcry_mpi_release (n); - gcry_mpi_release (e); - gcry_mpi_release (d); - if (p != NULL) - gcry_mpi_release (p); - if (q != NULL) - gcry_mpi_release (q); - if (u != NULL) - gcry_mpi_release (u); - - if (rc) - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); -#if EXTRA_CHECKS - if (gcry_pk_testkey (res)) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); - return NULL; - } -#endif - ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); - ret->sexp = res; - return ret; -} - - struct KBlockKeyCacheLine { + /** + * Hash from which the key was generated. + */ GNUNET_HashCode hc; + + /** + * The encoded key. + */ struct KskRsaPrivateKeyBinaryEncoded *pke; }; + +/** + * Cached KSK keys so that we don't have to recompute them + * all the time. + */ static struct KBlockKeyCacheLine **cache; + +/** + * Size of the 'cache' array. + */ static unsigned int cacheSize; + /** * Deterministically (!) create a hostkey using only the * given HashCode as input to the PRNG. + * + * @param hc hash code to generate the key from + * @return corresponding private key; must not be freed! */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create_from_hash (const GNUNET_HashCode * hc) { - struct GNUNET_CRYPTO_RsaPrivateKey *ret; struct KBlockKeyCacheLine *line; unsigned int i; - for (i = 0; i < cacheSize; i++) - { + for (i = 0; i < cacheSize; i++) if (0 == memcmp (hc, &cache[i]->hc, sizeof (GNUNET_HashCode))) - { - ret = ksk_decode_key (cache[i]->pke); - return ret; - } - } - + return GNUNET_CRYPTO_rsa_decode_key ((const char*) cache[i]->pke, + ntohs (cache[i]->pke->len)); line = GNUNET_malloc (sizeof (struct KBlockKeyCacheLine)); line->hc = *hc; line->pke = makeKblockKeyInternal (hc); GNUNET_array_grow (cache, cacheSize, cacheSize + 1); cache[cacheSize - 1] = line; - return ksk_decode_key (line->pke); + return GNUNET_CRYPTO_rsa_decode_key ((const char*) line->pke, + ntohs (line->pke->len)); } +/** + * Destructor that frees the KSK cache. + */ void __attribute__ ((destructor)) GNUNET_CRYPTO_ksk_fini () { unsigned int i; diff --git a/src/util/crypto_random.c b/src/util/crypto_random.c index 25226a3..35d3c41 100644 --- a/src/util/crypto_random.c +++ b/src/util/crypto_random.c @@ -256,7 +256,7 @@ entropy_generator (void *cls, const char *what, int printchar, int current, if (0 != GNUNET_OS_process_kill (genproc, SIGTERM)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill"); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); - GNUNET_OS_process_close (genproc); + GNUNET_OS_process_destroy (genproc); genproc = NULL; } return; @@ -274,7 +274,7 @@ entropy_generator (void *cls, const char *what, int printchar, int current, if (0 != GNUNET_OS_process_kill (genproc, SIGTERM)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill"); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); - GNUNET_OS_process_close (genproc); + GNUNET_OS_process_destroy (genproc); genproc = NULL; } LOG (GNUNET_ERROR_TYPE_INFO, _("Starting `%s' process to generate entropy\n"), @@ -293,7 +293,7 @@ killfind () if (genproc != NULL) { GNUNET_OS_process_kill (genproc, SIGKILL); - GNUNET_OS_process_close (genproc); + GNUNET_OS_process_destroy (genproc); genproc = NULL; } } diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c index 418fe83..0106f43 100644 --- a/src/util/crypto_rsa.c +++ b/src/util/crypto_rsa.c @@ -36,6 +36,7 @@ #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" +#include "gnunet_strings_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) @@ -53,32 +54,6 @@ struct GNUNET_CRYPTO_RsaPrivateKey }; -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * GNUnet mandates a certain format for the encoding - * of private RSA key information that is provided - * by the RSA implementations. This format is used - * to serialize a private RSA key (typically when - * writing it to disk). - */ -struct RsaPrivateKeyBinaryEncoded -{ - /** - * Total size of the structure, in bytes, in big-endian! - */ - uint16_t len GNUNET_PACKED; - uint16_t sizen GNUNET_PACKED; /* in big-endian! */ - uint16_t sizee GNUNET_PACKED; /* in big-endian! */ - uint16_t sized GNUNET_PACKED; /* in big-endian! */ - uint16_t sizep GNUNET_PACKED; /* in big-endian! */ - uint16_t sizeq GNUNET_PACKED; /* in big-endian! */ - uint16_t sizedmp1 GNUNET_PACKED; /* in big-endian! */ - uint16_t sizedmq1 GNUNET_PACKED; /* in big-endian! */ - /* followed by the actual values */ -}; -GNUNET_NETWORK_STRUCT_END - #define HOSTKEY_LEN 2048 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS @@ -107,7 +82,9 @@ adjust (unsigned char *buf, size_t size, size_t target) } /** - * This HostKey implementation uses RSA. + * Create a new private key. Caller must free return value. + * + * @return fresh private key */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create () @@ -132,6 +109,7 @@ GNUNET_CRYPTO_rsa_key_create () /** * Free memory occupied by hostkey + * @param hostkey pointer to the memory to free */ void GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) @@ -238,6 +216,70 @@ GNUNET_CRYPTO_rsa_key_get_public (const struct GNUNET_CRYPTO_RsaPrivateKey /** + * Convert a public key to a string. + * + * @param pub key to convert + * @return string representing 'pub' + */ +char * +GNUNET_CRYPTO_rsa_public_key_to_string (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub) +{ + char *pubkeybuf; + size_t keylen = (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) * 8; + char *end; + + if (keylen % 5 > 0) + keylen += 5 - keylen % 5; + keylen /= 5; + pubkeybuf = GNUNET_malloc (keylen + 1); + end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + pubkeybuf, + keylen); + if (NULL == end) + { + GNUNET_free (pubkeybuf); + return NULL; + } + *end = '\0'; + return pubkeybuf; +} + + +/** + * Convert a string representing a public key to a public key. + * + * @param enc encoded public key + * @param enclen number of bytes in enc (without 0-terminator) + * @param pub where to store the public key + * @return GNUNET_OK on success + */ +int +GNUNET_CRYPTO_rsa_public_key_from_string (const char *enc, + size_t enclen, + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub) +{ + size_t keylen = (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) * 8; + + if (keylen % 5 > 0) + keylen += 5 - keylen % 5; + keylen /= 5; + if (enclen != keylen) + return GNUNET_SYSERR; + + if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen, + (unsigned char*) pub, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) + return GNUNET_SYSERR; + if ( (ntohs (pub->len) != sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) || + (ntohs (pub->padding) != 0) || + (ntohs (pub->sizen) != GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH) ) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** * Internal: publicKey => RSA-Key. * * Note that the return type is not actually a private @@ -301,10 +343,10 @@ public2PrivateKey (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * @returns encoding of the private key. * The first 4 bytes give the size of the array, as usual. */ -static struct RsaPrivateKeyBinaryEncoded * -rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) +struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * +GNUNET_CRYPTO_rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) { - struct RsaPrivateKeyBinaryEncoded *retval; + struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *retval; gcry_mpi_t pkv[6]; void *pbu[6]; size_t sizes[6]; @@ -333,7 +375,7 @@ rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) if (rc) rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned"); GNUNET_assert (0 == rc); - size = sizeof (struct RsaPrivateKeyBinaryEncoded); + size = sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded); for (i = 0; i < 6; i++) { if (pkv[i] != NULL) @@ -383,6 +425,7 @@ rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) return retval; } + /** * Decode the private key from the file-format back * to the "normal", internal format. @@ -394,8 +437,8 @@ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len) { struct GNUNET_CRYPTO_RsaPrivateKey *ret; - const struct RsaPrivateKeyBinaryEncoded *encoding = - (const struct RsaPrivateKeyBinaryEncoded *) buf; + const struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *encoding = + (const struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *) buf; gcry_sexp_t res; gcry_mpi_t n, e, d, p, q, u; int rc; @@ -483,7 +526,7 @@ GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len) pos += ntohs (encoding->sizedmp1); pos += ntohs (encoding->sizedmq1); size = - ntohs (encoding->len) - sizeof (struct RsaPrivateKeyBinaryEncoded) - pos; + ntohs (encoding->len) - sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded) - pos; if (size > 0) { rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG, @@ -567,7 +610,7 @@ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) { struct GNUNET_CRYPTO_RsaPrivateKey *ret; - struct RsaPrivateKeyBinaryEncoded *enc; + struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *enc; uint16_t len; struct GNUNET_DISK_FileHandle *fd; unsigned int cnt; @@ -607,7 +650,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) while (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, - sizeof (struct RsaPrivateKeyBinaryEncoded), + sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), GNUNET_YES)) { sleep (1); @@ -623,7 +666,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) _("Creating a new private key. This may take a while.\n")); ret = GNUNET_CRYPTO_rsa_key_create (); GNUNET_assert (ret != NULL); - enc = rsa_encode_key (ret); + enc = GNUNET_CRYPTO_rsa_encode_key (ret); GNUNET_assert (enc != NULL); GNUNET_assert (ntohs (enc->len) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->len))); @@ -632,7 +675,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) GNUNET_DISK_file_sync (fd); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, - sizeof (struct RsaPrivateKeyBinaryEncoded))) + sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); GNUNET_CRYPTO_rsa_key_get_public (ret, &pub); @@ -655,7 +698,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) { if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, - sizeof (struct RsaPrivateKeyBinaryEncoded), + sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), GNUNET_NO)) { if (0 == ++cnt % 60) @@ -677,21 +720,21 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, - sizeof (struct RsaPrivateKeyBinaryEncoded))) + sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); return NULL; } - if (GNUNET_YES != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES)) + if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; - if (fs < sizeof (struct RsaPrivateKeyBinaryEncoded)) + if (fs < sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)) { /* maybe we got the read lock before the hostkey generating * process had a chance to get the write lock; give it up! */ if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, - sizeof (struct RsaPrivateKeyBinaryEncoded))) + sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); if (0 == ++cnt % 10) { @@ -699,7 +742,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) _ ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"), filename, (unsigned int) fs, - (unsigned int) sizeof (struct RsaPrivateKeyBinaryEncoded)); + (unsigned int) sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)); LOG (GNUNET_ERROR_TYPE_ERROR, _ ("This may be ok if someone is currently generating a hostkey.\n")); @@ -727,7 +770,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) GNUNET_free (enc); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, - sizeof (struct RsaPrivateKeyBinaryEncoded))) + sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); if (ret != NULL) @@ -743,6 +786,35 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) /** + * Setup a hostkey file for a peer given the name of the + * configuration file (!). This function is used so that + * at a later point code can be certain that reading a + * hostkey is fast (for example in time-dependent testcases). + * + * @param cfg_name name of the configuration file to use + */ +void +GNUNET_CRYPTO_setup_hostkey (const char *cfg_name) +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CRYPTO_RsaPrivateKey *pk; + char *fn; + + cfg = GNUNET_CONFIGURATION_create (); + (void) GNUNET_CONFIGURATION_load (cfg, cfg_name); + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &fn)) + { + pk = GNUNET_CRYPTO_rsa_key_create_from_file (fn); + if (NULL != pk) + GNUNET_CRYPTO_rsa_key_free (pk); + GNUNET_free (fn); + } + GNUNET_CONFIGURATION_destroy (cfg); +} + + +/** * Encrypt a block with the public key of another host that uses the * same cipher. * @@ -793,6 +865,7 @@ GNUNET_CRYPTO_rsa_encrypt (const void *block, size_t size, return GNUNET_OK; } + /** * Decrypt a given block with the hostkey. * diff --git a/src/util/disk.c b/src/util/disk.c index b6b458f..cba0d44 100644 --- a/src/util/disk.c +++ b/src/util/disk.c @@ -40,10 +40,6 @@ #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) -#define DEBUG_NPIPE GNUNET_EXTRA_LOGGING - -#define DEBUG_PIPE GNUNET_EXTRA_LOGGING - /** * Block size for IO for copying files. */ @@ -112,9 +108,22 @@ struct GetFileSizeData * GNUNET_YES if symbolic links should be included. */ int include_sym_links; + + /** + * GNUNET_YES if mode is file-only (return total == -1 for directories). + */ + int single_file_mode; }; +#ifndef MINGW +/** + * Translate GNUnet-internal permission bitmap to UNIX file + * access permission bitmap. + * + * @param perm file permissions, GNUnet style + * @return file permissions, UNIX style + */ static int translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm) { @@ -142,6 +151,7 @@ translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm) return mode; } +#endif /** @@ -166,16 +176,21 @@ getSizeRec (void *cls, const char *fn) #ifdef HAVE_STAT64 if (0 != STAT64 (fn, &buf)) { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat64", fn); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn); return GNUNET_SYSERR; } #else if (0 != STAT (fn, &buf)) { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fn); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn); return GNUNET_SYSERR; } #endif + if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES)) + { + errno = EISDIR; + return GNUNET_SYSERR; + } if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)) gfsd->total += buf.st_size; if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) && @@ -255,7 +270,8 @@ GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset, } #ifdef MINGW - LARGE_INTEGER li, new_pos; + LARGE_INTEGER li; + LARGE_INTEGER new_pos; BOOL b; static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN, @@ -290,11 +306,13 @@ GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset, * of all sizes of files in the directory) * @param includeSymLinks should symbolic links be * included? + * @param singleFileMode GNUNET_YES to only get size of one file + * and return GNUNET_SYSERR for directories. * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_DISK_file_size (const char *filename, uint64_t * size, - int includeSymLinks) + int includeSymLinks, int singleFileMode) { struct GetFileSizeData gfsd; int ret; @@ -302,6 +320,7 @@ GNUNET_DISK_file_size (const char *filename, uint64_t * size, GNUNET_assert (size != NULL); gfsd.total = 0; gfsd.include_sym_links = includeSymLinks; + gfsd.single_file_mode = singleFileMode; ret = getSizeRec (&gfsd, filename); *size = gfsd.total; return ret; @@ -719,27 +738,18 @@ GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result, } else { -#if DEBUG_PIPE - LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to read\n"); -#endif if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead)) { if (GetLastError () != ERROR_IO_PENDING) { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); -#endif SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n"); -#endif GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE); } -#if DEBUG_PIPE - LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead); } return bytesRead; #else @@ -781,33 +791,24 @@ GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h, } else { -#if DEBUG_PIPE - LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe, trying to read\n"); -#endif if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead)) { if (GetLastError () != ERROR_IO_PENDING) { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); -#endif SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } else { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "ReadFile() queued a read, cancelling\n"); -#endif CancelIo (h->h); errno = EAGAIN; return GNUNET_SYSERR; } } -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead); -#endif } return bytesRead; #else @@ -880,31 +881,23 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h, } else { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n); -#endif if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite)) { if (GetLastError () != ERROR_IO_PENDING) { SetErrnoFromWinError (GetLastError ()); -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", GetLastError ()); -#endif return GNUNET_SYSERR; } -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n"); -#endif if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE)) { SetErrnoFromWinError (GetLastError ()); -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Error getting overlapped result while writing to pipe: %u\n", GetLastError ()); -#endif return GNUNET_SYSERR; } } @@ -913,35 +906,27 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h, DWORD ovr; if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE)) { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Error getting control overlapped result while writing to pipe: %u\n", GetLastError ()); -#endif } else { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes (ovr says %u), picking the greatest\n", bytesWritten, ovr); -#endif } } if (bytesWritten == 0) { if (n > 0) { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten); -#endif errno = EAGAIN; return GNUNET_SYSERR; } } -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten); -#endif } return bytesWritten; #else @@ -970,37 +955,27 @@ GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, #ifdef MINGW DWORD bytesWritten; /* We do a non-overlapped write, which is as blocking as it gets */ -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n); -#endif if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) { SetErrnoFromWinError (GetLastError ()); -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", GetLastError ()); -#endif return GNUNET_SYSERR; } if (bytesWritten == 0 && n > 0) { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n"); -#endif WaitForSingleObject (h->h, INFINITE); if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) { SetErrnoFromWinError (GetLastError ()); -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", GetLastError ()); -#endif return GNUNET_SYSERR; } } -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten); -#endif return bytesWritten; #else int flags; @@ -1350,7 +1325,7 @@ GNUNET_DISK_file_copy (const char *src, const char *dst) struct GNUNET_DISK_FileHandle *in; struct GNUNET_DISK_FileHandle *out; - if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES)) + if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES)) return GNUNET_SYSERR; pos = 0; in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ, @@ -2008,10 +1983,8 @@ create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld", getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id)); -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n", pipename, psize); -#endif /* Use CreateNamedPipe instead of CreatePipe, because the latter * returns a write handle that does not permit FILE_READ_ATTRIBUTES * access, on versions of win32 earlier than WinXP SP2. @@ -2028,9 +2001,7 @@ create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, if (read_pipe != INVALID_HANDLE_VALUE) { -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe); -#endif break; } @@ -2041,33 +2012,24 @@ create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, case ERROR_PIPE_BUSY: /* The pipe is already open with compatible parameters. * Pick a new name and retry. */ -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n"); -#endif continue; case ERROR_ACCESS_DENIED: /* The pipe is already open with incompatible parameters. * Pick a new name and retry. */ -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n"); -#endif continue; case ERROR_CALL_NOT_IMPLEMENTED: /* We are on an older Win9x platform without named pipes. * Return an anonymous pipe as the best approximation. */ -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe not implemented, resorting to " "CreatePipe: size = %lu\n", psize); -#endif if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize)) { -#if DEBUG_PIPE - LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", - *read_pipe_ptr); - LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", + LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n", + *read_pipe_ptr, *write_pipe_ptr); -#endif return GNUNET_OK; } err = GetLastError (); @@ -2079,9 +2041,7 @@ create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, } /* NOTREACHED */ } -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename); -#endif /* Open the named pipe for writing. * Be sure to permit FILE_READ_ATTRIBUTES access. */ @@ -2094,15 +2054,11 @@ create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, /* Failure. */ DWORD err = GetLastError (); -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err); -#endif CloseHandle (read_pipe); return err; } -#if DEBUG_PIPE LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe); -#endif /* Success. */ *read_pipe_ptr = read_pipe; *write_pipe_ptr = write_pipe; diff --git a/src/util/getopt.c b/src/util/getopt.c index 1699498..572e534 100644 --- a/src/util/getopt.c +++ b/src/util/getopt.c @@ -202,9 +202,8 @@ char * getenv (); static char * -my_index (str, chr) - const char *str; - int chr; +my_index (const char *str, + int chr) { while (*str) { @@ -294,8 +293,7 @@ exchange (char **); #endif static void -exchange (argv) - char **argv; +exchange (char **argv) { int bottom = first_nonopt; int middle = last_nonopt; @@ -381,10 +379,9 @@ static const char * _getopt_initialize (int, char *const *, const char *); #endif static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +_getopt_initialize (int argc, + char *const *argv, + const char *optstring) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 * is the program name); the sequence of previously skipped diff --git a/src/util/getopt_helpers.c b/src/util/getopt_helpers.c index 8fb3673..a31080f 100644 --- a/src/util/getopt_helpers.c +++ b/src/util/getopt_helpers.c @@ -79,9 +79,12 @@ GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext const char *trans; const struct GNUNET_GETOPT_CommandLineOption *opt; - printf ("%s\n%s\n", ctx->binaryOptions, gettext (about)); - printf (_ - ("Arguments mandatory for long options are also mandatory for short options.\n")); + if (NULL != about) + { + printf ("%s\n%s\n", ctx->binaryOptions, gettext (about)); + printf (_ + ("Arguments mandatory for long options are also mandatory for short options.\n")); + } i = 0; opt = ctx->allOptions; while (opt[i].description != NULL) diff --git a/src/util/gnunet-rsa.c b/src/util/gnunet-rsa.c new file mode 100644 index 0000000..f3cd83a --- /dev/null +++ b/src/util/gnunet-rsa.c @@ -0,0 +1,128 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/gnunet-rsa.c + * @brief tool to manipulate RSA key files + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" + + +/** + * Flag for printing public key. + */ +static int print_public_key; + +/** + * Flag for printing hash of public key. + */ +static int print_peer_identity; + +/** + * Flag for printing short hash of public key. + */ +static int print_short_identity; + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CRYPTO_RsaPrivateKey *pk; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; + struct GNUNET_PeerIdentity pid; + + if (NULL == args[0]) + { + fprintf (stderr, _("No hostkey file specified on command line\n")); + return; + } + pk = GNUNET_CRYPTO_rsa_key_create_from_file (args[0]); + if (print_public_key) + { + char *s; + + GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); + s = GNUNET_CRYPTO_rsa_public_key_to_string (&pub); + fprintf (stdout, "%s\n", s); + GNUNET_free (s); + } + if (print_peer_identity) + { + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + + GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); + GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); + GNUNET_CRYPTO_hash_to_enc (&pid.hashPubKey, &enc); + fprintf (stdout, "%s\n", enc.encoding); + } + if (print_short_identity) + { + struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc; + struct GNUNET_CRYPTO_ShortHashCode sh; + + GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); + GNUNET_CRYPTO_short_hash (&pub, sizeof (pub), &sh); + GNUNET_CRYPTO_short_hash_to_enc (&sh, &enc); + fprintf (stdout, "%s\n", enc.short_encoding); + } + GNUNET_CRYPTO_rsa_key_free (pk); +} + + +/** + * The main function to obtain statistics in GNUnet. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + { 'p', "print-public-key", NULL, + gettext_noop ("print the public key in ASCII format"), + 0, &GNUNET_GETOPT_set_one, &print_public_key }, + { 'P', "print-peer-identity", NULL, + gettext_noop ("print the hash of the public key in ASCII format"), + 0, &GNUNET_GETOPT_set_one, &print_peer_identity }, + { 's', "print-short-identity", NULL, + gettext_noop ("print the short hash of the public key in ASCII format"), + 0, &GNUNET_GETOPT_set_one, &print_short_identity }, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-rsa [OPTIONS] keyfile", + gettext_noop ("Manipulate GNUnet private RSA key files"), + options, &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-rsa.c */ diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c index f20666a..97eba6d 100644 --- a/src/util/gnunet-service-resolver.c +++ b/src/util/gnunet-service-resolver.c @@ -490,10 +490,8 @@ handle_get (void *cls, struct GNUNET_SERVER_Client *client, GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } -#if DEBUG_RESOLVER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver asked to look up `%s'.\n"), + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolver asked to look up `%s'.\n", hostname); -#endif get_ip_from_hostname (client, hostname, af); return; } @@ -521,15 +519,13 @@ handle_get (void *cls, struct GNUNET_SERVER_Client *client, GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } -#if DEBUG_RESOLVER { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Resolver asked to look up IP address `%s'.\n"), + "Resolver asked to look up IP address `%s'.\n", inet_ntop (af, ip, buf, sizeof (buf))); } -#endif get_ip_as_string (client, af, ip); } diff --git a/src/util/helper.c b/src/util/helper.c index 43ec23a..6a84ff3 100644 --- a/src/util/helper.c +++ b/src/util/helper.c @@ -31,24 +31,29 @@ /** * Entry in the queue of messages we need to transmit to the helper. */ -struct HelperMessageQueueEntry +struct GNUNET_HELPER_SendHandle { /** * This is an entry in a DLL. */ - struct HelperMessageQueueEntry *next; + struct GNUNET_HELPER_SendHandle *next; /** * This is an entry in a DLL. */ - struct HelperMessageQueueEntry *prev; + struct GNUNET_HELPER_SendHandle *prev; /** * Message to transmit (allocated at the end of this struct) */ const struct GNUNET_MessageHeader *msg; - + + /** + * The handle to a helper process. + */ + struct GNUNET_HELPER_Handle *h; + /** * Function to call upon completion. */ @@ -106,12 +111,12 @@ struct GNUNET_HELPER_Handle /** * First message queued for transmission to helper. */ - struct HelperMessageQueueEntry *mq_head; + struct GNUNET_HELPER_SendHandle *sh_head; /** * Last message queued for transmission to helper. */ - struct HelperMessageQueueEntry *mq_tail; + struct GNUNET_HELPER_SendHandle *sh_tail; /** * Binary to run. @@ -148,13 +153,13 @@ struct GNUNET_HELPER_Handle static void stop_helper (struct GNUNET_HELPER_Handle *h) { - struct HelperMessageQueueEntry *qe; + struct GNUNET_HELPER_SendHandle *sh; if (NULL != h->helper_proc) { GNUNET_break (0 == GNUNET_OS_process_kill (h->helper_proc, SIGTERM)); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (h->helper_proc)); - GNUNET_OS_process_close (h->helper_proc); + GNUNET_OS_process_destroy (h->helper_proc); h->helper_proc = NULL; } if (GNUNET_SCHEDULER_NO_TASK != h->restart_task) @@ -184,14 +189,14 @@ stop_helper (struct GNUNET_HELPER_Handle *h) h->helper_out = NULL; h->fh_from_helper = NULL; } - while (NULL != (qe = h->mq_head)) + while (NULL != (sh = h->sh_head)) { - GNUNET_CONTAINER_DLL_remove (h->mq_head, - h->mq_tail, - qe); - if (NULL != qe->cont) - qe->cont (qe->cont_cls, GNUNET_NO); - GNUNET_free (qe); + GNUNET_CONTAINER_DLL_remove (h->sh_head, + h->sh_tail, + sh); + if (NULL != sh->cont) + sh->cont (sh->cont_cls, GNUNET_NO); + GNUNET_free (sh); } /* purge MST buffer */ (void) GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO); @@ -220,7 +225,7 @@ helper_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_HELPER_Handle *h = cls; - char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE]; + char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE] GNUNET_ALIGN; ssize_t t; h->read_task = GNUNET_SCHEDULER_NO_TASK; @@ -301,6 +306,9 @@ start_helper (struct GNUNET_HELPER_Handle *h) &restart_task, h); return; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Starting HELPER process `%s'\n"), + h->binary_name); h->fh_from_helper = GNUNET_DISK_pipe_handle (h->helper_out, GNUNET_DISK_PIPE_END_READ); h->fh_to_helper = @@ -380,17 +388,17 @@ GNUNET_HELPER_start (const char *binary_name, void GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h) { - struct HelperMessageQueueEntry *qe; + struct GNUNET_HELPER_SendHandle *sh; /* signal pending writes that we were stopped */ - while (NULL != (qe = h->mq_head)) + while (NULL != (sh = h->sh_head)) { - GNUNET_CONTAINER_DLL_remove (h->mq_head, - h->mq_tail, - qe); - if (NULL != qe->cont) - qe->cont (qe->cont_cls, GNUNET_SYSERR); - GNUNET_free (qe); + GNUNET_CONTAINER_DLL_remove (h->sh_head, + h->sh_tail, + sh); + if (NULL != sh->cont) + sh->cont (sh->cont_cls, GNUNET_SYSERR); + GNUNET_free (sh); } stop_helper (h); GNUNET_SERVER_mst_destroy (h->mst); @@ -409,7 +417,7 @@ helper_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_HELPER_Handle *h = cls; - struct HelperMessageQueueEntry *qe; + struct GNUNET_HELPER_SendHandle *sh; const char *buf; ssize_t t; @@ -421,10 +429,10 @@ helper_write (void *cls, h->fh_to_helper, &helper_write, h); return; } - if (NULL == (qe = h->mq_head)) + if (NULL == (sh = h->sh_head)) return; /* how did this happen? */ - buf = (const char*) qe->msg; - t = GNUNET_DISK_file_write (h->fh_to_helper, &buf[qe->wpos], ntohs (qe->msg->size) - qe->wpos); + buf = (const char*) sh->msg; + t = GNUNET_DISK_file_write (h->fh_to_helper, &buf[sh->wpos], ntohs (sh->msg->size) - sh->wpos); if (t <= 0) { /* On write-error, restart the helper */ @@ -439,17 +447,17 @@ helper_write (void *cls, &restart_task, h); return; } - qe->wpos += t; - if (qe->wpos == ntohs (qe->msg->size)) + sh->wpos += t; + if (sh->wpos == ntohs (sh->msg->size)) { - GNUNET_CONTAINER_DLL_remove (h->mq_head, - h->mq_tail, - qe); - if (NULL != qe->cont) - qe->cont (qe->cont_cls, GNUNET_YES); - GNUNET_free (qe); + GNUNET_CONTAINER_DLL_remove (h->sh_head, + h->sh_tail, + sh); + if (NULL != sh->cont) + sh->cont (sh->cont_cls, GNUNET_YES); + GNUNET_free (sh); } - if (NULL != h->mq_head) + if (NULL != h->sh_head) h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_to_helper, &helper_write, @@ -466,40 +474,68 @@ helper_write (void *cls, * @param cont continuation to run once the message is out (PREREQ_DONE on succees, CANCEL * if the helper process died, NULL during GNUNET_HELPER_stop). * @param cont_cls closure for 'cont' - * @return GNUNET_YES if the message will be sent - * GNUNET_NO if the message was dropped + * @return NULL if the message was dropped, + * otherwise handle to cancel *cont* (actual transmission may + * not be abortable) */ -int +struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, int can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls) { - struct HelperMessageQueueEntry *qe; + struct GNUNET_HELPER_SendHandle *sh; uint16_t mlen; if (NULL == h->fh_to_helper) - return GNUNET_NO; + return NULL; if ( (GNUNET_YES == can_drop) && - (h->mq_head != NULL) ) - return GNUNET_NO; + (NULL != h->sh_head) ) + return NULL; mlen = ntohs (msg->size); - qe = GNUNET_malloc (sizeof (struct HelperMessageQueueEntry) + mlen); - qe->msg = (const struct GNUNET_MessageHeader*) &qe[1]; - memcpy (&qe[1], msg, mlen); - qe->cont = cont; - qe->cont_cls = cont_cls; - GNUNET_CONTAINER_DLL_insert_tail (h->mq_head, - h->mq_tail, - qe); + sh = GNUNET_malloc (sizeof (struct GNUNET_HELPER_SendHandle) + mlen); + sh->msg = (const struct GNUNET_MessageHeader*) &sh[1]; + memcpy (&sh[1], msg, mlen); + sh->h = h; + sh->cont = cont; + sh->cont_cls = cont_cls; + GNUNET_CONTAINER_DLL_insert_tail (h->sh_head, + h->sh_tail, + sh); if (GNUNET_SCHEDULER_NO_TASK == h->write_task) h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_to_helper, &helper_write, h); - return GNUNET_YES; + return sh; +} + +/** + * Cancel a 'send' operation. If possible, transmitting the + * message is also aborted, but at least 'cont' won't be + * called. + * + * @param sh operation to cancel + */ +void +GNUNET_HELPER_send_cancel (struct GNUNET_HELPER_SendHandle *sh) +{ + struct GNUNET_HELPER_Handle *h = sh->h; + + sh->cont = NULL; + sh->cont_cls = NULL; + if (0 == sh->wpos) + { + GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); + if (NULL == h->sh_head) + { + GNUNET_SCHEDULER_cancel (h->write_task); + h->write_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (sh); + } } diff --git a/src/util/load.c b/src/util/load.c index e978a95..146e850 100644 --- a/src/util/load.c +++ b/src/util/load.c @@ -26,7 +26,6 @@ #include "platform.h" #include "gnunet_load_lib.h" -#define DEBUG_LOAD GNUNET_EXTRA_LOGGING #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) diff --git a/src/util/network.c b/src/util/network.c index e530ab7..972f938 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) + (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -193,6 +193,61 @@ socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h) /** + * Perform proper canonical initialization for a network handle. + * Set it to non-blocking, make it non-inheritable to child + * processes, disable SIGPIPE, enable "nodelay" (if non-UNIX + * stream socket) and check that it is smaller than FS_SETSIZE. + * + * @param h socket to initialize + * @param af address family of the socket + * @param type socket type + * @return GNUNET_OK on success, GNUNET_SYSERR if initialization + * failed and the handle was destroyed + */ +static int +initialize_network_handle (struct GNUNET_NETWORK_Handle *h, + int af, int type) +{ + h->af = af; + if (h->fd == INVALID_SOCKET) + { +#ifdef MINGW + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + GNUNET_free (h); + return GNUNET_SYSERR; + } +#ifndef MINGW + if (h->fd >= FD_SETSIZE) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h)); + errno = EMFILE; + return GNUNET_SYSERR; + } + if (GNUNET_OK != socket_set_inheritable (h)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "socket_set_inheritable"); +#endif + if (GNUNET_SYSERR == socket_set_blocking (h, GNUNET_NO)) + { + GNUNET_break (0); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h)); + return GNUNET_SYSERR; + } +#ifdef DARWIN + socket_set_nosigpipe (h); +#endif + if ( (type == SOCK_STREAM) +#ifdef AF_UNIX + && (af != AF_UNIX) +#endif + ) + socket_set_nodelay (h); + return GNUNET_OK; +} + + +/** * accept a new connection on a socket * * @param desc bound socket @@ -219,49 +274,10 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc, } #endif ret->fd = accept (desc->fd, address, address_len); - if (address != NULL) - ret->af = address->sa_family; - else - ret->af = desc->af; - if (ret->fd == INVALID_SOCKET) - { -#ifdef MINGW - SetErrnoFromWinsockError (WSAGetLastError ()); -#endif - GNUNET_free (ret); - return NULL; - } -#ifndef MINGW - if (ret->fd >= FD_SETSIZE) - { - GNUNET_break (0 == close (ret->fd)); - GNUNET_free (ret); - errno = EMFILE; - return NULL; - } -#endif - if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO)) - - { - - /* we might want to treat this one as fatal... */ - GNUNET_break (0); - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret)); + if (GNUNET_OK != initialize_network_handle (ret, + (NULL != address) ? address->sa_family : desc->af, + SOCK_STREAM)) return NULL; - } - -#ifndef MINGW - if (GNUNET_OK != socket_set_inheritable (ret)) - LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "socket_set_inheritable"); -#endif -#ifdef DARWIN - socket_set_nosigpipe (ret); -#endif -#ifdef AF_UNIX - if (ret->af != AF_UNIX) -#endif - socket_set_nodelay (ret); return ret; } @@ -492,15 +508,16 @@ GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle * error = ioctl (desc->fd, FIONREAD, &pending); if (error == 0) + return (ssize_t) pending; + return GNUNET_NO; #else u_long pending; error = ioctlsocket (desc->fd, FIONREAD, &pending); if (error != SOCKET_ERROR) + return (ssize_t) pending; + return GNUNET_NO; #endif - return pending; - else - return GNUNET_NO; } @@ -677,49 +694,10 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol) struct GNUNET_NETWORK_Handle *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); - ret->af = domain; ret->fd = socket (domain, type, protocol); - if (INVALID_SOCKET == ret->fd) - { -#ifdef MINGW - SetErrnoFromWinsockError (WSAGetLastError ()); -#endif - GNUNET_free (ret); - return NULL; - } - -#ifndef MINGW - if (ret->fd >= FD_SETSIZE) - { - GNUNET_break (0 == close (ret->fd)); - GNUNET_free (ret); - errno = EMFILE; - return NULL; - } - -#endif - if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO)) - { - /* we might want to treat this one as fatal... */ - GNUNET_break (0); - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret)); + if (GNUNET_OK != + initialize_network_handle (ret, domain, type)) return NULL; - } - -#ifndef MINGW - if (GNUNET_OK != socket_set_inheritable (ret)) - LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "socket_set_inheritable"); -#endif -#ifdef DARWIN - socket_set_nosigpipe (ret); -#endif - if ((type == SOCK_STREAM) -#ifdef AF_UNIX - && (domain != AF_UNIX) -#endif - ) - socket_set_nodelay (ret); return ret; } @@ -887,8 +865,30 @@ GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) return desc->fd; } +/** + * Return sockaddr for this network handle + * + * @param desc wrapper to process + * @return sockaddr + */ +struct sockaddr* +GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc) +{ + return desc->addr; +} /** + * Return sockaddr length for this network handle + * + * @param desc wrapper to process + * @return socklen_t for sockaddr + */ +socklen_t +GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc) +{ + return desc->addrlen; +} +/** * Copy a native fd set * * @param to destination @@ -1047,9 +1047,6 @@ GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, if (GNUNET_CONTAINER_slist_contains (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle))) { -#if DEBUG_NETWORK - LOG (GNUNET_ERROR_TYPE_DEBUG, "Match!\n"); -#endif return GNUNET_YES; } GNUNET_CONTAINER_slist_next (&it); @@ -1105,7 +1102,6 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, const struct GNUNET_TIME_Relative timeout) { int nfds = 0; - #ifdef MINGW int handles = 0; int ex_handles = 0; @@ -1116,7 +1112,9 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, int retcode = 0; DWORD ms_total = 0; - int nsock = 0, nhandles = 0, nSockEvents = 0; + int nsock = 0; + int nhandles = 0; + int nSockEvents = 0; static HANDLE hEventRead = 0; static HANDLE hEventWrite = 0; @@ -1132,12 +1130,18 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, DWORD newretcode = 0; int returnedpos = 0; - struct GNUNET_CONTAINER_SList *handles_read, *handles_write, *handles_except; + struct GNUNET_CONTAINER_SList *handles_read; + struct GNUNET_CONTAINER_SList *handles_write; + struct GNUNET_CONTAINER_SList *handles_except; - fd_set aread, awrite, aexcept; + fd_set aread; + fd_set awrite; + fd_set aexcept; #if DEBUG_NETWORK - fd_set bread, bwrite, bexcept; + fd_set bread; + fd_set bwrite; + fd_set bexcept; #endif /* TODO: Make this growable */ @@ -1421,21 +1425,14 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, } handle_array[nhandles] = NULL; - -#if DEBUG_NETWORK - LOG (GNUNET_ERROR_TYPE_DEBUG, "Number nfds : %d\n", nfds); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Number of handles : %d\n", nhandles); - LOG (GNUNET_ERROR_TYPE_DEBUG, "retcode : %d\n", newretcode); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Will wait : %d\n", ms_total); -#endif - + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Number nfds: %d, handles: %d, return code: %u will wait: %d ms\n", + nfds, nhandles, newretcode, ms_total); if (nhandles) returncode = WaitForMultipleObjects (nhandles, handle_array, FALSE, ms_total); -#if DEBUG_NETWORK LOG (GNUNET_ERROR_TYPE_DEBUG, "WaitForMultipleObjects Returned : %d\n", returncode); -#endif returnedpos = returncode - WAIT_OBJECT_0; LOG (GNUNET_ERROR_TYPE_DEBUG, "return pos is : %d\n", returnedpos); @@ -1455,7 +1452,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, struct timeval tvslice; tvslice.tv_sec = 0; - tvslice.tv_usec = 10; + tvslice.tv_usec = 0; retcode = select (nfds, &aread, &awrite, &aexcept, &tvslice); if (retcode == -1) retcode = 0; @@ -1546,10 +1543,8 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, } } } -#if DEBUG_NETWORK if (!nhandles || (returnedpos >= nhandles)) LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning from _select() with nothing!\n"); -#endif if (rfds) { struct GNUNET_CONTAINER_SList_Iterator t; diff --git a/src/util/os_installation.c b/src/util/os_installation.c index b82813d..e790ce1 100644 --- a/src/util/os_installation.c +++ b/src/util/os_installation.c @@ -62,7 +62,7 @@ get_path_from_proc_maps () while (NULL != fgets (line, sizeof (line), f)) { if ((1 == - sscanf (line, "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%s", dir)) && + SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%s", dir)) && (NULL != (lgu = strstr (dir, "libgnunetutil")))) { lgu[0] = '\0'; diff --git a/src/util/os_priority.c b/src/util/os_priority.c index a1f173a..b8b1ba1 100644 --- a/src/util/os_priority.c +++ b/src/util/os_priority.c @@ -31,6 +31,7 @@ #include "gnunet_strings_lib.h" #include "gnunet_crypto_lib.h" #include "disk.h" +#include <unistr.h> #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) @@ -299,7 +300,7 @@ npipe_open (const char *fn, } if (-1 == fd) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, (flags == GNUNET_DISK_OPEN_READ) ? _("Failed to open named pipe `%s' for reading: %s\n") : _("Failed to open named pipe `%s' for writing: %s\n"), @@ -325,29 +326,32 @@ parent_control_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DISK_FileHandle *control_pipe = cls; - int sig; - + char sig; + ssize_t ret; + LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__, tc->reason); - if (tc->reason & - (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | - GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + if (0 != (tc->reason & + (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT))) { GNUNET_DISK_file_close (control_pipe); + control_pipe = NULL; return; } - if (GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig)) != - sizeof (sig)) + ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig)); + if (sizeof (sig) != ret) { - LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read"); + if (-1 == ret) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read"); GNUNET_DISK_file_close (control_pipe); + control_pipe = NULL; return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig); GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe, &parent_control_handler, control_pipe); - raise (sig); + raise ((int) sig); } @@ -425,27 +429,22 @@ int GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig) { int ret; + char csig; + csig = (char) sig; #if !WINDOWS if ( (NULL == proc->control_pipe) && (NULL != proc->childpipename) ) proc->control_pipe = npipe_open (proc->childpipename, GNUNET_DISK_OPEN_WRITE); #endif - if (NULL == proc->control_pipe) + if (NULL != proc->control_pipe) { -#if WINDOWS - /* no pipe and windows? can't do this */ - errno = EINVAL; - return -1; -#else - return kill (proc->pid, sig); -#endif + ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig)); + if (ret == sizeof (csig)) + return 0; } - ret = GNUNET_DISK_file_write (proc->control_pipe, &sig, sizeof (sig)); - if (ret == sizeof (sig)) - return 0; - /* pipe failed, try other methods */ + /* pipe failed or non-existent, try other methods */ switch (sig) { #if !WINDOWS @@ -469,7 +468,7 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig) errno = EINVAL; return -1; #else - return kill (proc->pid, sig); + return PLIBC_KILL (proc->pid, sig); #endif } } @@ -488,13 +487,16 @@ GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc) } +/** + * Cleans up process structure contents (OS-dependent) and deallocates it + * + * @param proc pointer to process structure + */ void -GNUNET_OS_process_close (struct GNUNET_OS_Process *proc) +GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc) { -#if ENABLE_WINDOWS_WORKAROUNDS - if (proc->control_pipe) + if (NULL != proc->control_pipe) GNUNET_DISK_file_close (proc->control_pipe); -#endif // FIXME NILS #ifdef WINDOWS if (proc->handle != NULL) @@ -648,10 +650,15 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc, static char * CreateCustomEnvTable (char **vars) { - char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr; + char *win32_env_table; + char *ptr; + char **var_ptr; + char *result; + char *result_ptr; size_t tablesize = 0; size_t items_count = 0; - size_t n_found = 0, n_var; + size_t n_found = 0; + size_t n_var; char *index = NULL; size_t c; size_t var_len; @@ -804,8 +811,11 @@ GNUNET_OS_start_process_vap (int pipe_control, ret = fork (); if (-1 == ret) { + int eno = errno; + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); GNUNET_free_non_null (childpipename); + errno = eno; return NULL; } if (0 != ret) @@ -863,7 +873,10 @@ GNUNET_OS_start_process_vap (int pipe_control, char *libdir; char *ptr; char *non_const_filename; - wchar_t wpath[MAX_PATH + 1], wcmd[32768]; + char win_path[MAX_PATH + 1]; + wchar_t *wpath, *wcmd; + size_t wpath_len, wcmd_len; + long lRet; /* Search in prefix dir (hopefully - the directory from which * the current module was loaded), bindir and libdir, then in PATH @@ -895,7 +908,22 @@ GNUNET_OS_start_process_vap (int pipe_control, else GNUNET_asprintf (&non_const_filename, "%s", filename); + /* It could be in POSIX form, convert it to a DOS path early on */ + if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path))) + { + SetErrnoFromWinError (lRet); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path", + non_const_filename); + GNUNET_free (non_const_filename); + GNUNET_free (pathbuf); + return NULL; + } + GNUNET_free (non_const_filename); + non_const_filename = GNUNET_strdup (win_path); /* Check that this is the full path. If it isn't, search. */ + /* FIXME: convert it to wchar_t and use SearchPathW? + * Remember: arguments to _start_process() are technically in UTF-8... + */ if (non_const_filename[1] == ':') snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename); else if (!SearchPathA @@ -972,6 +1000,8 @@ GNUNET_OS_start_process_vap (int pipe_control, return NULL; } } + else + control_pipe = NULL; if (NULL != childpipename) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", @@ -985,19 +1015,39 @@ GNUNET_OS_start_process_vap (int pipe_control, our_env[0] = NULL; } env_block = CreateCustomEnvTable (our_env); - GNUNET_free (our_env[0]); - GNUNET_free (our_env[1]); + GNUNET_free_non_null (our_env[0]); + GNUNET_free_non_null (our_env[1]); + + wpath_len = 0; + if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len))) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno); + GNUNET_free (env_block); + GNUNET_free (cmd); + return NULL; + } + + wcmd_len = 0; + if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len))) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno); + GNUNET_free (env_block); + GNUNET_free (cmd); + free (wpath); + return NULL; + } - if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath) - || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd) - || !CreateProcessW - (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, - env_block, NULL, &start, &proc)) + if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, + DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path); GNUNET_free (env_block); GNUNET_free (cmd); + free (wpath); + free (wcmd); return NULL; } @@ -1014,7 +1064,8 @@ GNUNET_OS_start_process_vap (int pipe_control, CloseHandle (proc.hThread); GNUNET_free (cmd); - + free (wpath); + free (wcmd); return gnunet_proc; #endif } @@ -1136,9 +1187,12 @@ GNUNET_OS_start_process_v (int pipe_control, ret = fork (); if (-1 == ret) { + int eno = errno; + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); GNUNET_free_non_null (childpipename); GNUNET_array_grow (lscp, ls, 0); + errno = eno; return NULL; } if (0 != ret) @@ -1220,13 +1274,16 @@ GNUNET_OS_start_process_v (int pipe_control, char *libdir; char *ptr; char *non_const_filename; + char win_path[MAX_PATH + 1]; struct GNUNET_DISK_PipeHandle *lsocks_pipe; const struct GNUNET_DISK_FileHandle *lsocks_write_fd; HANDLE lsocks_read; HANDLE lsocks_write; - wchar_t wpath[MAX_PATH + 1], wcmd[32768]; + wchar_t *wpath, *wcmd; + size_t wpath_len, wcmd_len; int env_off; int fail; + long lRet; /* Search in prefix dir (hopefully - the directory from which * the current module was loaded), bindir and libdir, then in PATH @@ -1263,7 +1320,22 @@ GNUNET_OS_start_process_v (int pipe_control, else GNUNET_asprintf (&non_const_filename, "%s", filename); - /* Check that this is the full path. If it isn't, search. */ + /* It could be in POSIX form, convert it to a DOS path early on */ + if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path))) + { + SetErrnoFromWinError (lRet); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path", + non_const_filename); + GNUNET_free (non_const_filename); + GNUNET_free (pathbuf); + return NULL; + } + GNUNET_free (non_const_filename); + non_const_filename = GNUNET_strdup (win_path); + /* Check that this is the full path. If it isn't, search. */ + /* FIXME: convert it to wchar_t and use SearchPathW? + * Remember: arguments to _start_process() are technically in UTF-8... + */ if (non_const_filename[1] == ':') snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename); else if (!SearchPathA @@ -1345,6 +1417,8 @@ GNUNET_OS_start_process_v (int pipe_control, return NULL; } } + else + control_pipe = NULL; if (lsocks != NULL && lsocks[0] != INVALID_SOCKET) { lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); @@ -1384,11 +1458,30 @@ GNUNET_OS_start_process_v (int pipe_control, env_block = CreateCustomEnvTable (our_env); while (0 > env_off) GNUNET_free_non_null (our_env[--env_off]); - if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath) - || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd) - || !CreateProcessW - (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, - env_block, NULL, &start, &proc)) + + wpath_len = 0; + if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len))) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno); + GNUNET_free (env_block); + GNUNET_free (cmd); + return NULL; + } + + wcmd_len = 0; + if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len))) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno); + GNUNET_free (env_block); + GNUNET_free (cmd); + free (wpath); + return NULL; + } + + if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, + DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess"); @@ -1398,6 +1491,8 @@ GNUNET_OS_start_process_v (int pipe_control, GNUNET_DISK_pipe_close (lsocks_pipe); GNUNET_free (env_block); GNUNET_free (cmd); + free (wpath); + free (wcmd); return NULL; } @@ -1413,6 +1508,8 @@ GNUNET_OS_start_process_v (int pipe_control, ResumeThread (proc.hThread); CloseHandle (proc.hThread); GNUNET_free (cmd); + free (wpath); + free (wcmd); if (lsocks == NULL || lsocks[0] == INVALID_SOCKET) return gnunet_proc; @@ -1499,7 +1596,9 @@ GNUNET_OS_start_process_v (int pipe_control, /** - * Retrieve the status of a process + * Retrieve the status of a process, waiting on him if dead. + * Nonblocking version. + * * @param proc process ID * @param type status type * @param code return code/signal number @@ -1716,7 +1815,7 @@ GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd) } (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip)); - GNUNET_OS_process_close (cmd->eip); + GNUNET_OS_process_destroy (cmd->eip); GNUNET_DISK_pipe_close (cmd->opipe); GNUNET_free (cmd); } diff --git a/src/util/program.c b/src/util/program.c index 6a0e5a5..9e1a83d 100644 --- a/src/util/program.c +++ b/src/util/program.c @@ -72,6 +72,11 @@ struct CommandContext }; +int +GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg); + +int +GNUNET_SPEEDUP_stop_ (void); /** * Initial task called by the scheduler for each @@ -81,6 +86,7 @@ static void program_main (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CommandContext *cc = cls; + GNUNET_SPEEDUP_start_(cc->cfg); GNUNET_RESOLVER_connect (cc->cfg); cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg); @@ -95,10 +101,10 @@ program_main (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param a2 second command line option */ static int -cmd_sorter (__const void *a1, __const void *a2) +cmd_sorter (const void *a1, const void *a2) { - __const struct GNUNET_GETOPT_CommandLineOption *c1 = a1; - __const struct GNUNET_GETOPT_CommandLineOption *c2 = a2; + const struct GNUNET_GETOPT_CommandLineOption *c1 = a1; + const struct GNUNET_GETOPT_CommandLineOption *c2 = a2; if (toupper ((unsigned char) c1->shortName) > toupper ((unsigned char) c2->shortName)) @@ -125,13 +131,16 @@ cmd_sorter (__const void *a1, __const void *a2) * @param options command line options * @param task main function to run * @param task_cls closure for task + * @param run_without_scheduler GNUNET_NO start the scheduler, GNUNET_YES do not + * start the scheduler just run the main task * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int -GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, +GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, - GNUNET_PROGRAM_Main task, void *task_cls) + GNUNET_PROGRAM_Main task, void *task_cls, + int run_without_scheduler) { struct CommandContext cc; char *path; @@ -247,9 +256,17 @@ GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, } /* run */ cc.args = &argv[ret]; - GNUNET_SCHEDULER_run (&program_main, &cc); - + if (GNUNET_NO == run_without_scheduler) + { + GNUNET_SCHEDULER_run (&program_main, &cc); + } + else + { + GNUNET_RESOLVER_connect (cc.cfg); + cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg); + } /* clean up */ + GNUNET_SPEEDUP_stop_ (); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free_non_null (cc.cfgfile); GNUNET_free_non_null (loglev); @@ -257,5 +274,28 @@ GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, return GNUNET_OK; } +/** + * Run a standard GNUnet command startup sequence (initialize loggers + * and configuration, parse options). + * + * @param argc number of command line arguments + * @param argv command line arguments + * @param binaryName our expected name + * @param binaryHelp help text for the program + * @param options command line options + * @param task main function to run + * @param task_cls closure for task + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +int +GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, + const char *binaryHelp, + const struct GNUNET_GETOPT_CommandLineOption *options, + GNUNET_PROGRAM_Main task, void *task_cls) +{ + return GNUNET_PROGRAM_run2 (argc, argv, binaryName, binaryHelp, options, task, task_cls, GNUNET_NO); +} + + /* end of program.c */ diff --git a/src/util/pseudonym.c b/src/util/pseudonym.c index 782a405..0165738 100644 --- a/src/util/pseudonym.c +++ b/src/util/pseudonym.c @@ -96,7 +96,7 @@ internal_notify (const GNUNET_HashCode * id, pos = head; while (pos != NULL) { - pos->callback (pos->closure, id, md, rating); + pos->callback (pos->closure, id, NULL, NULL, md, rating); pos = pos->next; } } @@ -104,6 +104,9 @@ internal_notify (const GNUNET_HashCode * id, /** * Register callback to be invoked whenever we discover * a new pseudonym. + * Will immediately call provided iterator callback for all + * already discovered pseudonyms. + * * @param cfg configuration to use * @param iterator iterator over pseudonym * @param closure point to a closure @@ -185,7 +188,7 @@ get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, * @param nsid hash code of a pseudonym * @param meta meta data to be written into a file * @param ranking ranking of a pseudonym - * @param ns_name name of a pseudonym + * @param ns_name non-unique name of a pseudonym */ static void write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg, @@ -219,9 +222,9 @@ write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg, } GNUNET_free (fn); /* create entry for pseudonym name in names */ - /* FIXME: 90% of what this call does is not needed - * here => refactor code to only create the entry! */ - GNUNET_free_non_null (GNUNET_PSEUDONYM_id_to_name (cfg, nsid)); + if (ns_name != NULL) + GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, nsid, ns_name, + NULL)); } @@ -286,63 +289,38 @@ read_info (const struct GNUNET_CONFIGURATION_Handle *cfg, } - /** - * Return the unique, human readable name for the given namespace. + * Return unique variant of the namespace name. + * Use it after GNUNET_PSEUDONYM_get_info() to make sure + * that name is unique. * * @param cfg configuration * @param nsid cryptographic ID of the namespace - * @return NULL on failure (should never happen) + * @param name name to uniquify + * @param suffix if not NULL, filled with the suffix value + * @return NULL on failure (should never happen), name on success. + * Free the name with GNUNET_free(). */ char * -GNUNET_PSEUDONYM_id_to_name (const struct GNUNET_CONFIGURATION_Handle *cfg, - const GNUNET_HashCode * nsid) +GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid, const char *name, unsigned int *suffix) { - struct GNUNET_CONTAINER_MetaData *meta; - char *name; GNUNET_HashCode nh; - char *fn; uint64_t len; + char *fn; struct GNUNET_DISK_FileHandle *fh; unsigned int i; unsigned int idx; char *ret; struct stat sbuf; - int32_t temp = 0; - int32_t *rank = &temp; - meta = NULL; - name = NULL; - if (GNUNET_OK == read_info (cfg, nsid, &meta, rank, &name)) - { - if ((meta != NULL) && (name == NULL)) - name = - GNUNET_CONTAINER_meta_data_get_first_by_types (meta, - EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, - EXTRACTOR_METATYPE_FILENAME, - EXTRACTOR_METATYPE_DESCRIPTION, - EXTRACTOR_METATYPE_SUBJECT, - EXTRACTOR_METATYPE_PUBLISHER, - EXTRACTOR_METATYPE_AUTHOR_NAME, - EXTRACTOR_METATYPE_COMMENT, - EXTRACTOR_METATYPE_SUMMARY, - -1); - if (meta != NULL) - { - GNUNET_CONTAINER_meta_data_destroy (meta); - meta = NULL; - } - } - if (name == NULL) - name = GNUNET_strdup (_("no-name")); GNUNET_CRYPTO_hash (name, strlen (name), &nh); fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); GNUNET_assert (fn != NULL); len = 0; if (0 == STAT (fn, &sbuf)) - GNUNET_DISK_file_size (fn, &len, GNUNET_YES); + GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES)); fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, @@ -372,22 +350,107 @@ GNUNET_PSEUDONYM_id_to_name (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_DISK_file_close (fh); ret = GNUNET_malloc (strlen (name) + 32); GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx); - GNUNET_free (name); + if (suffix != NULL) + *suffix = idx; GNUNET_free (fn); return ret; } /** + * Get namespace name, metadata and rank + * This is a wrapper around internal read_info() call, and ensures that + * returned data is not invalid (not NULL). + * + * @param cfg configuration + * @param nsid cryptographic ID of the namespace + * @param ret_meta a location to store metadata pointer. NULL, if metadata + * is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy(). + * @param ret_rank a location to store rank. NULL, if rank not needed. + * @param ret_name a location to store human-readable name. Name is not unique. + * NULL, if name is not needed. Free with GNUNET_free(). + * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with + * a duplicate of a "no-name" placeholder + * @return GNUNET_OK on success. GNUENT_SYSERR if the data was + * unobtainable (in that case ret_* are filled with placeholders - + * empty metadata container, rank -1 and a "no-name" name). + */ +int +GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid, struct GNUNET_CONTAINER_MetaData **ret_meta, + int32_t *ret_rank, char **ret_name, int *name_is_a_dup) +{ + struct GNUNET_CONTAINER_MetaData *meta; + char *name; + int32_t rank = -1; + + meta = NULL; + name = NULL; + if (GNUNET_OK == read_info (cfg, nsid, &meta, &rank, &name)) + { + if ((meta != NULL) && (name == NULL)) + name = + GNUNET_CONTAINER_meta_data_get_first_by_types (meta, + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, + EXTRACTOR_METATYPE_FILENAME, + EXTRACTOR_METATYPE_DESCRIPTION, + EXTRACTOR_METATYPE_SUBJECT, + EXTRACTOR_METATYPE_PUBLISHER, + EXTRACTOR_METATYPE_AUTHOR_NAME, + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METATYPE_SUMMARY, + -1); + if (ret_name != NULL) + { + if (name == NULL) + { + name = GNUNET_strdup (_("no-name")); + if (name_is_a_dup != NULL) + *name_is_a_dup = GNUNET_YES; + } + else if (name_is_a_dup != NULL) + *name_is_a_dup = GNUNET_NO; + *ret_name = name; + } + else if (name != NULL) + GNUNET_free (name); + + if (ret_meta != NULL) + { + if (meta == NULL) + meta = GNUNET_CONTAINER_meta_data_create (); + *ret_meta = meta; + } + else if (meta != NULL) + GNUNET_CONTAINER_meta_data_destroy (meta); + + if (ret_rank != NULL) + *ret_rank = rank; + + return GNUNET_OK; + } + if (ret_name != NULL) + *ret_name = GNUNET_strdup (_("no-name")); + if (ret_meta != NULL) + *ret_meta = GNUNET_CONTAINER_meta_data_create (); + if (ret_rank != NULL) + *ret_rank = -1; + if (name_is_a_dup != NULL) + *name_is_a_dup = GNUNET_YES; + return GNUNET_SYSERR; +} + +/** * Get the namespace ID belonging to the given namespace name. * * @param cfg configuration to use - * @param ns_uname human-readable name for the namespace + * @param ns_uname unique (!) human-readable name for the namespace * @param nsid set to namespace ID based on 'ns_uname' - * @return GNUNET_OK on success + * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *ns_uname, GNUNET_HashCode * nsid) + const char *ns_uname, GNUNET_HashCode * nsid) { size_t slen; uint64_t len; @@ -399,19 +462,20 @@ GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, idx = -1; slen = strlen (ns_uname); - while ((slen > 0) && (1 != sscanf (&ns_uname[slen - 1], "-%u", &idx))) + while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx))) slen--; if (slen == 0) return GNUNET_SYSERR; name = GNUNET_strdup (ns_uname); name[slen - 1] = '\0'; + GNUNET_CRYPTO_hash (name, strlen (name), &nh); GNUNET_free (name); fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); GNUNET_assert (fn != NULL); if ((GNUNET_OK != GNUNET_DISK_file_test (fn) || - (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES))) || + (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) || ((idx + 1) * sizeof (GNUNET_HashCode) > len)) { GNUNET_free (fn); @@ -472,10 +536,11 @@ list_pseudonym_helper (void *cls, const char *fullname) struct ListPseudonymClosure *c = cls; int ret; GNUNET_HashCode id; - int rating; + int32_t rating; struct GNUNET_CONTAINER_MetaData *meta; const char *fn; char *str; + char *name_unique; if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) return GNUNET_OK; @@ -487,11 +552,22 @@ list_pseudonym_helper (void *cls, const char *fullname) if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (fn, &id)) return GNUNET_OK; /* invalid name */ str = NULL; - if (GNUNET_OK != read_info (c->cfg, &id, &meta, &rating, &str)) - return GNUNET_OK; /* ignore entry */ - GNUNET_free_non_null (str); + if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (c->cfg, &id, &meta, &rating, + &str, NULL)) + { + /* ignore entry. FIXME: Why? Lack of data about a pseudonym is not a reason + * to ignore it... So yeah, it will have placeholders instead of name, + * empty metadata container and a default rank == -1, so what? We know + * its nsid - that's all we really need. Right? */ + GNUNET_free (str); + GNUNET_CONTAINER_meta_data_destroy (meta); + return GNUNET_OK; + } + name_unique = GNUNET_PSEUDONYM_name_uniquify (c->cfg, &id, str, NULL); if (c->iterator != NULL) - ret = c->iterator (c->closure, &id, meta, rating); + ret = c->iterator (c->closure, &id, str, name_unique, meta, rating); + GNUNET_free_non_null (str); + GNUNET_free_non_null (name_unique); GNUNET_CONTAINER_meta_data_destroy (meta); return ret; } @@ -559,6 +635,31 @@ GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, /** + * Set the pseudonym metadata, rank and name. + * + * @param cfg overall configuration + * @param nsid id of the pseudonym + * @param name name to set. Must be the non-unique version of it. + * May be NULL, in which case it erases pseudonym's name! + * @param md metadata to set + * May be NULL, in which case it erases pseudonym's metadata! + * @param rank rank to assign + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid, const char *name, + const struct GNUNET_CONTAINER_MetaData *md, int rank) +{ + GNUNET_assert (cfg != NULL); + GNUNET_assert (nsid != NULL); + + write_pseudonym_info (cfg, nsid, md, rank, name); + return GNUNET_OK; +} + + +/** * Add a pseudonym to the set of known pseudonyms. * For all pseudonym advertisements that we discover * FS should automatically call this function. diff --git a/src/util/resolver.conf.in b/src/util/resolver.conf.in index 671ea0e..7abe1c9 100644 --- a/src/util/resolver.conf.in +++ b/src/util/resolver.conf.in @@ -1,6 +1,6 @@ [resolver] AUTOSTART = YES -@UNIXONLY@ PORT = 2089 +@JAVAPORT@PORT = 2089 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG diff --git a/src/util/resolver.h b/src/util/resolver.h index 2c0de99..b77c199 100644 --- a/src/util/resolver.h +++ b/src/util/resolver.h @@ -27,8 +27,6 @@ #include "gnunet_common.h" -#define DEBUG_RESOLVER GNUNET_EXTRA_LOGGING - GNUNET_NETWORK_STRUCT_BEGIN /** diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c index 9d5ae6c..87b76f1 100644 --- a/src/util/resolver_api.c +++ b/src/util/resolver_api.c @@ -250,10 +250,8 @@ GNUNET_RESOLVER_disconnect () GNUNET_assert (NULL == req_tail); if (NULL != client) { -#if DEBUG_RESOLVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from DNS service\n"); -#endif - GNUNET_CLIENT_disconnect (client, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); client = NULL; } if (r_task != GNUNET_SCHEDULER_NO_TASK) @@ -339,9 +337,7 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg) struct GNUNET_RESOLVER_RequestHandle *rh = cls; uint16_t size; -#if DEBUG_RESOLVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving response from DNS service\n"); -#endif if (msg == NULL) { char buf[INET6_ADDRSTRLEN]; @@ -374,7 +370,7 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg) } GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); - GNUNET_CLIENT_disconnect (client, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; @@ -382,7 +378,7 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg) if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) { GNUNET_break (0); - GNUNET_CLIENT_disconnect (client, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; @@ -417,15 +413,13 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg) rh->name_callback (rh->cls, NULL); GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); - GNUNET_CLIENT_disconnect (client, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } -#if DEBUG_RESOLVER - LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s' for IP `%s'.\n"), + LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s' for IP `%s'.\n", hostname, GNUNET_a2s ((const void *) &rh[1], rh->data_len)); -#endif if (rh->was_transmitted != GNUNET_SYSERR) rh->name_callback (rh->cls, hostname); rh->received_response = GNUNET_YES; @@ -473,7 +467,7 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg) rh->addr_callback (rh->cls, NULL, 0); GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); - GNUNET_CLIENT_disconnect (client, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; @@ -606,7 +600,7 @@ static void process_requests () { struct GNUNET_RESOLVER_GetMessage *msg; - char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; struct GNUNET_RESOLVER_RequestHandle *rh; if (NULL == client) @@ -633,17 +627,15 @@ process_requests () msg->direction = htonl (rh->direction); msg->af = htonl (rh->af); memcpy (&msg[1], &rh[1], rh->data_len); -#if DEBUG_RESOLVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting DNS resolution request to DNS service\n"); -#endif if (GNUNET_OK != GNUNET_CLIENT_transmit_and_get_response (client, &msg->header, GNUNET_TIME_absolute_get_remaining (rh->timeout), GNUNET_YES, &handle_response, rh)) { - GNUNET_CLIENT_disconnect (client, GNUNET_NO); + GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; @@ -666,9 +658,7 @@ reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) return; /* no work pending */ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; -#if DEBUG_RESOLVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to DNS service\n"); -#endif client = GNUNET_CLIENT_connect ("resolver", resolver_cfg); if (NULL == client) { @@ -712,11 +702,9 @@ reconnect () break; } } -#if DEBUG_RESOLVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Will try to connect to DNS service in %llu ms\n", (unsigned long long) backoff.rel_value); -#endif GNUNET_assert (NULL != resolver_cfg); r_task = GNUNET_SCHEDULER_add_delayed (backoff, &reconnect_task, NULL); backoff = GNUNET_TIME_relative_multiply (backoff, 2); @@ -803,9 +791,7 @@ numeric_reverse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) char *result; result = no_resolve (rh->af, &rh[1], rh->data_len); -#if DEBUG_RESOLVER - LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), result); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s'.\n", result); if (result != NULL) { rh->name_callback (rh->cls, result); @@ -897,9 +883,7 @@ GNUNET_RESOLVER_local_fqdn_get () "gethostname"); return NULL; } -#if DEBUG_RESOLVER - LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolving our FQDN `%s'\n"), hostname); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving our FQDN `%s'\n", hostname); host = gethostbyname (hostname); if (NULL == host) { @@ -934,9 +918,7 @@ GNUNET_RESOLVER_hostname_resolve (int af, "gethostname"); return NULL; } -#if DEBUG_RESOLVER - LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolving our hostname `%s'\n"), hostname); -#endif + LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving our hostname `%s'\n", hostname); return GNUNET_RESOLVER_ip_get (hostname, af, timeout, callback, cls); } diff --git a/src/util/scheduler.c b/src/util/scheduler.c index c54672f..45cc020 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c @@ -115,11 +115,6 @@ struct Task GNUNET_SCHEDULER_TaskIdentifier id; /** - * Identifier of a prerequisite task. - */ - GNUNET_SCHEDULER_TaskIdentifier prereq_id; - - /** * Absolute timeout value for the task, or * GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout". */ @@ -216,13 +211,6 @@ static struct Task *ready[GNUNET_SCHEDULER_PRIORITY_COUNT]; static GNUNET_SCHEDULER_TaskIdentifier last_id; /** - * Highest number so that all tasks with smaller identifiers - * have already completed. Also the lowest number of a task - * still waiting to be executed. - */ -static GNUNET_SCHEDULER_TaskIdentifier lowest_pending_id; - -/** * Number of tasks on the ready list. */ static unsigned int ready_count; @@ -293,60 +281,6 @@ check_priority (enum GNUNET_SCHEDULER_Priority p) /** - * Is a task with this identifier still pending? Also updates - * "lowest_pending_id" as a side-effect (for faster checks in the - * future), but only if the return value is "GNUNET_NO" (and - * the "lowest_pending_id" check failed). - * - * @param id which task are we checking for - * @return GNUNET_YES if so, GNUNET_NO if not - */ -static int -is_pending (GNUNET_SCHEDULER_TaskIdentifier id) -{ - struct Task *pos; - enum GNUNET_SCHEDULER_Priority p; - GNUNET_SCHEDULER_TaskIdentifier min; - - if (id < lowest_pending_id) - return GNUNET_NO; - min = -1; /* maximum value */ - pos = pending; - while (pos != NULL) - { - if (pos->id == id) - return GNUNET_YES; - if (pos->id < min) - min = pos->id; - pos = pos->next; - } - pos = pending_timeout; - while (pos != NULL) - { - if (pos->id == id) - return GNUNET_YES; - if (pos->id < min) - min = pos->id; - pos = pos->next; - } - for (p = 0; p < GNUNET_SCHEDULER_PRIORITY_COUNT; p++) - { - pos = ready[p]; - while (pos != NULL) - { - if (pos->id == id) - return GNUNET_YES; - if (pos->id < min) - min = pos->id; - pos = pos->next; - } - } - lowest_pending_id = min; - return GNUNET_NO; -} - - -/** * Update all sets and timeout for select. * * @param rs read-set, set to all FDs we would like to read (updated) @@ -374,12 +308,6 @@ update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws, pos = pending; while (pos != NULL) { - if ((pos->prereq_id != GNUNET_SCHEDULER_NO_TASK) && - (GNUNET_YES == is_pending (pos->prereq_id))) - { - pos = pos->next; - continue; - } if (pos->timeout.abs_value != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) { to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); @@ -459,15 +387,7 @@ is_ready (struct Task *task, struct GNUNET_TIME_Absolute now, reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; if (reason == 0) return GNUNET_NO; /* not ready */ - if (task->prereq_id != GNUNET_SCHEDULER_NO_TASK) - { - if (GNUNET_YES == is_pending (task->prereq_id)) - { - task->reason = reason; - return GNUNET_NO; /* prereq waiting */ - } - reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; - } + reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; task->reason = reason; return GNUNET_YES; } @@ -1107,31 +1027,6 @@ GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls, /** - * Schedule a new task to be run after the specified prerequisite task - * has completed. It will be run with the DEFAULT priority. - * - * @param prerequisite_task run this task after the task with the given - * task identifier completes (and any of our other - * conditions, such as delay, read or write-readiness - * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency - * on completion of other tasks (this will cause the task to run as - * soon as possible). - * @param task main function of the task - * @param task_cls closure of task - * @return unique task identifier for the job - * only valid until "task" is started! - */ -GNUNET_SCHEDULER_TaskIdentifier -GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, - GNUNET_SCHEDULER_Task task, void *task_cls) -{ - return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - prerequisite_task, GNUNET_TIME_UNIT_ZERO, - NULL, NULL, task, task_cls); -} - - -/** * Schedule a new task to be run with a specified priority. * * @param prio how important is the new task? @@ -1144,7 +1039,7 @@ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_Task task, void *task_cls) { - return GNUNET_SCHEDULER_add_select (prio, GNUNET_SCHEDULER_NO_TASK, + return GNUNET_SCHEDULER_add_select (prio, GNUNET_TIME_UNIT_ZERO, NULL, NULL, task, task_cls); } @@ -1299,7 +1194,6 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_ZERO, NULL, NULL, task, task_cls); GNUNET_assert (pending->id == ret); @@ -1399,7 +1293,6 @@ add_without_sets (struct GNUNET_TIME_Relative delay, #if PROFILE_DELAYS t->start_time = GNUNET_TIME_absolute_get (); #endif - t->prereq_id = GNUNET_SCHEDULER_NO_TASK; t->timeout = GNUNET_TIME_relative_to_absolute (delay); t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : priority); t->lifeness = current_lifeness; @@ -1441,6 +1334,35 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task task, void *task_cls) { + return GNUNET_SCHEDULER_add_read_net_with_priority (delay, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + rfd, task, task_cls); +} + + +/** + * Schedule a new task to be run with a specified priority and to be + * run after the specified delay or when the specified file descriptor + * is ready for reading. The delay can be used as a timeout on the + * socket being ready. The task will be scheduled for execution once + * either the delay has expired or the socket operation is ready. It + * will be run with the DEFAULT priority. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param priority priority to use for the task + * @param rfd read file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, + enum GNUNET_SCHEDULER_Priority priority, + struct GNUNET_NETWORK_Handle *rfd, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ #if MINGW struct GNUNET_NETWORK_FDSet *rs; GNUNET_SCHEDULER_TaskIdentifier ret; @@ -1449,20 +1371,21 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, rs = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_set (rs, rfd); ret = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL, + GNUNET_SCHEDULER_add_select (priority, + delay, rs, NULL, task, task_cls); GNUNET_NETWORK_fdset_destroy (rs); return ret; #else return add_without_sets (delay, - GNUNET_SCHEDULER_PRIORITY_DEFAULT, + priority, GNUNET_NETWORK_get_fd (rfd), -1, task, task_cls); #endif } + /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for writing. The delay can be @@ -1493,7 +1416,7 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, GNUNET_NETWORK_fdset_set (ws, wfd); ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws, + delay, NULL, ws, task, task_cls); GNUNET_NETWORK_fdset_destroy (ws); return ret; @@ -1536,7 +1459,7 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, GNUNET_NETWORK_fdset_handle_set (rs, rfd); ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL, + delay, rs, NULL, task, task_cls); GNUNET_NETWORK_fdset_destroy (rs); return ret; @@ -1581,7 +1504,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, GNUNET_NETWORK_fdset_handle_set (ws, wfd); ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws, + delay, NULL, ws, task, task_cls); GNUNET_NETWORK_fdset_destroy (ws); return ret; @@ -1617,11 +1540,6 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, * </code> * * @param prio how important is this task? - * @param prerequisite_task run this task after the task with the given - * task identifier completes (and any of our other - * conditions, such as delay, read or write-readiness - * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency - * on completion of other tasks. * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", * which means that the task will only be run after we receive SIGTERM * @param rs set of file descriptors we want to read (can be NULL) @@ -1633,7 +1551,6 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, - GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, @@ -1671,7 +1588,6 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, #if PROFILE_DELAYS t->start_time = GNUNET_TIME_absolute_get (); #endif - t->prereq_id = prerequisite_task; t->timeout = GNUNET_TIME_relative_to_absolute (delay); t->priority = check_priority ((prio == diff --git a/src/util/server.c b/src/util/server.c index 24804d2..409e89f 100644 --- a/src/util/server.c +++ b/src/util/server.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) + (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -26,11 +26,7 @@ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_connection_lib.h" -#include "gnunet_scheduler_lib.h" -#include "gnunet_server_lib.h" -#include "gnunet_time_lib.h" -#include "gnunet_disk_lib.h" +#include "gnunet_util_lib.h" #include "gnunet_protocols.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) @@ -39,7 +35,6 @@ #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) -#define DEBUG_SERVER GNUNET_EXTRA_LOGGING /** * List of arrays of message handlers. @@ -64,11 +59,16 @@ struct HandlerList struct NotifyList { /** - * This is a linked list. + * This is a doubly linked list. */ struct NotifyList *next; /** + * This is a doubly linked list. + */ + struct NotifyList *prev; + + /** * Function to call. */ GNUNET_SERVER_DisconnectCallback callback; @@ -91,14 +91,24 @@ struct GNUNET_SERVER_Handle struct HandlerList *handlers; /** - * List of our current clients. + * Head of list of our current clients. */ - struct GNUNET_SERVER_Client *clients; + struct GNUNET_SERVER_Client *clients_head; /** - * Linked list of functions to call on disconnects by clients. + * Head of list of our current clients. */ - struct NotifyList *disconnect_notify_list; + struct GNUNET_SERVER_Client *clients_tail; + + /** + * Head of linked list of functions to call on disconnects by clients. + */ + struct NotifyList *disconnect_notify_list_head; + + /** + * Tail of linked list of functions to call on disconnects by clients. + */ + struct NotifyList *disconnect_notify_list_tail; /** * Function to call for access control. @@ -128,22 +138,62 @@ struct GNUNET_SERVER_Handle GNUNET_SCHEDULER_TaskIdentifier listen_task; /** + * Alternative function to create a MST instance. + */ + GNUNET_SERVER_MstCreateCallback mst_create; + + /** + * Alternative function to destroy a MST instance. + */ + GNUNET_SERVER_MstDestroyCallback mst_destroy; + + /** + * Alternative function to give data to a MST instance. + */ + GNUNET_SERVER_MstReceiveCallback mst_receive; + + /** + * Closure for 'mst_'-callbacks. + */ + void *mst_cls; + + /** * Do we ignore messages of types that we do not understand or do we * require that a handler is found (and if not kill the connection)? */ int require_found; /** - * Should all of the clients of this server continue to process - * connections as usual even if we get a shutdown request? (the - * listen socket always ignores shutdown). + * Set to GNUNET_YES once we are in 'soft' shutdown where we wait for + * all non-monitor clients to disconnect before we call + * GNUNET_SERVER_destroy. See 'test_monitor_clients'. Set to + * GNUNET_SYSERR once the final destroy task has been scheduled + * (we cannot run it in the same task). */ - int clients_ignore_shutdown; + int in_soft_shutdown; +}; + + +/** + * Handle server returns for aborting transmission to a client. + */ +struct GNUNET_SERVER_TransmitHandle +{ + /** + * Function to call to get the message. + */ + GNUNET_CONNECTION_TransmitReadyNotify callback; + + /** + * Closure for 'callback' + */ + void *callback_cls; + + /** + * Active connection transmission handle. + */ + struct GNUNET_CONNECTION_TransmitHandle *cth; - GNUNET_SERVER_MstCreateCallback mst_create; - GNUNET_SERVER_MstDestroyCallback mst_destroy; - GNUNET_SERVER_MstReceiveCallback mst_receive; - void *mst_cls; }; @@ -154,11 +204,16 @@ struct GNUNET_SERVER_Client { /** - * This is a linked list. + * This is a doubly linked list. */ struct GNUNET_SERVER_Client *next; /** + * This is a doubly linked list. + */ + struct GNUNET_SERVER_Client *prev; + + /** * Processing of incoming data. */ void *mst; @@ -195,14 +250,10 @@ struct GNUNET_SERVER_Client struct GNUNET_TIME_Absolute last_activity; /** - * + * Transmission handle we return for this client from + * GNUNET_SERVER_notify_transmit_ready. */ - GNUNET_CONNECTION_TransmitReadyNotify callback; - - /** - * callback - */ - void *callback_cls; + struct GNUNET_SERVER_TransmitHandle th; /** * After how long should an idle connection time @@ -235,8 +286,7 @@ struct GNUNET_SERVER_Client int in_process_client_buffer; /** - * We're about to close down this client due to some serious - * error. + * We're about to close down this client. */ int shutdown_now; @@ -259,6 +309,13 @@ struct GNUNET_SERVER_Client int persist; /** + * Is this client a 'monitor' client that should not be counted + * when deciding on destroying the server during soft shutdown? + * (see also GNUNET_SERVICE_start) + */ + int is_monitor; + + /** * Type of last message processed (for warn_no_receive_done). */ uint16_t warn_type; @@ -273,28 +330,66 @@ struct GNUNET_SERVER_Client * @param tc reason why we are running right now */ static void -process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Add a listen task with the scheduler for this server. + * + * @param server handle to our server for which we are adding the listen + * socket + */ +static void +schedule_listen_task (struct GNUNET_SERVER_Handle *server) { - struct GNUNET_SERVER_Handle *server = cls; - struct GNUNET_CONNECTION_Handle *sock; - struct GNUNET_SERVER_Client *client; struct GNUNET_NETWORK_FDSet *r; unsigned int i; - server->listen_task = GNUNET_SCHEDULER_NO_TASK; + if (NULL == server->listen_sockets[0]) + return; /* nothing to do, no listen sockets! */ + if (NULL == server->listen_sockets[1]) + { + /* simplified method: no fd set needed; this is then much simpler and + much more efficient */ + server->listen_task = + GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_SCHEDULER_PRIORITY_HIGH, + server->listen_sockets[0], + &process_listen_socket, server); + return; + } r = GNUNET_NETWORK_fdset_create (); i = 0; while (NULL != server->listen_sockets[i]) GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]); + server->listen_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, + &process_listen_socket, server); + GNUNET_NETWORK_fdset_destroy (r); +} + + +/** + * Scheduler says our listen socket is ready. Process it! + * + * @param cls handle to our server for which we are processing the listen + * socket + * @param tc reason why we are running right now + */ +static void +process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Handle *server = cls; + struct GNUNET_CONNECTION_Handle *sock; + struct GNUNET_SERVER_Client *client; + unsigned int i; + + server->listen_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { /* ignore shutdown, someone else will take care of it! */ - server->listen_task = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, - GNUNET_SCHEDULER_NO_TASK, - GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, - &process_listen_socket, server); - GNUNET_NETWORK_fdset_destroy (r); + schedule_listen_task (server); return; } i = 0; @@ -306,14 +401,10 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_CONNECTION_create_from_accept (server->access, server->access_cls, server->listen_sockets[i]); - if (sock != NULL) + if (NULL != sock) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server accepted incoming connection.\n"); -#endif client = GNUNET_SERVER_connect_socket (server, sock); - GNUNET_CONNECTION_ignore_shutdown (sock, - server->clients_ignore_shutdown); /* decrement reference count, we don't keep "client" alive */ GNUNET_SERVER_client_drop (client); } @@ -321,12 +412,7 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) i++; } /* listen for more! */ - server->listen_task = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, - GNUNET_SCHEDULER_NO_TASK, - GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, - &process_listen_socket, server); - GNUNET_NETWORK_fdset_destroy (r); + schedule_listen_task (server); } @@ -340,7 +426,7 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static struct GNUNET_NETWORK_Handle * open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) { - const static int on = 1; + static int on = 1; struct GNUNET_NETWORK_Handle *sock; uint16_t port; int eno; @@ -368,14 +454,14 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) errno = 0; return NULL; } - if (port != 0) + if (0 != port) { if (GNUNET_NETWORK_socket_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); #ifdef IPV6_V6ONLY - if ((serverAddr->sa_family == AF_INET6) && + if ((AF_INET6 == serverAddr->sa_family) && (GNUNET_NETWORK_socket_setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, @@ -383,30 +469,30 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) #endif } /* bind the socket */ - if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK) + if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen)) { eno = errno; - if (errno != EADDRINUSE) + if (EADDRINUSE != errno) { /* we don't log 'EADDRINUSE' here since an IPv4 bind may * fail if we already took the port on IPv6; if both IPv4 and * IPv6 binds fail, then our caller will log using the * errno preserved in 'eno' */ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind"); - if (port != 0) + if (0 != port) LOG (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed for port %d (%s).\n"), "bind", port, - (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6"); + (AF_INET == serverAddr->sa_family) ? "IPv4" : "IPv6"); eno = 0; } else { - if (port != 0) + if (0 != port) LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for port %d (%s): address already in use\n"), "bind", port, - (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6"); - else if (serverAddr->sa_family == AF_UNIX) + (AF_INET == serverAddr->sa_family) ? "IPv4" : "IPv6"); + else if (AF_UNIX == serverAddr->sa_family) LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for `%s': address already in use\n"), "bind", ((const struct sockaddr_un *) serverAddr)->sun_path); @@ -423,11 +509,9 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) errno = 0; return NULL; } -#if DEBUG_SERVER - if (port != 0) + if (0 != port) LOG (GNUNET_ERROR_TYPE_DEBUG, "Server starts to listen on port %u.\n", port); -#endif return sock; } @@ -451,30 +535,17 @@ GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access, struct GNUNET_TIME_Relative idle_timeout, int require_found) { - struct GNUNET_SERVER_Handle *ret; - struct GNUNET_NETWORK_FDSet *r; - int i; - - ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle)); - ret->idle_timeout = idle_timeout; - ret->listen_sockets = lsocks; - ret->access = access; - ret->access_cls = access_cls; - ret->require_found = require_found; - if (lsocks != NULL) - { - r = GNUNET_NETWORK_fdset_create (); - i = 0; - while (NULL != ret->listen_sockets[i]) - GNUNET_NETWORK_fdset_set (r, ret->listen_sockets[i++]); - ret->listen_task = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, - GNUNET_SCHEDULER_NO_TASK, - GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, - &process_listen_socket, ret); - GNUNET_NETWORK_fdset_destroy (r); - } - return ret; + struct GNUNET_SERVER_Handle *server; + + server = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle)); + server->idle_timeout = idle_timeout; + server->listen_sockets = lsocks; + server->access = access; + server->access_cls = access_cls; + server->require_found = require_found; + if (NULL != lsocks) + schedule_listen_task (server); + return server; } @@ -501,25 +572,41 @@ GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle **lsocks; unsigned int i; unsigned int j; + unsigned int k; + int seen; i = 0; - while (serverAddr[i] != NULL) + while (NULL != serverAddr[i]) i++; if (i > 0) { lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1)); i = 0; j = 0; - while (serverAddr[i] != NULL) + while (NULL != serverAddr[i]) { + seen = 0; + for (k=0;k<i;k++) + if ( (socklen[k] == socklen[i]) && + (0 == memcmp (serverAddr[k], serverAddr[i], socklen[i])) ) + { + seen = 1; + break; + } + if (0 != seen) + { + /* duplicate address, skip */ + i++; + continue; + } lsocks[j] = open_listen_socket (serverAddr[i], socklen[i]); - if (lsocks[j] != NULL) + if (NULL != lsocks[j]) j++; i++; } - if (j == 0) + if (0 == j) { - if (errno != 0) + if (0 != errno) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind"); GNUNET_free (lsocks); lsocks = NULL; @@ -535,48 +622,137 @@ GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls, /** + * Set the 'monitor' flag on this client. Clients which have been + * marked as 'monitors' won't prevent the server from shutting down + * once 'GNUNET_SERVER_stop_listening' has been invoked. The idea is + * that for "normal" clients we likely want to allow them to process + * their requests; however, monitor-clients are likely to 'never' + * disconnect during shutdown and thus will not be considered when + * determining if the server should continue to exist after + * 'GNUNET_SERVER_destroy' has been called. + * + * @param client the client to set the 'monitor' flag on + */ +void +GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client) +{ + client->is_monitor = GNUNET_YES; +} + + +/** + * Helper function for 'test_monitor_clients' to trigger + * 'GNUNET_SERVER_destroy' after the stack has unwound. + * + * @param cls the 'struct GNUNET_SERVER_Handle' to destroy + * @param tc unused + */ +static void +do_destroy (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Handle *server = cls; + GNUNET_SERVER_destroy (server); +} + + +/** + * Check if only 'monitor' clients are left. If so, destroy the + * server completely. + * + * @param server server to test for full shutdown + */ +static void +test_monitor_clients (struct GNUNET_SERVER_Handle *server) +{ + struct GNUNET_SERVER_Client *client; + + if (GNUNET_YES != server->in_soft_shutdown) + return; + for (client = server->clients_head; NULL != client; client = client->next) + if (GNUNET_NO == client->is_monitor) + return; /* not done yet */ + server->in_soft_shutdown = GNUNET_SYSERR; + GNUNET_SCHEDULER_add_continuation (&do_destroy, server, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +/** + * Stop the listen socket and get ready to shutdown the server + * once only 'monitor' clients are left. + * + * @param server server to stop listening on + */ +void +GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server) +{ + unsigned int i; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Server in soft shutdown\n"); + if (GNUNET_SCHEDULER_NO_TASK != server->listen_task) + { + GNUNET_SCHEDULER_cancel (server->listen_task); + server->listen_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != server->listen_sockets) + { + i = 0; + while (NULL != server->listen_sockets[i]) + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (server->listen_sockets[i++])); + GNUNET_free (server->listen_sockets); + server->listen_sockets = NULL; + } + if (GNUNET_NO == server->in_soft_shutdown) + server->in_soft_shutdown = GNUNET_YES; + test_monitor_clients (server); +} + + +/** * Free resources held by this server. * - * @param s server to destroy + * @param server server to destroy */ void -GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) +GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server) { struct HandlerList *hpos; struct NotifyList *npos; unsigned int i; -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n"); -#endif - if (GNUNET_SCHEDULER_NO_TASK != s->listen_task) + if (GNUNET_SCHEDULER_NO_TASK != server->listen_task) { - GNUNET_SCHEDULER_cancel (s->listen_task); - s->listen_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel (server->listen_task); + server->listen_task = GNUNET_SCHEDULER_NO_TASK; } - if (s->listen_sockets != NULL) + if (NULL != server->listen_sockets) { i = 0; - while (s->listen_sockets[i] != NULL) + while (NULL != server->listen_sockets[i]) GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (s->listen_sockets[i++])); - GNUNET_free (s->listen_sockets); - s->listen_sockets = NULL; + GNUNET_NETWORK_socket_close (server->listen_sockets[i++])); + GNUNET_free (server->listen_sockets); + server->listen_sockets = NULL; } - while (s->clients != NULL) - GNUNET_SERVER_client_disconnect (s->clients); - while (NULL != (hpos = s->handlers)) + while (NULL != server->clients_head) + GNUNET_SERVER_client_disconnect (server->clients_head); + while (NULL != (hpos = server->handlers)) { - s->handlers = hpos->next; + server->handlers = hpos->next; GNUNET_free (hpos); } - while (NULL != (npos = s->disconnect_notify_list)) + while (NULL != (npos = server->disconnect_notify_list_head)) { npos->callback (npos->callback_cls, NULL); - s->disconnect_notify_list = npos->next; + GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head, + server->disconnect_notify_list_tail, + npos); GNUNET_free (npos); } - GNUNET_free (s); + GNUNET_free (server); } @@ -606,6 +782,16 @@ GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server, } +/** + * Change functions used by the server to tokenize the message stream. + * (very rarely used). + * + * @param server server to modify + * @param create new tokenizer initialization function + * @param destroy new tokenizer destruction function + * @param receive new tokenizer receive function + * @param cls closure for 'create', 'receive', 'destroy' + */ void GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server, GNUNET_SERVER_MstCreateCallback create, @@ -631,6 +817,7 @@ warn_no_receive_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Client *client = cls; + GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */ client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_no_receive_done, client); @@ -691,15 +878,11 @@ GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, type = ntohs (message->type); size = ntohs (message->size); -#if DEBUG_SERVER - LOG (GNUNET_ERROR_TYPE_DEBUG, "Server schedules transmission of %u-byte message of type %u to client.\n", size, type); -#endif - pos = server->handlers; found = GNUNET_NO; - while (pos != NULL) + for (pos = server->handlers; NULL != pos; pos = pos->next) { i = 0; while (pos->handlers[i].callback != NULL) @@ -707,7 +890,7 @@ GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, mh = &pos->handlers[i]; if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL)) { - if ((mh->expected_size != 0) && (mh->expected_size != size)) + if ((0 != mh->expected_size) && (mh->expected_size != size)) { #if GNUNET8_NETWORK_IS_DEAD LOG (GNUNET_ERROR_TYPE_WARNING, @@ -717,11 +900,13 @@ GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, #endif return GNUNET_SYSERR; } - if (sender != NULL) + if (NULL != sender) { - if (0 == sender->suspended) + if ( (0 == sender->suspended) && + (GNUNET_SCHEDULER_NO_TASK == sender->warn_task) ) { - sender->warn_start = GNUNET_TIME_absolute_get (); + GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */ + sender->warn_start = GNUNET_TIME_absolute_get (); sender->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_no_receive_done, sender); @@ -734,13 +919,12 @@ GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, } i++; } - pos = pos->next; } - if (found == GNUNET_NO) + if (GNUNET_NO == found) { LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Received message of unknown type %d\n", type); - if (server->require_found == GNUNET_YES) + if (GNUNET_YES == server->require_found) return GNUNET_SYSERR; } return GNUNET_OK; @@ -778,28 +962,24 @@ process_incoming (void *cls, const void *buf, size_t available, static void process_mst (struct GNUNET_SERVER_Client *client, int ret) { - while ((ret != GNUNET_SYSERR) && (client->server != NULL) && + while ((GNUNET_SYSERR != ret) && (NULL != client->server) && (GNUNET_YES != client->shutdown_now) && (0 == client->suspended)) { - if (ret == GNUNET_OK) + if (GNUNET_OK == ret) { - client->receive_pending = GNUNET_YES; -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server re-enters receive loop, timeout: %llu.\n", client->idle_timeout.rel_value); -#endif + client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, client->idle_timeout, &process_incoming, client); break; } -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server processes additional messages instantly.\n"); -#endif - if (client->server->mst_receive != NULL) + if (NULL != client->server->mst_receive) ret = client->server->mst_receive (client->server->mst_cls, client->mst, client, NULL, 0, GNUNET_NO, GNUNET_YES); @@ -808,23 +988,17 @@ process_mst (struct GNUNET_SERVER_Client *client, int ret) GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO, GNUNET_YES); } -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n", ret, client->server, client->shutdown_now, client->suspended); -#endif - - if (ret == GNUNET_NO) + if (GNUNET_NO == ret) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server has more data pending but is suspended.\n"); -#endif client->receive_pending = GNUNET_SYSERR; /* data pending */ } - if ((ret == GNUNET_SYSERR) || (GNUNET_YES == client->shutdown_now)) + if ((GNUNET_SYSERR == ret) || (GNUNET_YES == client->shutdown_now)) GNUNET_SERVER_client_disconnect (client); - GNUNET_SERVER_client_drop (client); } @@ -848,22 +1022,20 @@ process_incoming (void *cls, const void *buf, size_t available, struct GNUNET_TIME_Absolute now; int ret; - GNUNET_assert (client->receive_pending == GNUNET_YES); + GNUNET_assert (GNUNET_YES == client->receive_pending); client->receive_pending = GNUNET_NO; now = GNUNET_TIME_absolute_get (); end = GNUNET_TIME_absolute_add (client->last_activity, client->idle_timeout); - if ((buf == NULL) && (available == 0) && (addr == NULL) && (errCode == 0) && - (client->shutdown_now != GNUNET_YES) && (server != NULL) && + if ((NULL == buf) && (0 == available) && (NULL == addr) && (0 == errCode) && + (GNUNET_YES != client->shutdown_now) && (NULL != server) && (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) && (end.abs_value > now.abs_value)) { /* wait longer, timeout changed (i.e. due to us sending) */ -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Receive time out, but no disconnect due to sending (%p)\n", GNUNET_a2s (addr, addrlen)); -#endif client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, @@ -871,31 +1043,37 @@ process_incoming (void *cls, const void *buf, size_t available, &process_incoming, client); return; } - if ((buf == NULL) || (available == 0) || (errCode != 0) || (server == NULL) || - (client->shutdown_now == GNUNET_YES) || + if ((NULL == buf) || (0 == available) || (0 != errCode) || (NULL == server) || + (GNUNET_YES == client->shutdown_now) || (GNUNET_YES != GNUNET_CONNECTION_check (client->connection))) { /* other side closed connection, error connecting, etc. */ GNUNET_SERVER_client_disconnect (client); return; } -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server receives %u bytes from `%s'.\n", (unsigned int) available, GNUNET_a2s (addr, addrlen)); -#endif GNUNET_SERVER_client_keep (client); client->last_activity = now; - if (server->mst_receive != NULL) + if (NULL != server->mst_receive) ret = client->server->mst_receive (client->server->mst_cls, client->mst, client, buf, available, GNUNET_NO, GNUNET_YES); - else + else if (NULL != client->mst) + { ret = GNUNET_SERVER_mst_receive (client->mst, client, buf, available, GNUNET_NO, GNUNET_YES); + } + else + { + GNUNET_break (0); + return; + } process_mst (client, ret); + GNUNET_SERVER_client_drop (client); } @@ -910,33 +1088,24 @@ static void restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Client *client = cls; - struct GNUNET_SERVER_Handle *server = client->server; + GNUNET_assert (GNUNET_YES != client->shutdown_now); client->restart_task = GNUNET_SCHEDULER_NO_TASK; - if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && - (GNUNET_NO == server->clients_ignore_shutdown)) - { - GNUNET_SERVER_client_disconnect (client); - return; - } - if (client->receive_pending == GNUNET_NO) + if (GNUNET_NO == client->receive_pending) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n"); -#endif client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, client->idle_timeout, &process_incoming, client); return; } -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Server continues processing messages still in the buffer.\n"); -#endif GNUNET_SERVER_client_keep (client); client->receive_pending = GNUNET_NO; process_mst (client, GNUNET_NO); + GNUNET_SERVER_client_drop (client); } @@ -947,8 +1116,10 @@ restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param cls closure (struct GNUNET_SERVER_Handle) * @param client identification of the client (struct GNUNET_SERVER_Client*) * @param message the actual message + * + * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing */ -static void +static int client_message_tokenizer_callback (void *cls, void *client, const struct GNUNET_MessageHeader *message) { @@ -956,17 +1127,18 @@ client_message_tokenizer_callback (void *cls, void *client, struct GNUNET_SERVER_Client *sender = client; int ret; -#if DEBUG_SERVER - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tokenizer gives server message of type %u from client\n", ntohs (message->type)); -#endif sender->in_process_client_buffer = GNUNET_YES; ret = GNUNET_SERVER_inject (server, sender, message); sender->in_process_client_buffer = GNUNET_NO; - if (GNUNET_OK != ret) + if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) ) + { GNUNET_SERVER_client_disconnect (sender); + return GNUNET_SYSERR; + } + return GNUNET_OK; } @@ -990,25 +1162,21 @@ GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client)); client->connection = connection; - client->mst = - GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server); client->reference_count = 1; client->server = server; client->last_activity = GNUNET_TIME_absolute_get (); - client->next = server->clients; client->idle_timeout = server->idle_timeout; - server->clients = client; - client->receive_pending = GNUNET_YES; - client->callback = NULL; - client->callback_cls = NULL; - - if (server->mst_create != NULL) + GNUNET_CONTAINER_DLL_insert (server->clients_head, + server->clients_tail, + client); + if (NULL != server->mst_create) client->mst = server->mst_create (server->mst_cls, client); else client->mst = GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server); - + GNUNET_assert (NULL != client->mst); + client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, client->idle_timeout, &process_incoming, client); @@ -1032,14 +1200,6 @@ GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client, } -void -GNUNET_SERVER_client_set_finish_pending_write (struct GNUNET_SERVER_Client *client, - int finish) -{ - client->finish_pending_write = finish; -} - - /** * Notify the server that the given client handle should * be kept (keeps the connection up if possible, increments @@ -1067,7 +1227,7 @@ GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client) { GNUNET_assert (client->reference_count > 0); client->reference_count--; - if ((client->shutdown_now == GNUNET_YES) && (client->reference_count == 0)) + if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count)) GNUNET_SERVER_client_disconnect (client); } @@ -1108,8 +1268,9 @@ GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, n = GNUNET_malloc (sizeof (struct NotifyList)); n->callback = callback; n->callback_cls = callback_cls; - n->next = server->disconnect_notify_list; - server->disconnect_notify_list = n; + GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head, + server->disconnect_notify_list_tail, + n); } @@ -1126,31 +1287,42 @@ GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, callback, void *callback_cls) { struct NotifyList *pos; - struct NotifyList *prev; - prev = NULL; - pos = server->disconnect_notify_list; - while (pos != NULL) - { + for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next) if ((pos->callback == callback) && (pos->callback_cls == callback_cls)) break; - prev = pos; - pos = pos->next; - } - if (pos == NULL) + if (NULL == pos) { GNUNET_break (0); return; } - if (prev == NULL) - server->disconnect_notify_list = pos->next; - else - prev->next = pos->next; + GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head, + server->disconnect_notify_list_tail, + pos); GNUNET_free (pos); } /** + * Destroy the connection that is passed in via 'cls'. Used + * as calling 'GNUNET_CONNECTION_destroy' from within a function + * that was itself called from within 'process_notify' of + * 'connection.c' is not allowed (see #2329). + * + * @param cls connection to destroy + * @param tc scheduler context (unused) + */ +static void +destroy_connection (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONNECTION_Handle *connection = cls; + + GNUNET_CONNECTION_destroy (connection); +} + + +/** * Ask the server to disconnect from the given client. * This is the same as returning GNUNET_SYSERR from a message * handler, except that it allows dropping of a client even @@ -1161,22 +1333,17 @@ GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, void GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) { - struct GNUNET_SERVER_Client *prev; - struct GNUNET_SERVER_Client *pos; - struct GNUNET_SERVER_Handle *server; + struct GNUNET_SERVER_Handle *server = client->server; struct NotifyList *n; - unsigned int rc; -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Client is being disconnected from the server.\n"); -#endif - if (client->restart_task != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != client->restart_task) { GNUNET_SCHEDULER_cancel (client->restart_task); client->restart_task = GNUNET_SCHEDULER_NO_TASK; } - if (client->warn_task != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) { GNUNET_SCHEDULER_cancel (client->warn_task); client->warn_task = GNUNET_SCHEDULER_NO_TASK; @@ -1186,68 +1353,58 @@ GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) GNUNET_CONNECTION_receive_cancel (client->connection); client->receive_pending = GNUNET_NO; } - - rc = client->reference_count; - if (client->shutdown_now != GNUNET_YES) + client->shutdown_now = GNUNET_YES; + client->reference_count++; /* make sure nobody else clean up client... */ + if ( (NULL != client->mst) && + (NULL != server) ) { - server = client->server; - client->shutdown_now = GNUNET_YES; - prev = NULL; - pos = server->clients; - while ((pos != NULL) && (pos != client)) - { - prev = pos; - pos = pos->next; - } - GNUNET_assert (pos != NULL); - if (prev == NULL) - server->clients = pos->next; + GNUNET_CONTAINER_DLL_remove (server->clients_head, + server->clients_tail, + client); + if (NULL != server->mst_destroy) + server->mst_destroy (server->mst_cls, client->mst); else - prev->next = pos->next; - if (client->restart_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (client->restart_task); - client->restart_task = GNUNET_SCHEDULER_NO_TASK; - } - if (client->warn_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (client->warn_task); - client->warn_task = GNUNET_SCHEDULER_NO_TASK; - } - n = server->disconnect_notify_list; - while (n != NULL) - { + GNUNET_SERVER_mst_destroy (client->mst); + client->mst = NULL; + for (n = server->disconnect_notify_list_head; NULL != n; n = n->next) n->callback (n->callback_cls, client); - n = n->next; - } } - if (rc > 0) + client->reference_count--; + if (client->reference_count > 0) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "RC still positive, not destroying everything.\n"); -#endif + client->server = NULL; return; } - if (client->in_process_client_buffer == GNUNET_YES) + if (GNUNET_YES == client->in_process_client_buffer) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "Still processing inputs, not destroying everything.\n"); -#endif return; } - - if (client->persist == GNUNET_YES) + if (GNUNET_YES == client->persist) GNUNET_CONNECTION_persist_ (client->connection); - GNUNET_CONNECTION_destroy (client->connection, client->finish_pending_write); - - if (client->server->mst_destroy != NULL) - client->server->mst_destroy (client->server->mst_cls, client->mst); - else - GNUNET_SERVER_mst_destroy (client->mst); - + if (NULL != client->th.cth) + GNUNET_SERVER_notify_transmit_ready_cancel (&client->th); + (void) GNUNET_SCHEDULER_add_now (&destroy_connection, + client->connection); + /* need to cancel again, as it might have been re-added + in the meantime (i.e. during callbacks) */ + if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) + { + GNUNET_SCHEDULER_cancel (client->warn_task); + client->warn_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_YES == client->receive_pending) + { + GNUNET_CONNECTION_receive_cancel (client->connection); + client->receive_pending = GNUNET_NO; + } GNUNET_free (client); + /* we might be in soft-shutdown, test if we're done */ + if (NULL != server) + test_monitor_clients (server); } @@ -1279,12 +1436,13 @@ static size_t transmit_ready_callback_wrapper (void *cls, size_t size, void *buf) { struct GNUNET_SERVER_Client *client = cls; - size_t ret; + GNUNET_CONNECTION_TransmitReadyNotify callback; - ret = client->callback (client->callback_cls, size, buf); - if (ret > 0) - client->last_activity = GNUNET_TIME_absolute_get (); - return ret; + client->th.cth = NULL; + callback = client->th.callback; + client->th.callback = NULL; + client->last_activity = GNUNET_TIME_absolute_get (); + return callback (client->th.callback_cls, size, buf); } @@ -1300,22 +1458,39 @@ transmit_ready_callback_wrapper (void *cls, size_t size, void *buf) * @param callback_cls closure for callback * @return non-NULL if the notify callback was queued; can be used * to cancel the request using - * GNUNET_CONNECTION_notify_transmit_ready_cancel. + * GNUNET_SERVER_notify_transmit_ready_cancel. * NULL if we are already going to notify someone else (busy) */ -struct GNUNET_CONNECTION_TransmitHandle * +struct GNUNET_SERVER_TransmitHandle * GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify callback, void *callback_cls) { - client->callback_cls = callback_cls; - client->callback = callback; - return GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, - timeout, - &transmit_ready_callback_wrapper, - client); + if (NULL != client->th.callback) + return NULL; + client->th.callback_cls = callback_cls; + client->th.callback = callback; + client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, + timeout, + &transmit_ready_callback_wrapper, + client); + return &client->th; +} + + +/** + * Abort transmission request. + * + * @param th request to abort + */ +void +GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th) +{ + GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth); + th->cth = NULL; + th->callback = NULL; } @@ -1347,25 +1522,24 @@ GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client) void GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success) { - if (client == NULL) + if (NULL == client) return; GNUNET_assert (client->suspended > 0); client->suspended--; - if (success != GNUNET_OK) + if (GNUNET_OK != success) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done called with failure indication\n"); -#endif - GNUNET_SERVER_client_disconnect (client); + if ( (client->reference_count > 0) || (client->suspended > 0) ) + client->shutdown_now = GNUNET_YES; + else + GNUNET_SERVER_client_disconnect (client); return; } if (client->suspended > 0) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done called, but more clients pending\n"); -#endif return; } if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) @@ -1373,43 +1547,22 @@ GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success) GNUNET_SCHEDULER_cancel (client->warn_task); client->warn_task = GNUNET_SCHEDULER_NO_TASK; } - if (client->in_process_client_buffer == GNUNET_YES) + if (GNUNET_YES == client->in_process_client_buffer) { -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done called while still in processing loop\n"); -#endif return; } - if ((client->server == NULL) || (GNUNET_YES == client->shutdown_now)) + if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now)) { GNUNET_SERVER_client_disconnect (client); return; } -#if DEBUG_SERVER LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done causes restart in reading from the socket\n"); -#endif GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->restart_task); client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing, client); } -/** - * Configure this server's connections to continue handling client - * requests as usual even after we get a shutdown signal. The change - * only applies to clients that connect to the server from the outside - * using TCP after this call. Clients managed previously or those - * added using GNUNET_SERVER_connect_socket and - * GNUNET_SERVER_connect_callback are not affected by this option. - * - * @param h server handle - * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default - */ -void -GNUNET_SERVER_ignore_shutdown (struct GNUNET_SERVER_Handle *h, int do_ignore) -{ - h->clients_ignore_shutdown = do_ignore; -} - /* end of server.c */ diff --git a/src/util/server_mst.c b/src/util/server_mst.c index 6161770..9dd04f0 100644 --- a/src/util/server_mst.c +++ b/src/util/server_mst.c @@ -31,7 +31,6 @@ #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" -#define DEBUG_SERVER_MST GNUNET_EXTRA_LOGGING #if HAVE_UNALIGNED_64_ACCESS #define ALIGN_FACTOR 4 @@ -134,11 +133,9 @@ GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, GNUNET_assert (mst->off <= mst->pos); GNUNET_assert (mst->pos <= mst->curr_buf); -#if DEBUG_SERVER_MST LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst receives %u bytes with %u bytes already in private buffer\n", (unsigned int) size, (unsigned int) (mst->pos - mst->off)); -#endif ret = GNUNET_OK; ibuf = (char *) mst->hdr; while (mst->pos > 0) @@ -224,7 +221,8 @@ do_align: if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; mst->off += want; - mst->cb (mst->cb_cls, client_identity, hdr); + if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) + return GNUNET_SYSERR; if (mst->off == mst->pos) { /* reset to beginning of buffer, it's free right now! */ @@ -235,11 +233,9 @@ do_align: GNUNET_assert (0 == mst->pos); while (size > 0) { -#if DEBUG_SERVER_MST LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst has %u bytes left in inbound buffer\n", (unsigned int) size); -#endif if (size < sizeof (struct GNUNET_MessageHeader)) break; offset = (unsigned long) buf; @@ -266,7 +262,8 @@ do_align: } if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; - mst->cb (mst->cb_cls, client_identity, hdr); + if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) + return GNUNET_SYSERR; buf += want; size -= want; } @@ -295,11 +292,9 @@ copy: mst->off = 0; mst->pos = 0; } -#if DEBUG_SERVER_MST LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst leaves %u bytes in private buffer\n", (unsigned int) (mst->pos - mst->off)); -#endif return ret; } diff --git a/src/util/server_nc.c b/src/util/server_nc.c index 08ffd4b..6e0181e 100644 --- a/src/util/server_nc.c +++ b/src/util/server_nc.c @@ -36,8 +36,6 @@ #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) -#define DEBUG_SERVER_NC GNUNET_EXTRA_LOGGING - /** * Entry in list of messages pending to be transmitted. */ @@ -75,11 +73,16 @@ struct ClientList { /** - * This is a linked list. + * This is a doubly linked list. */ struct ClientList *next; /** + * This is a doubly linked list. + */ + struct ClientList *prev; + + /** * Overall context this client belongs to. */ struct GNUNET_SERVER_NotificationContext *nc; @@ -92,7 +95,7 @@ struct ClientList /** * Handle for pending transmission request to the client (or NULL). */ - struct GNUNET_CONNECTION_TransmitHandle *th; + struct GNUNET_SERVER_TransmitHandle *th; /** * Head of linked list of requests queued for transmission. @@ -129,9 +132,14 @@ struct GNUNET_SERVER_NotificationContext struct GNUNET_SERVER_Handle *server; /** - * List of clients receiving notifications. + * Head of list of clients receiving notifications. */ - struct ClientList *clients; + struct ClientList *clients_head; + + /** + * Tail of list of clients receiving notifications. + */ + struct ClientList *clients_tail; /** * Maximum number of optional messages to queue per client. @@ -152,45 +160,37 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct GNUNET_SERVER_NotificationContext *nc = cls; struct ClientList *pos; - struct ClientList *prev; struct PendingMessageList *pml; - if (client == NULL) + if (NULL == client) { nc->server = NULL; return; } - prev = NULL; - pos = nc->clients; - while (NULL != pos) - { + for (pos = nc->clients_head; NULL != pos; pos = pos->next) if (pos->client == client) break; - prev = pos; - pos = pos->next; - } - if (pos == NULL) + if (NULL == pos) return; -#if DEBUG_SERVER_NC LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected, cleaning up %u messages in NC queue\n", pos->num_pending); -#endif - if (prev == NULL) - nc->clients = pos->next; - else - prev->next = pos->next; + GNUNET_CONTAINER_DLL_remove (nc->clients_head, + nc->clients_tail, + pos); while (NULL != (pml = pos->pending_head)) { GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, pml); GNUNET_free (pml); + pos->num_pending--; } - if (pos->th != NULL) + if (NULL != pos->th) { - GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th); + GNUNET_SERVER_notify_transmit_ready_cancel (pos->th); pos->th = NULL; } GNUNET_SERVER_client_drop (client); + GNUNET_assert (0 == pos->num_pending); GNUNET_free (pos); } @@ -231,18 +231,27 @@ GNUNET_SERVER_notification_context_destroy (struct struct ClientList *pos; struct PendingMessageList *pml; - while (NULL != (pos = nc->clients)) + while (NULL != (pos = nc->clients_head)) { - nc->clients = pos->next; + GNUNET_CONTAINER_DLL_remove (nc->clients_head, + nc->clients_tail, + pos); + if (NULL != pos->th) + { + GNUNET_SERVER_notify_transmit_ready_cancel(pos->th); + pos->th = NULL; + } GNUNET_SERVER_client_drop (pos->client); while (NULL != (pml = pos->pending_head)) { GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, pml); GNUNET_free (pml); + pos->num_pending--; } + GNUNET_assert (0 == pos->num_pending); GNUNET_free (pos); } - if (nc->server != NULL) + if (NULL != nc->server) GNUNET_SERVER_disconnect_notify_cancel (nc->server, &handle_client_disconnect, nc); GNUNET_free (nc); @@ -262,15 +271,16 @@ GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext { struct ClientList *cl; - for (cl = nc->clients; NULL != cl; cl = cl->next) + for (cl = nc->clients_head; NULL != cl; cl = cl->next) if (cl->client == client) return; /* already present */ cl = GNUNET_malloc (sizeof (struct ClientList)); - cl->next = nc->clients; + GNUNET_CONTAINER_DLL_insert (nc->clients_head, + nc->clients_tail, + cl); cl->nc = nc; cl->client = client; GNUNET_SERVER_client_keep (client); - nc->clients = cl; } @@ -294,13 +304,11 @@ transmit_message (void *cls, size_t size, void *buf) size_t ret; cl->th = NULL; - if (buf == NULL) + if (NULL == buf) { /* 'cl' should be freed via disconnect notification shortly */ -#if DEBUG_SERVER_NC LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit message from NC queue to client\n"); -#endif return 0; } ret = 0; @@ -310,31 +318,29 @@ transmit_message (void *cls, size_t size, void *buf) if (size < msize) break; GNUNET_CONTAINER_DLL_remove (cl->pending_head, cl->pending_tail, pml); -#if DEBUG_SERVER_NC LOG (GNUNET_ERROR_TYPE_DEBUG, "Copying message of type %u and size %u from pending queue to transmission buffer\n", ntohs (pml->msg->type), msize); -#endif memcpy (&cbuf[ret], pml->msg, msize); ret += msize; size -= msize; GNUNET_free (pml); cl->num_pending--; } - if (pml != NULL) + if (NULL != pml) { -#if DEBUG_SERVER_NC LOG (GNUNET_ERROR_TYPE_DEBUG, "Have %u messages left in NC queue, will try transmission again\n", cl->num_pending); -#endif cl->th = GNUNET_SERVER_notify_transmit_ready (cl->client, ntohs (pml->msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_message, cl); } else - GNUNET_assert (cl->num_pending == 0); + { + GNUNET_assert (0 == cl->num_pending); + } return ret; } @@ -372,11 +378,9 @@ do_unicast (struct GNUNET_SERVER_NotificationContext *nc, pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size); pml->msg = (const struct GNUNET_MessageHeader *) &pml[1]; pml->can_drop = can_drop; -#if DEBUG_SERVER_NC LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding message of type %u and size %u to pending queue (which has %u entries)\n", ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length); -#endif memcpy (&pml[1], msg, size); /* append */ GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail, @@ -410,14 +414,10 @@ GNUNET_SERVER_notification_context_unicast (struct { struct ClientList *pos; - pos = nc->clients; - while (NULL != pos) - { + for (pos = nc->clients_head; NULL != pos; pos = pos->next) if (pos->client == client) break; - pos = pos->next; - } - GNUNET_assert (pos != NULL); + GNUNET_assert (NULL != pos); do_unicast (nc, pos, msg, can_drop); } @@ -438,12 +438,8 @@ GNUNET_SERVER_notification_context_broadcast (struct { struct ClientList *pos; - pos = nc->clients; - while (NULL != pos) - { + for (pos = nc->clients_head; NULL != pos; pos = pos->next) do_unicast (nc, pos, msg, can_drop); - pos = pos->next; - } } diff --git a/src/util/server_tc.c b/src/util/server_tc.c index ce40db1..f803af4 100644 --- a/src/util/server_tc.c +++ b/src/util/server_tc.c @@ -82,7 +82,7 @@ transmit_response (void *cls, size_t size, void *buf) struct GNUNET_SERVER_TransmitContext *tc = cls; size_t msize; - if (buf == NULL) + if (NULL == buf) { GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); return 0; @@ -95,7 +95,6 @@ transmit_response (void *cls, size_t size, void *buf) tc->off += msize; if (tc->total == tc->off) { - GNUNET_SERVER_receive_done (tc->client, GNUNET_OK); GNUNET_SERVER_client_drop (tc->client); GNUNET_free_non_null (tc->buf); @@ -131,7 +130,7 @@ GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client) { struct GNUNET_SERVER_TransmitContext *tc; - GNUNET_assert (client != NULL); + GNUNET_assert (NULL != client); tc = GNUNET_malloc (sizeof (struct GNUNET_SERVER_TransmitContext)); GNUNET_SERVER_client_keep (client); tc->client = client; diff --git a/src/util/service.c b/src/util/service.c index 243e7da..6a6fb6c 100644 --- a/src/util/service.c +++ b/src/util/service.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) + (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -42,7 +42,6 @@ #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) -#define DEBUG_SERVICE GNUNET_EXTRA_LOGGING /* ******************* access control ******************** */ @@ -51,7 +50,14 @@ */ struct IPv4NetworkSet { + /** + * IPv4 address. + */ struct in_addr network; + + /** + * IPv4 netmask. + */ struct in_addr netmask; }; @@ -60,11 +66,25 @@ struct IPv4NetworkSet */ struct IPv6NetworkSet { + /** + * IPv6 address. + */ struct in6_addr network; + + /** + * IPv6 netmask. + */ struct in6_addr netmask; }; +int +GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg); + +int +GNUNET_SPEEDUP_stop_ (void); + + /** * Parse a network specification. The argument specifies * a list of networks. The format is @@ -72,7 +92,7 @@ struct IPv6NetworkSet * with a semicolon). The network must be given in dotted-decimal * notation. The netmask can be given in CIDR notation (/16) or * in dotted-decimal (/255.255.0.0). - * <p> + * * @param routeList a string specifying the forbidden networks * @return the converted list, NULL if the synatx is flawed */ @@ -89,27 +109,25 @@ parse_ipv4_specification (const char *routeList) int slash; struct IPv4NetworkSet *result; - if (routeList == NULL) + if (NULL == routeList) return NULL; len = strlen (routeList); - if (len == 0) + if (0 == len) return NULL; count = 0; for (i = 0; i < len; i++) if (routeList[i] == ';') count++; result = GNUNET_malloc (sizeof (struct IPv4NetworkSet) * (count + 1)); - /* add termination */ - memset (result, 0, sizeof (struct IPv4NetworkSet) * (count + 1)); i = 0; pos = 0; while (i < count) { cnt = - sscanf (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0], + SSCANF (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0], &temps[1], &temps[2], &temps[3], &temps[4], &temps[5], &temps[6], &temps[7]); - if (cnt == 8) + if (8 == cnt) { for (j = 0; j < 8; j++) if (temps[j] > 0xFF) @@ -133,9 +151,9 @@ parse_ipv4_specification (const char *routeList) } /* try second notation */ cnt = - sscanf (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1], + SSCANF (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1], &temps[2], &temps[3], &slash); - if (cnt == 5) + if (5 == cnt) { for (j = 0; j < 4; j++) if (temps[j] > 0xFF) @@ -158,7 +176,7 @@ parse_ipv4_specification (const char *routeList) slash--; } result[i].netmask.s_addr = htonl (result[i].netmask.s_addr); - while (routeList[pos] != ';') + while (';' != routeList[pos]) pos++; pos++; i++; @@ -176,9 +194,9 @@ parse_ipv4_specification (const char *routeList) /* try third notation */ slash = 32; cnt = - sscanf (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1], + SSCANF (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1], &temps[2], &temps[3]); - if (cnt == 4) + if (4 == cnt) { for (j = 0; j < 4; j++) if (temps[j] > 0xFF) @@ -227,7 +245,7 @@ parse_ipv4_specification (const char *routeList) * with a semicolon). The network must be given in colon-hex * notation. The netmask must be given in CIDR notation (/16) or * can be omitted to specify a single host. - * <p> + * * @param routeListX a string specifying the forbidden networks * @return the converted list, NULL if the synatx is flawed */ @@ -247,17 +265,17 @@ parse_ipv6_specification (const char *routeListX) unsigned int off; int save; - if (routeListX == NULL) + if (NULL == routeListX) return NULL; len = strlen (routeListX); - if (len == 0) + if (0 == len) return NULL; routeList = GNUNET_strdup (routeListX); count = 0; for (i = 0; i < len; i++) - if (routeList[i] == ';') + if (';' == routeList[i]) count++; - if (routeList[len - 1] != ';') + if (';' != routeList[len - 1]) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid network notation (does not end with ';': `%s')\n"), @@ -267,13 +285,12 @@ parse_ipv6_specification (const char *routeListX) } result = GNUNET_malloc (sizeof (struct IPv6NetworkSet) * (count + 1)); - memset (result, 0, sizeof (struct IPv6NetworkSet) * (count + 1)); i = 0; pos = 0; while (i < count) { start = pos; - while (routeList[pos] != ';') + while (';' != routeList[pos]) pos++; slash = pos; while ((slash >= start) && (routeList[slash] != '/')) @@ -292,7 +309,7 @@ parse_ipv6_specification (const char *routeListX) save = errno; if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128)) { - if (ret == 0) + if (0 == ret) LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for netmask\n"), &routeList[slash + 1]); else @@ -322,7 +339,7 @@ parse_ipv6_specification (const char *routeListX) ret = inet_pton (AF_INET6, &routeList[start], &result[i].network); if (ret <= 0) { - if (ret == 0) + if (0 == ret) LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for network\n"), &routeList[slash + 1]); else @@ -349,12 +366,11 @@ parse_ipv6_specification (const char *routeListX) static int check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add) { - int i; + unsigned int i; - i = 0; - if (list == NULL) + if (NULL == list) return GNUNET_NO; - + i = 0; while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0)) { if ((add->s_addr & list[i].netmask.s_addr) == @@ -365,6 +381,7 @@ check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add) return GNUNET_NO; } + /** * Check if the given IP address is in the list of IP addresses. * @@ -379,13 +396,12 @@ check_ipv6_listed (const struct IPv6NetworkSet *list, const struct in6_addr *ip) unsigned int j; struct in6_addr zero; - if (list == NULL) + if (NULL == list) return GNUNET_NO; - memset (&zero, 0, sizeof (struct in6_addr)); i = 0; NEXT: - while (memcmp (&zero, &list[i].network, sizeof (struct in6_addr)) != 0) + while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr))) { for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != @@ -427,7 +443,7 @@ struct GNUNET_SERVICE_Context /** * Name of our service. */ - const char *serviceName; + const char *service_name; /** * Main service-specific task to run. @@ -478,6 +494,11 @@ struct GNUNET_SERVICE_Context struct GNUNET_NETWORK_Handle **lsocks; /** + * Task ID of the shutdown task. + */ + GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + + /** * Idle timeout for server. */ struct GNUNET_TIME_Relative timeout; @@ -526,6 +547,14 @@ struct GNUNET_SERVICE_Context /* ****************** message handlers ****************** */ +/** + * Send a 'TEST' message back to the client. + * + * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to + * @param size number of bytes available in 'buf' + * @param buf where to copy the message + * @return number of bytes written to 'buf' + */ static size_t write_test (void *cls, size_t size, void *buf) { @@ -544,6 +573,7 @@ write_test (void *cls, size_t size, void *buf) return sizeof (struct GNUNET_MessageHeader); } + /** * Handler for TEST message. * @@ -577,7 +607,6 @@ static const struct GNUNET_SERVER_MessageHandler defhandlers[] = { }; - /* ****************** service core routines ************** */ @@ -605,31 +634,32 @@ check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, case AF_INET: GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); i4 = (const struct sockaddr_in *) addr; - ret = ((sctx->v4_allowed == NULL) || + ret = ((NULL == sctx->v4_allowed) || (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) && - ((sctx->v4_denied == NULL) || + ((NULL == sctx->v4_denied) || (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr))); break; case AF_INET6: GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); i6 = (const struct sockaddr_in6 *) addr; - ret = ((sctx->v6_allowed == NULL) || + ret = ((NULL == sctx->v6_allowed) || (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) && - ((sctx->v6_denied == NULL) || + ((NULL == sctx->v6_denied) || (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); break; #ifndef WINDOWS case AF_UNIX: ret = GNUNET_OK; /* always OK for now */ - if (sctx->match_uid == GNUNET_YES) + if (GNUNET_YES == sctx->match_uid) { /* UID match required */ - ret = (uc != NULL) && (uc->uid == geteuid ()); + ret = (NULL != uc) && (uc->uid == geteuid ()); } - else if (sctx->match_gid == GNUNET_YES) + else if ( (GNUNET_YES == sctx->match_gid) && + ( (NULL == uc) || (uc->uid != geteuid ()) ) ) { - /* group match required */ - if (uc == NULL) + /* group match required and UID does not match */ + if (NULL == uc) { /* no credentials, group match not possible */ ret = GNUNET_NO; @@ -666,7 +696,7 @@ check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, } if (GNUNET_NO == ret) LOG (GNUNET_ERROR_TYPE_WARNING, _("Access denied to UID %d / GID %d\n"), - (uc == NULL) ? -1 : uc->uid, (uc == NULL) ? -1 : uc->gid); + (NULL == uc) ? -1 : uc->uid, (NULL == uc) ? -1 : uc->gid); break; #endif default: @@ -674,12 +704,12 @@ check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, addr->sa_family); return GNUNET_SYSERR; } - if (ret != GNUNET_OK) + if (GNUNET_OK != ret) { LOG (GNUNET_ERROR_TYPE_WARNING, - _("Access from `%s' denied to service `%s'\n"), GNUNET_a2s (addr, - addrlen), - sctx->serviceName); + _("Access from `%s' denied to service `%s'\n"), + GNUNET_a2s (addr, addrlen), + sctx->service_name); } return ret; } @@ -688,15 +718,17 @@ check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, /** * Get the name of the file where we will * write the PID of the service. + * + * @param sctx service context + * @return name of the file for the process ID */ static char * get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) { - char *pif; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->serviceName, + GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, "PIDFILE", &pif)) return NULL; return pif; @@ -705,6 +737,12 @@ get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) /** * Parse an IPv4 access control list. + * + * @param ret location where to write the ACL (set) + * @param sctx service context to use to get the configuration + * @param option name of the ACL option to parse + * @return GNUNET_SYSERR on parse error, GNUNET_OK on success (including + * no ACL configured) */ static int process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, @@ -712,17 +750,20 @@ process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, { char *opt; - if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option)) + if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) + { + *ret = NULL; return GNUNET_OK; + } GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg, - sctx->serviceName, + sctx->service_name, option, &opt)); if (NULL == (*ret = parse_ipv4_specification (opt))) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), - opt, sctx->serviceName, option); + opt, sctx->service_name, option); GNUNET_free (opt); return GNUNET_SYSERR; } @@ -732,7 +773,13 @@ process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, /** - * Parse an IPv4 access control list. + * Parse an IPv6 access control list. + * + * @param ret location where to write the ACL (set) + * @param sctx service context to use to get the configuration + * @param option name of the ACL option to parse + * @return GNUNET_SYSERR on parse error, GNUNET_OK on success (including + * no ACL configured) */ static int process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, @@ -740,17 +787,20 @@ process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, { char *opt; - if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option)) + if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) + { + *ret = NULL; return GNUNET_OK; + } GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg, - sctx->serviceName, + sctx->service_name, option, &opt)); if (NULL == (*ret = parse_ipv6_specification (opt))) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), - opt, sctx->serviceName, option); + opt, sctx->service_name, option); GNUNET_free (opt); return GNUNET_SYSERR; } @@ -758,6 +808,7 @@ process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, return GNUNET_OK; } + /** * Add the given UNIX domain path as an address to the * list (as the first entry). @@ -802,7 +853,7 @@ add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens, * Get the list of addresses that a server for the given service * should bind to. * - * @param serviceName name of the service + * @param service_name name of the service * @param cfg configuration (which specifies the addresses) * @param addrs set (call by reference) to an array of pointers to the * addresses the server should bind to and listen on; the @@ -819,7 +870,7 @@ add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens, * set to NULL). */ int -GNUNET_SERVICE_get_server_addresses (const char *serviceName, +GNUNET_SERVICE_get_server_addresses (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t ** addr_lens) @@ -842,11 +893,11 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, *addrs = NULL; *addr_lens = NULL; desc = NULL; - if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "DISABLEV6")) + if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) { if (GNUNET_SYSERR == (disablev6 = - GNUNET_CONFIGURATION_get_value_yesno (cfg, serviceName, "DISABLEV6"))) + GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6"))) return GNUNET_SYSERR; } else @@ -858,8 +909,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); if (NULL == desc) { - if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || - (errno == EACCES)) + if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || + (EACCES == errno)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); return GNUNET_SYSERR; @@ -867,7 +918,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, LOG (GNUNET_ERROR_TYPE_INFO, _ ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), - serviceName, STRERROR (errno)); + service_name, STRERROR (errno)); disablev6 = GNUNET_YES; } else @@ -878,24 +929,24 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, } port = 0; - if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT")) + if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) { GNUNET_break (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_number (cfg, serviceName, + GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)); if (port > 65535) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Require valid port number for service `%s' in configuration!\n"), - serviceName); + service_name); return GNUNET_SYSERR; } } - if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO")) + if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) { GNUNET_break (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, + GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "BINDTO", &hostname)); } else @@ -904,9 +955,9 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, unixpath = NULL; #ifdef AF_UNIX if ((GNUNET_YES == - GNUNET_CONFIGURATION_have_value (cfg, serviceName, "UNIXPATH")) && + GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, "UNIXPATH", + GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) { @@ -926,8 +977,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); if (NULL == desc) { - if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || - (errno == EACCES)) + if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || + (EACCES == errno)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); GNUNET_free_non_null (hostname); @@ -937,7 +988,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, LOG (GNUNET_ERROR_TYPE_INFO, _ ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), - serviceName, STRERROR (errno)); + service_name, STRERROR (errno)); GNUNET_free (unixpath); unixpath = NULL; } @@ -949,16 +1000,16 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, } #endif - if ((port == 0) && (unixpath == NULL)) + if ((0 == port) && (NULL == unixpath)) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), - serviceName); + service_name); GNUNET_free_non_null (hostname); return GNUNET_SYSERR; } - if (port == 0) + if (0 == port) { saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); @@ -970,16 +1021,15 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, return 1; } - if (hostname != NULL) + if (NULL != hostname) { -#if DEBUG_SERVICE LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving `%s' since that is where `%s' will bind to.\n", hostname, - serviceName); -#endif + service_name); memset (&hints, 0, sizeof (struct addrinfo)); if (disablev6) hints.ai_family = AF_INET; + hints.ai_protocol = IPPROTO_TCP; if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || (res == NULL)) { @@ -1022,19 +1072,17 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, while (NULL != (pos = next)) { next = pos->ai_next; - if ((disablev6) && (pos->ai_family == AF_INET6)) + if ((disablev6) && (AF_INET6 == pos->ai_family)) continue; - if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0)) + if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) continue; /* not TCP */ - if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0)) + if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) continue; /* huh? */ -#if DEBUG_SERVICE LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", - serviceName, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); -#endif - if (pos->ai_family == AF_INET) + service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); + if (AF_INET == pos->ai_family) { - GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in)); + GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); @@ -1042,8 +1090,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, } else { - GNUNET_assert (pos->ai_family == AF_INET6); - GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6)); + GNUNET_assert (AF_INET6 == pos->ai_family); + GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); @@ -1120,6 +1168,9 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName, #ifdef MINGW /** + * Read listen sockets from the parent process (ARM). + * + * @param sctx service context to initialize * @return GNUNET_YES if ok, GNUNET_NO if not ok (must bind yourself), * and GNUNET_SYSERR on error. */ @@ -1128,22 +1179,20 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) { const char *env_buf; int fail; - uint64_t count, i; + uint64_t count; + uint64_t i; HANDLE lsocks_pipe; env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); - if ((env_buf == NULL) || (strlen (env_buf) <= 0)) - { + if ((NULL == env_buf) || (strlen (env_buf) <= 0)) return GNUNET_NO; - } /* Using W32 API directly here, because this pipe will * never be used outside of this function, and it's just too much of a bother * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) */ lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10); - if (lsocks_pipe == 0 || lsocks_pipe == INVALID_HANDLE_VALUE) + if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe)) return GNUNET_NO; - fail = 1; do { @@ -1152,7 +1201,7 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) DWORD rd; ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL); - if (ret == 0 || rd != sizeof (count) || count == 0) + if ((0 == ret) || (sizeof (count) != rd) || (0 == count)) break; sctx->lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1)); @@ -1163,15 +1212,16 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) WSAPROTOCOL_INFOA pi; uint64_t size; SOCKET s; + ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL); - if (ret == 0 || rd != sizeof (size) || size != sizeof (pi)) + if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) ) break; ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL); - if (ret == 0 || rd != sizeof (pi)) + if ( (0 == ret) || (sizeof (pi) != rd)) break; s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s); - if (sctx->lsocks[i] == NULL) + if (NULL == sctx->lsocks[i]) break; else if (i == count - 1) fail2 = 0; @@ -1189,13 +1239,12 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not access a pre-bound socket, will try to bind myself\n")); - for (i = 0; i < count && sctx->lsocks[i] != NULL; i++) + for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++) GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i])); GNUNET_free_non_null (sctx->lsocks); sctx->lsocks = NULL; return GNUNET_NO; } - return GNUNET_YES; } #endif @@ -1216,6 +1265,7 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) * + * @param sctx service context to initialize * @return GNUNET_OK if configuration succeeded */ static int @@ -1232,15 +1282,15 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) int flags; #endif - if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, "TIMEOUT")) + if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT")) { if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->serviceName, + GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name, "TIMEOUT", &idleout)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Specified value for `%s' of service `%s' is invalid\n"), - "TIMEOUT", sctx->serviceName); + "TIMEOUT", sctx->service_name); return GNUNET_SYSERR; } sctx->timeout = idleout; @@ -1249,16 +1299,16 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; if (GNUNET_CONFIGURATION_have_value - (sctx->cfg, sctx->serviceName, "TOLERANT")) + (sctx->cfg, sctx->service_name, "TOLERANT")) { if (GNUNET_SYSERR == (tolerant = - GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName, + GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "TOLERANT"))) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Specified value for `%s' of service `%s' is invalid\n"), - "TOLERANT", sctx->serviceName); + "TOLERANT", sctx->service_name); return GNUNET_SYSERR; } } @@ -1268,9 +1318,9 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) #ifndef MINGW errno = 0; if ((NULL != (lpid = getenv ("LISTEN_PID"))) && - (1 == sscanf (lpid, "%u", &pid)) && (getpid () == (pid_t) pid) && + (1 == SSCANF (lpid, "%u", &pid)) && (getpid () == (pid_t) pid) && (NULL != (nfds = getenv ("LISTEN_FDS"))) && - (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && + (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE)) { sctx->lsocks = @@ -1305,17 +1355,17 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) } #endif - if ((sctx->lsocks == NULL) && + if ((NULL == sctx->lsocks) && (GNUNET_SYSERR == - GNUNET_SERVICE_get_server_addresses (sctx->serviceName, sctx->cfg, + GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg, &sctx->addrs, &sctx->addrlens))) return GNUNET_SYSERR; sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; sctx->match_uid = - GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName, + GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "UNIX_MATCH_UID"); sctx->match_gid = - GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName, + GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "UNIX_MATCH_GID"); process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); @@ -1329,15 +1379,17 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) /** * Get the name of the user that'll be used * to provide the service. + * + * @param sctx service context + * @return value of the 'USERNAME' option */ static char * get_user_name (struct GNUNET_SERVICE_Context *sctx) { - char *un; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->serviceName, + GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, "USERNAME", &un)) return NULL; return un; @@ -1345,6 +1397,10 @@ get_user_name (struct GNUNET_SERVICE_Context *sctx) /** * Write PID file. + * + * @param sctx service context + * @param pid PID to write (should be equal to 'getpid()' + * @return GNUNET_OK on success (including no work to be done) */ static int write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) @@ -1368,7 +1424,7 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) /* we get to create a directory -- and claim it * as ours! */ GNUNET_DISK_directory_create (rdir); - if ((user != NULL) && (0 < strlen (user))) + if ((NULL != user) && (0 < strlen (user))) GNUNET_DISK_file_change_owner (rdir, user); } if (0 != ACCESS (rdir, W_OK | X_OK)) @@ -1381,7 +1437,7 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) } GNUNET_free (rdir); pidfd = FOPEN (pif, "w"); - if (pidfd == NULL) + if (NULL == pidfd) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif); GNUNET_free (pif); @@ -1391,7 +1447,7 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) if (0 > FPRINTF (pidfd, "%u", pid)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif); GNUNET_break (0 == FCLOSE (pidfd)); - if ((user != NULL) && (0 < strlen (user))) + if ((NULL != user) && (0 < strlen (user))) GNUNET_DISK_file_change_owner (pif, user); GNUNET_free_non_null (user); GNUNET_free (pif); @@ -1400,22 +1456,30 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) /** - * Task run during shutdown. + * Task run during shutdown. Stops the server/service. * - * @param cls unused + * @param cls the 'struct GNUNET_SERVICE_Context' * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_SERVER_Handle *server = cls; + struct GNUNET_SERVICE_Context *service = cls; + struct GNUNET_SERVER_Handle *server = service->server; - GNUNET_SERVER_destroy (server); + service->shutdown_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN)) + GNUNET_SERVER_stop_listening (server); + else + GNUNET_SERVER_destroy (server); } /** * Initial task for the service. + * + * @param cls service context + * @param tc unused */ static void service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) @@ -1424,7 +1488,7 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) unsigned int i; GNUNET_RESOLVER_connect (sctx->cfg); - if (sctx->lsocks != NULL) + if (NULL != sctx->lsocks) sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, sctx->timeout, sctx->require_found); @@ -1432,15 +1496,15 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) sctx->server = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, sctx->timeout, sctx->require_found); - if (sctx->server == NULL) + if (NULL == sctx->server) { - if (sctx->addrs != NULL) + if (NULL != sctx->addrs) { i = 0; - while (sctx->addrs[i] != NULL) + while (NULL != sctx->addrs[i]) { LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to start `%s' at `%s'\n"), - sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); + sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); i++; } } @@ -1451,29 +1515,29 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { /* install a task that will kill the server * process if the scheduler ever gets a shutdown signal */ - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, - sctx->server); + sctx->shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + sctx); } sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); i = 0; - while ((sctx->my_handlers[i].callback != NULL)) + while (NULL != sctx->my_handlers[i].callback) sctx->my_handlers[i++].callback_cls = sctx; GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); - if (sctx->ready_confirm_fd != -1) + if (-1 != sctx->ready_confirm_fd) { GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1)); GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd)); sctx->ready_confirm_fd = -1; write_pid_file (sctx, getpid ()); } - if (sctx->addrs != NULL) + if (NULL != sctx->addrs) { i = 0; - while (sctx->addrs[i] != NULL) + while (NULL != sctx->addrs[i]) { LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"), - sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); + sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); i++; } } @@ -1483,6 +1547,9 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) /** * Detach from terminal. + * + * @param sctx service context + * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int detach_terminal (struct GNUNET_SERVICE_Context *sctx) @@ -1503,7 +1570,7 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); return GNUNET_SYSERR; } - if (pid != 0) + if (0 != pid) { /* Parent */ char c; @@ -1547,7 +1614,7 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) (void) CLOSE (nullfd); /* Detach from controlling terminal */ pid = setsid (); - if (pid == -1) + if (-1 == pid) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid"); sctx->ready_confirm_fd = filedes[1]; #else @@ -1561,6 +1628,9 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) /** * Set user ID. + * + * @param sctx service context + * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int set_user_id (struct GNUNET_SERVICE_Context *sctx) @@ -1574,7 +1644,7 @@ set_user_id (struct GNUNET_SERVICE_Context *sctx) errno = 0; pws = getpwnam (user); - if (pws == NULL) + if (NULL == pws) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot obtain information about user `%s': %s\n"), user, @@ -1605,13 +1675,15 @@ set_user_id (struct GNUNET_SERVICE_Context *sctx) /** * Delete the PID file that was created by our parent. + * + * @param sctx service context */ static void pid_file_delete (struct GNUNET_SERVICE_Context *sctx) { char *pif = get_pid_file_name (sctx); - if (pif == NULL) + if (NULL == pif) return; /* no PID file */ if (0 != UNLINK (pif)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif); @@ -1625,16 +1697,16 @@ pid_file_delete (struct GNUNET_SERVICE_Context *sctx) * * @param argc number of command line arguments * @param argv command line arguments - * @param serviceName our service name - * @param opt service options + * @param service_name our service name + * @param options service options * @param task main task of the service * @param task_cls closure for task * @return GNUNET_SYSERR on error, GNUNET_OK * if we shutdown nicely */ int -GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName, - enum GNUNET_SERVICE_Options opt, GNUNET_SERVICE_Main task, +GNUNET_SERVICE_run (int argc, char *const *argv, const char *service_name, + enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_Main task, void *task_cls) { #define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0) @@ -1656,7 +1728,7 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName, {'d', "daemonize", NULL, gettext_noop ("do daemonize (detach from terminal)"), 0, GNUNET_GETOPT_set_one, &do_daemonize}, - GNUNET_GETOPT_OPTION_HELP (serviceName), + GNUNET_GETOPT_OPTION_HELP (NULL), GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), GNUNET_GETOPT_OPTION_LOGFILE (&logfile), GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION), @@ -1668,32 +1740,30 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName, loglev = NULL; cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); memset (&sctx, 0, sizeof (sctx)); - sctx.options = opt; + sctx.options = options; sctx.ready_confirm_fd = -1; sctx.ret = GNUNET_OK; sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; sctx.task = task; sctx.task_cls = task_cls; - sctx.serviceName = serviceName; + sctx.service_name = service_name; sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); /* setup subsystems */ if (GNUNET_SYSERR == - GNUNET_GETOPT_run (serviceName, service_options, argc, argv)) + GNUNET_GETOPT_run (service_name, service_options, argc, argv)) goto shutdown; - if (GNUNET_OK != GNUNET_log_setup (serviceName, loglev, logfile)) + if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile)) HANDLE_ERROR; if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_fn)) goto shutdown; if (GNUNET_OK != setup_service (&sctx)) goto shutdown; - if ((do_daemonize == 1) && (GNUNET_OK != detach_terminal (&sctx))) + if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx))) HANDLE_ERROR; if (GNUNET_OK != set_user_id (&sctx)) goto shutdown; -#if DEBUG_SERVICE LOG (GNUNET_ERROR_TYPE_DEBUG, - "Service `%s' runs with configuration from `%s'\n", serviceName, cfg_fn); -#endif + "Service `%s' runs with configuration from `%s'\n", service_name, cfg_fn); if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", "SKEW_OFFSET", &skew_offset)) && @@ -1703,31 +1773,30 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName, { clock_offset = skew_offset - skew_variance; GNUNET_TIME_set_offset (clock_offset); -#if DEBUG_SERVICE LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset); -#endif } /* actually run service */ err = 0; GNUNET_SCHEDULER_run (&service_task, &sctx); - + GNUNET_SPEEDUP_start_ (cfg); /* shutdown */ - if ((do_daemonize == 1) && (sctx.server != NULL)) + if ((1 == do_daemonize) && (NULL != sctx.server)) pid_file_delete (&sctx); GNUNET_free_non_null (sctx.my_handlers); shutdown: - if (sctx.ready_confirm_fd != -1) + if (-1 != sctx.ready_confirm_fd) { if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1)) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd)); } + GNUNET_SPEEDUP_stop_ (); GNUNET_CONFIGURATION_destroy (cfg); i = 0; - if (sctx.addrs != NULL) - while (sctx.addrs[i] != NULL) + if (NULL != sctx.addrs) + while (NULL != sctx.addrs[i]) GNUNET_free (sctx.addrs[i++]); GNUNET_free_non_null (sctx.addrs); GNUNET_free_non_null (sctx.addrlens); @@ -1747,13 +1816,15 @@ shutdown: * Run a service startup sequence within an existing * initialized system. * - * @param serviceName our service name + * @param service_name our service name * @param cfg configuration to use + * @param options service options * @return NULL on error, service handle */ struct GNUNET_SERVICE_Context * -GNUNET_SERVICE_start (const char *serviceName, - const struct GNUNET_CONFIGURATION_Handle *cfg) +GNUNET_SERVICE_start (const char *service_name, + const struct GNUNET_CONFIGURATION_Handle *cfg, + enum GNUNET_SERVICE_Options options) { int i; struct GNUNET_SERVICE_Context *sctx; @@ -1762,8 +1833,9 @@ GNUNET_SERVICE_start (const char *serviceName, sctx->ready_confirm_fd = -1; /* no daemonizing */ sctx->ret = GNUNET_OK; sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - sctx->serviceName = serviceName; + sctx->service_name = service_name; sctx->cfg = cfg; + sctx->options = options; /* setup subsystems */ if (GNUNET_OK != setup_service (sctx)) @@ -1771,7 +1843,7 @@ GNUNET_SERVICE_start (const char *serviceName, GNUNET_SERVICE_stop (sctx); return NULL; } - if (sctx->lsocks != NULL) + if (NULL != sctx->lsocks) sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, sctx->timeout, sctx->require_found); @@ -1794,6 +1866,7 @@ GNUNET_SERVICE_start (const char *serviceName, return sctx; } + /** * Obtain the server used by a service. Note that the server must NOT * be destroyed by the caller. @@ -1818,13 +1891,18 @@ GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx) { unsigned int i; + if (GNUNET_SCHEDULER_NO_TASK != sctx->shutdown_task) + { + GNUNET_SCHEDULER_cancel (sctx->shutdown_task); + sctx->shutdown_task = GNUNET_SCHEDULER_NO_TASK; + } if (NULL != sctx->server) GNUNET_SERVER_destroy (sctx->server); GNUNET_free_non_null (sctx->my_handlers); - if (sctx->addrs != NULL) + if (NULL != sctx->addrs) { i = 0; - while (sctx->addrs[i] != NULL) + while (NULL != sctx->addrs[i]) GNUNET_free (sctx->addrs[i++]); GNUNET_free (sctx->addrs); } diff --git a/src/util/speedup.c b/src/util/speedup.c new file mode 100644 index 0000000..0a005c0 --- /dev/null +++ b/src/util/speedup.c @@ -0,0 +1,92 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2006, 2009 Christian Grothoff (and other contributing authors) + + 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 2, 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/speedup.c + * @author Matthias Wachs + * @brief functions to speedup peer execution by manipulation system time + */ +#include "platform.h" +#include "gnunet_time_lib.h" +#include "gnunet_scheduler_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + + +static struct GNUNET_TIME_Relative interval; + +static struct GNUNET_TIME_Relative delta; + +static GNUNET_SCHEDULER_TaskIdentifier speedup_task; + + +static void +do_speedup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static long long current_offset; + + speedup_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + current_offset += delta.rel_value; + GNUNET_TIME_set_offset (current_offset); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Speeding up execution time by %llu ms\n", delta.rel_value); + speedup_task = GNUNET_SCHEDULER_add_delayed (interval, &do_speedup, NULL); +} + + +int +GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SPEEDUP_INTERVAL", &interval)) + return GNUNET_SYSERR; + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SPEEDUP_DELTA", &delta)) + return GNUNET_SYSERR; + + if ((0 == interval.rel_value) || (0 == delta.rel_value)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Speed up disabled\n"); + return GNUNET_OK; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Speed up execution time %llu ms every %llu ms\n", + delta.rel_value, interval.rel_value); + speedup_task = GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, &do_speedup, NULL); + return GNUNET_OK; +} + + +void +GNUNET_SPEEDUP_stop_ ( ) +{ + if (GNUNET_SCHEDULER_NO_TASK != speedup_task) + { + GNUNET_SCHEDULER_cancel (speedup_task); + speedup_task = GNUNET_SCHEDULER_NO_TASK; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Stopped execution speed up\n"); +} + + + +/* end of speedup.c */ diff --git a/src/util/strings.c b/src/util/strings.c index 8000a93..11134f1 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -31,6 +31,7 @@ #endif #include "gnunet_common.h" #include "gnunet_strings_lib.h" +#include <unicase.h> #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) @@ -170,51 +171,38 @@ GNUNET_STRINGS_byte_size_fancy (unsigned long long size) /** - * Convert a given fancy human-readable size to bytes. + * Unit conversion table entry for 'convert_with_table'. + */ +struct ConversionTable +{ + /** + * Name of the unit (or NULL for end of table). + */ + const char *name; + + /** + * Factor to apply for this unit. + */ + unsigned long long value; +}; + + +/** + * Convert a string of the form "4 X 5 Y" into a numeric value + * by interpreting "X" and "Y" as units and then multiplying + * the numbers with the values associated with the respective + * unit from the conversion table. * - * @param fancy_size human readable string (i.e. 1 MB) - * @param size set to the size in bytes + * @param input input string to parse + * @param table table with the conversion of unit names to numbers + * @param output where to store the result * @return GNUNET_OK on success, GNUNET_SYSERR on error */ -int -GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, - unsigned long long *size) +static int +convert_with_table (const char *input, + const struct ConversionTable *table, + unsigned long long *output) { - struct - { - const char *name; - unsigned long long value; - } table[] = - { - { - "B", 1}, - { - "KiB", 1024}, - { - "kB", 1000}, - { - "MiB", 1024 * 1024}, - { - "MB", 1000 * 1000}, - { - "GiB", 1024 * 1024 * 1024}, - { - "GB", 1000 * 1000 * 1000}, - { - "TiB", 1024LL * 1024LL * 1024LL * 1024LL}, - { - "TB", 1000LL * 1000LL * 1000LL * 1024LL}, - { - "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, - { - "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL}, - { - "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, - { - "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL}, - { - NULL, 0} - }; unsigned long long ret; char *in; const char *tok; @@ -223,7 +211,7 @@ GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, ret = 0; last = 0; - in = GNUNET_strdup (fancy_size); + in = GNUNET_strdup (input); for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " ")) { i = 0; @@ -235,7 +223,7 @@ GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, { ret += last; last = 0; - if (1 != sscanf (tok, "%llu", &last)) + if (1 != SSCANF (tok, "%llu", &last)) { GNUNET_free (in); return GNUNET_SYSERR; /* expected number */ @@ -243,88 +231,80 @@ GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, } } ret += last; - *size = ret; + *output = ret; GNUNET_free (in); return GNUNET_OK; } /** + * Convert a given fancy human-readable size to bytes. + * + * @param fancy_size human readable string (i.e. 1 MB) + * @param size set to the size in bytes + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, + unsigned long long *size) +{ + static const struct ConversionTable table[] = + { + { "B", 1}, + { "KiB", 1024}, + { "kB", 1000}, + { "MiB", 1024 * 1024}, + { "MB", 1000 * 1000}, + { "GiB", 1024 * 1024 * 1024}, + { "GB", 1000 * 1000 * 1000}, + { "TiB", 1024LL * 1024LL * 1024LL * 1024LL}, + { "TB", 1000LL * 1000LL * 1000LL * 1024LL}, + { "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, + { "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL}, + { "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, + { "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL}, + { NULL, 0} + }; + + return convert_with_table (fancy_size, + table, + size); +} + + +/** * Convert a given fancy human-readable time to our internal * representation. * - * @param fancy_size human readable string (i.e. 1 minute) + * @param fancy_time human readable string (i.e. 1 minute) * @param rtime set to the relative time * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int -GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_size, +GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time, struct GNUNET_TIME_Relative *rtime) { - struct - { - const char *name; - unsigned long long value; - } table[] = + static const struct ConversionTable table[] = { - { - "ms", 1}, - { - "s", 1000}, - { - "\"", 1000}, - { - "min", 60 * 1000}, - { - "minutes", 60 * 1000}, - { - "'", 60 * 1000}, - { - "h", 60 * 60 * 1000}, - { - "d", 24 * 60 * 60 * 1000}, - { - "a", 31557600 /* year */ }, - { - NULL, 0} + { "ms", 1}, + { "s", 1000}, + { "\"", 1000}, + { "min", 60 * 1000}, + { "minutes", 60 * 1000}, + { "'", 60 * 1000}, + { "h", 60 * 60 * 1000}, + { "d", 24 * 60 * 60 * 1000}, + { "a", 31536000000LL /* year */ }, + { NULL, 0} }; - unsigned long long ret; - char *in; - const char *tok; - unsigned long long last; - unsigned int i; + int ret; + unsigned long long val; - if ((0 == strcasecmp (fancy_size, "infinity")) || - (0 == strcasecmp (fancy_size, "forever"))) - { - *rtime = GNUNET_TIME_UNIT_FOREVER_REL; - return GNUNET_OK; - } - ret = 0; - last = 0; - in = GNUNET_strdup (fancy_size); - for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " ")) - { - i = 0; - while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok))) - i++; - if (table[i].name != NULL) - last *= table[i].value; - else - { - ret += last; - last = 0; - if (1 != sscanf (tok, "%llu", &last)) - { - GNUNET_free (in); - return GNUNET_SYSERR; /* expected number */ - } - } - } - ret += last; - rtime->rel_value = (uint64_t) ret; - GNUNET_free (in); - return GNUNET_OK; + ret = convert_with_table (fancy_time, + table, + &val); + rtime->rel_value = (uint64_t) val; + return ret; } /** @@ -422,6 +402,45 @@ GNUNET_STRINGS_from_utf8 (const char *input, size_t len, const char *charset) return GNUNET_STRINGS_conv (input, len, "UTF-8", charset); } +/** + * Convert the utf-8 input string to lowercase + * Output needs to be allocated appropriately + * + * @param input input string + * @param output output buffer + */ +void +GNUNET_STRINGS_utf8_tolower(const char* input, char** output) +{ + uint8_t *tmp_in; + size_t len; + + tmp_in = u8_tolower ((uint8_t*)input, strlen ((char *) input), + NULL, UNINORM_NFD, NULL, &len); + memcpy(*output, tmp_in, len); + (*output)[len] = '\0'; + free(tmp_in); +} + +/** + * Convert the utf-8 input string to uppercase + * Output needs to be allocated appropriately + * + * @param input input string + * @param output output buffer + */ +void +GNUNET_STRINGS_utf8_toupper(const char* input, char** output) +{ + uint8_t *tmp_in; + size_t len; + + tmp_in = u8_toupper ((uint8_t*)input, strlen ((char *) input), + NULL, UNINORM_NFD, NULL, &len); + memcpy(*output, tmp_in, len); + (*output)[len] = '\0'; + free(tmp_in); +} /** @@ -630,4 +649,468 @@ GNUNET_STRINGS_get_short_name (const char *filename) return short_fn; } + +/** + * Get the numeric value corresponding to a character. + * + * @param a a character + * @return corresponding numeric value + */ +static unsigned int +getValue__ (unsigned char a) +{ + if ((a >= '0') && (a <= '9')) + return a - '0'; + if ((a >= 'A') && (a <= 'V')) + return (a - 'A' + 10); + return -1; +} + + +/** + * Convert binary data to ASCII encoding. The ASCII encoding is rather + * GNUnet specific. It was chosen such that it only uses characters + * in [0-9A-V], can be produced without complex arithmetics and uses a + * small number of characters. + * Does not append 0-terminator, but returns a pointer to the place where + * it should be placed, if needed. + * + * @param data data to encode + * @param size size of data (in bytes) + * @param out buffer to fill + * @param out_size size of the buffer. Must be large enough to hold + * ((size*8) + (((size*8) % 5) > 0 ? 5 - ((size*8) % 5) : 0)) / 5 bytes + * @return pointer to the next byte in 'out' or NULL on error. + */ +char * +GNUNET_STRINGS_data_to_string (const unsigned char *data, size_t size, char *out, size_t out_size) +{ + /** + * 32 characters for encoding + */ + static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; + unsigned int wpos; + unsigned int rpos; + unsigned int bits; + unsigned int vbit; + + GNUNET_assert (data != NULL); + GNUNET_assert (out != NULL); + if (out_size < (((size*8) + ((size*8) % 5)) % 5)) + { + GNUNET_break (0); + return NULL; + } + vbit = 0; + wpos = 0; + rpos = 0; + bits = 0; + while ((rpos < size) || (vbit > 0)) + { + if ((rpos < size) && (vbit < 5)) + { + bits = (bits << 8) | data[rpos++]; /* eat 8 more bits */ + vbit += 8; + } + if (vbit < 5) + { + bits <<= (5 - vbit); /* zero-padding */ + GNUNET_assert (vbit == ((size * 8) % 5)); + vbit = 5; + } + if (wpos >= out_size) + { + GNUNET_break (0); + return NULL; + } + out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; + vbit -= 5; + } + if (wpos != out_size) + { + GNUNET_break (0); + return NULL; + } + GNUNET_assert (vbit == 0); + return &out[wpos]; +} + + +/** + * Convert ASCII encoding back to data + * out_size must match exactly the size of the data before it was encoded. + * + * @param enc the encoding + * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) + * @param out location where to store the decoded data + * @param out_size sizeof the output buffer + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ +int +GNUNET_STRINGS_string_to_data (const char *enc, size_t enclen, + unsigned char *out, size_t out_size) +{ + unsigned int rpos; + unsigned int wpos; + unsigned int bits; + unsigned int vbit; + int ret; + int shift; + int encoded_len = out_size * 8; + if (encoded_len % 5 > 0) + { + vbit = encoded_len % 5; /* padding! */ + shift = 5 - vbit; + } + else + { + vbit = 0; + shift = 0; + } + if ((encoded_len + shift) / 5 != enclen) + return GNUNET_SYSERR; + + wpos = out_size; + rpos = enclen; + bits = (ret = getValue__ (enc[--rpos])) >> (5 - encoded_len % 5); + if (-1 == ret) + return GNUNET_SYSERR; + while (wpos > 0) + { + GNUNET_assert (rpos > 0); + bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; + if (-1 == ret) + return GNUNET_SYSERR; + vbit += 5; + if (vbit >= 8) + { + out[--wpos] = (unsigned char) bits; + bits >>= 8; + vbit -= 8; + } + } + GNUNET_assert (rpos == 0); + GNUNET_assert (vbit == 0); + return GNUNET_OK; +} + + +/** + * Parse a path that might be an URI. + * + * @param path path to parse. Must be NULL-terminated. + * @param scheme_part a pointer to 'char *' where a pointer to a string that + * represents the URI scheme will be stored. Can be NULL. The string is + * allocated by the function, and should be freed by GNUNET_free() when + * it is no longer needed. + * @param path_part a pointer to 'const char *' where a pointer to the path + * part of the URI will be stored. Can be NULL. Points to the same block + * of memory as 'path', and thus must not be freed. Might point to '\0', + * if path part is zero-length. + * @return GNUNET_YES if it's an URI, GNUNET_NO otherwise. If 'path' is not + * an URI, '* scheme_part' and '*path_part' will remain unchanged + * (if they weren't NULL). + */ +int +GNUNET_STRINGS_parse_uri (const char *path, char **scheme_part, + const char **path_part) +{ + size_t len; + int i, end; + int pp_state = 0; + const char *post_scheme_part = NULL; + len = strlen (path); + for (end = 0, i = 0; !end && i < len; i++) + { + switch (pp_state) + { + case 0: + if (path[i] == ':' && i > 0) + { + pp_state += 1; + continue; + } + if (!((path[i] >= 'A' && path[i] <= 'Z') || (path[i] >= 'a' && path[i] <= 'z') + || (path[i] >= '0' && path[i] <= '9') || path[i] == '+' || path[i] == '-' + || (path[i] == '.'))) + end = 1; + break; + case 1: + case 2: + if (path[i] == '/') + { + pp_state += 1; + continue; + } + end = 1; + break; + case 3: + post_scheme_part = &path[i]; + end = 1; + break; + default: + end = 1; + } + } + if (post_scheme_part == NULL) + return GNUNET_NO; + if (scheme_part) + { + *scheme_part = GNUNET_malloc (post_scheme_part - path + 1); + memcpy (*scheme_part, path, post_scheme_part - path); + (*scheme_part)[post_scheme_part - path] = '\0'; + } + if (path_part) + *path_part = post_scheme_part; + return GNUNET_YES; +} + + +/** + * Check whether 'filename' is absolute or not, and if it's an URI + * + * @param filename filename to check + * @param can_be_uri GNUNET_YES to check for being URI, GNUNET_NO - to + * assume it's not URI + * @param r_is_uri a pointer to an int that is set to GNUNET_YES if 'filename' + * is URI and to GNUNET_NO otherwise. Can be NULL. If 'can_be_uri' is + * not GNUNET_YES, *r_is_uri is set to GNUNET_NO. + * @param r_uri_scheme a pointer to a char * that is set to a pointer to URI scheme. + * The string is allocated by the function, and should be freed with + * GNUNET_free (). Can be NULL. + * @return GNUNET_YES if 'filename' is absolute, GNUNET_NO otherwise. + */ +int +GNUNET_STRINGS_path_is_absolute (const char *filename, int can_be_uri, + int *r_is_uri, char **r_uri_scheme) +{ +#if WINDOWS + size_t len; +#endif + const char *post_scheme_path; + int is_uri; + char * uri; + /* consider POSIX paths to be absolute too, even on W32, + * as plibc expansion will fix them for us. + */ + if (filename[0] == '/') + return GNUNET_YES; + if (can_be_uri) + { + is_uri = GNUNET_STRINGS_parse_uri (filename, &uri, &post_scheme_path); + if (r_is_uri) + *r_is_uri = is_uri; + if (is_uri) + { + if (r_uri_scheme) + *r_uri_scheme = uri; + else + GNUNET_free_non_null (uri); +#if WINDOWS + len = strlen(post_scheme_path); + /* Special check for file:///c:/blah + * We want to parse 'c:/', not '/c:/' + */ + if (post_scheme_path[0] == '/' && len >= 3 && post_scheme_path[2] == ':') + post_scheme_path = &post_scheme_path[1]; +#endif + return GNUNET_STRINGS_path_is_absolute (post_scheme_path, GNUNET_NO, NULL, NULL); + } + } + else + { + is_uri = GNUNET_NO; + if (r_is_uri) + *r_is_uri = GNUNET_NO; + } +#if WINDOWS + len = strlen (filename); + if (len >= 3 && + ((filename[0] >= 'A' && filename[0] <= 'Z') + || (filename[0] >= 'a' && filename[0] <= 'z')) + && filename[1] == ':' && (filename[2] == '/' || filename[2] == '\\')) + return GNUNET_YES; +#endif + return GNUNET_NO; +} + +#if MINGW +#define _IFMT 0170000 /* type of file */ +#define _IFLNK 0120000 /* symbolic link */ +#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) +#endif + + +/** + * Perform 'checks' on 'filename' + * + * @param filename file to check + * @param checks checks to perform + * @return GNUNET_YES if all checks pass, GNUNET_NO if at least one of them + * fails, GNUNET_SYSERR when a check can't be performed + */ +int +GNUNET_STRINGS_check_filename (const char *filename, + enum GNUNET_STRINGS_FilenameCheck checks) +{ + struct stat st; + if ( (NULL == filename) || (filename[0] == '\0') ) + return GNUNET_SYSERR; + if (0 != (checks & GNUNET_STRINGS_CHECK_IS_ABSOLUTE)) + if (!GNUNET_STRINGS_path_is_absolute (filename, GNUNET_NO, NULL, NULL)) + return GNUNET_NO; + if (0 != (checks & (GNUNET_STRINGS_CHECK_EXISTS + | GNUNET_STRINGS_CHECK_IS_DIRECTORY + | GNUNET_STRINGS_CHECK_IS_LINK))) + { + if (0 != STAT (filename, &st)) + { + if (0 != (checks & GNUNET_STRINGS_CHECK_EXISTS)) + return GNUNET_NO; + else + return GNUNET_SYSERR; + } + } + if (0 != (checks & GNUNET_STRINGS_CHECK_IS_DIRECTORY)) + if (!S_ISDIR (st.st_mode)) + return GNUNET_NO; + if (0 != (checks & GNUNET_STRINGS_CHECK_IS_LINK)) + if (!S_ISLNK (st.st_mode)) + return GNUNET_NO; + return GNUNET_YES; +} + + + +/** + * Tries to convert 'zt_addr' string to an IPv6 address. + * The string is expected to have the format "[ABCD::01]:80". + * + * @param zt_addr 0-terminated string. May be mangled by the function. + * @param addrlen length of zt_addr (not counting 0-terminator). + * @param r_buf a buffer to fill. Initially gets filled with zeroes, + * then its sin6_port, sin6_family and sin6_addr are set appropriately. + * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which + * case the contents of r_buf are undefined. + */ +int +GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr, + uint16_t addrlen, + struct sockaddr_in6 *r_buf) +{ + char zbuf[addrlen + 1]; + int ret; + char *port_colon; + unsigned int port; + + if (addrlen < 6) + return GNUNET_SYSERR; + memcpy (zbuf, zt_addr, addrlen); + if ('[' != zbuf[0]) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv6 address did not start with `['\n")); + return GNUNET_SYSERR; + } + zbuf[addrlen] = '\0'; + port_colon = strrchr (zbuf, ':'); + if (NULL == port_colon) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv6 address did contain ':' to separate port number\n")); + return GNUNET_SYSERR; + } + if (']' != *(port_colon - 1)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv6 address did contain ']' before ':' to separate port number\n")); + return GNUNET_SYSERR; + } + ret = SSCANF (port_colon, ":%u", &port); + if ( (1 != ret) || (port > 65535) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv6 address did contain a valid port number after the last ':'\n")); + return GNUNET_SYSERR; + } + *(port_colon-1) = '\0'; + memset (r_buf, 0, sizeof (struct sockaddr_in6)); + ret = inet_pton (AF_INET6, &zbuf[1], &r_buf->sin6_addr); + if (ret <= 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Invalid IPv6 address `%s': %s\n"), + &zbuf[1], + STRERROR (errno)); + return GNUNET_SYSERR; + } + r_buf->sin6_port = htons (port); + r_buf->sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + r_buf->sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + return GNUNET_OK; +} + + +/** + * Tries to convert 'zt_addr' string to an IPv4 address. + * The string is expected to have the format "1.2.3.4:80". + * + * @param zt_addr 0-terminated string. May be mangled by the function. + * @param addrlen length of zt_addr (not counting 0-terminator). + * @param r_buf a buffer to fill. + * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which case + * the contents of r_buf are undefined. + */ +int +GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen, + struct sockaddr_in *r_buf) +{ + unsigned int temps[4]; + unsigned int port; + unsigned int cnt; + + if (addrlen < 9) + return GNUNET_SYSERR; + cnt = SSCANF (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port); + if (5 != cnt) + return GNUNET_SYSERR; + for (cnt = 0; cnt < 4; cnt++) + if (temps[cnt] > 0xFF) + return GNUNET_SYSERR; + if (port > 65535) + return GNUNET_SYSERR; + r_buf->sin_family = AF_INET; + r_buf->sin_port = htons (port); + r_buf->sin_addr.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) + + (temps[2] << 8) + temps[3]); +#if HAVE_SOCKADDR_IN_SIN_LEN + r_buf->sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + return GNUNET_OK; +} + + +/** + * Tries to convert 'addr' string to an IP (v4 or v6) address. + * Will automatically decide whether to treat 'addr' as v4 or v6 address. + * + * @param addr a string, may not be 0-terminated. + * @param addrlen number of bytes in addr (if addr is 0-terminated, + * 0-terminator should not be counted towards addrlen). + * @param r_buf a buffer to fill. + * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which + * case the contents of r_buf are undefined. + */ +int +GNUNET_STRINGS_to_address_ip (const char *addr, + uint16_t addrlen, + struct sockaddr_storage *r_buf) +{ + if (addr[0] == '[') + return GNUNET_STRINGS_to_address_ipv6 (addr, addrlen, (struct sockaddr_in6 *) r_buf); + return GNUNET_STRINGS_to_address_ipv4 (addr, addrlen, (struct sockaddr_in *) r_buf); +} + /* end of strings.c */ diff --git a/src/util/test_client.c b/src/util/test_client.c index f9d961a..54881b2 100644 --- a/src/util/test_client.c +++ b/src/util/test_client.c @@ -109,7 +109,7 @@ recv_bounce (void *cls, const struct GNUNET_MessageHeader *got) msg.type = htons (MY_TYPE); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); GNUNET_assert (0 == memcmp (got, &msg, sizeof (struct GNUNET_MessageHeader))); - GNUNET_CLIENT_disconnect (client, GNUNET_YES); + GNUNET_CLIENT_disconnect (client); client = NULL; GNUNET_SERVER_destroy (server); server = NULL; @@ -137,6 +137,10 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct sockaddr *sap[2]; socklen_t slens[2]; + /* test that ill-configured client fails instantly */ + GNUNET_assert (NULL == GNUNET_CLIENT_connect ("invalid-service", cfg)); + + /* test IPC between client and server */ sap[0] = (struct sockaddr *) &sa; slens[0] = sizeof (sa); sap[1] = NULL; diff --git a/src/util/test_common_logging_runtime_loglevels.c b/src/util/test_common_logging_runtime_loglevels.c index cdf1f66..b914ae1 100644 --- a/src/util/test_common_logging_runtime_loglevels.c +++ b/src/util/test_common_logging_runtime_loglevels.c @@ -55,7 +55,7 @@ end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_OS_process_wait (proc); - GNUNET_OS_process_close (proc); + GNUNET_OS_process_destroy (proc); proc = NULL; GNUNET_DISK_pipe_close (pipe_stdout); if (ok == 1) diff --git a/src/util/test_configuration.c b/src/util/test_configuration.c index b1a446f..1242a5c 100644 --- a/src/util/test_configuration.c +++ b/src/util/test_configuration.c @@ -28,7 +28,6 @@ #include "gnunet_configuration_lib.h" #include "gnunet_disk_lib.h" -#define DEBUG GNUNET_EXTRA_LOGGING /* Test Configuration Diffs Options */ enum @@ -40,10 +39,8 @@ enum ADD_NEW_ENTRY, REMOVE_SECTION, REMOVE_ENTRY, - COMPARE -#if DEBUG - , PRINT -#endif + COMPARE, + PRINT }; static struct GNUNET_CONFIGURATION_Handle *cfg; diff --git a/src/util/test_connection.c b/src/util/test_connection.c index cb69f40..4568f8e 100644 --- a/src/util/test_connection.c +++ b/src/util/test_connection.c @@ -102,7 +102,8 @@ receive_check (void *cls, const void *buf, size_t available, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive closes accepted socket\n"); #endif *ok = 0; - GNUNET_CONNECTION_destroy (asock, GNUNET_YES); + GNUNET_CONNECTION_destroy (asock); + GNUNET_CONNECTION_destroy (csock); } } @@ -119,7 +120,7 @@ run_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys listen socket\n"); #endif - GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); + GNUNET_CONNECTION_destroy (lsock); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks to receive on accepted socket\n"); @@ -142,7 +143,6 @@ make_hello (void *cls, size_t size, void *buf) #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n"); #endif - GNUNET_CONNECTION_destroy (csock, GNUNET_YES); return 12; } diff --git a/src/util/test_connection_addressing.c b/src/util/test_connection_addressing.c index 2d08acc..ba7acae 100644 --- a/src/util/test_connection_addressing.c +++ b/src/util/test_connection_addressing.c @@ -99,7 +99,8 @@ receive_check (void *cls, const void *buf, size_t available, else { *ok = 0; - GNUNET_CONNECTION_destroy (asock, GNUNET_YES); + GNUNET_CONNECTION_destroy (csock); + GNUNET_CONNECTION_destroy (asock); } } @@ -128,7 +129,7 @@ run_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) expect.sin_addr.s_addr = htonl (INADDR_LOOPBACK); GNUNET_assert (0 == memcmp (&expect, v4, alen)); GNUNET_free (addr); - GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); + GNUNET_CONNECTION_destroy (lsock); GNUNET_CONNECTION_receive (asock, 1024, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, @@ -143,6 +144,7 @@ make_hello (void *cls, size_t size, void *buf) return 12; } + static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { @@ -167,7 +169,6 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_CONNECTION_notify_transmit_ready (csock, 12, GNUNET_TIME_UNIT_SECONDS, &make_hello, NULL)); - GNUNET_CONNECTION_destroy (csock, GNUNET_YES); GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept, cls); } diff --git a/src/util/test_connection_receive_cancel.c b/src/util/test_connection_receive_cancel.c index aa16724..93fcd5f 100644 --- a/src/util/test_connection_receive_cancel.c +++ b/src/util/test_connection_receive_cancel.c @@ -86,11 +86,10 @@ dead_receive (void *cls, const void *buf, size_t available, static void run_accept_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); GNUNET_assert (asock != NULL); GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); - GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); + GNUNET_CONNECTION_destroy (lsock); GNUNET_CONNECTION_receive (asock, 1024, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &dead_receive, cls); @@ -103,8 +102,8 @@ receive_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) int *ok = cls; GNUNET_CONNECTION_receive_cancel (asock); - GNUNET_CONNECTION_destroy (csock, GNUNET_YES); - GNUNET_CONNECTION_destroy (asock, GNUNET_YES); + GNUNET_CONNECTION_destroy (csock); + GNUNET_CONNECTION_destroy (asock); *ok = 0; } diff --git a/src/util/test_connection_timeout.c b/src/util/test_connection_timeout.c index 2338665..c0597b2 100644 --- a/src/util/test_connection_timeout.c +++ b/src/util/test_connection_timeout.c @@ -83,8 +83,8 @@ send_kilo (void *cls, size_t size, void *buf) #endif GNUNET_assert (buf == NULL); *ok = 0; - GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); - GNUNET_CONNECTION_destroy (csock, GNUNET_YES); + GNUNET_CONNECTION_destroy (lsock); + GNUNET_CONNECTION_destroy (csock); return 0; } #if VERBOSE diff --git a/src/util/test_connection_transmit_cancel.c b/src/util/test_connection_transmit_cancel.c index d81c32a..fec72d2 100644 --- a/src/util/test_connection_transmit_cancel.c +++ b/src/util/test_connection_transmit_cancel.c @@ -56,7 +56,7 @@ task_transmit_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) ¬_run, cls); GNUNET_assert (NULL != th); GNUNET_CONNECTION_notify_transmit_ready_cancel (th); - GNUNET_CONNECTION_destroy (csock, GNUNET_YES); + GNUNET_CONNECTION_destroy (csock); *ok = 0; } diff --git a/src/util/test_disk.c b/src/util/test_disk.c index 5462772..149cec0 100644 --- a/src/util/test_disk.c +++ b/src/util/test_disk.c @@ -97,7 +97,7 @@ testOpenClose () GNUNET_break (5 == GNUNET_DISK_file_write (fh, "Hello", 5)); GNUNET_DISK_file_close (fh); GNUNET_break (GNUNET_OK == - GNUNET_DISK_file_size (".testfile", &size, GNUNET_NO)); + GNUNET_DISK_file_size (".testfile", &size, GNUNET_NO, GNUNET_YES)); if (size != 5) return 1; GNUNET_break (0 == UNLINK (".testfile")); diff --git a/src/util/test_os_start_process.c b/src/util/test_os_start_process.c index 54638c1..0d14818 100644 --- a/src/util/test_os_start_process.c +++ b/src/util/test_os_start_process.c @@ -51,13 +51,12 @@ static GNUNET_SCHEDULER_TaskIdentifier die_task; static void end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_close (proc); + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc)); + GNUNET_OS_process_destroy (proc); proc = NULL; GNUNET_DISK_pipe_close (hello_pipe_stdout); GNUNET_DISK_pipe_close (hello_pipe_stdin); @@ -106,7 +105,7 @@ read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void -task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *fn; const struct GNUNET_DISK_FileHandle *stdout_read_handle; @@ -160,22 +159,79 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_read_handle, &read_call, (void *) stdout_read_handle); - } + /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int -check () +check_run () { ok = 1; - GNUNET_SCHEDULER_run (&task, &ok); + GNUNET_SCHEDULER_run (&run_task, &ok); return ok; } +/** + * Test killing via pipe. + */ +static int +check_kill () +{ + hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL)) + { + return 1; + } + proc = + GNUNET_OS_start_process (GNUNET_YES, hello_pipe_stdin, hello_pipe_stdout, "cat", + "gnunet-service-resolver", "-", NULL); + sleep (1); /* give process time to start and open pipe */ + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc)); + GNUNET_OS_process_destroy (proc); + proc = NULL; + GNUNET_DISK_pipe_close (hello_pipe_stdout); + GNUNET_DISK_pipe_close (hello_pipe_stdin); + return 0; +} + + +/** + * Test killing via pipe. + */ +static int +check_instant_kill () +{ + hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL)) + { + return 1; + } + proc = + GNUNET_OS_start_process (GNUNET_YES, hello_pipe_stdin, hello_pipe_stdout, "cat", + "gnunet-service-resolver", "-", NULL); + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc)); + GNUNET_OS_process_destroy (proc); + proc = NULL; + GNUNET_DISK_pipe_close (hello_pipe_stdout); + GNUNET_DISK_pipe_close (hello_pipe_stdin); + return 0; +} + + int main (int argc, char *argv[]) { @@ -188,7 +244,10 @@ main (int argc, char *argv[]) "WARNING", #endif NULL); - ret = check (); + ret = 0; + ret |= check_run (); + ret |= check_kill (); + ret |= check_instant_kill (); return ret; } diff --git a/src/util/test_pseudonym.c b/src/util/test_pseudonym.c index 20a3d3d..4ce8b38 100644 --- a/src/util/test_pseudonym.c +++ b/src/util/test_pseudonym.c @@ -39,6 +39,7 @@ static GNUNET_HashCode id1; static int iter (void *cls, const GNUNET_HashCode * pseudonym, + const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { int *ok = cls; @@ -54,6 +55,7 @@ iter (void *cls, const GNUNET_HashCode * pseudonym, static int noti_callback (void *cls, const GNUNET_HashCode * pseudonym, + const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { int *ret = cls; @@ -64,6 +66,7 @@ noti_callback (void *cls, const GNUNET_HashCode * pseudonym, static int fake_noti_callback (void *cls, const GNUNET_HashCode * pseudonym, + const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { int *ret = cls; @@ -74,6 +77,7 @@ fake_noti_callback (void *cls, const GNUNET_HashCode * pseudonym, static int false_callback (void *cls, const GNUNET_HashCode * pseudonym, + const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { return GNUNET_OK; @@ -95,7 +99,10 @@ main (int argc, char *argv[]) char *name1; char *name2; char *name3; + char *name1_unique; + char *name2_unique; char *noname; + int noname_is_a_dup; int notiCount, fakenotiCount; int count; static char m[1024 * 1024 * 10]; @@ -152,15 +159,21 @@ main (int argc, char *argv[]) strlen (m) + 1)); GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id3); GNUNET_PSEUDONYM_add (cfg, &id3, meta); - name3 = GNUNET_PSEUDONYM_id_to_name (cfg, &id3); - name2 = GNUNET_PSEUDONYM_id_to_name (cfg, &id2); + GNUNET_PSEUDONYM_get_info (cfg, &id3, NULL, NULL, &name3, NULL); + CHECK (name3 != NULL); + GNUNET_PSEUDONYM_get_info (cfg, &id2, NULL, NULL, &name2, NULL); CHECK (name2 != NULL); - name1 = GNUNET_PSEUDONYM_id_to_name (cfg, &id1); + GNUNET_PSEUDONYM_get_info (cfg, &id1, NULL, NULL, &name1, NULL); CHECK (name1 != NULL); - CHECK (0 != strcmp (name1, name2)); + CHECK (0 == strcmp (name1, name2)); + name1_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id1, name1, NULL); + name2_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id2, name2, NULL); + CHECK (0 != strcmp (name1_unique, name2_unique)); CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, "fake", &rid2)); - CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name2, &rid2)); - CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name1, &rid1)); + CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name2, &rid2)); + CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name1, &rid1)); + CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name2_unique, &rid2)); + CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name1_unique, &rid1)); CHECK (0 == memcmp (&id1, &rid1, sizeof (GNUNET_HashCode))); CHECK (0 == memcmp (&id2, &rid2, sizeof (GNUNET_HashCode))); @@ -168,14 +181,17 @@ main (int argc, char *argv[]) GNUNET_log_skip (1, GNUNET_NO); CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &fid, 0)); GNUNET_log_skip (0, GNUNET_YES); - noname = GNUNET_PSEUDONYM_id_to_name (cfg, &fid); + CHECK (GNUNET_OK == GNUNET_PSEUDONYM_get_info (cfg, &fid, NULL, NULL, &noname, &noname_is_a_dup)); CHECK (noname != NULL); + CHECK (noname_is_a_dup == GNUNET_YES); CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 0)); CHECK (5 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); CHECK (-5 == GNUNET_PSEUDONYM_rank (cfg, &id1, -10)); CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); GNUNET_free (name1); GNUNET_free (name2); + GNUNET_free (name1_unique); + GNUNET_free (name2_unique); GNUNET_free (name3); GNUNET_free (noname); /* END OF TEST CODE */ diff --git a/src/util/test_resolver_api.c b/src/util/test_resolver_api.c index 67d5f46..4a3a203 100644 --- a/src/util/test_resolver_api.c +++ b/src/util/test_resolver_api.c @@ -64,10 +64,8 @@ check_localhost_num (void *cls, const char *hostname) return; if (0 == strcmp (hostname, "127.0.0.1")) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct hostname `%s'.\n", hostname); -#endif (*ok) &= ~4; } else @@ -88,10 +86,8 @@ check_localhost (void *cls, const char *hostname) return; if (0 == strcmp (hostname, "localhost")) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct hostname `%s'.\n", hostname); -#endif (*ok) &= ~2; } else @@ -113,9 +109,7 @@ check_127 (void *cls, const struct sockaddr *sa, socklen_t salen) GNUNET_assert (sizeof (struct sockaddr_in) == salen); if (sai->sin_addr.s_addr == htonl (INADDR_LOOPBACK)) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct address.\n"); -#endif (*ok) &= ~1; } else @@ -142,10 +136,8 @@ check_local_fqdn (void *cls, const char *gnunet_fqdn) "gethostname"); return; } -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolving our FQDN `%s'\n"), hostname); -#endif host = gethostbyname (hostname); if (NULL == host) { @@ -180,18 +172,14 @@ check_rootserver_ip (void *cls, const struct sockaddr *sa, socklen_t salen) if (0 == strcmp (inet_ntoa (sai->sin_addr), ROOTSERVER_IP)) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct rootserver ip address.\n"); -#endif (*ok) &= ~1; } else { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received incorrect rootserver ip address.\n"); -#endif GNUNET_break (0); } } @@ -206,10 +194,8 @@ check_rootserver_name (void *cls, const char *hostname) if (0 == strcmp (hostname, ROOTSERVER_NAME)) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct rootserver hostname `%s'.\n", hostname); -#endif (*ok) &= ~2; } else @@ -270,10 +256,8 @@ run (void *cls, char *const *args, const char *cfgfile, count_ips++; if (count_ips > 1) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "IP received range for root name server, but a root name server has only 1 IP\n"); -#endif GNUNET_break (0); } @@ -286,11 +270,8 @@ run (void *cls, char *const *args, const char *cfgfile, "IP received and IP for root name server differ\n"); GNUNET_break (0); } -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_INFO, "System's own forward name resolution is working\n"); -#endif - /* Resolve the same using GNUNET */ GNUNET_RESOLVER_ip_get (ROOTSERVER_NAME, AF_INET, timeout, &check_rootserver_ip, cls); @@ -305,10 +286,8 @@ run (void *cls, char *const *args, const char *cfgfile, rootserver->h_name = ""; if (1 != inet_pton (AF_INET, ROOTSERVER_IP, &rootserver_addr)) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transform root name server IP address\n"); -#endif GNUNET_break (0); } @@ -326,19 +305,14 @@ run (void *cls, char *const *args, const char *cfgfile, { if (0 != strcmp (rootserver->h_name, ROOTSERVER_NAME)) { -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received hostname and hostname for root name server differ\n"); -#endif GNUNET_break (0); } } -#if DEBUG_RESOLVER GNUNET_log (GNUNET_ERROR_TYPE_INFO, "System's own reverse name resolution is working\n"); -#endif - /* Resolve the same using GNUNET */ memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; @@ -410,7 +384,7 @@ check () ok = 1; } GNUNET_OS_process_wait (proc); - GNUNET_OS_process_close (proc); + GNUNET_OS_process_destroy (proc); proc = NULL; if (ok != 0) FPRINTF (stderr, "Missed some resolutions: %u\n", ok); diff --git a/src/util/test_scheduler.c b/src/util/test_scheduler.c index 01982ee..9832ade 100644 --- a/src/util/test_scheduler.c +++ b/src/util/test_scheduler.c @@ -30,37 +30,25 @@ #define VERBOSE GNUNET_NO static void -task3 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +task2 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; - /* t4 should be ready (albeit with lower priority) */ + /* t3 should be ready (albeit with lower priority) */ GNUNET_assert (1 == GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_COUNT)); - GNUNET_assert (3 == *ok); - (*ok) = 4; -} - - -static void -task2 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - int *ok = cls; - GNUNET_assert (2 == *ok); (*ok) = 3; - /* t3 will go before t4: higher priority */ - GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, &task3, - cls); } + static void -task4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +task3 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; - GNUNET_assert (4 == *ok); - (*ok) = 5; + GNUNET_assert (3 == *ok); + (*ok) = 4; } struct GNUNET_DISK_PipeHandle *p; @@ -113,11 +101,11 @@ taskRd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void -task5 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +task4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; - GNUNET_assert (5 == *ok); + GNUNET_assert (4 == *ok); (*ok) = 6; p = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); GNUNET_assert (NULL != p); @@ -134,17 +122,13 @@ static void task1 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; - GNUNET_SCHEDULER_TaskIdentifier t2; - GNUNET_SCHEDULER_TaskIdentifier t4; GNUNET_assert (1 == *ok); (*ok) = 2; - /* t2 will go first -- prereq for all */ - t2 = GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK, &task2, cls); - /* t4 will go after t2 ('add after') and after t3 (priority) */ - t4 = GNUNET_SCHEDULER_add_after (t2, &task4, cls); - /* t5 will go last (after p4) */ - GNUNET_SCHEDULER_add_after (t4, &task5, cls); + GNUNET_SCHEDULER_add_now (&task3, cls); + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, &task2, + cls); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &task4, cls); } @@ -225,8 +209,8 @@ taskCancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_assert (1 == *ok); *ok = 0; - GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_add_after - (GNUNET_SCHEDULER_NO_TASK, &taskNeverRun, NULL)); + GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_add_now + (&taskNeverRun, NULL)); } diff --git a/src/util/test_server.c b/src/util/test_server.c index 6718c65..0faf61b 100644 --- a/src/util/test_server.c +++ b/src/util/test_server.c @@ -54,7 +54,7 @@ finish_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_assert (ok == 6); ok = 0; GNUNET_SERVER_destroy (server); - GNUNET_CLIENT_disconnect (cc, GNUNET_NO); + GNUNET_CLIENT_disconnect (cc); GNUNET_CONFIGURATION_destroy (cfg); } diff --git a/src/util/test_server_disconnect.c b/src/util/test_server_disconnect.c index 8010695..c54f9cb 100644 --- a/src/util/test_server_disconnect.c +++ b/src/util/test_server_disconnect.c @@ -51,7 +51,7 @@ finish_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_assert (ok == 5); ok = 0; GNUNET_SERVER_destroy (server); - GNUNET_CLIENT_disconnect (cc, GNUNET_NO); + GNUNET_CLIENT_disconnect (cc); GNUNET_CONFIGURATION_destroy (cfg); } diff --git a/src/util/test_server_mst_interrupt.c b/src/util/test_server_mst_interrupt.c new file mode 100644 index 0000000..fd34bd0 --- /dev/null +++ b/src/util/test_server_mst_interrupt.c @@ -0,0 +1,81 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_server_mst_interrupt.c + * @brief test for interrupt message processing in server_mst.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_protocols.h" +#include "gnunet_client_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +static struct GNUNET_SERVER_MessageStreamTokenizer * mst; +static int ret; + +/* Callback destroying mst with data in buffer */ +static int +mst_cb (void *cls, void *client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MST gave me message, destroying\n"); + GNUNET_SERVER_mst_destroy (mst); + return GNUNET_SYSERR; +} + +/** + * Main method + */ +static int +check () +{ + + struct GNUNET_PeerIdentity id; + struct GNUNET_MessageHeader msg[2]; + + /* Prepare */ + memset (&id, sizeof (id), '\0'); + msg[0].size = htons (sizeof (msg)); + msg[0].type = htons (sizeof (GNUNET_MESSAGE_TYPE_DUMMY)); + + mst = GNUNET_SERVER_mst_create(mst_cb, NULL); + + GNUNET_SERVER_mst_receive(mst, &id, (const char *) &msg, 2 * sizeof (msg), GNUNET_NO, GNUNET_NO); + + /* If we reach this line, it did not crash */ + ret = 0; + + return ret; +} + +int +main (int argc, char *argv[]) +{ + ret = 1; + + GNUNET_log_setup ("test_server", "WARNING", NULL); + check (); + + return ret; +} + +/* end of test_server_mst_interrupt.c */ diff --git a/src/util/test_server_with_client.c b/src/util/test_server_with_client.c index 06a4b71..ad56071 100644 --- a/src/util/test_server_with_client.c +++ b/src/util/test_server_with_client.c @@ -89,7 +89,7 @@ recv_cb (void *cls, struct GNUNET_SERVER_Client *argclient, break; case 4: ok++; - GNUNET_CLIENT_disconnect (client, GNUNET_YES); + GNUNET_CLIENT_disconnect (client); GNUNET_SERVER_receive_done (argclient, GNUNET_OK); break; default: diff --git a/src/util/test_server_with_client_unix.c b/src/util/test_server_with_client_unix.c index 99af4e8..eae80e4 100644 --- a/src/util/test_server_with_client_unix.c +++ b/src/util/test_server_with_client_unix.c @@ -68,7 +68,7 @@ recv_cb (void *cls, struct GNUNET_SERVER_Client *argclient, break; case 4: ok++; - GNUNET_CLIENT_disconnect (client, GNUNET_YES); + GNUNET_CLIENT_disconnect (client); GNUNET_SERVER_receive_done (argclient, GNUNET_OK); break; default: diff --git a/src/util/test_service.c b/src/util/test_service.c index 049282d..5547249 100644 --- a/src/util/test_service.c +++ b/src/util/test_service.c @@ -41,18 +41,49 @@ static struct GNUNET_SERVICE_Context *sctx; static int ok = 1; +static struct GNUNET_CLIENT_Connection *client; + + + + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != client) + { + GNUNET_CLIENT_disconnect (client); + client = NULL; + } + if (NULL != sctx) + { + GNUNET_SERVICE_stop (sctx); + sctx = NULL; + } + else + { + GNUNET_SCHEDULER_shutdown (); + } +} + static size_t build_msg (void *cls, size_t size, void *buf) { - struct GNUNET_CLIENT_Connection *client = cls; struct GNUNET_MessageHeader *msg = buf; + if (size < sizeof (struct GNUNET_MessageHeader)) + { + /* timeout */ + GNUNET_break (0); + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + ok = 1; + return 0; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected, transmitting\n"); GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg->type = htons (MY_TYPE); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); - GNUNET_CLIENT_disconnect (client, GNUNET_NO); return sizeof (struct GNUNET_MessageHeader); } @@ -61,7 +92,6 @@ static void ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_CLIENT_Connection *client; GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service confirmed running\n"); @@ -72,27 +102,19 @@ ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_SECONDS, GNUNET_NO, - &build_msg, client); -} - - -static void -do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_SERVICE_stop (sctx); + &build_msg, NULL); } static void -recv_cb (void *cls, struct GNUNET_SERVER_Client *client, +recv_cb (void *cls, struct GNUNET_SERVER_Client *sc, const struct GNUNET_MessageHeader *message) { + if (NULL == message) + return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving client message...\n"); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - if (sctx != NULL) - GNUNET_SCHEDULER_add_now (&do_stop, NULL); - else - GNUNET_SCHEDULER_shutdown (); + GNUNET_SERVER_receive_done (sc, GNUNET_OK); + GNUNET_SCHEDULER_add_now (&do_stop, NULL); ok = 0; } @@ -146,7 +168,6 @@ static void ready6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_CLIENT_Connection *client; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 ready\n"); GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); @@ -156,7 +177,7 @@ ready6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_SECONDS, GNUNET_NO, - &build_msg, client); + &build_msg, NULL); } static void @@ -206,7 +227,7 @@ start_stop_main (void *cls, char *const *args, const char *cfgfile, int *ret = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service using start method\n"); - sctx = GNUNET_SERVICE_start ("test_service", cfg); + sctx = GNUNET_SERVICE_start ("test_service", cfg, GNUNET_SERVICE_OPTION_NONE); GNUNET_assert (NULL != sctx); runner (cls, GNUNET_SERVICE_get_server (sctx), cfg); *ret = 0; @@ -257,7 +278,6 @@ main (int argc, char *argv[]) NULL); ret += check (); ret += check (); - // FIXME #ifndef MINGW s = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); @@ -280,7 +300,6 @@ main (int argc, char *argv[]) ret += check6 (); } ret += check_start_stop (); - return ret; } diff --git a/src/util/test_speedup.c b/src/util/test_speedup.c new file mode 100644 index 0000000..03cffbd --- /dev/null +++ b/src/util/test_speedup.c @@ -0,0 +1,120 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_speedup.c + * @brief testcase for speedup.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_program_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_strings_lib.h" + +/** + * Start time of the testcase + */ +static struct GNUNET_TIME_Absolute start; + +/** + * End-time of the testcase (affected by speed-up) + */ +static struct GNUNET_TIME_Absolute end; + +/** + * Number of cycles we have spent in 'run'. + */ +static unsigned int cycles; + + +/** + * Main task that is scheduled with the speed-up. + * + * @param cls NULL + * @param tc scheduler context, unused + */ +static void +run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + cycles++; + fprintf (stderr, "..%u", cycles); + if (cycles <= 5) + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &run, NULL); + return; + } + end = GNUNET_TIME_absolute_get(); + fprintf (stderr, "\n"); + fflush(stdout); +} + + +/** + * + */ +static void +check (void *cls, char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle * + cfg) +{ + fprintf (stderr, "0"); + fflush(stdout); + GNUNET_SCHEDULER_add_now(&run, NULL); +} + + +int +main (int argc, char *argv[]) +{ + static char *const argvn[] = { "test-speedup", + "-c", "test_speedup_data.conf", + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + time_t start_real; + time_t end_real; + struct GNUNET_TIME_Relative delta; + + start_real = time (NULL); + start = GNUNET_TIME_absolute_get(); + GNUNET_PROGRAM_run ((sizeof (argvn) / sizeof (char *)) - 1, argvn, "test-speedup", + "nohelp", options, &check, NULL); + + end_real = time (NULL); + delta = GNUNET_TIME_absolute_get_difference(start, end); + + if (delta.rel_value > ((end_real - start_real) * 1500LL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Execution time in GNUnet time: %llu ms\n", + (unsigned long long) delta.rel_value); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Execution time in system time: %llu ms\n", + (unsigned long long) ((end_real - start_real) * 1000LL)); + return 0; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Execution time in GNUnet time: %llu ms\n", + (unsigned long long) delta.rel_value); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Execution time in system time: %llu ms\n", + (unsigned long long) ((end_real - start_real) * 1000LL)); + return 1; +} + +/* end of test_speedup.c */ diff --git a/src/util/test_speedup_data.conf b/src/util/test_speedup_data.conf new file mode 100644 index 0000000..699cdc9 --- /dev/null +++ b/src/util/test_speedup_data.conf @@ -0,0 +1,3 @@ +[testing] +SPEEDUP_INTERVAL = 100 ms +SPEEDUP_DELTA = 100 ms diff --git a/src/util/test_strings.c b/src/util/test_strings.c index 570776a..b662623 100644 --- a/src/util/test_strings.c +++ b/src/util/test_strings.c @@ -97,10 +97,12 @@ check () GNUNET_free (r); b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "ASCII"); WANT ("TEST", b); +#if ENABLE_NLS && HAVE_ICONV GNUNET_log_skip (2, GNUNET_NO); b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "unknown"); GNUNET_log_skip (0, GNUNET_YES); WANT ("TEST", b); +#endif return 0; } diff --git a/src/util/test_time.c b/src/util/test_time.c index 788884f..b4c7233 100644 --- a/src/util/test_time.c +++ b/src/util/test_time.c @@ -43,9 +43,9 @@ check () struct GNUNET_TIME_RelativeNBO reln; unsigned int i; - forever = GNUNET_TIME_absolute_get_forever (); - relForever = GNUNET_TIME_relative_get_forever (); - relUnit = GNUNET_TIME_relative_get_unit (); + forever = GNUNET_TIME_UNIT_FOREVER_ABS; + relForever = GNUNET_TIME_UNIT_FOREVER_REL; + relUnit = GNUNET_TIME_UNIT_MILLISECONDS; zero.abs_value = 0; last = now = GNUNET_TIME_absolute_get (); @@ -62,7 +62,7 @@ check () GNUNET_assert (rel.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value); /*check zero */ rel.rel_value = (UINT64_MAX) - 1024; - GNUNET_assert (GNUNET_TIME_relative_get_zero ().rel_value == + GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value == GNUNET_TIME_relative_multiply (rel, 0).rel_value); /* test infinity-check for relative to absolute */ @@ -77,7 +77,7 @@ check () GNUNET_TIME_relative_to_absolute (rel).abs_value); /*check forever */ rel.rel_value = UINT64_MAX; - GNUNET_assert (GNUNET_TIME_absolute_get_forever ().abs_value == + GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == GNUNET_TIME_relative_to_absolute (rel).abs_value); /* check overflow for r2a */ rel.rel_value = (UINT64_MAX) - 1024; @@ -125,8 +125,8 @@ check () rel = GNUNET_TIME_absolute_get_remaining (future); GNUNET_assert (rel.rel_value > 0); GNUNET_assert (rel.rel_value <= 1000000); - forever = GNUNET_TIME_absolute_get_forever (); - GNUNET_assert (GNUNET_TIME_relative_get_forever ().rel_value == + forever = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == GNUNET_TIME_absolute_get_remaining (forever).rel_value); /* check endianess */ @@ -175,13 +175,13 @@ check () /* check Return absolute time of 0ms */ - zero = GNUNET_TIME_absolute_get_zero (); + zero = GNUNET_TIME_UNIT_ZERO_ABS; /* check GNUNET_TIME_calculate_eta */ last.abs_value = GNUNET_TIME_absolute_get ().abs_value - 1024; - forever = GNUNET_TIME_absolute_get_forever (); + forever = GNUNET_TIME_UNIT_FOREVER_ABS; forever.abs_value = forever.abs_value - 1024; - GNUNET_assert (GNUNET_TIME_absolute_get_zero ().abs_value == + GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value == GNUNET_TIME_calculate_eta (forever, 50000, 100000).rel_value); /* check zero */ GNUNET_log_skip (1, GNUNET_NO); @@ -199,11 +199,11 @@ check () GNUNET_assert (1024 == GNUNET_TIME_relative_subtract (relForever, rel).rel_value); /*check zero */ - GNUNET_assert (GNUNET_TIME_relative_get_zero ().rel_value == + GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value == GNUNET_TIME_relative_subtract (rel, relForever).rel_value); /*check forever */ rel.rel_value = UINT64_MAX; - GNUNET_assert (GNUNET_TIME_relative_get_forever ().rel_value == + GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == GNUNET_TIME_relative_subtract (rel, relForever).rel_value); /*check GNUNET_TIME_relative_min */ diff --git a/src/util/time.c b/src/util/time.c index c57ccd1..7467b44 100644 --- a/src/util/time.c +++ b/src/util/time.c @@ -68,7 +68,7 @@ GNUNET_TIME_absolute_get () * Return relative time of 0ms. */ struct GNUNET_TIME_Relative -GNUNET_TIME_relative_get_zero () +GNUNET_TIME_relative_get_zero_ () { static struct GNUNET_TIME_Relative zero; @@ -80,28 +80,63 @@ GNUNET_TIME_relative_get_zero () * Return absolute time of 0ms. */ struct GNUNET_TIME_Absolute -GNUNET_TIME_absolute_get_zero () +GNUNET_TIME_absolute_get_zero_ () { static struct GNUNET_TIME_Absolute zero; return zero; } + /** * Return relative time of 1ms. */ struct GNUNET_TIME_Relative -GNUNET_TIME_relative_get_unit () +GNUNET_TIME_relative_get_unit_ () { static struct GNUNET_TIME_Relative one = { 1 }; return one; } + +/** + * Return relative time of 1s. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_second_ () +{ + static struct GNUNET_TIME_Relative one = { 1000 }; + return one; +} + + +/** + * Return relative time of 1 minute. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_minute_ () +{ + static struct GNUNET_TIME_Relative one = { 60 * 1000 }; + return one; +} + + +/** + * Return relative time of 1 hour. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_hour_ () +{ + static struct GNUNET_TIME_Relative one = { 60 * 60 * 1000 }; + return one; +} + + /** * Return "forever". */ struct GNUNET_TIME_Relative -GNUNET_TIME_relative_get_forever () +GNUNET_TIME_relative_get_forever_ () { static struct GNUNET_TIME_Relative forever = { UINT64_MAX }; return forever; @@ -111,7 +146,7 @@ GNUNET_TIME_relative_get_forever () * Return "forever". */ struct GNUNET_TIME_Absolute -GNUNET_TIME_absolute_get_forever () +GNUNET_TIME_absolute_get_forever_ () { static struct GNUNET_TIME_Absolute forever = { UINT64_MAX }; return forever; @@ -129,13 +164,13 @@ GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel) struct GNUNET_TIME_Absolute ret; if (rel.rel_value == UINT64_MAX) - return GNUNET_TIME_absolute_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_ABS; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); if (rel.rel_value + now.abs_value < rel.rel_value) { GNUNET_break (0); /* overflow... */ - return GNUNET_TIME_absolute_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_ABS; } ret.abs_value = rel.rel_value + now.abs_value; return ret; @@ -193,7 +228,7 @@ GNUNET_TIME_absolute_min (struct GNUNET_TIME_Absolute t1, * * @param t1 first timestamp * @param t2 other timestamp - * @return timestamp that is smaller + * @return timestamp that is bigger */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1, @@ -215,11 +250,11 @@ GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future) struct GNUNET_TIME_Relative ret; if (future.abs_value == UINT64_MAX) - return GNUNET_TIME_relative_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_REL; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); if (now.abs_value > future.abs_value) - return GNUNET_TIME_relative_get_zero (); + return GNUNET_TIME_UNIT_ZERO; ret.rel_value = future.abs_value - now.abs_value; return ret; } @@ -238,9 +273,9 @@ GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative ret; if (end.abs_value == UINT64_MAX) - return GNUNET_TIME_relative_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_REL; if (end.abs_value < start.abs_value) - return GNUNET_TIME_relative_get_zero (); + return GNUNET_TIME_UNIT_ZERO; ret.rel_value = end.abs_value - start.abs_value; return ret; } @@ -260,7 +295,7 @@ GNUNET_TIME_absolute_get_duration (struct GNUNET_TIME_Absolute whence) now = GNUNET_TIME_absolute_get (); GNUNET_assert (whence.abs_value != UINT64_MAX); if (whence.abs_value > now.abs_value) - return GNUNET_TIME_relative_get_zero (); + return GNUNET_TIME_UNIT_ZERO; ret.rel_value = now.abs_value - whence.abs_value; return ret; } @@ -279,11 +314,11 @@ GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute ret; if ((start.abs_value == UINT64_MAX) || (duration.rel_value == UINT64_MAX)) - return GNUNET_TIME_absolute_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_ABS; if (start.abs_value + duration.rel_value < start.abs_value) { GNUNET_break (0); - return GNUNET_TIME_absolute_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_ABS; } ret.abs_value = start.abs_value + duration.rel_value; return ret; @@ -325,12 +360,12 @@ GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, struct GNUNET_TIME_Relative ret; if (factor == 0) - return GNUNET_TIME_relative_get_zero (); + return GNUNET_TIME_UNIT_ZERO; ret.rel_value = rel.rel_value * (unsigned long long) factor; if (ret.rel_value / factor != rel.rel_value) { GNUNET_break (0); - return GNUNET_TIME_relative_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_REL; } return ret; } @@ -401,11 +436,11 @@ GNUNET_TIME_relative_add (struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative ret; if ((a1.rel_value == UINT64_MAX) || (a2.rel_value == UINT64_MAX)) - return GNUNET_TIME_relative_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_REL; if (a1.rel_value + a2.rel_value < a1.rel_value) { GNUNET_break (0); - return GNUNET_TIME_relative_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_REL; } ret.rel_value = a1.rel_value + a2.rel_value; return ret; @@ -426,9 +461,9 @@ GNUNET_TIME_relative_subtract (struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative ret; if (a2.rel_value >= a1.rel_value) - return GNUNET_TIME_relative_get_zero (); + return GNUNET_TIME_UNIT_ZERO; if (a1.rel_value == UINT64_MAX) - return GNUNET_TIME_relative_get_forever (); + return GNUNET_TIME_UNIT_FOREVER_REL; ret.rel_value = a1.rel_value - a2.rel_value; return ret; } diff --git a/src/util/util.conf b/src/util/util.conf index ba9dfec..f3d301e 100644 --- a/src/util/util.conf +++ b/src/util/util.conf @@ -14,3 +14,5 @@ HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO +SPEEDUP_INTERVAL = 0 ms +SPEEDUP_DELTA = 0 ms diff --git a/src/util/winproc.c b/src/util/winproc.c index 7cd80a9..b75fc86 100644 --- a/src/util/winproc.c +++ b/src/util/winproc.c @@ -27,7 +27,6 @@ #include "platform.h" #include "gnunet_common.h" -#define DEBUG_WINPROC 0 #ifdef MINGW @@ -146,7 +145,7 @@ GNInitWinEnv () plibc_initialized (); plibc_set_panic_proc (plibc_panic); - ret = plibc_init ("GNU", PACKAGE); + ret = plibc_init_utf8 ("GNU", PACKAGE, 1); /* don't load other DLLs twice */ if (hNTDLL) |