From 71cbe865666e9f9850bab642262a1ac747c86bfd Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Thu, 13 Oct 2016 13:28:23 +1030 Subject: [PATCH] Switch to feature-driven linking This introduces a new way of linking Serval executables and dynamic libraries from static libraries like libservald.a -- called "feature-driven" linking. The Makefile now links servald and serval-tests from libservald.a, rather than from an explicit list of object (.o) files. Thanks to the section-based method for registering functions such as HTTP handlers, CLI commands and MDP handlers, these object files had become "stand-alone" and hence were no longer included in the link because there was no unresolved reference that required them to be linked in. The new "feature.h" provides the DECLARE_FEATURE(name) macro that each stand-alone source file uses to declare the named feature(s) it provides. Each executable can call the USE_FEATURE(name) macro in any of its explicitly-linked source files to cause the corresponding object(s) to be included in the link, eg, servald_features.c. The DEFINE_BINDING() macro has been extended so that every individual MDP binding is given a feature name based on its port number macro, eg, "mdp_binding_MDP_PORT_ECHO". Some features have been factored into their own separate source files so they can be omitted or included in a build independently of each other: - the MDP bindings for MDP_PORT_DNALOOKUP, MDP_PORT_ECHO, MDP_PORT_TRACE, MDP_PORT_KEYMAPREQUEST, MDP_PORT_RHIZOME_xxx, MDP_PORT_PROBE, MDP_PORT_STUN, MDP_PORT_STUNREQ - the CLI "log" and "echo" commands - the CLI "rhizome direct" command The JNI source files are only compiled if the header is present, otherwise they are omitted from libservald.so. --- Makefile.in | 70 +++---- commandline.c | 55 +----- conf_cli.c | 2 + configure.ac | 18 ++ echo_cli.c | 48 +++++ feature.h | 66 +++++++ jni_server.c | 3 +- keyring.c | 207 +------------------ keyring.h | 3 + keyring_cli.c | 2 + keyring_restful.c | 2 + log.c | 12 +- log_cli.c | 42 ++++ meshms_cli.c | 2 + meshms_restful.c | 2 + monitor-cli.c | 4 +- msp_proxy.c | 2 + network_cli.c | 2 + overlay_address.h | 1 + overlay_buffer.h | 4 + overlay_link.c | 118 +---------- overlay_mdp_dnalookup.c | 86 ++++++++ overlay_mdp_echo.c | 42 ++++ overlay_mdp_keymaprequest.c | 229 +++++++++++++++++++++ overlay_mdp_rhizome.c | 185 +++++++++++++++++ overlay_mdp_services.c | 383 ------------------------------------ overlay_mdp_trace.c | 136 +++++++++++++ overlay_packet.h | 2 + overlay_probe.c | 54 +++++ overlay_stun.c | 60 ++++++ overlay_stunreq.c | 81 ++++++++ rhizome.h | 13 +- rhizome_cli.c | 2 + rhizome_direct.c | 178 +---------------- rhizome_direct_cli.c | 110 +++++++++++ rhizome_direct_http.c | 86 ++++++++ rhizome_http.c | 2 + rhizome_restful.c | 2 + route_link.h | 4 +- serval.h | 7 +- servald_features.c | 75 +++++++ servald_main.c | 28 +-- server.c | 20 +- server_httpd.c | 5 +- sighandlers.c | 6 +- sourcefiles.mk | 50 ++--- test_cli.c | 4 +- test_features.c | 30 +++ testdefs_java.sh | 6 +- version_cli.c | 39 ++++ version_servald.c | 2 + version_servald.h | 21 ++ vomp_console.c | 2 + 53 files changed, 1564 insertions(+), 1051 deletions(-) create mode 100644 echo_cli.c create mode 100644 feature.h create mode 100644 log_cli.c create mode 100644 overlay_mdp_dnalookup.c create mode 100644 overlay_mdp_echo.c create mode 100644 overlay_mdp_keymaprequest.c create mode 100644 overlay_mdp_rhizome.c delete mode 100644 overlay_mdp_services.c create mode 100644 overlay_mdp_trace.c create mode 100644 overlay_probe.c create mode 100644 overlay_stun.c create mode 100644 overlay_stunreq.c create mode 100644 rhizome_direct_cli.c create mode 100644 servald_features.c create mode 100644 test_features.c create mode 100644 version_cli.c create mode 100644 version_servald.h diff --git a/Makefile.in b/Makefile.in index d46dde9c..e2f0d57a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -23,8 +23,6 @@ ALL_SOURCES = \ $(MDP_CLIENT_SOURCES) \ $(SERVAL_DAEMON_SOURCES) \ $(SERVAL_DAEMON_JNI_SOURCES) \ - $(TEST_SOURCES) \ - $(SERVAL_LIB_SOURCES) \ $(MONITOR_CLIENT_SRCS) \ $(SIMULATOR_SOURCES) \ $(SQLITE3_SOURCES) @@ -32,23 +30,21 @@ ALL_SOURCES = \ SERVAL_DAEMON_OBJS = \ $(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) \ $(addprefix $(OBJSDIR_SERVALD)/, $(MDP_CLIENT_SOURCES:.c=.o)) \ - $(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_DAEMON_SOURCES:.c=.o)) \ + $(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_DAEMON_SOURCES:.c=.o)) +ifeq (@HAVE_JNI_H@,yes) +SERVAL_DAEMON_OBJS += \ $(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_DAEMON_JNI_SOURCES:.c=.o)) +endif SQLITE3_OBJS = \ $(addprefix $(OBJSDIR_SERVALD)/, $(notdir $(SQLITE3_SOURCES:.c=.o))) SERVALD_OBJS = \ $(SQLITE3_OBJS) \ $(SERVAL_DAEMON_OBJS) -TEST_OBJS = \ - $(addprefix $(OBJSDIR_SERVALD)/, $(TEST_SOURCES:.c=.o)) \ - $(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) LIB_SERVAL_OBJS = \ $(addprefix $(OBJSDIR_LIB)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) \ - $(addprefix $(OBJSDIR_LIB)/, $(SERVAL_LIB_SOURCES:.c=.o)) \ $(addprefix $(OBJSDIR_LIB)/, $(MDP_CLIENT_SOURCES:.c=.o)) MONITOR_CLIENT_OBJS = \ $(addprefix $(OBJSDIR_LIB)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) \ - $(addprefix $(OBJSDIR_LIB)/, $(SERVAL_LIB_SOURCES:.c=.o)) \ $(addprefix $(OBJSDIR_LIB)/, $(MONITOR_CLIENT_SRCS:.c=.o)) SIMULATOR_OBJS = \ $(addprefix $(OBJSDIR_TOOLS)/, $(SIMULATOR_SOURCES:.c=.o)) @@ -93,7 +89,7 @@ DEFS= @DEFS@ all: libs servald servaldwrap test -libs: libservald.so libservald.a \ +libs: libservald.so \ libservalclient.so libservalclient.a \ libmonitorclient.so libmonitorclient.a @@ -108,7 +104,7 @@ uninstall: clean: @$(RM) -r $(OBJSDIRS:%=%/*) \ servald \ - libservald.so libservald.a \ + libservald.a \ libservalclient.so libservalclient.a \ libmonitorclient.so libmonitorclient.a \ tfw_createfile directory_service fakeradio simulator serval-tests @@ -223,7 +219,6 @@ $(OBJSDIR_LIB)/%.o: $(SOURCE_PREFIX)%.c $(SERVAL_DAEMON_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS) $(SERVALD_OBJS): $(SOURCE_PREFIX)Makefile $(LIB_SERVAL_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS) -$(TEST_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS) $(OBJSDIR_TOOLS)/tfw_createfile.o: $(SOURCE_PREFIX)Makefile $(SOURCE_PREFIX)str.h $(OBJSDIR_TOOLS)/directory_service.o: $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS) $(MONITOR_CLIENT_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS) @@ -231,57 +226,62 @@ $(SIMULATOR_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS) # Rules for main targets. -servald: $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o +libservald.a: $(SERVALD_OBJS) \ + $(OBJSDIR_TOOLS)/version.o + @echo AR $@ + @$(AR) -cr $@ $^ + +libservald.so: \ + $(OBJSDIR_SERVALD)/servald_features.o \ + $(OBJSDIR_SERVALD)/jni_commandline.o \ + $(OBJSDIR_SERVALD)/jni_server.o \ + libservald.a @echo LINK $@ - @$(CC) -Wall -o $@ $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS) + @$(CC) -Wall -shared -o $@ $^ $(LDFLAGS) + +servald: $(OBJSDIR_SERVALD)/servald_features.o libservald.a + @echo LINK $@ + @$(CC) -Wall -o $@ $^ $(LDFLAGS) servaldwrap: $(OBJSDIR_SERVALD)/servalwrap.o $(OBJSDIR_TOOLS)/version.o @echo LINK $@ @$(CC) -Wall -o $@ $^ $(LDFLAGS) -serval-tests: $(TEST_OBJS) $(OBJSDIR_TOOLS)/version.o +serval-tests: $(OBJSDIR_SERVALD)/test_features.o libservald.a @echo LINK $@ - @$(CC) -Wall -o $@ $(TEST_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS) + @$(CC) -Wall -o $@ $^ $(LDFLAGS) directory_service: $(OBJSDIR_TOOLS)/directory_service.o libservalclient.a @echo LINK $@ - @$(CC) -Wall -o $@ $(OBJSDIR_TOOLS)/directory_service.o libservalclient.a $(LDFLAGS) + @$(CC) -Wall -o $@ $^ $(LDFLAGS) tfw_createfile: $(OBJSDIR_TOOLS)/tfw_createfile.o libservalclient.a @echo LINK $@ - @$(CC) -Wall -o $@ $(OBJSDIR_TOOLS)/tfw_createfile.o libservalclient.a $(LDFLAGS) + @$(CC) -Wall -o $@ $^ $(LDFLAGS) fakeradio: $(OBJSDIR_TOOLS)/fakeradio.o libservalclient.a @echo LINK $@ - @$(CC) -Wall -o $@ $(OBJSDIR_TOOLS)/fakeradio.o libservalclient.a $(LDFLAGS) + @$(CC) -Wall -o $@ $^ $(LDFLAGS) simulator: $(SIMULATOR_OBJS) libservalclient.a @echo LINK $@ - @$(CC) -Wall -o $@ $(SIMULATOR_OBJS) libservalclient.a $(LDFLAGS) - -libservalclient.so: $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o - @echo AR $@ - @$(CC) -Wall -shared -o $@ $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o + @$(CC) -Wall -o $@ $^ $(LDFLAGS) libservalclient.a: $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o @echo AR $@ - @$(AR) -cr $@ $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o + @$(AR) -cr $@ $^ -libservald.so: $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o - @echo LINK $@ - @$(CC) -Wall -shared -o $@ $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS) - -libservald.a: $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o +libservalclient.so: $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o @echo AR $@ - @$(AR) -cr $@ $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o - -libmonitorclient.so: $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o - @echo LINK $@ - @$(CC) -Wall -shared -o $@ $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS) + @$(CC) -Wall -shared -o $@ $^ libmonitorclient.a: $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o @echo AR $@ - @$(AR) -cr $@ $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o + @$(AR) -cr $@ $^ + +libmonitorclient.so: $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o + @echo LINK $@ + @$(CC) -Wall -shared -o $@ $^ $(LDFLAGS) # Helpful target to update the COPYRIGHT.txt file by harvesting copyright # information from the contents of all the source and header files. This diff --git a/commandline.c b/commandline.c index c50b244b..32bb3156 100644 --- a/commandline.c +++ b/commandline.c @@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "commandline.h" -#include "serval.h" #include "conf.h" #include "str.h" #include "cli_stdio.h" @@ -32,20 +31,6 @@ static int app_usage(const struct cli_parsed *parsed, struct cli_context *UNUSED return cli_usage_parsed(parsed, XPRINTF_STDIO(stdout)); } -DEFINE_CMD(version_message,CLIFLAG_PERMISSIVE_CONFIG, - "Display copyright information.", - "version|copyright"); -static int version_message(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context)) -{ - printf("Serval DNA version %s\n%s\n", version_servald, copyright_servald); - printf("\ -License GPLv2+: GNU GPL version 2 or later .\n\ -This is free software: you are free to change and redistribute it.\n\ -There is NO WARRANTY, to the extent permitted by law.\n\ -"); - return 0; -} - /* Parse the command line and load the configuration. If a command was found then execute the * parsed command and return its return value. * @@ -60,6 +45,8 @@ int commandline_main(struct cli_context *context, const char *argv0, int argc, c { fd_clearstats(); IN(); + + cf_init(); struct cli_parsed parsed; int result = cli_parse(argc, args, SECTION_START(commands), SECTION_END(commands), &parsed); @@ -108,41 +95,3 @@ int commandline_main_stdio(FILE *output, const char *argv0, int argc, const char return commandline_main(&cli_context, argv0, argc, args); } - -DEFINE_CMD(app_echo,CLIFLAG_PERMISSIVE_CONFIG, - "Output the supplied string.", - "echo","[-e]","[--]","..."); -static int app_echo(const struct cli_parsed *parsed, struct cli_context *context) -{ - DEBUG_cli_parsed(verbose, parsed); - int escapes = !cli_arg(parsed, "-e", NULL, NULL, NULL); - unsigned i; - for (i = parsed->varargi; i < parsed->argc; ++i) { - const char *arg = parsed->args[i]; - DEBUGF(verbose, "echo:argv[%d]=\"%s\"", i, arg); - if (escapes) { - char buf[strlen(arg)]; - size_t len = strn_fromprint(buf, sizeof buf, arg, 0, '\0', NULL); - cli_write(context, buf, len); - } else - cli_puts(context, arg); - cli_delim(context, NULL); - } - return 0; -} - -DEFINE_CMD(app_log,CLIFLAG_PERMISSIVE_CONFIG, - "Log the supplied message at given level.", - "log","error|warn|hint|info|debug",""); -static int app_log(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) -{ - DEBUG_cli_parsed(verbose, parsed); - assert(parsed->argc == 3); - const char *lvl = parsed->args[1]; - const char *msg = parsed->args[2]; - int level = string_to_log_level(lvl); - if (level == LOG_LEVEL_INVALID) - return WHYF("invalid log level: %s", lvl); - logMessage(level, __NOWHERE__, "%s", msg); - return 0; -} diff --git a/conf_cli.c b/conf_cli.c index dfe0905b..3e38c949 100644 --- a/conf_cli.c +++ b/conf_cli.c @@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mdp_client.h" #include "server.h" +DEFINE_FEATURE(cli_config); + DEFINE_CMD(app_config_schema, CLIFLAG_PERMISSIVE_CONFIG, "Display configuration schema.", "config", "schema"); diff --git a/configure.ac b/configure.ac index 9f0601f2..8ec4358e 100644 --- a/configure.ac +++ b/configure.ac @@ -149,6 +149,8 @@ AC_CHECK_HEADERS( #endif ]) +AC_SUBST([HAVE_JNI_H], [$ac_cv_header_jni_h]) + dnl libsodium m4_define([LIBSODIUM_MESSAGE], [ @@ -167,6 +169,22 @@ AC_CHECK_HEADERS( AC_CHECK_LIB(sodium, sodium_init,, [AC_MSG_ERROR([missing libsodium LIBSODIUM_MESSAGE([LIBRARY_PATH])])]) +dnl Check if the Linux gettid() and tgkill() system calls are supported. +AC_CACHE_CHECK([Linux gettid() and tgkill()], ac_cv_have_linux_gettid_tgkill, [ + ac_cv_have_linux_gettid_tgkill=no + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([ + #include + #include + #include + ], + [syscall(SYS_tgkill, getpid(), syscall(SYS_gettid), SIGHUP)] + )], + [ac_cv_have_linux_gettid_tgkill=yes] + ) +]) +AS_IF([test "x$ac_cv_have_linux_gettid_tgkill" = xyes], [AC_DEFINE([HAVE_LINUX_THREADS])]) + dnl Lazy way of checking for Linux AS_IF([test "x$ac_cv_header_linux_if_h" = xyes], [AC_DEFINE([USE_ABSTRACT_NAMESPACE])]) diff --git a/echo_cli.c b/echo_cli.c new file mode 100644 index 00000000..089675ad --- /dev/null +++ b/echo_cli.c @@ -0,0 +1,48 @@ +/* +Serval DNA utilities +Copyright (C) 2014-2015 Serval Project Inc. +Copyright (C) 2016 Flinders University + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "feature.h" +#include "commandline.h" +#include "debug.h" +#include "conf.h" // for IF_DEBUG() + +DEFINE_FEATURE(cli_echo); + +DEFINE_CMD(app_echo, CLIFLAG_PERMISSIVE_CONFIG, + "Output the supplied string.", + "echo","[-e]","[--]","..."); +static int app_echo(const struct cli_parsed *parsed, struct cli_context *context) +{ + DEBUG_cli_parsed(verbose, parsed); + int escapes = !cli_arg(parsed, "-e", NULL, NULL, NULL); + unsigned i; + for (i = parsed->varargi; i < parsed->argc; ++i) { + const char *arg = parsed->args[i]; + DEBUGF(verbose, "echo:argv[%d]=\"%s\"", i, arg); + if (escapes) { + char buf[strlen(arg)]; + size_t len = strn_fromprint(buf, sizeof buf, arg, 0, '\0', NULL); + cli_write(context, buf, len); + } else + cli_puts(context, arg); + cli_delim(context, NULL); + } + return 0; +} diff --git a/feature.h b/feature.h new file mode 100644 index 00000000..b7aa39f0 --- /dev/null +++ b/feature.h @@ -0,0 +1,66 @@ +/* +Serval DNA features +Copyright (C) 2016 Flinders University + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __SERVAL_DNA__FEATURE_H +#define __SERVAL_DNA__FEATURE_H + +/* These are macros for assembling an executable out of an explicitly-listed + * subset of "features". A feature is an object file (.o file) that contains + * the entire implementation of the feature, and is optional, ie, can be + * omitted from an executable without breaking the build. + * + * In Serval DNA, features are joined up with their infrastructure using + * linkage sections; see "sections.h" for more details. + * + * For example, a source file can add its own static function to the list of + * all URL path-to-function mappings for the HTTPD server using + * DECLARE_HANDLER() macro defined in "httpd.h". There is no + * explicitly-initialised array that lists all the URL paths; the array is + * constructed implicitly by the linker when it assembles the "httpd" section. + * Simply including the relevant object files in the link brings their + * functions into the array. + * + * Features are also used to add commands to the CLI interface and to add + * port-number handlers to the MDP interface. + * + * In order to build an executable from libservald.a, the executable needs a + * way to specify which optional features it wishes to link in, otherwise they + * will be omitted from the build, and as a result it will offer few or no CLI + * commands, no MDP services, and no HTTP services. + * + * Each source file that implements a feature must contain a DEFINE_FEATURE() + * macro, with the name of the feature as its argument. + * + * Every executable that links against libservald.a must contain a source file + * that invokes the USE_FEATURE() macro once for every defined feature it + * wishes to link in. This is typically done inside the main() function, but + * may be done within any function that is guaranteed to be included in the + * link. + */ + +#define DEFINE_FEATURE(name) \ + void _serval_feature__ ## name () {} \ + +#define USE_FEATURE(name) \ + do { \ + extern void _serval_feature__ ## name (); \ + _serval_feature__ ## name (); \ + } while (0) + +#endif // __SERVAL_DNA__FEATURE_H diff --git a/jni_server.c b/jni_server.c index a523b9ba..8c8faf8d 100644 --- a/jni_server.c +++ b/jni_server.c @@ -21,7 +21,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "jni_common.h" #include "server.h" -#include "serval.h" +#include "serval.h" // for mdp_loopback_port +#include "keyring.h" #include "conf.h" #include "instance.h" diff --git a/keyring.c b/keyring.c index 1e348290..d4d47422 100644 --- a/keyring.c +++ b/keyring.c @@ -23,17 +23,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "conf.h" #include "constants.h" +#include "overlay_buffer.h" #include "overlay_address.h" #include "crypto.h" -#include "overlay_interface.h" -#include "overlay_packet.h" -#include "overlay_buffer.h" #include "keyring.h" #include "dataformats.h" #include "str.h" #include "mem.h" #include "rotbuf.h" -#include "server.h" #include "route_link.h" static keyring_file *keyring_open_or_create(const char *path, int writeable); @@ -1740,76 +1737,6 @@ int keyring_sign_message(struct keyring_identity *identity, unsigned char *conte return 0; } -static int keyring_store_id(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - if (header->source->id_valid){ - DEBUGF(keyring, "Ignoring SID:SAS mapping for %s, already have one", alloca_tohex_sid_t(header->source->sid)); - return 0; - } - size_t len = ob_remaining(payload); - - DEBUGF(keyring, "Received SID:SAS mapping, %zd bytes", len); - - if (ob_remaining(payload) < IDENTITY_SIZE + crypto_sign_BYTES) - return WHY("Truncated key mapping announcement?"); - - const uint8_t *id_public = ob_get_bytes_ptr(payload, IDENTITY_SIZE); - const uint8_t *compactsignature = ob_get_bytes_ptr(payload, crypto_sign_BYTES); - - if (crypto_sign_verify_detached(compactsignature, header->source->sid.binary, SID_SIZE, id_public)) - return WHY("SID:SAS mapping verification signature does not verify"); - - // test if the signing key can be used to derive the sid - sid_t sid; - if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id_public)==0 - && memcmp(&sid, &header->source->sid, sizeof sid) == 0) - header->source->id_combined=1; - - /* now store it */ - bcopy(id_public, &header->source->id_public, IDENTITY_SIZE); - header->source->id_valid=1; - header->source->id_last_request=-1; - - DEBUGF(keyring, "Stored SID:SAS mapping, SID=%s to SAS=%s", - alloca_tohex_sid_t(header->source->sid), - alloca_tohex_identity_t(&header->source->id_public) - ); - return 0; -} - -static int keyring_respond_id(struct internal_mdp_header *header) -{ - keyring_identity *id = header->destination->identity; - - /* It's a request, so find the SAS for the SID the request was addressed to, - use that to sign that SID, and then return it in an authcrypted frame. */ - struct internal_mdp_header response; - bzero(&response, sizeof response); - mdp_init_response(header, &response); - - uint8_t buff[MDP_MTU]; - struct overlay_buffer *response_payload = ob_static(buff, sizeof buff); - ob_limitsize(response_payload, sizeof buff); - - ob_append_byte(response_payload, KEYTYPE_CRYPTOSIGN); - ob_append_bytes(response_payload, id->sign_keypair->public_key.binary, crypto_sign_PUBLICKEYBYTES); - uint8_t *sig = ob_append_space(response_payload, crypto_sign_BYTES); - - if (crypto_sign_detached(sig, NULL, header->destination->sid.binary, SID_SIZE, id->sign_keypair->binary)) - return WHY("crypto_sign() failed"); - - DEBUGF(keyring, "Sending SID:SAS mapping, %zd bytes, %s:%"PRImdp_port_t" -> %s:%"PRImdp_port_t, - ob_position(response_payload), - alloca_tohex_sid_t(header->destination->sid), header->destination_port, - alloca_tohex_sid_t(header->source->sid), header->source_port - ); - - ob_flip(response_payload); - int ret = overlay_send_frame(&response, response_payload); - ob_free(response_payload); - return ret; -} - // someone else is claiming to be me on this network // politely request that they release my identity int keyring_send_unlock(struct subscriber *subscriber) @@ -1846,138 +1773,6 @@ int keyring_send_unlock(struct subscriber *subscriber) return ret; } -static int keyring_send_challenge(struct subscriber *source, struct subscriber *dest) -{ - struct internal_mdp_header header; - bzero(&header, sizeof header); - - header.source = source; - header.destination = dest; - header.source_port = MDP_PORT_KEYMAPREQUEST; - header.destination_port = MDP_PORT_KEYMAPREQUEST; - header.qos = OQ_MESH_MANAGEMENT; - - time_ms_t now = gettime_ms(); - - struct keyring_challenge *challenge = source->identity->challenge; - if (challenge && challenge->expires < now){ - free(challenge); - challenge = NULL; - } - if (!challenge){ - challenge = emalloc_zero(sizeof(struct keyring_challenge)); - if (challenge){ - // give the remote party 15s to respond (should this could be based on measured link latency?) - challenge->expires = now + 15000; - randombytes_buf(challenge->challenge, sizeof(challenge->challenge)); - } - } - source->identity->challenge = challenge; - if (!challenge) - return -1; - - struct overlay_buffer *payload = ob_new(); - ob_append_byte(payload, UNLOCK_CHALLENGE); - ob_append_bytes(payload, challenge->challenge, sizeof challenge->challenge); - - DEBUGF(keyring, "Sending Unlock challenge for sid %s", alloca_tohex_sid_t(source->sid)); - - ob_flip(payload); - int ret = overlay_send_frame(&header, payload); - ob_free(payload); - return ret; -} - -static int keyring_respond_challenge(struct subscriber *subscriber, struct overlay_buffer *payload) -{ - if (!subscriber->identity) - return WHY("Cannot unlock an identity we don't have in our keyring"); - if (subscriber->reachable==REACHABLE_SELF) - return 0; - - struct internal_mdp_header header; - bzero(&header, sizeof header); - - header.source = get_my_subscriber(); - header.destination = subscriber; - header.source_port = MDP_PORT_KEYMAPREQUEST; - header.destination_port = MDP_PORT_KEYMAPREQUEST; - header.qos = OQ_MESH_MANAGEMENT; - - uint8_t buff[MDP_MTU]; - struct overlay_buffer *response = ob_static(buff, sizeof buff); - ob_append_byte(response, UNLOCK_RESPONSE); - ob_append_bytes(response, ob_current_ptr(payload), ob_remaining(payload)); - - size_t len = ob_position(response); - if (keyring_sign_message(subscriber->identity, ob_ptr(response), sizeof(buff), &len)) - return -1; - - ob_append_space(response, len - ob_position(response)); - DEBUGF(keyring, "Responding to Unlock challenge for sid %s", alloca_tohex_sid_t(subscriber->sid)); - ob_flip(response); - int ret = overlay_send_frame(&header, response); - ob_free(response); - return ret; -} - -static int keyring_process_challenge(keyring_file *k, struct subscriber *subscriber, struct overlay_buffer *payload) -{ - int ret=-1; - time_ms_t now = gettime_ms(); - - struct keyring_challenge *challenge = subscriber->identity->challenge; - - if (challenge){ - subscriber->identity->challenge = NULL; - size_t len = ob_remaining(payload)+1; - // verify that the payload was signed by our key and contains the same challenge bytes that we sent - // TODO allow for signing the challenge bytes without sending them twice? - if (challenge->expires >= now - && crypto_verify_message(subscriber, ob_current_ptr(payload) -1, &len) == 0 - && len - 1 == sizeof(challenge->challenge) - && memcmp(ob_current_ptr(payload), challenge->challenge, sizeof(challenge->challenge)) == 0){ - - keyring_release_subscriber(k, &subscriber->sid); - ret=0; - }else{ - WHY("Challenge failed"); - } - free(challenge); - } - return ret; -} - -DEFINE_BINDING(MDP_PORT_KEYMAPREQUEST, keyring_mapping_request); -static int keyring_mapping_request(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - - /* The authcryption of the MDP frame proves that the SAS key is owned by the - owner of the SID, and so is absolutely compulsory. */ - if (header->crypt_flags&(MDP_NOCRYPT|MDP_NOSIGN)) - return WHY("mapping requests must be performed under authcryption"); - - switch(ob_get(payload)){ - case KEYTYPE_CRYPTOSIGN: - if (ob_remaining(payload)==0) - return keyring_respond_id(header); - return keyring_store_id(header, payload); - break; - case UNLOCK_REQUEST: - { - size_t len = ob_remaining(payload) +1; - if (crypto_verify_message(header->destination, ob_current_ptr(payload) -1, &len)) - return WHY("Signature check failed"); - } - return keyring_send_challenge(header->destination, header->source); - case UNLOCK_CHALLENGE: - return keyring_respond_challenge(header->source, payload); - case UNLOCK_RESPONSE: - return keyring_process_challenge(keyring, header->destination, payload); - } - return WHY("Not implemented"); -} - int keyring_send_identity_request(struct subscriber *subscriber){ if (subscriber->id_valid) return 0; diff --git a/keyring.h b/keyring.h index e8d3ad02..536f75f8 100644 --- a/keyring.h +++ b/keyring.h @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef __SERVAL_DNA__KEYRING_H #define __SERVAL_DNA__KEYRING_H +#include "serval_types.h" // for sid_t +#include "os.h" // for time_ms_t + struct cli_parsed; #include "xprintf.h" diff --git a/keyring_cli.c b/keyring_cli.c index 403ff02f..17bcda0e 100644 --- a/keyring_cli.c +++ b/keyring_cli.c @@ -29,6 +29,8 @@ #include "commandline.h" #include "keyring.h" +DEFINE_FEATURE(cli_keyring); + DEFINE_CMD(app_keyring_create, 0, "Create a new keyring file.", "keyring","create"); diff --git a/keyring_restful.c b/keyring_restful.c index 87efcc94..8abc0976 100644 --- a/keyring_restful.c +++ b/keyring_restful.c @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "keyring.h" #include "strbuf_helpers.h" +DEFINE_FEATURE(http_rest_keyring); + #define keyring_TOKEN_STRLEN (BASE64_ENCODED_LEN(sizeof(rhizome_bid_t) + sizeof(uint64_t))) #define alloca_keyring_token(bid, offset) keyring_ token_to_str(alloca(keyring_TOKEN_STRLEN + 1), (bid), (offset)) diff --git a/log.c b/log.c index 24afa69f..1d4cb9b0 100644 --- a/log.c +++ b/log.c @@ -34,7 +34,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include -#include "serval.h" +#include "version_servald.h" +#include "instance.h" #include "log.h" #include "net.h" #include "os.h" @@ -102,11 +103,6 @@ static time_t _log_file_start_time; static char _log_file_buf[8192]; static struct strbuf _log_file_strbuf = STRUCT_STRBUF_EMPTY; -/* The log context is a string that can be set as a prefix to all subsequent log messages. - */ -static char _log_context[16]; -struct strbuf log_context = STRUCT_STRBUF_INIT_STATIC(_log_context); - #ifdef ANDROID /* Static variables for sending log output to the Android log. * @@ -227,9 +223,9 @@ static void _log_prefix_context(_log_iterator *it) xprintf(it->xpf, "%s.%03u ", buf, (unsigned int)it->tv.tv_usec / 1000); } } - if (_log_context[0]) { + if (strbuf_len(&log_context)) { xputs("[", it->xpf); - xputs(_log_context, it->xpf); + xputs(strbuf_str(&log_context), it->xpf); xputs("] ", it->xpf); } } diff --git a/log_cli.c b/log_cli.c new file mode 100644 index 00000000..b37b07a1 --- /dev/null +++ b/log_cli.c @@ -0,0 +1,42 @@ +/* +Serval DNA logging +Copyright (C) 2014-2015 Serval Project Inc. +Copyright (C) 2016 Flinders University + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "feature.h" +#include "commandline.h" +#include "log.h" +#include "conf.h" // for IF_DEBUG() + +DEFINE_FEATURE(cli_log); + +DEFINE_CMD(app_log, CLIFLAG_PERMISSIVE_CONFIG, + "Log the supplied message at given level.", + "log","error|warn|hint|info|debug",""); +static int app_log(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) +{ + DEBUG_cli_parsed(verbose, parsed); + assert(parsed->argc == 3); + const char *lvl = parsed->args[1]; + const char *msg = parsed->args[2]; + int level = string_to_log_level(lvl); + if (level == LOG_LEVEL_INVALID) + return WHYF("invalid log level: %s", lvl); + logMessage(level, __NOWHERE__, "%s", msg); + return 0; +} diff --git a/meshms_cli.c b/meshms_cli.c index 9e6d2d1b..87ff7406 100644 --- a/meshms_cli.c +++ b/meshms_cli.c @@ -11,6 +11,8 @@ #include "str.h" #include "numeric_str.h" +DEFINE_FEATURE(cli_meshms); + // output the list of existing conversations for a given local identity DEFINE_CMD(app_meshms_conversations, 0, "List MeshMS threads that include ", diff --git a/meshms_restful.c b/meshms_restful.c index f7fcb700..a85b0539 100644 --- a/meshms_restful.c +++ b/meshms_restful.c @@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "base64.h" #include "strbuf_helpers.h" +DEFINE_FEATURE(http_rest_meshms); + DECLARE_HANDLER("/restful/meshms/", restful_meshms_); static void on_rhizome_bundle_added(httpd_request *r, rhizome_manifest *m); diff --git a/monitor-cli.c b/monitor-cli.c index eafc3bbe..1eb8136c 100644 --- a/monitor-cli.c +++ b/monitor-cli.c @@ -32,7 +32,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "monitor-client.h" #include "commandline.h" -int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *UNUSED(context)) +DEFINE_FEATURE(cli_monitor); + +static int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *UNUSED(context)) { int i; printf("%s",cmd); diff --git a/msp_proxy.c b/msp_proxy.c index 9a3d7888..69aaee22 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -561,6 +561,8 @@ void sigQuit(int UNUSED(signal)) proxy_state->quit=1; } +DEFINE_FEATURE(cli_msp_proxy); + DEFINE_CMD(app_msp_connection, 0, "Listen for incoming connections", "msp", "listen", "[--once]", "[--forward=]", "[--service=]", ""); diff --git a/network_cli.c b/network_cli.c index 38b18410..c5eef1c8 100644 --- a/network_cli.c +++ b/network_cli.c @@ -34,6 +34,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "uri.h" #include "overlay_buffer.h" +DEFINE_FEATURE(cli_network); + DEFINE_CMD(app_mdp_ping, 0, "Attempts to ping specified node via Mesh Datagram Protocol (MDP).", "mdp","ping","[--interval=]","[--timeout=]","[--wait-for-duplicates]", diff --git a/overlay_address.h b/overlay_address.h index 901be9b7..f5a1195f 100644 --- a/overlay_address.h +++ b/overlay_address.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define __SERVAL_DNA__OVERLAY_ADDRESS_H #include "constants.h" +#include "serval_types.h" // for sid_t #include "os.h" // for time_ms_t #include "socket.h" #include "nibble_tree.h" diff --git a/overlay_buffer.h b/overlay_buffer.h index 10b5313f..56c0f969 100644 --- a/overlay_buffer.h +++ b/overlay_buffer.h @@ -20,6 +20,10 @@ #ifndef __SERVAL_DNA___OVERLAY_BUFFER_H #define __SERVAL_DNA___OVERLAY_BUFFER_H +#include // for size_t +#include +#include "whence.h" + struct overlay_buffer { unsigned char *bytes; diff --git a/overlay_link.c b/overlay_link.c index 16da2084..1b622d10 100644 --- a/overlay_link.c +++ b/overlay_link.c @@ -1,5 +1,6 @@ /* Serval DNA MDP overlay network link tracking +Copyright (C) 2016 Flinders University Copyright (C) 2012-2013 Serval Project Inc. Copyright (C) 2010-2012 Paul Gardner-Stephen @@ -79,7 +80,7 @@ int set_reachable(struct subscriber *subscriber, return 1; } -int resolve_name(const char *name, struct in_addr *addr){ +static int resolve_name(const char *name, struct in_addr *addr){ // TODO this can block, move to worker thread. IN(); int ret=0; @@ -139,32 +140,6 @@ struct network_destination *load_subscriber_address(struct subscriber *subscribe return create_unicast_destination(&addr, interface); } -/* Collection of unicast echo responses to detect working links */ -DEFINE_BINDING(MDP_PORT_PROBE, overlay_mdp_service_probe); -static int overlay_mdp_service_probe(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - IN(); - if (header->source_port!=MDP_PORT_ECHO){ - WARN("Probe packets should be returned from remote echo port"); - RETURN(-1); - } - DEBUGF(overlayrouting, "Received probe response from %s", alloca_tohex_sid_t(header->source->sid)); - - if (header->source->reachable == REACHABLE_SELF) - RETURN(0); - - uint8_t interface = ob_get(payload); - struct socket_address addr; - addr.addrlen = ob_remaining(payload); - - if (addr.addrlen > sizeof(addr.store)) - RETURN(WHY("Badly formatted probe packet")); - - ob_get_bytes(payload, (unsigned char*)&addr.addr, addr.addrlen); - - RETURN(link_unicast_ack(header->source, &overlay_interfaces[interface], &addr)); - OUT(); -} int overlay_send_probe(struct subscriber *peer, struct network_destination *destination, int queue){ time_ms_t now = gettime_ms(); @@ -207,95 +182,6 @@ int overlay_send_probe(struct subscriber *peer, struct network_destination *dest return 0; } -// append the address of a unicast link into a packet buffer -static void overlay_append_unicast_address(struct subscriber *subscriber, struct overlay_buffer *buff) -{ - if ( subscriber->destination - && subscriber->destination->unicast - && subscriber->destination->address.addr.sa_family==AF_INET - ) { - overlay_address_append(NULL, buff, subscriber); - ob_append_ui32(buff, subscriber->destination->address.inet.sin_addr.s_addr); - ob_append_ui16(buff, subscriber->destination->address.inet.sin_port); - DEBUGF(overlayrouting, "Added STUN info for %s", alloca_tohex_sid_t(subscriber->sid)); - }else{ - DEBUGF(overlayrouting, "Unable to give address of %s, %d", alloca_tohex_sid_t(subscriber->sid),subscriber->reachable); - } -} - -DEFINE_BINDING(MDP_PORT_STUNREQ, overlay_mdp_service_stun_req); -static int overlay_mdp_service_stun_req(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - DEBUGF(overlayrouting, "Processing STUN request from %s", alloca_tohex_sid_t(header->source->sid)); - - struct internal_mdp_header reply; - bzero(&reply, sizeof reply); - - mdp_init_response(header, &reply); - reply.qos = OQ_MESH_MANAGEMENT; - - struct overlay_buffer *replypayload = ob_new(); - ob_limitsize(replypayload, MDP_MTU); - - ob_checkpoint(replypayload); - while (ob_remaining(payload) > 0) { - struct subscriber *subscriber=NULL; - if (overlay_address_parse(NULL, payload, &subscriber)) - break; - if (!subscriber){ - DEBUGF(overlayrouting, "Unknown subscriber"); - continue; - } - overlay_append_unicast_address(subscriber, replypayload); - if (ob_overrun(payload)) - break; - ob_checkpoint(replypayload); - } - ob_rewind(replypayload); - - if (ob_position(replypayload)){ - DEBUGF(overlayrouting, "Sending reply"); - ob_flip(replypayload); - overlay_send_frame(&reply, replypayload); - } - ob_free(replypayload); - return 0; -} - -DEFINE_BINDING(MDP_PORT_STUN, overlay_mdp_service_stun); -static int overlay_mdp_service_stun(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - DEBUGF(overlayrouting, "Processing STUN info from %s", alloca_tohex_sid_t(header->source->sid)); - - while(ob_remaining(payload)>0){ - struct subscriber *subscriber=NULL; - - // TODO explain addresses, link expiry time, resolve differences between addresses... - - if (overlay_address_parse(NULL, payload, &subscriber)){ - break; - } - struct socket_address addr; - addr.addrlen = sizeof(addr.inet); - addr.inet.sin_family = AF_INET; - addr.inet.sin_addr.s_addr = ob_get_ui32(payload); - addr.inet.sin_port = ob_get_ui16(payload); - - if (!subscriber || (subscriber->reachable&REACHABLE_DIRECT)) - continue; - - // only trust stun responses from our directory service or about the packet sender. - if (directory_service == header->source || subscriber == header->source){ - struct network_destination *destination = create_unicast_destination(&addr, NULL); - if (destination){ - overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT); - release_destination_ref(destination); - } - } - } - return 0; -} - int overlay_send_stun_request(struct subscriber *server, struct subscriber *request){ // don't bother with a stun request if the peer is already reachable directly if (request->reachable&REACHABLE_DIRECT) diff --git a/overlay_mdp_dnalookup.c b/overlay_mdp_dnalookup.c new file mode 100644 index 00000000..b937cf2d --- /dev/null +++ b/overlay_mdp_dnalookup.c @@ -0,0 +1,86 @@ +/* +Serval DNA MDP lookup service +Copyright (C) 2016 Flinders University +Copyright (C) 2010-2015 Serval Project Inc. +Copyright (C) 2010-2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "serval.h" +#include "conf.h" +#include "debug.h" +#include "overlay_buffer.h" + +DEFINE_BINDING(MDP_PORT_DNALOOKUP, overlay_mdp_service_dnalookup); +static int overlay_mdp_service_dnalookup(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + IN(); + keyring_iterator it; + keyring_iterator_start(keyring, &it); + char did[64+1]; + + int pll=ob_remaining(payload); + if (pll>64) pll=64; + + /* get did from the packet */ + if (pll<1) + RETURN(WHY("Empty DID in DNA resolution request")); + + ob_get_bytes(payload, (unsigned char *)did, pll); + did[pll]=0; + + DEBUG(mdprequests, "MDP_PORT_DNALOOKUP"); + + int results=0; + while(keyring_find_did(&it, did)) + { + /* package DID and Name into reply (we include the DID because + it could be a wild-card DID search, but the SID is implied + in the source address of our reply). */ + if (it.keypair->private_key_len > DID_MAXSIZE) + /* skip excessively long DID records */ + continue; + + struct subscriber *subscriber = it.identity->subscriber; + const char *unpackedDid = (const char *) it.keypair->private_key; + const char *name = (const char *)it.keypair->public_key; + // URI is sid://SIDHEX/DID + strbuf b = strbuf_alloca(SID_STRLEN + DID_MAXSIZE + 10); + strbuf_puts(b, "sid://"); + strbuf_tohex(b, SID_STRLEN, subscriber->sid.binary); + strbuf_puts(b, "/local/"); + strbuf_puts(b, unpackedDid); + overlay_mdp_dnalookup_reply(header->source, header->source_port, subscriber, strbuf_str(b), unpackedDid, name); + results++; + } + if (!results) { + /* No local results, so see if servald has been configured to use + a DNA-helper that can provide additional mappings. This provides + a generalised interface for resolving telephone numbers into URIs. + The first use will be for resolving DIDs to SIP addresses for + OpenBTS boxes run by the OTI/Commotion project. + + The helper is run asynchronously, and the replies will be delivered + when results become available, so this function will return + immediately, so as not to cause blockages and delays in servald. + */ + dna_helper_enqueue(header->source, header->source_port, did); + monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n", + alloca_tohex_sid_t(header->source->sid), header->source_port, + did); + } + RETURN(0); +} diff --git a/overlay_mdp_echo.c b/overlay_mdp_echo.c new file mode 100644 index 00000000..21500f2b --- /dev/null +++ b/overlay_mdp_echo.c @@ -0,0 +1,42 @@ +/* +Serval DNA MDP echo service +Copyright (C) 2016 Flinders University +Copyright (C) 2012-2015 Serval Project Inc. +Copyright (C) 2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "mdp_client.h" +#include "overlay_packet.h" +#include "fdqueue.h" + +DEFINE_BINDING(MDP_PORT_ECHO, overlay_mdp_service_echo); +static int overlay_mdp_service_echo(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + IN(); + + if (header->source_port == MDP_PORT_ECHO) + RETURN(WHY("Prevented infinite echo loop")); + + struct internal_mdp_header response_header; + bzero(&response_header, sizeof response_header); + + mdp_init_response(header, &response_header); + // keep all defaults + + RETURN(overlay_send_frame(&response_header, payload)); + OUT(); +} diff --git a/overlay_mdp_keymaprequest.c b/overlay_mdp_keymaprequest.c new file mode 100644 index 00000000..cd0fb381 --- /dev/null +++ b/overlay_mdp_keymaprequest.c @@ -0,0 +1,229 @@ +/* +Serval DNA keyring MDP key map request +Copyright (C) 2016 Flinders University +Copyright (C) 2010-2015 Serval Project Inc. +Copyright (C) 2010-2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "keyring.h" +#include "conf.h" +#include "debug.h" +#include "overlay_buffer.h" +#include "crypto.h" +#include "mem.h" + +static int keyring_respond_id(struct internal_mdp_header *header) +{ + keyring_identity *id = header->destination->identity; + + /* It's a request, so find the SAS for the SID the request was addressed to, + use that to sign that SID, and then return it in an authcrypted frame. */ + struct internal_mdp_header response; + bzero(&response, sizeof response); + mdp_init_response(header, &response); + + uint8_t buff[MDP_MTU]; + struct overlay_buffer *response_payload = ob_static(buff, sizeof buff); + ob_limitsize(response_payload, sizeof buff); + + ob_append_byte(response_payload, KEYTYPE_CRYPTOSIGN); + ob_append_bytes(response_payload, id->sign_keypair->public_key.binary, crypto_sign_PUBLICKEYBYTES); + uint8_t *sig = ob_append_space(response_payload, crypto_sign_BYTES); + + if (crypto_sign_detached(sig, NULL, header->destination->sid.binary, SID_SIZE, id->sign_keypair->binary)) + return WHY("crypto_sign() failed"); + + DEBUGF(keyring, "Sending SID:SAS mapping, %zd bytes, %s:%"PRImdp_port_t" -> %s:%"PRImdp_port_t, + ob_position(response_payload), + alloca_tohex_sid_t(header->destination->sid), header->destination_port, + alloca_tohex_sid_t(header->source->sid), header->source_port + ); + + ob_flip(response_payload); + int ret = overlay_send_frame(&response, response_payload); + ob_free(response_payload); + return ret; +} + +static int keyring_store_id(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + if (header->source->id_valid){ + DEBUGF(keyring, "Ignoring SID:SAS mapping for %s, already have one", alloca_tohex_sid_t(header->source->sid)); + return 0; + } + size_t len = ob_remaining(payload); + + DEBUGF(keyring, "Received SID:SAS mapping, %zd bytes", len); + + if (ob_remaining(payload) < IDENTITY_SIZE + crypto_sign_BYTES) + return WHY("Truncated key mapping announcement?"); + + const uint8_t *id_public = ob_get_bytes_ptr(payload, IDENTITY_SIZE); + const uint8_t *compactsignature = ob_get_bytes_ptr(payload, crypto_sign_BYTES); + + if (crypto_sign_verify_detached(compactsignature, header->source->sid.binary, SID_SIZE, id_public)) + return WHY("SID:SAS mapping verification signature does not verify"); + + // test if the signing key can be used to derive the sid + sid_t sid; + if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id_public)==0 + && memcmp(&sid, &header->source->sid, sizeof sid) == 0) + header->source->id_combined=1; + + /* now store it */ + bcopy(id_public, &header->source->id_public, IDENTITY_SIZE); + header->source->id_valid=1; + header->source->id_last_request=-1; + + DEBUGF(keyring, "Stored SID:SAS mapping, SID=%s to SAS=%s", + alloca_tohex_sid_t(header->source->sid), + alloca_tohex_identity_t(&header->source->id_public) + ); + return 0; +} + +static int keyring_send_challenge(struct subscriber *source, struct subscriber *dest) +{ + struct internal_mdp_header header; + bzero(&header, sizeof header); + + header.source = source; + header.destination = dest; + header.source_port = MDP_PORT_KEYMAPREQUEST; + header.destination_port = MDP_PORT_KEYMAPREQUEST; + header.qos = OQ_MESH_MANAGEMENT; + + time_ms_t now = gettime_ms(); + + struct keyring_challenge *challenge = source->identity->challenge; + if (challenge && challenge->expires < now){ + free(challenge); + challenge = NULL; + } + if (!challenge){ + challenge = emalloc_zero(sizeof(struct keyring_challenge)); + if (challenge){ + // give the remote party 15s to respond (should this could be based on measured link latency?) + challenge->expires = now + 15000; + randombytes_buf(challenge->challenge, sizeof(challenge->challenge)); + } + } + source->identity->challenge = challenge; + if (!challenge) + return -1; + + struct overlay_buffer *payload = ob_new(); + ob_append_byte(payload, UNLOCK_CHALLENGE); + ob_append_bytes(payload, challenge->challenge, sizeof challenge->challenge); + + DEBUGF(keyring, "Sending Unlock challenge for sid %s", alloca_tohex_sid_t(source->sid)); + + ob_flip(payload); + int ret = overlay_send_frame(&header, payload); + ob_free(payload); + return ret; +} + +static int keyring_respond_challenge(struct subscriber *subscriber, struct overlay_buffer *payload) +{ + if (!subscriber->identity) + return WHY("Cannot unlock an identity we don't have in our keyring"); + if (subscriber->reachable==REACHABLE_SELF) + return 0; + + struct internal_mdp_header header; + bzero(&header, sizeof header); + + header.source = get_my_subscriber(); + header.destination = subscriber; + header.source_port = MDP_PORT_KEYMAPREQUEST; + header.destination_port = MDP_PORT_KEYMAPREQUEST; + header.qos = OQ_MESH_MANAGEMENT; + + uint8_t buff[MDP_MTU]; + struct overlay_buffer *response = ob_static(buff, sizeof buff); + ob_append_byte(response, UNLOCK_RESPONSE); + ob_append_bytes(response, ob_current_ptr(payload), ob_remaining(payload)); + + size_t len = ob_position(response); + if (keyring_sign_message(subscriber->identity, ob_ptr(response), sizeof(buff), &len)) + return -1; + + ob_append_space(response, len - ob_position(response)); + DEBUGF(keyring, "Responding to Unlock challenge for sid %s", alloca_tohex_sid_t(subscriber->sid)); + ob_flip(response); + int ret = overlay_send_frame(&header, response); + ob_free(response); + return ret; +} + +static int keyring_process_challenge(keyring_file *k, struct subscriber *subscriber, struct overlay_buffer *payload) +{ + int ret=-1; + time_ms_t now = gettime_ms(); + + struct keyring_challenge *challenge = subscriber->identity->challenge; + + if (challenge){ + subscriber->identity->challenge = NULL; + size_t len = ob_remaining(payload)+1; + // verify that the payload was signed by our key and contains the same challenge bytes that we sent + // TODO allow for signing the challenge bytes without sending them twice? + if (challenge->expires >= now + && crypto_verify_message(subscriber, ob_current_ptr(payload) -1, &len) == 0 + && len - 1 == sizeof(challenge->challenge) + && memcmp(ob_current_ptr(payload), challenge->challenge, sizeof(challenge->challenge)) == 0){ + + keyring_release_subscriber(k, &subscriber->sid); + ret=0; + }else{ + WHY("Challenge failed"); + } + free(challenge); + } + return ret; +} + +DEFINE_BINDING(MDP_PORT_KEYMAPREQUEST, keyring_mapping_request); +static int keyring_mapping_request(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + + /* The authcryption of the MDP frame proves that the SAS key is owned by the + owner of the SID, and so is absolutely compulsory. */ + if (header->crypt_flags&(MDP_NOCRYPT|MDP_NOSIGN)) + return WHY("mapping requests must be performed under authcryption"); + + switch(ob_get(payload)){ + case KEYTYPE_CRYPTOSIGN: + if (ob_remaining(payload)==0) + return keyring_respond_id(header); + return keyring_store_id(header, payload); + break; + case UNLOCK_REQUEST: + { + size_t len = ob_remaining(payload) +1; + if (crypto_verify_message(header->destination, ob_current_ptr(payload) -1, &len)) + return WHY("Signature check failed"); + } + return keyring_send_challenge(header->destination, header->source); + case UNLOCK_CHALLENGE: + return keyring_respond_challenge(header->source, payload); + case UNLOCK_RESPONSE: + return keyring_process_challenge(keyring, header->destination, payload); + } + return WHY("Not implemented"); +} diff --git a/overlay_mdp_rhizome.c b/overlay_mdp_rhizome.c new file mode 100644 index 00000000..2c26fa52 --- /dev/null +++ b/overlay_mdp_rhizome.c @@ -0,0 +1,185 @@ +/* +Serval DNA basic MDP services +Copyright (C) 2016 Flinders University +Copyright (C) 2010-2015 Serval Project Inc. +Copyright (C) 2010-2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "serval.h" +#include "conf.h" +#include "overlay_buffer.h" +#include "rhizome.h" +#include "mdp_client.h" + +static int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength) +{ + IN(); + if (!is_rhizome_mdp_server_running()) + RETURN(-1); + if (blockLength<=0 || blockLength>1024) + RETURN(WHYF("Invalid block length %d", blockLength)); + + DEBUGF(rhizome_tx, "Requested blocks for bid=%s, ver=%"PRIu64" @%"PRIx64" bitmap %x", alloca_tohex_rhizome_bid_t(*bid), version, fileOffset, bitmap); + + struct internal_mdp_header header; + bzero(&header, sizeof header); + + uint8_t buff[MDP_MTU]; + struct overlay_buffer *payload = ob_static(buff, sizeof(buff)); + + // Reply is broadcast, so we cannot authcrypt, and signing is too time consuming + // for low devices. The result is that an attacker can prevent rhizome transfers + // if they want to by injecting fake blocks. The alternative is to not broadcast + // back replies, and then we can authcrypt. + // multiple receivers starting at different times, we really need merkle-tree hashing. + // so multiple receivers is not realistic for now. So use non-broadcast unicode + // for now would seem the safest. But that would stop us from allowing multiple + // receivers in the special case where additional nodes begin listening in from the + // beginning. + + header.crypt_flags = MDP_FLAG_NO_CRYPT | MDP_FLAG_NO_SIGN; + header.source = get_my_subscriber(); + header.source_port = MDP_PORT_RHIZOME_RESPONSE; + + if (dest && (dest->reachable==REACHABLE_UNICAST || dest->reachable==REACHABLE_INDIRECT)){ + // if we get a request from a peer that we can only talk to via unicast, send data via unicast too. + header.destination = dest; + }else{ + // send replies to broadcast so that others can hear blocks and record them + // (not that preemptive listening is implemented yet). + header.ttl = 1; + } + + header.destination_port = MDP_PORT_RHIZOME_RESPONSE; + header.qos = OQ_OPPORTUNISTIC; + + int i; + for(i=0;i<32;i++){ + if (bitmap&(1u<<(31-i))) + continue; + + if (overlay_queue_remaining(header.qos) < 10) + break; + + // calculate and set offset of block + uint64_t offset = fileOffset+i*blockLength; + ob_clear(payload); + ob_append_byte(payload, 'B'); // contains blocks + // include 16 bytes of BID prefix for identification + ob_append_bytes(payload, bid->binary, 16); + // and version of manifest (in the correct byte order) + ob_append_ui64_rv(payload, version); + + ob_append_ui64_rv(payload, offset); + + ssize_t bytes_read = rhizome_read_cached(bid, version, gettime_ms()+5000, offset, ob_current_ptr(payload), blockLength); + if (bytes_read<=0) + break; + + ob_append_space(payload, bytes_read); + + // Mark the last block of the file, if required + if ((size_t)bytes_read < blockLength) + ob_set(payload, 0, 'T'); + + // send packet + ob_flip(payload); + if (overlay_send_frame(&header, payload)) + break; + } + ob_free(payload); + + RETURN(0); + OUT(); +} + +DEFINE_BINDING(MDP_PORT_RHIZOME_REQUEST, overlay_mdp_service_rhizomerequest); +static int overlay_mdp_service_rhizomerequest(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + const rhizome_bid_t *bidp = (const rhizome_bid_t *) ob_get_bytes_ptr(payload, sizeof bidp->binary); + // Note, was originally built using read_uint64 which has reverse byte order of ob_get_ui64 + uint64_t version = ob_get_ui64_rv(payload); + uint64_t fileOffset = ob_get_ui64_rv(payload); + uint32_t bitmap = ob_get_ui32_rv(payload); + uint16_t blockLength = ob_get_ui16_rv(payload); + if (ob_overrun(payload)) + return -1; + return rhizome_mdp_send_block(header->source, bidp, version, fileOffset, bitmap, blockLength); +} + +DEFINE_BINDING(MDP_PORT_RHIZOME_RESPONSE, overlay_mdp_service_rhizomeresponse); +static int overlay_mdp_service_rhizomeresponse(struct internal_mdp_header *UNUSED(header), struct overlay_buffer *payload) +{ + IN(); + + int type=ob_get(payload); + + DEBUGF(rhizome_mdp_rx, "Received Rhizome over MDP block, type=%02x",type); + + switch (type) { + case 'B': /* data block */ + case 'T': /* terminal data block */ + { + unsigned char *bidprefix=ob_get_bytes_ptr(payload, 16); + uint64_t version=ob_get_ui64_rv(payload); + uint64_t offset=ob_get_ui64_rv(payload); + if (ob_overrun(payload)) + RETURN(WHYF("Payload too short")); + size_t count = ob_remaining(payload); + unsigned char *bytes=ob_current_ptr(payload); + + DEBUGF(rhizome_mdp_rx, "bidprefix=%02x%02x%02x%02x*, offset=%"PRId64", count=%zu", + bidprefix[0],bidprefix[1],bidprefix[2],bidprefix[3],offset,count); + + /* Now see if there is a slot that matches. If so, then + see if the bytes are in the window, and write them. + + If there is not matching slot, then consider setting + a slot to capture this files as it is being requested + by someone else. + */ + rhizome_received_content(bidprefix,version,offset, count, bytes); + + RETURN(0); + } + break; + } + + RETURN(-1); + OUT(); +} + +DEFINE_BINDING(MDP_PORT_RHIZOME_MANIFEST_REQUEST, overlay_mdp_service_manifest_requests); +static int overlay_mdp_service_manifest_requests(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + while (ob_remaining(payload)) { + const unsigned char *bar = ob_get_bytes_ptr(payload, RHIZOME_BAR_BYTES); + if (!bar) + break; + rhizome_manifest *m = rhizome_new_manifest(); + if (!m) + return WHY("Unable to allocate manifest"); + if (rhizome_retrieve_manifest_by_prefix(&bar[RHIZOME_BAR_PREFIX_OFFSET], RHIZOME_BAR_PREFIX_BYTES, m)==RHIZOME_BUNDLE_STATUS_SAME){ + rhizome_advertise_manifest(header->source, m); + // pre-emptively send the payload if it will fit in a single packet + if (m->filesize > 0 && m->filesize <= 1024) + rhizome_mdp_send_block(header->source, &m->keypair.public_key, m->version, 0, 0, m->filesize); + } + rhizome_manifest_free(m); + } + return 0; +} diff --git a/overlay_mdp_services.c b/overlay_mdp_services.c deleted file mode 100644 index 1921c952..00000000 --- a/overlay_mdp_services.c +++ /dev/null @@ -1,383 +0,0 @@ -/* -Copyright (C) 2010-2012 Paul Gardner-Stephen -Copyright (C) 2010-2013 Serval Project Inc. - -This program 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 -of the License, or (at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include "serval.h" -#include "conf.h" -#include "str.h" -#include "strbuf.h" -#include "overlay_buffer.h" -#include "overlay_address.h" -#include "overlay_packet.h" -#include "mdp_client.h" -#include "rhizome.h" -#include "crypto.h" -#include "log.h" -#include "debug.h" -#include "keyring.h" -#include "dataformats.h" -#include "route_link.h" - -int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength) -{ - IN(); - if (!is_rhizome_mdp_server_running()) - RETURN(-1); - if (blockLength<=0 || blockLength>1024) - RETURN(WHYF("Invalid block length %d", blockLength)); - - DEBUGF(rhizome_tx, "Requested blocks for bid=%s, ver=%"PRIu64" @%"PRIx64" bitmap %x", alloca_tohex_rhizome_bid_t(*bid), version, fileOffset, bitmap); - - struct internal_mdp_header header; - bzero(&header, sizeof header); - - uint8_t buff[MDP_MTU]; - struct overlay_buffer *payload = ob_static(buff, sizeof(buff)); - - // Reply is broadcast, so we cannot authcrypt, and signing is too time consuming - // for low devices. The result is that an attacker can prevent rhizome transfers - // if they want to by injecting fake blocks. The alternative is to not broadcast - // back replies, and then we can authcrypt. - // multiple receivers starting at different times, we really need merkle-tree hashing. - // so multiple receivers is not realistic for now. So use non-broadcast unicode - // for now would seem the safest. But that would stop us from allowing multiple - // receivers in the special case where additional nodes begin listening in from the - // beginning. - - header.crypt_flags = MDP_FLAG_NO_CRYPT | MDP_FLAG_NO_SIGN; - header.source = get_my_subscriber(); - header.source_port = MDP_PORT_RHIZOME_RESPONSE; - - if (dest && (dest->reachable==REACHABLE_UNICAST || dest->reachable==REACHABLE_INDIRECT)){ - // if we get a request from a peer that we can only talk to via unicast, send data via unicast too. - header.destination = dest; - }else{ - // send replies to broadcast so that others can hear blocks and record them - // (not that preemptive listening is implemented yet). - header.ttl = 1; - } - - header.destination_port = MDP_PORT_RHIZOME_RESPONSE; - header.qos = OQ_OPPORTUNISTIC; - - int i; - for(i=0;i<32;i++){ - if (bitmap&(1u<<(31-i))) - continue; - - if (overlay_queue_remaining(header.qos) < 10) - break; - - // calculate and set offset of block - uint64_t offset = fileOffset+i*blockLength; - ob_clear(payload); - ob_append_byte(payload, 'B'); // contains blocks - // include 16 bytes of BID prefix for identification - ob_append_bytes(payload, bid->binary, 16); - // and version of manifest (in the correct byte order) - ob_append_ui64_rv(payload, version); - - ob_append_ui64_rv(payload, offset); - - ssize_t bytes_read = rhizome_read_cached(bid, version, gettime_ms()+5000, offset, ob_current_ptr(payload), blockLength); - if (bytes_read<=0) - break; - - ob_append_space(payload, bytes_read); - - // Mark the last block of the file, if required - if ((size_t)bytes_read < blockLength) - ob_set(payload, 0, 'T'); - - // send packet - ob_flip(payload); - if (overlay_send_frame(&header, payload)) - break; - } - ob_free(payload); - - RETURN(0); - OUT(); -} - -DEFINE_BINDING(MDP_PORT_RHIZOME_REQUEST, overlay_mdp_service_rhizomerequest); -static int overlay_mdp_service_rhizomerequest(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - const rhizome_bid_t *bidp = (const rhizome_bid_t *) ob_get_bytes_ptr(payload, sizeof bidp->binary); - // Note, was originally built using read_uint64 which has reverse byte order of ob_get_ui64 - uint64_t version = ob_get_ui64_rv(payload); - uint64_t fileOffset = ob_get_ui64_rv(payload); - uint32_t bitmap = ob_get_ui32_rv(payload); - uint16_t blockLength = ob_get_ui16_rv(payload); - if (ob_overrun(payload)) - return -1; - return rhizome_mdp_send_block(header->source, bidp, version, fileOffset, bitmap, blockLength); -} - -DEFINE_BINDING(MDP_PORT_RHIZOME_RESPONSE, overlay_mdp_service_rhizomeresponse); -static int overlay_mdp_service_rhizomeresponse(struct internal_mdp_header *UNUSED(header), struct overlay_buffer *payload) -{ - IN(); - - int type=ob_get(payload); - - DEBUGF(rhizome_mdp_rx, "Received Rhizome over MDP block, type=%02x",type); - - switch (type) { - case 'B': /* data block */ - case 'T': /* terminal data block */ - { - unsigned char *bidprefix=ob_get_bytes_ptr(payload, 16); - uint64_t version=ob_get_ui64_rv(payload); - uint64_t offset=ob_get_ui64_rv(payload); - if (ob_overrun(payload)) - RETURN(WHYF("Payload too short")); - size_t count = ob_remaining(payload); - unsigned char *bytes=ob_current_ptr(payload); - - DEBUGF(rhizome_mdp_rx, "bidprefix=%02x%02x%02x%02x*, offset=%"PRId64", count=%zu", - bidprefix[0],bidprefix[1],bidprefix[2],bidprefix[3],offset,count); - - /* Now see if there is a slot that matches. If so, then - see if the bytes are in the window, and write them. - - If there is not matching slot, then consider setting - a slot to capture this files as it is being requested - by someone else. - */ - rhizome_received_content(bidprefix,version,offset, count, bytes); - - RETURN(0); - } - break; - } - - RETURN(-1); - OUT(); -} - -DEFINE_BINDING(MDP_PORT_DNALOOKUP, overlay_mdp_service_dnalookup); -static int overlay_mdp_service_dnalookup(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - IN(); - keyring_iterator it; - keyring_iterator_start(keyring, &it); - char did[64+1]; - - int pll=ob_remaining(payload); - if (pll>64) pll=64; - - /* get did from the packet */ - if (pll<1) - RETURN(WHY("Empty DID in DNA resolution request")); - - ob_get_bytes(payload, (unsigned char *)did, pll); - did[pll]=0; - - DEBUG(mdprequests, "MDP_PORT_DNALOOKUP"); - - int results=0; - while(keyring_find_did(&it, did)) - { - /* package DID and Name into reply (we include the DID because - it could be a wild-card DID search, but the SID is implied - in the source address of our reply). */ - if (it.keypair->private_key_len > DID_MAXSIZE) - /* skip excessively long DID records */ - continue; - - struct subscriber *subscriber = it.identity->subscriber; - const char *unpackedDid = (const char *) it.keypair->private_key; - const char *name = (const char *)it.keypair->public_key; - // URI is sid://SIDHEX/DID - strbuf b = strbuf_alloca(SID_STRLEN + DID_MAXSIZE + 10); - strbuf_puts(b, "sid://"); - strbuf_tohex(b, SID_STRLEN, subscriber->sid.binary); - strbuf_puts(b, "/local/"); - strbuf_puts(b, unpackedDid); - overlay_mdp_dnalookup_reply(header->source, header->source_port, subscriber, strbuf_str(b), unpackedDid, name); - results++; - } - if (!results) { - /* No local results, so see if servald has been configured to use - a DNA-helper that can provide additional mappings. This provides - a generalised interface for resolving telephone numbers into URIs. - The first use will be for resolving DIDs to SIP addresses for - OpenBTS boxes run by the OTI/Commotion project. - - The helper is run asynchronously, and the replies will be delivered - when results become available, so this function will return - immediately, so as not to cause blockages and delays in servald. - */ - dna_helper_enqueue(header->source, header->source_port, did); - monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n", - alloca_tohex_sid_t(header->source->sid), header->source_port, - did); - } - RETURN(0); -} - -DEFINE_BINDING(MDP_PORT_ECHO, overlay_mdp_service_echo); -static int overlay_mdp_service_echo(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - IN(); - - if (header->source_port == MDP_PORT_ECHO) - RETURN(WHY("Prevented infinite echo loop")); - - struct internal_mdp_header response_header; - bzero(&response_header, sizeof response_header); - - mdp_init_response(header, &response_header); - // keep all defaults - - RETURN(overlay_send_frame(&response_header, payload)); - OUT(); -} - -/* - * Trace packets are a little weird so that they can be modified by every node - * and so they can bypass the routing table. - * - * The true source and destination addresses are encoded inside the payload - * each node that processes the packet appends their own address before forwarding it to the next hop - * if their SID is already in the packet, the next hop is chosen from the immediately preceeding SID in the list. - * otherwise the next SID is chosen based on the current routing table. - * - * In this way the packet can follow the path defined by each node's routing table - * Until the packet reaches the destination, the destination is unreachable, or the packet loops around the network - * Once any of these end states occurs, the packet attempts to travel back to the source node, - * while using the source addresses in the trace packet for guidance instead of trusting the routing table. - * - * It is hoped that this information can be useful to better understand the current network state - * in situations where a routing protocol is in development. - */ - -DEFINE_BINDING(MDP_PORT_TRACE, overlay_mdp_service_trace); -static int overlay_mdp_service_trace(struct internal_mdp_header *header, struct overlay_buffer *payload){ - IN(); - struct overlay_buffer *next_payload = ob_new(); - if (!next_payload) - RETURN(-1); - ob_append_bytes(next_payload, ob_current_ptr(payload), ob_remaining(payload)); - - int ret=0; - struct subscriber *src=NULL, *dst=NULL, *last=NULL; - struct decode_context context; - bzero(&context, sizeof context); - - if (header->source_port == MDP_PORT_TRACE){ - ret=WHYF("Invalid source port"); - goto end; - } - if (overlay_address_parse(&context, payload, &src)){ - ret=WHYF("Invalid source SID"); - goto end; - } - if (overlay_address_parse(&context, payload, &dst)){ - ret=WHYF("Invalid destination SID"); - goto end; - } - if (context.flags & DECODE_FLAG_INVALID_ADDRESS){ - ret=WHYF("Unknown address in trace packet"); - goto end; - } - - INFOF("Trace from %s to %s", alloca_tohex_sid_t(src->sid), alloca_tohex_sid_t(dst->sid)); - struct internal_mdp_header next_header; - next_header = *header; - next_header.source = get_my_subscriber(); - next_header.destination = NULL; - - while(ob_remaining(payload)>0){ - struct subscriber *trace=NULL; - if (overlay_address_parse(&context, payload, &trace)){ - ret=WHYF("Invalid SID in packet payload"); - goto end; - } - if (context.flags & DECODE_FLAG_INVALID_ADDRESS){ - ret=WHYF("Unknown SID in packet payload"); - goto end; - } - INFOF("Via %s", alloca_tohex_sid_t(trace->sid)); - - if (trace->reachable==REACHABLE_SELF && !next_header.destination) - // We're already in this trace, send the next packet to the node before us in the list - next_header.destination = last; - last = trace; - } - - if (src->reachable==REACHABLE_SELF && last){ - // it came back to us, we can send the reply to our mdp client... - next_header.destination=src; - next_header.destination_port = header->source_port; - next_header.source_port = MDP_PORT_TRACE; - } - - if (!next_header.destination){ - // destination is our neighbour? - if (dst->reachable & REACHABLE_DIRECT) - next_header.destination = dst; - // destination is indirect? - else if (dst->reachable & REACHABLE_INDIRECT) - next_header.destination = dst->next_hop; - // destination is not reachable or is ourselves? bounce back to the previous node or the sender. - else if (last) - next_header.destination = last; - else - next_header.destination = src; - } - - INFOF("Next node is %s", alloca_tohex_sid_t(next_header.destination->sid)); - - // always write a full sid into the payload - next_header.source->send_full=1; - overlay_address_append(&context, next_payload, next_header.source); - if (ob_overrun(next_payload)) { - ret = WHYF("Unable to append my address to the trace"); - goto end; - } - ob_flip(next_payload); - ret = overlay_send_frame(&next_header, next_payload); -end: - ob_free(next_payload); - RETURN(ret); -} - -DEFINE_BINDING(MDP_PORT_RHIZOME_MANIFEST_REQUEST, overlay_mdp_service_manifest_requests); -static int overlay_mdp_service_manifest_requests(struct internal_mdp_header *header, struct overlay_buffer *payload) -{ - while (ob_remaining(payload)) { - const unsigned char *bar = ob_get_bytes_ptr(payload, RHIZOME_BAR_BYTES); - if (!bar) - break; - rhizome_manifest *m = rhizome_new_manifest(); - if (!m) - return WHY("Unable to allocate manifest"); - if (rhizome_retrieve_manifest_by_prefix(&bar[RHIZOME_BAR_PREFIX_OFFSET], RHIZOME_BAR_PREFIX_BYTES, m)==RHIZOME_BUNDLE_STATUS_SAME){ - rhizome_advertise_manifest(header->source, m); - // pre-emptively send the payload if it will fit in a single packet - if (m->filesize > 0 && m->filesize <= 1024) - rhizome_mdp_send_block(header->source, &m->keypair.public_key, m->version, 0, 0, m->filesize); - } - rhizome_manifest_free(m); - } - return 0; -} - diff --git a/overlay_mdp_trace.c b/overlay_mdp_trace.c new file mode 100644 index 00000000..8ced9600 --- /dev/null +++ b/overlay_mdp_trace.c @@ -0,0 +1,136 @@ +/* +Serval DNA MDP trace service +Copyright (C) 2016 Flinders University +Copyright (C) 2012-2015 Serval Project Inc. +Copyright (C) 2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "overlay_buffer.h" +#include "overlay_address.h" +#include "overlay_packet.h" +#include "mdp_client.h" +#include "fdqueue.h" +#include "str.h" + +/* + * Trace packets are a little weird so that they can be modified by every node + * and so they can bypass the routing table. + * + * The true source and destination addresses are encoded inside the payload + * each node that processes the packet appends their own address before forwarding it to the next hop + * if their SID is already in the packet, the next hop is chosen from the immediately preceeding SID in the list. + * otherwise the next SID is chosen based on the current routing table. + * + * In this way the packet can follow the path defined by each node's routing table + * Until the packet reaches the destination, the destination is unreachable, or the packet loops around the network + * Once any of these end states occurs, the packet attempts to travel back to the source node, + * while using the source addresses in the trace packet for guidance instead of trusting the routing table. + * + * It is hoped that this information can be useful to better understand the current network state + * in situations where a routing protocol is in development. + */ + +DEFINE_BINDING(MDP_PORT_TRACE, overlay_mdp_service_trace); +static int overlay_mdp_service_trace(struct internal_mdp_header *header, struct overlay_buffer *payload){ + IN(); + struct overlay_buffer *next_payload = ob_new(); + if (!next_payload) + RETURN(-1); + ob_append_bytes(next_payload, ob_current_ptr(payload), ob_remaining(payload)); + + int ret=0; + struct subscriber *src=NULL, *dst=NULL, *last=NULL; + struct decode_context context; + bzero(&context, sizeof context); + + if (header->source_port == MDP_PORT_TRACE){ + ret=WHYF("Invalid source port"); + goto end; + } + if (overlay_address_parse(&context, payload, &src)){ + ret=WHYF("Invalid source SID"); + goto end; + } + if (overlay_address_parse(&context, payload, &dst)){ + ret=WHYF("Invalid destination SID"); + goto end; + } + if (context.flags & DECODE_FLAG_INVALID_ADDRESS){ + ret=WHYF("Unknown address in trace packet"); + goto end; + } + + INFOF("Trace from %s to %s", alloca_tohex_sid_t(src->sid), alloca_tohex_sid_t(dst->sid)); + struct internal_mdp_header next_header; + next_header = *header; + next_header.source = get_my_subscriber(); + next_header.destination = NULL; + + while(ob_remaining(payload)>0){ + struct subscriber *trace=NULL; + if (overlay_address_parse(&context, payload, &trace)){ + ret=WHYF("Invalid SID in packet payload"); + goto end; + } + if (context.flags & DECODE_FLAG_INVALID_ADDRESS){ + ret=WHYF("Unknown SID in packet payload"); + goto end; + } + INFOF("Via %s", alloca_tohex_sid_t(trace->sid)); + + if (trace->reachable==REACHABLE_SELF && !next_header.destination) + // We're already in this trace, send the next packet to the node before us in the list + next_header.destination = last; + last = trace; + } + + if (src->reachable==REACHABLE_SELF && last){ + // it came back to us, we can send the reply to our mdp client... + next_header.destination=src; + next_header.destination_port = header->source_port; + next_header.source_port = MDP_PORT_TRACE; + } + + if (!next_header.destination){ + // destination is our neighbour? + if (dst->reachable & REACHABLE_DIRECT) + next_header.destination = dst; + // destination is indirect? + else if (dst->reachable & REACHABLE_INDIRECT) + next_header.destination = dst->next_hop; + // destination is not reachable or is ourselves? bounce back to the previous node or the sender. + else if (last) + next_header.destination = last; + else + next_header.destination = src; + } + + INFOF("Next node is %s", alloca_tohex_sid_t(next_header.destination->sid)); + + // always write a full sid into the payload + next_header.source->send_full=1; + overlay_address_append(&context, next_payload, next_header.source); + if (ob_overrun(next_payload)) { + ret = WHYF("Unable to append my address to the trace"); + goto end; + } + ob_flip(next_payload); + ret = overlay_send_frame(&next_header, next_payload); +end: + ob_free(next_payload); + RETURN(ret); +} diff --git a/overlay_packet.h b/overlay_packet.h index d8a5cafe..f47246d0 100644 --- a/overlay_packet.h +++ b/overlay_packet.h @@ -21,6 +21,7 @@ #define __SERVAL_DNA__OVERLAY_PACKET_H #include "serval_types.h" +#include "feature.h" #include "overlay_address.h" #include "section.h" @@ -143,6 +144,7 @@ struct internal_binding{ DECLARE_SECTION(struct internal_binding, bindings); #define DEFINE_BINDING(PORT, FUNC) \ + DEFINE_FEATURE(mdp_binding_ ## PORT); \ static int FUNC(struct internal_mdp_header *, struct overlay_buffer *);\ static struct internal_binding BIND ## FUNC IN_SECTION(bindings) = { \ .port = PORT, \ diff --git a/overlay_probe.c b/overlay_probe.c new file mode 100644 index 00000000..8f9476ba --- /dev/null +++ b/overlay_probe.c @@ -0,0 +1,54 @@ +/* +Serval DNA MDP overlay network link tracking +Copyright (C) 2016 Flinders University +Copyright (C) 2012-2013 Serval Project Inc. +Copyright (C) 2010-2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "serval.h" +#include "conf.h" +#include "route_link.h" +#include "overlay_interface.h" +#include "overlay_buffer.h" +#include "fdqueue.h" + +/* Collection of unicast echo responses to detect working links */ +DEFINE_BINDING(MDP_PORT_PROBE, overlay_mdp_service_probe); +static int overlay_mdp_service_probe(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + IN(); + if (header->source_port!=MDP_PORT_ECHO){ + WARN("Probe packets should be returned from remote echo port"); + RETURN(-1); + } + DEBUGF(overlayrouting, "Received probe response from %s", alloca_tohex_sid_t(header->source->sid)); + + if (header->source->reachable == REACHABLE_SELF) + RETURN(0); + + uint8_t interface = ob_get(payload); + struct socket_address addr; + addr.addrlen = ob_remaining(payload); + + if (addr.addrlen > sizeof(addr.store)) + RETURN(WHY("Badly formatted probe packet")); + + ob_get_bytes(payload, (unsigned char*)&addr.addr, addr.addrlen); + + RETURN(link_unicast_ack(header->source, &overlay_interfaces[interface], &addr)); + OUT(); +} diff --git a/overlay_stun.c b/overlay_stun.c new file mode 100644 index 00000000..c687ee19 --- /dev/null +++ b/overlay_stun.c @@ -0,0 +1,60 @@ +/* +Serval DNA MDP overlay network link tracking +Copyright (C) 2016 Flinders University +Copyright (C) 2012-2013 Serval Project Inc. +Copyright (C) 2010-2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "serval.h" +#include "conf.h" +#include "route_link.h" +#include "overlay_interface.h" +#include "overlay_buffer.h" + +DEFINE_BINDING(MDP_PORT_STUN, overlay_mdp_service_stun); +static int overlay_mdp_service_stun(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + DEBUGF(overlayrouting, "Processing STUN info from %s", alloca_tohex_sid_t(header->source->sid)); + + while(ob_remaining(payload)>0){ + struct subscriber *subscriber=NULL; + + // TODO explain addresses, link expiry time, resolve differences between addresses... + + if (overlay_address_parse(NULL, payload, &subscriber)){ + break; + } + struct socket_address addr; + addr.addrlen = sizeof(addr.inet); + addr.inet.sin_family = AF_INET; + addr.inet.sin_addr.s_addr = ob_get_ui32(payload); + addr.inet.sin_port = ob_get_ui16(payload); + + if (!subscriber || (subscriber->reachable&REACHABLE_DIRECT)) + continue; + + // only trust stun responses from our directory service or about the packet sender. + if (directory_service == header->source || subscriber == header->source){ + struct network_destination *destination = create_unicast_destination(&addr, NULL); + if (destination){ + overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT); + release_destination_ref(destination); + } + } + } + return 0; +} diff --git a/overlay_stunreq.c b/overlay_stunreq.c new file mode 100644 index 00000000..920b5bf9 --- /dev/null +++ b/overlay_stunreq.c @@ -0,0 +1,81 @@ +/* +Serval DNA MDP overlay network link tracking +Copyright (C) 2016 Flinders University +Copyright (C) 2012-2013 Serval Project Inc. +Copyright (C) 2010-2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "serval.h" +#include "conf.h" +#include "route_link.h" +#include "overlay_interface.h" +#include "overlay_buffer.h" + +// append the address of a unicast link into a packet buffer +static void overlay_append_unicast_address(struct subscriber *subscriber, struct overlay_buffer *buff) +{ + if ( subscriber->destination + && subscriber->destination->unicast + && subscriber->destination->address.addr.sa_family==AF_INET + ) { + overlay_address_append(NULL, buff, subscriber); + ob_append_ui32(buff, subscriber->destination->address.inet.sin_addr.s_addr); + ob_append_ui16(buff, subscriber->destination->address.inet.sin_port); + DEBUGF(overlayrouting, "Added STUN info for %s", alloca_tohex_sid_t(subscriber->sid)); + }else{ + DEBUGF(overlayrouting, "Unable to give address of %s, %d", alloca_tohex_sid_t(subscriber->sid),subscriber->reachable); + } +} + +DEFINE_BINDING(MDP_PORT_STUNREQ, overlay_mdp_service_stun_req); +static int overlay_mdp_service_stun_req(struct internal_mdp_header *header, struct overlay_buffer *payload) +{ + DEBUGF(overlayrouting, "Processing STUN request from %s", alloca_tohex_sid_t(header->source->sid)); + + struct internal_mdp_header reply; + bzero(&reply, sizeof reply); + + mdp_init_response(header, &reply); + reply.qos = OQ_MESH_MANAGEMENT; + + struct overlay_buffer *replypayload = ob_new(); + ob_limitsize(replypayload, MDP_MTU); + + ob_checkpoint(replypayload); + while (ob_remaining(payload) > 0) { + struct subscriber *subscriber=NULL; + if (overlay_address_parse(NULL, payload, &subscriber)) + break; + if (!subscriber){ + DEBUGF(overlayrouting, "Unknown subscriber"); + continue; + } + overlay_append_unicast_address(subscriber, replypayload); + if (ob_overrun(payload)) + break; + ob_checkpoint(replypayload); + } + ob_rewind(replypayload); + + if (ob_position(replypayload)){ + DEBUGF(overlayrouting, "Sending reply"); + ob_flip(replypayload); + overlay_send_frame(&reply, replypayload); + } + ob_free(replypayload); + return 0; +} diff --git a/rhizome.h b/rhizome.h index a350beda..3667f77b 100644 --- a/rhizome.h +++ b/rhizome.h @@ -624,7 +624,6 @@ enum rhizome_bundle_status rhizome_retrieve_manifest_by_prefix(const unsigned ch enum rhizome_bundle_status rhizome_retrieve_manifest_by_hash_prefix(const uint8_t *prefix, unsigned prefix_len, rhizome_manifest *m); enum rhizome_bundle_status rhizome_retrieve_bar_by_hash_prefix(const uint8_t *prefix, unsigned prefix_len, rhizome_bar_t *bar); int rhizome_advertise_manifest(struct subscriber *dest, rhizome_manifest *m); -int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength); int rhizome_delete_bundle(const rhizome_bid_t *bidp); int rhizome_delete_manifest(const rhizome_bid_t *bidp); int rhizome_delete_payload(const rhizome_bid_t *bidp); @@ -767,7 +766,6 @@ void rhizome_direct_bundle_iterator_unlimit(rhizome_direct_bundle_cursor *r); int rhizome_direct_bundle_iterator_pickle_range(rhizome_direct_bundle_cursor *r, unsigned char *pickled, int pickle_buffer_size); -rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length); int rhizome_direct_bundle_iterator_unpickle_range(rhizome_direct_bundle_cursor *r, const unsigned char *pickled, int pickle_buffer_size); @@ -821,15 +819,14 @@ extern rhizome_direct_sync_request *rd_sync_handles[RHIZOME_DIRECT_MAX_SYNC_HAND extern int rd_sync_handle_count; rhizome_direct_sync_request -*rhizome_direct_new_sync_request( - void (*transport_specific_dispatch_function) - (struct rhizome_direct_sync_request *), - size_t buffer_size, int interval, int mode, +*rhizome_direct_new_sync_request(void (*transport_specific_dispatch_function)(struct rhizome_direct_sync_request *), + size_t buffer_size, + int interval, + int mode, void *transport_specific_state); int rhizome_direct_continue_sync_request(rhizome_direct_sync_request *r); int rhizome_direct_conclude_sync_request(rhizome_direct_sync_request *r); -rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response -(unsigned char *buffer,int size,int max_response_bytes); +rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response(unsigned char *buffer,int size,int max_response_bytes); typedef struct rhizome_direct_transport_state_http { int port; diff --git a/rhizome_cli.c b/rhizome_cli.c index 836052b1..25c77400 100644 --- a/rhizome_cli.c +++ b/rhizome_cli.c @@ -25,6 +25,8 @@ #include "rhizome.h" #include "instance.h" +DEFINE_FEATURE(cli_rhizome); + static void cli_put_manifest(struct cli_context *context, const rhizome_manifest *m) { assert(m->filesize != RHIZOME_SIZE_UNSET); diff --git a/rhizome_direct.c b/rhizome_direct.c index ea3bc6eb..4370089e 100644 --- a/rhizome_direct.c +++ b/rhizome_direct.c @@ -1,6 +1,7 @@ /* -Serval Mesh Software -Copyright (C) 2010-2012 Paul Gardner-Stephen +Serval DNA Rhizome Direct +Copyright (C) 2012-2015 Serval Project Inc. +Copyright (C) 2012 Paul Gardner-Stephen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -107,12 +108,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "serval.h" -#include "conf.h" -#include "rhizome.h" -#include "str.h" -#include "commandline.h" #include +#include "serval.h" +#include "rhizome.h" +#include "conf.h" +#include "str.h" rhizome_direct_sync_request *rd_sync_handles[RHIZOME_DIRECT_MAX_SYNC_HANDLES]; int rd_sync_handle_count=0; @@ -160,20 +160,6 @@ rhizome_direct_sync_request rd_sync_handles[rd_sync_handle_count++]=r; return r; } - -/* - Initiate a synchronisation episode. -*/ -int rhizome_direct_start_sync_request(rhizome_direct_sync_request *r) -{ - assert(r); - assert(r->syncs_started==r->syncs_completed); - - r->syncs_started++; - - return rhizome_direct_continue_sync_request(r); -} - int rhizome_direct_continue_sync_request(rhizome_direct_sync_request *r) { assert(r); @@ -390,156 +376,6 @@ rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response(unsigned char *bu return c; } -rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length) -{ - /* Give a BID prefix, e.g., from a BAR, find the matching manifest and return it. - Of course, it is possible that more than one manifest matches. This should - occur only very rarely (with the possible exception of intentional attack, and - even then a 64-bit prefix creates a reasonable barrier. If we move to a new - BAR format with 120 or 128 bits of BID prefix, then we should be safe for some - time, thus this function taking the BID prefix as an input in preparation for - that change). - - Of course, we need to be able to find the manifest. - Easiest way is to select with a BID range. We could instead have an extra - database column with the prefix. - */ - rhizome_bid_t low = RHIZOME_BID_ZERO; - rhizome_bid_t high = RHIZOME_BID_MAX; - assert(prefix_length <= sizeof(rhizome_bid_t)); - bcopy(bid_prefix, low.binary, prefix_length); - bcopy(bid_prefix, high.binary, prefix_length); - sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; - sqlite3_stmt *statement = sqlite_prepare_bind(&retry, - "SELECT manifest, rowid FROM MANIFESTS WHERE id >= ? AND id <= ?", - RHIZOME_BID_T, &low, - RHIZOME_BID_T, &high, - END); - sqlite3_blob *blob=NULL; - if (sqlite_step_retry(&retry, statement) == SQLITE_ROW) - { - int ret; - int64_t rowid = sqlite3_column_int64(statement, 1); - do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar", - rowid, 0 /* read only */, &blob); - while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open")); - if (!sqlite_code_ok(ret)) { - WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db)); - sqlite3_finalize(statement); - return NULL; - - } - sqlite_retry_done(&retry, "sqlite3_blob_open"); - - /* Read manifest data from blob */ - - size_t manifestblobsize = sqlite3_column_bytes(statement, 0); - if (manifestblobsize<1||manifestblobsize>1024) goto error; - - const char *manifestblob = (char *) sqlite3_column_blob(statement, 0); - if (!manifestblob) - goto error; - - rhizome_manifest *m = rhizome_new_manifest(); - if (!m) - goto error; - memcpy(m->manifestdata, manifestblob, manifestblobsize); - m->manifest_all_bytes = manifestblobsize; - if ( rhizome_manifest_parse(m) == -1 - || !rhizome_manifest_validate(m) - ) { - rhizome_manifest_free(m); - goto error; - } - - DEBUGF(rhizome_direct, "Read manifest"); - sqlite3_blob_close(blob); - sqlite3_finalize(statement); - return m; - - error: - sqlite3_blob_close(blob); - sqlite3_finalize(statement); - return NULL; - } - else - { - DEBUGF(rhizome_direct, "no matching manifests"); - sqlite3_finalize(statement); - return NULL; - } - -} - -static int rhizome_sync_with_peers(int mode, int peer_count, const struct config_rhizome_peer *const *peers) -{ - - /* Get iterator capable of 64KB buffering. - In future we should parse the sync URL and base the buffer size on the - transport and allowable traffic volumes. */ - rhizome_direct_transport_state_http *state = emalloc_zero(sizeof(rhizome_direct_transport_state_http)); - /* XXX This code runs each sync in series, when we can probably do them in - parallel. But we can't really do them in parallel until we make the - synchronisation process fully asynchronous, which probably won't happen - for a while yet. - Also, we don't currently parse the URI protocol field fully. */ - int peer_number; - for (peer_number = 0; peer_number < peer_count; ++peer_number) { - const struct config_rhizome_peer *peer = peers[peer_number]; - if (strcasecmp(peer->protocol, "http") != 0) - return WHYF("Unsupported Rhizome Direct protocol %s", alloca_str_toprint(peer->protocol)); - strbuf h = strbuf_local_buf(state->host); - strbuf_puts(h, peer->host); - if (strbuf_overrun(h)) - return WHYF("Rhizome Direct host name too long: %s", alloca_str_toprint(peer->host)); - state->port = peer->port; - DEBUGF(rhizome_direct, "Rhizome direct peer is %s://%s:%d", peer->protocol, state->host, state->port); - rhizome_direct_sync_request *s = rhizome_direct_new_sync_request(rhizome_direct_http_dispatch, 65536, 0, mode, state); - rhizome_direct_start_sync_request(s); - if (rd_sync_handle_count > 0) - while (fd_poll() && rd_sync_handle_count > 0) - ; - } - return 0; -} - -DEFINE_CMD(app_rhizome_direct_sync, 0, - "Synchronise with the specified Rhizome Direct server.", - "rhizome","direct","push|pull|sync","[]"); -static int app_rhizome_direct_sync(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) -{ - DEBUG_cli_parsed(verbose, parsed); - /* Attempt to connect with a remote Rhizome Direct instance, - and negotiate which BARs to synchronise. */ - const char *modeName = (parsed->argc >= 3 ? parsed->args[2] : "sync"); - int mode=3; /* two-way sync */ - if (!strcasecmp(modeName,"push")) mode=1; /* push only */ - if (!strcasecmp(modeName,"pull")) mode=2; /* pull only */ - DEBUGF(rhizome_direct, "sync direction = %d",mode); - rhizome_opendb(); - if (parsed->args[3]) { - struct config_rhizome_peer peer; - const struct config_rhizome_peer *peers[1] = { &peer }; - int result = cf_opt_rhizome_peer_from_uri(&peer, parsed->args[3]); - if (result == CFOK) - return rhizome_sync_with_peers(mode, 1, peers); - else { - strbuf b = strbuf_alloca(128); - strbuf_cf_flag_reason(b, result); - return WHYF("Invalid peer URI %s -- %s", alloca_str_toprint(parsed->args[3]), strbuf_str(b)); - } - } else if (config.rhizome.direct.peer.ac == 0) { - DEBUG(rhizome_direct, "No rhizome direct peers were configured or supplied"); - return -1; - } else { - const struct config_rhizome_peer *peers[config.rhizome.direct.peer.ac]; - unsigned i; - for (i = 0; i < config.rhizome.direct.peer.ac; ++i) - peers[i] = &config.rhizome.direct.peer.av[i].value; - return rhizome_sync_with_peers(mode, config.rhizome.direct.peer.ac, peers); - } -} - rhizome_direct_bundle_cursor *rhizome_direct_bundle_iterator(size_t buffer_size) { rhizome_direct_bundle_cursor *r=calloc(sizeof(rhizome_direct_bundle_cursor),1); diff --git a/rhizome_direct_cli.c b/rhizome_direct_cli.c new file mode 100644 index 00000000..21e60477 --- /dev/null +++ b/rhizome_direct_cli.c @@ -0,0 +1,110 @@ +/* +Serval DNA Rhizome Direct +Copyright (C) 2012-2015 Serval Project Inc. +Copyright (C) 2012 Paul Gardner-Stephen + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "feature.h" +#include "commandline.h" +#include "rhizome.h" +#include "mem.h" +#include "conf.h" +#include "debug.h" +#include "str.h" + +DEFINE_FEATURE(cli_rhizome_direct); + +/* + Initiate a synchronisation episode. +*/ +static int rhizome_direct_start_sync_request(rhizome_direct_sync_request *r) +{ + assert(r); + assert(r->syncs_started==r->syncs_completed); + + r->syncs_started++; + + return rhizome_direct_continue_sync_request(r); +} + +static int rhizome_sync_with_peers(int mode, int peer_count, const struct config_rhizome_peer *const *peers) +{ + /* Get iterator capable of 64KB buffering. + In future we should parse the sync URL and base the buffer size on the + transport and allowable traffic volumes. */ + rhizome_direct_transport_state_http *state = emalloc_zero(sizeof(rhizome_direct_transport_state_http)); + /* XXX This code runs each sync in series, when we can probably do them in + parallel. But we can't really do them in parallel until we make the + synchronisation process fully asynchronous, which probably won't happen + for a while yet. + Also, we don't currently parse the URI protocol field fully. */ + int peer_number; + for (peer_number = 0; peer_number < peer_count; ++peer_number) { + const struct config_rhizome_peer *peer = peers[peer_number]; + if (strcasecmp(peer->protocol, "http") != 0) + return WHYF("Unsupported Rhizome Direct protocol %s", alloca_str_toprint(peer->protocol)); + strbuf h = strbuf_local_buf(state->host); + strbuf_puts(h, peer->host); + if (strbuf_overrun(h)) + return WHYF("Rhizome Direct host name too long: %s", alloca_str_toprint(peer->host)); + state->port = peer->port; + DEBUGF(rhizome_direct, "Rhizome direct peer is %s://%s:%d", peer->protocol, state->host, state->port); + rhizome_direct_sync_request *s = rhizome_direct_new_sync_request(rhizome_direct_http_dispatch, 65536, 0, mode, state); + rhizome_direct_start_sync_request(s); + if (rd_sync_handle_count > 0) + while (fd_poll() && rd_sync_handle_count > 0) + ; + } + return 0; +} + +DEFINE_CMD(app_rhizome_direct_sync, 0, + "Synchronise with the specified Rhizome Direct server.", + "rhizome","direct","push|pull|sync","[]"); +static int app_rhizome_direct_sync(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) +{ + DEBUG_cli_parsed(verbose, parsed); + /* Attempt to connect with a remote Rhizome Direct instance, + and negotiate which BARs to synchronise. */ + const char *modeName = (parsed->argc >= 3 ? parsed->args[2] : "sync"); + int mode=3; /* two-way sync */ + if (!strcasecmp(modeName,"push")) mode=1; /* push only */ + if (!strcasecmp(modeName,"pull")) mode=2; /* pull only */ + DEBUGF(rhizome_direct, "sync direction = %d",mode); + rhizome_opendb(); + if (parsed->args[3]) { + struct config_rhizome_peer peer; + const struct config_rhizome_peer *peers[1] = { &peer }; + int result = cf_opt_rhizome_peer_from_uri(&peer, parsed->args[3]); + if (result == CFOK) + return rhizome_sync_with_peers(mode, 1, peers); + else { + strbuf b = strbuf_alloca(128); + strbuf_cf_flag_reason(b, result); + return WHYF("Invalid peer URI %s -- %s", alloca_str_toprint(parsed->args[3]), strbuf_str(b)); + } + } else if (config.rhizome.direct.peer.ac == 0) { + DEBUG(rhizome_direct, "No rhizome direct peers were configured or supplied"); + return -1; + } else { + const struct config_rhizome_peer *peers[config.rhizome.direct.peer.ac]; + unsigned i; + for (i = 0; i < config.rhizome.direct.peer.ac; ++i) + peers[i] = &config.rhizome.direct.peer.av[i].value; + return rhizome_sync_with_peers(mode, config.rhizome.direct.peer.ac, peers); + } +} diff --git a/rhizome_direct_http.c b/rhizome_direct_http.c index c5245536..b522688e 100644 --- a/rhizome_direct_http.c +++ b/rhizome_direct_http.c @@ -31,6 +31,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "strbuf_helpers.h" #include "socket.h" +DEFINE_FEATURE(http_rhizome_direct); + DECLARE_HANDLER("/rhizome/import", rhizome_direct_import); DECLARE_HANDLER("/rhizome/enquiry", rhizome_direct_enquiry); DECLARE_HANDLER("/rhizome/", rhizome_direct_dispatch); @@ -461,6 +463,8 @@ static int fill_buffer(int sock, unsigned char *buffer, int len, int buffer_size return 0; } +static rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length); + void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r) { DEBUGF(rhizome_tx, "Dispatch size_high=%"PRId64,r->cursor->size_high); @@ -806,3 +810,85 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r) But this will do for now. */ rhizome_direct_continue_sync_request(r); } + +static rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length) +{ + /* Give a BID prefix, e.g., from a BAR, find the matching manifest and return it. + Of course, it is possible that more than one manifest matches. This should + occur only very rarely (with the possible exception of intentional attack, and + even then a 64-bit prefix creates a reasonable barrier. If we move to a new + BAR format with 120 or 128 bits of BID prefix, then we should be safe for some + time, thus this function taking the BID prefix as an input in preparation for + that change). + + Of course, we need to be able to find the manifest. + Easiest way is to select with a BID range. We could instead have an extra + database column with the prefix. + */ + rhizome_bid_t low = RHIZOME_BID_ZERO; + rhizome_bid_t high = RHIZOME_BID_MAX; + assert(prefix_length <= sizeof(rhizome_bid_t)); + bcopy(bid_prefix, low.binary, prefix_length); + bcopy(bid_prefix, high.binary, prefix_length); + sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; + sqlite3_stmt *statement = sqlite_prepare_bind(&retry, + "SELECT manifest, rowid FROM MANIFESTS WHERE id >= ? AND id <= ?", + RHIZOME_BID_T, &low, + RHIZOME_BID_T, &high, + END); + sqlite3_blob *blob=NULL; + if (sqlite_step_retry(&retry, statement) == SQLITE_ROW) + { + int ret; + int64_t rowid = sqlite3_column_int64(statement, 1); + do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar", + rowid, 0 /* read only */, &blob); + while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open")); + if (!sqlite_code_ok(ret)) { + WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db)); + sqlite3_finalize(statement); + return NULL; + + } + sqlite_retry_done(&retry, "sqlite3_blob_open"); + + /* Read manifest data from blob */ + + size_t manifestblobsize = sqlite3_column_bytes(statement, 0); + if (manifestblobsize<1||manifestblobsize>1024) goto error; + + const char *manifestblob = (char *) sqlite3_column_blob(statement, 0); + if (!manifestblob) + goto error; + + rhizome_manifest *m = rhizome_new_manifest(); + if (!m) + goto error; + memcpy(m->manifestdata, manifestblob, manifestblobsize); + m->manifest_all_bytes = manifestblobsize; + if ( rhizome_manifest_parse(m) == -1 + || !rhizome_manifest_validate(m) + ) { + rhizome_manifest_free(m); + goto error; + } + + DEBUGF(rhizome_direct, "Read manifest"); + sqlite3_blob_close(blob); + sqlite3_finalize(statement); + return m; + + error: + sqlite3_blob_close(blob); + sqlite3_finalize(statement); + return NULL; + } + else + { + DEBUGF(rhizome_direct, "no matching manifests"); + sqlite3_finalize(statement); + return NULL; + } + +} + diff --git a/rhizome_http.c b/rhizome_http.c index f08f8b45..2f079874 100644 --- a/rhizome_http.c +++ b/rhizome_http.c @@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "str.h" #include "strbuf.h" +DEFINE_FEATURE(http_rhizome); + DECLARE_HANDLER("/rhizome/status", rhizome_status_page); DECLARE_HANDLER("/rhizome/file/", rhizome_file_page); DECLARE_HANDLER("/rhizome/manifestbyprefix/", manifest_by_prefix_page); diff --git a/rhizome_restful.c b/rhizome_restful.c index 26dadcf2..b09a7770 100644 --- a/rhizome_restful.c +++ b/rhizome_restful.c @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "base64.h" #include "strbuf_helpers.h" +DEFINE_FEATURE(http_rest_rhizome); + DECLARE_HANDLER("/restful/rhizome/bundlelist.json", restful_rhizome_bundlelist_json); DECLARE_HANDLER("/restful/rhizome/newsince/", restful_rhizome_newsince); DECLARE_HANDLER("/restful/rhizome/insert", restful_rhizome_insert); diff --git a/route_link.h b/route_link.h index 12e1e8be..1c4958e9 100644 --- a/route_link.h +++ b/route_link.h @@ -1,5 +1,5 @@ /* -Serval DNA header file +Serval DNA link-state routing Copyright (C) 2015 Serval Project Inc. This program is free software; you can redistribute it and/or @@ -46,4 +46,4 @@ int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now); DECLARE_TRIGGER(nbr_change, struct subscriber *neighbour, uint8_t found, unsigned count); DECLARE_TRIGGER(link_change, struct subscriber *subscriber, int prior_reachable); -#endif +#endif // __SERVAL_DNA__ROUTE_LINK_H diff --git a/serval.h b/serval.h index 11e459fb..64c5fbf2 100644 --- a/serval.h +++ b/serval.h @@ -1,6 +1,6 @@ -/* +/* Serval DNA header file -Copyright (C) 2010-2012 Paul Gardner-Stephen +Copyright (C) 2010-2012 Paul Gardner-Stephen Copyright (C) 2012-2013 Serval Project Inc. This program is free software; you can redistribute it and/or @@ -149,9 +149,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. /* Limit packet payloads to minimise packet loss of big packets in mesh networks */ #define MAX_DATA_BYTES 256 - -extern const char version_servald[]; -extern const char copyright_servald[]; int rhizome_enabled(); int rhizome_http_server_running(); diff --git a/servald_features.c b/servald_features.c new file mode 100644 index 00000000..971182db --- /dev/null +++ b/servald_features.c @@ -0,0 +1,75 @@ +/* +Serval DNA daemon features +Copyright (C) 2016 Flinders University + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "feature.h" + +void servald_features() +{ + USE_FEATURE(cli_version); + USE_FEATURE(cli_echo); + USE_FEATURE(cli_log); + USE_FEATURE(cli_config); + USE_FEATURE(cli_server); + USE_FEATURE(cli_keyring); + USE_FEATURE(cli_network); + USE_FEATURE(cli_rhizome); + USE_FEATURE(cli_meshms); + USE_FEATURE(cli_monitor); + USE_FEATURE(cli_msp_proxy); + USE_FEATURE(cli_vomp_console); + USE_FEATURE(cli_rhizome_direct); + + USE_FEATURE(mdp_binding_MDP_PORT_ECHO); + USE_FEATURE(mdp_binding_MDP_PORT_TRACE); + USE_FEATURE(mdp_binding_MDP_PORT_KEYMAPREQUEST); + USE_FEATURE(mdp_binding_MDP_PORT_DNALOOKUP); + USE_FEATURE(mdp_binding_MDP_PORT_PROBE); + USE_FEATURE(mdp_binding_MDP_PORT_STUN); + USE_FEATURE(mdp_binding_MDP_PORT_STUNREQ); + USE_FEATURE(mdp_binding_MDP_PORT_LINKSTATE); + USE_FEATURE(mdp_binding_MDP_PORT_VOMP); + USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_SYNC); + USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_SYNC_KEYS); + USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_REQUEST); + USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_RESPONSE); + USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_MANIFEST_REQUEST); + + USE_FEATURE(http_server); + USE_FEATURE(http_rhizome); + USE_FEATURE(http_rhizome_direct); + USE_FEATURE(http_rest_keyring); + USE_FEATURE(http_rest_rhizome); + USE_FEATURE(http_rest_meshms); +} + +#include +#include "overlay_address.h" +#include "rhizome.h" +#include "cli.h" +#include "keyring.h" + +__thread keyring_file *keyring = NULL; + +void cli_cleanup() +{ + /* clean up after ourselves */ + rhizome_close_db(); + free_subscribers(); + assert(keyring==NULL); +} diff --git a/servald_main.c b/servald_main.c index 55db1598..ce62b620 100644 --- a/servald_main.c +++ b/servald_main.c @@ -43,10 +43,8 @@ int servald_main(int argc, char **argv) sigaction(SIGABRT, &sig, NULL); /* Setup i/o signal handlers */ - signal(SIGPIPE,sigPipeHandler); - signal(SIGIO,sigIoHandler); - - cf_init(); + signal(SIGPIPE, sigPipeHandler); + signal(SIGIO, sigIoHandler); int status = commandline_main_stdio(stdout, argv[0], argc - 1, (const char*const*)&argv[1]); @@ -58,16 +56,22 @@ int servald_main(int argc, char **argv) char crash_handler_clue[1024] = "no clue"; -static void crash_handler(int signal) +static void crash_handler(int signum) { - LOGF(LOG_LEVEL_FATAL, "Caught signal %s", alloca_signal_name(signal)); + LOGF(LOG_LEVEL_FATAL, "Caught signal %s", alloca_signal_name(signum)); LOGF(LOG_LEVEL_FATAL, "The following clue may help: %s", crash_handler_clue); dump_stack(LOG_LEVEL_FATAL); BACKTRACE; - // Now die of the same signal, so that our exit status reflects the cause. - INFOF("Re-sending signal %d to self", signal); - kill(getpid(), signal); - // If that didn't work, then die normally. - INFOF("exit(%d)", -signal); - exit(-signal); + // Exit with a status code indicating the caught signal. This involves removing the signal + // handler for the caught signal then re-sending the same signal to ourself. If that doesn't + // work, then exit with an error code. + struct sigaction sig; + bzero(&sig, sizeof sig); + sig.sa_flags = 0; + sig.sa_handler = SIG_DFL; + sigemptyset(&sig.sa_mask); + sigaction(signum, &sig, NULL); + INFOF("Re-sending signal %d to self", signum); + kill(getpid(), signum); // should terminate self + exit(-1); } diff --git a/server.c b/server.c index 2b5b4d90..ed1b907a 100644 --- a/server.c +++ b/server.c @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "server.h" #include "serval.h" +#include "rhizome.h" #include "conf.h" #include "log.h" #include "str.h" @@ -48,19 +49,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mdp_client.h" #include "route_link.h" +DEFINE_FEATURE(cli_server); + #define PROC_SUBDIR "proc" #define PIDFILE_NAME "servald.pid" #define STOPFILE_NAME "servald.stop" __thread enum server_mode serverMode = SERVER_NOT_RUNNING; -__thread keyring_file *keyring=NULL; struct pid_tid { pid_t pid; pid_t tid; }; -static char pidfile_path[256]; static struct pid_tid server_pid_tid = { .pid = 0, .tid = 0 }; static int server_pidfd = -1; static int server(); @@ -73,14 +74,6 @@ static const char *_server_pidfile_path(struct __sourceloc __whence); static int server_write_proc_state(const char *path, const char *fmt, ...); static int server_get_proc_state(const char *path, char *buff, size_t buff_len); -void cli_cleanup() -{ - /* clean up after ourselves */ - rhizome_close_db(); - free_subscribers(); - assert(keyring==NULL); -} - static pid_t gettid() { #ifdef HAVE_LINUX_THREADS @@ -182,6 +175,7 @@ static int send_signal(const struct pid_tid *id, int signum) static const char *_server_pidfile_path(struct __sourceloc __whence) { + static char pidfile_path[256]; if (!pidfile_path[0]) { if (!FORMF_SERVAL_RUN_PATH(pidfile_path, PIDFILE_NAME)) return NULL; @@ -689,13 +683,11 @@ static int app_server_start(const struct cli_parsed *parsed, struct cli_context RETURN(-1); int seed = cli_arg(parsed, "--seed", NULL, NULL, NULL) == 0; int foregroundP = cli_arg(parsed, "foreground", NULL, NULL, NULL) == 0; + if (config.interfaces.ac == 0) + NOWHENCE(WARN("No network interfaces configured (empty 'interfaces' config option)")); /* Create the instance directory if it does not yet exist */ if (create_serval_instance_dir() == -1) RETURN(-1); - /* Now that we know our instance path, we can ask for the default set of - network interfaces that we will take interest in. */ - if (config.interfaces.ac == 0) - NOWHENCE(WARN("No network interfaces configured (empty 'interfaces' config option)")); struct pid_tid id = get_server_pid_tid(); if (id.pid < 0) RETURN(-1); diff --git a/server_httpd.c b/server_httpd.c index 689ce15b..06bb4dbe 100644 --- a/server_httpd.c +++ b/server_httpd.c @@ -26,12 +26,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "os.h" #include "route_link.h" +DEFINE_FEATURE(http_server); + +DECLARE_HANDLER("/", root_page); DECLARE_HANDLER("/static/", static_page); DECLARE_HANDLER("/interface/", interface_page); DECLARE_HANDLER("/neighbour/", neighbour_page); DECLARE_HANDLER("/favicon.ico", fav_icon_header); -DECLARE_HANDLER("/", root_page); - static int root_page(httpd_request *r, const char *remainder) { diff --git a/sighandlers.c b/sighandlers.c index d925e094..8aa74a57 100644 --- a/sighandlers.c +++ b/sighandlers.c @@ -2,17 +2,17 @@ Serval DNA signal handlers Copyright (C) 2014 Serval Project Inc. Copyright (C) 2012 Paul Gardner-Stephen - + This program 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 of the License, or (at your option) any later version. - + This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/sourcefiles.mk b/sourcefiles.mk index 0ab2ec3f..c826c462 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -1,6 +1,7 @@ # The "client" source files do not depend on "serval.h" or "rhizome.h", ie, # they can be linked into executables other than servald. SERVAL_CLIENT_SOURCES = \ + base64.c \ cli.c \ cli_stdio.c \ commandline.c \ @@ -9,14 +10,20 @@ SERVAL_CLIENT_SOURCES = \ conf_parse.c \ conf_schema.c \ console.c \ + context1.c \ dataformats.c \ + echo_cli.c \ fdqueue.c \ instance.c \ limit.c \ logMessage.c \ + log_cli.c \ + log_context.c \ + log_stderr.c \ log_util.c \ mem.c \ net.c \ + numeric_str.c \ os.c \ performance_timing.c \ rotbuf.c \ @@ -25,21 +32,14 @@ SERVAL_CLIENT_SOURCES = \ strbuf.c \ strbuf_helpers.c \ str.c \ - numeric_str.c \ - base64.c \ - uri.c \ strlcpy.c \ + test_cli.c \ + uri.c \ uuid.c \ + version_cli.c \ whence.c \ xprintf.c -# These objects do not belong in the Serval DNA daemon but are available for -# client applications. -SERVAL_LIB_SOURCES = \ - log_context.c \ - log_on_config_change.c \ - log_stderr.c - # These source files are imported and do not depend on any local header files. # They also take a long time to compile, so their dependencies should be as # narrow as possible to avoid unnecessary recompilations when developers modify @@ -51,9 +51,6 @@ SERVAL_DAEMON_SOURCES = \ main.c \ servald_main.c \ conf_cli.c \ - rhizome_cli.c \ - keyring_cli.c \ - network_cli.c \ crypto.c \ directory_client.c \ dna_helper.c \ @@ -61,14 +58,15 @@ SERVAL_DAEMON_SOURCES = \ httpd.c \ http_server.c \ keyring.c \ + keyring_cli.c \ + keyring_restful.c \ log.c \ lsif.c \ radio_link.c \ meshms.c \ meshmb.c \ - meshms_cli.c \ message_ply.c \ - keyring_restful.c \ + meshms_cli.c \ meshms_restful.c \ msp_client.c \ msp_proxy.c \ @@ -79,13 +77,20 @@ SERVAL_DAEMON_SOURCES = \ overlay_buffer.c \ overlay_interface.c \ overlay_link.c \ + overlay_probe.c \ + overlay_stun.c \ + overlay_stunreq.c \ overlay_packetradio.c \ overlay_queue.c \ overlay_mdp.c \ - overlay_mdp_services.c \ + overlay_mdp_echo.c \ + overlay_mdp_trace.c \ + overlay_mdp_keymaprequest.c \ + overlay_mdp_dnalookup.c \ mdp_filter.c \ msp_server.c \ nibble_tree.c \ + network_cli.c \ overlay_olsr.c \ overlay_packetformats.c \ overlay_payload.c \ @@ -94,15 +99,18 @@ SERVAL_DAEMON_SOURCES = \ rhizome_bundle.c \ rhizome_crypto.c \ rhizome_database.c \ + overlay_mdp_rhizome.c \ rhizome_direct.c \ + rhizome_direct_cli.c \ rhizome_direct_http.c \ rhizome_fetch.c \ rhizome_http.c \ - rhizome_restful.c \ rhizome_packetformats.c \ rhizome_store.c \ rhizome_sync.c \ rhizome_sync_keys.c \ + rhizome_restful.c \ + rhizome_cli.c \ sync_keys.c \ serval_packetvisualise.c \ server.c \ @@ -119,14 +127,6 @@ SERVAL_DAEMON_JNI_SOURCES = \ jni_commandline.c \ jni_server.c -TEST_SOURCES = \ - main.c \ - servald_main.c \ - test_cli.c \ - log_context.c \ - log_stderr.c \ - context1.c - MDP_CLIENT_SOURCES = \ mdp_client.c diff --git a/test_cli.c b/test_cli.c index 576fa5f9..103937ee 100644 --- a/test_cli.c +++ b/test_cli.c @@ -34,8 +34,7 @@ #include "mem.h" #include "str.h" -void cli_cleanup(){} -void cf_on_config_change(){} +DEFINE_FEATURE(cli_tests); DEFINE_CMD(app_byteorder_test, 0, "Run byte order handling test", @@ -323,4 +322,3 @@ static int app_config_test(const struct cli_parsed *UNUSED(parsed), struct cli_c } return 0; } - diff --git a/test_features.c b/test_features.c new file mode 100644 index 00000000..400f2dec --- /dev/null +++ b/test_features.c @@ -0,0 +1,30 @@ +/* +Serval DNA test features +Copyright (C) 2016 Flinders University + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "feature.h" + +void test_features() +{ + USE_FEATURE(cli_version); + USE_FEATURE(cli_echo); + USE_FEATURE(cli_log); + USE_FEATURE(cli_tests); +} + +void cli_cleanup() {} diff --git a/testdefs_java.sh b/testdefs_java.sh index 40df3cd0..a1117be6 100644 --- a/testdefs_java.sh +++ b/testdefs_java.sh @@ -18,10 +18,10 @@ source "${0%/*}/../testconfig.sh" # Utility function for setting up servald JNI fixtures: -# - check that libserval.so is present -# - set LD_LIBRARY_PATH so that libserval.so can be found +# - check that libservald.so is present +# - set LD_LIBRARY_PATH so that libservald.so can be found setup_servald_so() { - assert [ -r "$servald_build_root/libserval.so" ] + assert [ -r "$servald_build_root/libservald.so" ] export LD_LIBRARY_PATH="$servald_build_root" } diff --git a/version_cli.c b/version_cli.c new file mode 100644 index 00000000..626eeddf --- /dev/null +++ b/version_cli.c @@ -0,0 +1,39 @@ +/* +Serval DNA version and copyright +Copyright (C) 2014-2015 Serval Project Inc. +Copyright (C) 2016 Flinders University + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "feature.h" +#include "commandline.h" +#include "version_servald.h" + +DEFINE_FEATURE(cli_version); + +DEFINE_CMD(version_message, CLIFLAG_PERMISSIVE_CONFIG, + "Display version and copyright information.", + "version|copyright"); +static int version_message(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context)) +{ + printf("Serval DNA version %s\n%s\n", version_servald, copyright_servald); + printf("\ +License GPLv2+: GNU GPL version 2 or later .\n\ +This is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\n\ +"); + return 0; +} diff --git a/version_servald.c b/version_servald.c index 1bf11a42..be007bf2 100644 --- a/version_servald.c +++ b/version_servald.c @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "version_servald.h" + #ifndef SERVALD_VERSION #error "SERVALD_VERSION is not defined" #endif diff --git a/version_servald.h b/version_servald.h new file mode 100644 index 00000000..9d939cf0 --- /dev/null +++ b/version_servald.h @@ -0,0 +1,21 @@ +/* +Serval DNA version and copyright strings +Copyright (C) 2016 Flinders University + +This program 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 +of the License, or (at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +extern const char version_servald[]; +extern const char copyright_servald[]; diff --git a/vomp_console.c b/vomp_console.c index c9d379bb..b02c45de 100644 --- a/vomp_console.c +++ b/vomp_console.c @@ -382,6 +382,8 @@ static void monitor_read(struct sched_ent *alarm){ } } +DEFINE_FEATURE(cli_vomp_console); + DEFINE_CMD(app_vomp_console, 0, "Test phone call life-cycle from the console", "console");