diff --git a/Makefile.in b/Makefile.in index 1b56272b..73060668 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,6 +18,17 @@ OBJSDIR_TOOLS = objs OBJSDIRS = $(OBJSDIR_SERVALD) $(OBJSDIR_LIB) $(OBJSDIR_TOOLS) +ALL_SOURCES = \ + $(SERVAL_CLIENT_SOURCES) \ + $(MDP_CLIENT_SOURCES) \ + $(SERVAL_DAEMON_SOURCES) \ + $(NACL_SOURCES) \ + $(TEST_SOURCES) \ + $(SERVAL_LIB_SOURCES) \ + $(MONITOR_CLIENT_SRCS) \ + $(SIMULATOR_SOURCES) \ + $(SQLITE3_SOURCES) + SERVAL_DAEMON_OBJS = \ $(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) \ $(addprefix $(OBJSDIR_SERVALD)/, $(MDP_CLIENT_SOURCES:.c=.o)) \ @@ -26,6 +37,10 @@ SERVALD_OBJS = \ $(addprefix $(OBJSDIR_SERVALD)/, $(notdir $(SQLITE3_SOURCES:.c=.o))) \ $(addprefix $(OBJSDIR_SERVALD)/, $(NACL_SOURCES:.c=.o)) \ $(SERVAL_DAEMON_OBJS) +TEST_OBJS = \ + $(addprefix $(OBJSDIR_SERVALD)/, $(TEST_SOURCES:.c=.o)) \ + $(addprefix $(OBJSDIR_SERVALD)/, $(NACL_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)) \ @@ -67,7 +82,7 @@ DEFS= @DEFS@ all: servald libserval.so libmonitorclient.so libmonitorclient.a test -test: tfw_createfile directory_service fakeradio config_test simulator +test: tfw_createfile directory_service fakeradio simulator serval-tests covzero: | is_built_with_coverage @echo REMOVE all .gcda files @@ -117,7 +132,7 @@ config.status: configure configure: configure.in $(warning configure may be out of date, please run autoreconf -f -i) -$(OBJSDIR_TOOLS)/version.o: $(SERVALD_OBJS) version_servald.c version_string.sh $(wildcard VERSION.txt) COPYRIGHT.txt +$(OBJSDIR_TOOLS)/version.o: $(ALL_SOURCES) $(HDRS) version_servald.c version_string.sh $(wildcard VERSION.txt) COPYRIGHT.txt @echo CC version_servald.c @mkdir -p $(dir $@) @$(RM) $(@:.o=.gcno) $(@:.o=.gcda) @@ -159,14 +174,15 @@ $(SERVALD_OBJS): Makefile $(LIB_SERVAL_OBJS): $(HDRS) Makefile $(MONITOR_CLIENT_OBJS): $(HDRS) Makefile $(SIMULATOR_OBJS): $(HDRS) Makefile -$(OBJSDIR_TOOLS)/directory_service.o $(OBJSDIR_TOOLS)/tfw_createfile.o $(OBJSDIR_TOOLS)/fakeradio.o \ -$(OBJSDIR_TOOLS)/config_test.o $(OBJSDIR_TOOLS)/conf_om.o $(OBJSDIR_TOOLS)/conf_schema.o $(OBJSDIR_TOOLS)/conf_parse.o libserval.a \ - : $(HDRS) Makefile servald: $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o @echo LINK $@ @$(CC) -Wall -o $@ $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS) +serval-tests: $(TEST_OBJS) $(OBJSDIR_TOOLS)/version.o + @echo LINK $@ + @$(CC) -Wall -o $@ $(TEST_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS) + libserval.a: $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o @echo AR $@ @$(AR) -cr $@ $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o @@ -187,10 +203,6 @@ simulator: $(SIMULATOR_OBJS) libserval.a @echo LINK $@ @$(CC) -Wall -o $@ $(SIMULATOR_OBJS) libserval.a $(LDFLAGS) -config_test: $(OBJSDIR_TOOLS)/config_test.o $(OBJSDIR_TOOLS)/conf_om.o $(OBJSDIR_TOOLS)/conf_schema.o $(OBJSDIR_TOOLS)/conf_parse.o libserval.a - @echo LINK $@ - @$(CC) -Wall -o $@ $(OBJSDIR_TOOLS)/config_test.o $(OBJSDIR_TOOLS)/conf_om.o $(OBJSDIR_TOOLS)/conf_schema.o $(OBJSDIR_TOOLS)/conf_parse.o libserval.a $(LDFLAGS) - copyright: @if [ -x "$(COPYRIGHT_TOOL)" ]; then \ echo GENERATE COPYRIGHT.txt; \ diff --git a/commandline.c b/commandline.c index 3e64efaf..32aebef0 100644 --- a/commandline.c +++ b/commandline.c @@ -250,10 +250,7 @@ int parseCommandLine(struct cli_context *context, const char *argv0, int argc, c break; } - /* clean up after ourselves */ - rhizome_close_db(); - free_subscribers(); - assert(keyring==NULL); + cli_cleanup(); OUT(); @@ -555,278 +552,3 @@ static int app_log(const struct cli_parsed *parsed, struct cli_context *UNUSED(c return 0; } -static void lookup_send_request(int mdp_sockfd, const sid_t *srcsid, int srcport, const sid_t *dstsid, const char *did) -{ - overlay_mdp_frame mdp; - bzero(&mdp,sizeof(mdp)); - - /* set source address to the local address and port */ - mdp.out.src.port = srcport; - mdp.out.src.sid = *srcsid; - - /* Send to destination address and DNA lookup port */ - if (dstsid) { - /* Send an encrypted unicast packet */ - mdp.packetTypeAndFlags=MDP_TX; - mdp.out.dst.sid = *dstsid; - }else{ - /* Send a broadcast packet, flooding across the local mesh network */ - mdp.packetTypeAndFlags=MDP_TX|MDP_NOCRYPT; - mdp.out.dst.sid = SID_BROADCAST; - } - mdp.out.dst.port=MDP_PORT_DNALOOKUP; - - /* put DID into packet */ - bcopy(did,&mdp.out.payload[0],strlen(did)+1); - mdp.out.payload_length=strlen(did)+1; - - overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); - - /* Also send an encrypted unicast request to a configured directory service */ - if (!dstsid){ - if (!is_sid_t_any(config.directory.service)) { - mdp.out.dst.sid = config.directory.service; - mdp.packetTypeAndFlags=MDP_TX; - overlay_mdp_send(mdp_sockfd, &mdp,0,0); - } - } -} - -DEFINE_CMD(app_dna_lookup, 0, - "Lookup the subscribers (SID) with the supplied telephone number (DID).", - "dna","lookup","","[]"); -static int app_dna_lookup(const struct cli_parsed *parsed, struct cli_context *context) -{ - int mdp_sockfd; - if (config.debug.verbose) - DEBUG_cli_parsed(parsed); - - /* Create the instance directory if it does not yet exist */ - if (create_serval_instance_dir() == -1) - return -1; - - int uri_count=0; -#define MAXREPLIES 256 -#define MAXURILEN 256 - char uris[MAXREPLIES][MAXURILEN]; - - const char *did, *delay; - if (cli_arg(parsed, "did", &did, cli_lookup_did, "*") == -1) - return -1; - if (cli_arg(parsed, "timeout", &delay, NULL, "3000") == -1) - return -1; - - int idelay=atoi(delay); - int one_reply=0; - - // Ugly hack, if timeout is negative, stop after first reply - if (idelay<0){ - one_reply=1; - idelay=-idelay; - } - - if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) - return WHY("Cannot create MDP socket"); - - /* Bind to MDP socket and await confirmation */ - sid_t srcsid; - mdp_port_t port=32768+(random()&32767); - if (overlay_mdp_getmyaddr(mdp_sockfd, 0, &srcsid)) { - overlay_mdp_client_close(mdp_sockfd); - return WHY("Could not get local address"); - } - if (overlay_mdp_bind(mdp_sockfd, &srcsid, port)) { - overlay_mdp_client_close(mdp_sockfd); - return WHY("Could not bind to MDP socket"); - } - - /* use MDP to send the lookup request to MDP_PORT_DNALOOKUP, and wait for - replies. */ - - /* Now repeatedly send resolution request and collect results until we reach - timeout. */ - time_ms_t timeout = gettime_ms() + idelay; - time_ms_t last_tx = 0; - time_ms_t now; - int interval=125; - - const char *names[]={ - "uri", - "did", - "name" - }; - cli_columns(context, 3, names); - size_t rowcount = 0; - - while (timeout > (now = gettime_ms())){ - if ((last_tx+interval)>1; - } - time_ms_t short_timeout=125; - while(short_timeout>0) { - if (overlay_mdp_client_poll(mdp_sockfd, short_timeout)){ - overlay_mdp_frame rx; - int ttl; - if (overlay_mdp_recv(mdp_sockfd, &rx, port, &ttl)==0){ - if (rx.packetTypeAndFlags==MDP_ERROR){ - WHYF(" Error message: %s", rx.error.message); - } else if ((rx.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_TX) { - /* Extract DID, Name, URI from response. */ - if (strlen((char *)rx.out.payload)<512) { - char sidhex[SID_STRLEN + 1]; - char did[DID_MAXSIZE + 1]; - char name[64]; - char uri[512]; - if ( !parseDnaReply((char *)rx.out.payload, rx.out.payload_length, sidhex, did, name, uri, NULL) - || !str_is_subscriber_id(sidhex) - || !str_is_did(did) - || !str_is_uri(uri) - ) { - WHYF("Received malformed DNA reply: %s", alloca_toprint(160, (const char *)rx.out.payload, rx.out.payload_length)); - } else { - /* Have we seen this response before? */ - int i; - for(i=0;i", "[]"); -static int app_reverse_lookup(const struct cli_parsed *parsed, struct cli_context *context) -{ - int mdp_sockfd; - if (config.debug.verbose) - DEBUG_cli_parsed(parsed); - const char *sidhex, *delay; - if (cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, "") == -1) - return -1; - if (cli_arg(parsed, "timeout", &delay, NULL, "3000") == -1) - return -1; - - mdp_port_t port=32768+(random()&0xffff); - - sid_t srcsid; - sid_t dstsid; - - if (str_to_sid_t(&dstsid, sidhex) == -1) - return WHY("str_to_sid_t() failed"); - - if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) - return WHY("Cannot create MDP socket"); - - if (overlay_mdp_getmyaddr(mdp_sockfd, 0, &srcsid)){ - overlay_mdp_client_close(mdp_sockfd); - return WHY("Unable to get my address"); - } - if (overlay_mdp_bind(mdp_sockfd, &srcsid, port)){ - overlay_mdp_client_close(mdp_sockfd); - return WHY("Unable to bind port"); - } - - time_ms_t now = gettime_ms(); - time_ms_t timeout = now + atoi(delay); - time_ms_t next_send = now; - overlay_mdp_frame mdp_reply; - - while (now < timeout){ - now=gettime_ms(); - - if (now >= next_send){ - /* Send a unicast packet to this node, asking for any did */ - lookup_send_request(mdp_sockfd, &srcsid, port, &dstsid, ""); - next_send+=125; - continue; - } - - time_ms_t poll_timeout = (next_send>timeout?timeout:next_send) - now; - if (overlay_mdp_client_poll(mdp_sockfd, poll_timeout)<=0) - continue; - - int ttl=-1; - if (overlay_mdp_recv(mdp_sockfd, &mdp_reply, port, &ttl)) - continue; - - if ((mdp_reply.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR){ - // TODO log error? - continue; - } - - if (mdp_reply.packetTypeAndFlags!=MDP_TX) { - WHYF("MDP returned an unexpected message (type=0x%x)", - mdp_reply.packetTypeAndFlags); - - if (mdp_reply.packetTypeAndFlags==MDP_ERROR) - WHYF("MDP message is return/error: %d:%s", - mdp_reply.error.error,mdp_reply.error.message); - continue; - } - - // we might receive a late response from an ealier request on the same socket, ignore it - if (cmp_sid_t(&mdp_reply.out.src.sid, &dstsid) != 0) { - WHYF("Unexpected result from SID %s", alloca_tohex_sid_t(mdp_reply.out.src.sid)); - continue; - } - - { - char sidhex[SID_STRLEN + 1]; - char did[DID_MAXSIZE + 1]; - char name[64]; - char uri[512]; - if ( !parseDnaReply((char *)mdp_reply.out.payload, mdp_reply.out.payload_length, sidhex, did, name, uri, NULL) - || !str_is_subscriber_id(sidhex) - || !str_is_did(did) - || !str_is_uri(uri) - ) { - WHYF("Received malformed DNA reply: %s", - alloca_toprint(160, (const char *)mdp_reply.out.payload, mdp_reply.out.payload_length)); - continue; - } - - /* Got a good DNA reply, copy it into place and stop polling */ - cli_field_name(context, "sid", ":"); - cli_put_string(context, sidhex, "\n"); - cli_field_name(context, "did", ":"); - cli_put_string(context, did, "\n"); - cli_field_name(context, "name", ":"); - cli_put_string(context, name, "\n"); - overlay_mdp_client_close(mdp_sockfd); - return 0; - } - } - overlay_mdp_client_close(mdp_sockfd); - return 1; -} - diff --git a/commandline.h b/commandline.h index 23024725..6bdb46d2 100644 --- a/commandline.h +++ b/commandline.h @@ -67,4 +67,6 @@ void cli_put_string(struct cli_context *context, const char *value, const char * void cli_put_hexvalue(struct cli_context *context, const unsigned char *value, int length, const char *delim); int cli_write(struct cli_context *context, const unsigned char *buf, size_t len); +void cli_cleanup(); + #endif \ No newline at end of file diff --git a/conf.c b/conf.c index ed5bdd3b..30125fb0 100644 --- a/conf.c +++ b/conf.c @@ -51,7 +51,7 @@ static int reload(const char *path, int *resultp) if (config.debug.config) DEBUGF(" file path=%s", alloca_str_toprint(path)); struct file_meta meta; - if (get_file_meta(conffile_path(), &meta) == -1) + if (get_file_meta(path, &meta) == -1) return -1; if (config.debug.config) { DEBUGF(" file meta=%s", alloca_file_meta(&meta)); @@ -60,7 +60,7 @@ static int reload(const char *path, int *resultp) if (cmp_file_meta(&meta, &conffile_meta) == 0) return 0; if (conffile_meta.mtime.tv_sec != -1) - INFOF("config file %s -- detected new version", conffile_path()); + INFOF("config file %s -- detected new version", path); char *buf = NULL; if (meta.mtime.tv_sec == -1) { WARNF("config file %s does not exist -- using all defaults", path); diff --git a/config_test.c b/config_test.c deleted file mode 100644 index d19b7e38..00000000 --- a/config_test.c +++ /dev/null @@ -1,114 +0,0 @@ -/* -Serval DNA configuration stand-alone configuration check utility -Copyright 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 -#include -#include -#include -#include -#include - -#include "str.h" -#define __SERVAL_LOG_INLINE -#include "log.h" -#include "conf.h" - -int main(int argc, char **argv) -{ - int i; - for (i = 1; i < argc; ++i) { - int fd = open(argv[i], O_RDONLY); - if (fd == -1) { - perror("open"); - exit(1); - } - struct stat st; - fstat(fd, &st); - char *buf = malloc(st.st_size); - if (!buf) { - perror("malloc"); - exit(1); - } - if (read(fd, buf, st.st_size) != st.st_size) { - perror("read"); - exit(1); - } - struct cf_om_node *root = NULL; - int ret = cf_om_parse(argv[i], buf, st.st_size, &root); - close(fd); - DEBUGF("ret = %s", strbuf_str(strbuf_cf_flags(strbuf_alloca(128), ret))); - //cf_dump_node(root, 0); - struct config_main config; - memset(&config, 0, sizeof config); - cf_dfl_config_main(&config); - int result = root ? cf_opt_config_main(&config, root) : CFEMPTY; - cf_om_free_node(&root); - free(buf); - DEBUGF("result = %s", strbuf_str(strbuf_cf_flags(strbuf_alloca(128), result))); - DEBUGF("config.log.file.path = %s", alloca_str_toprint(config.log.file.path)); - DEBUGF("config.log.file.show_pid = %d", config.log.file.show_pid); - DEBUGF("config.log.file.show_time = %d", config.log.file.show_time); - DEBUGF("config.server.chdir = %s", alloca_str_toprint(config.server.chdir)); - DEBUGF("config.debug.verbose = %d", config.debug.verbose); - DEBUGF("config.directory.service = %s", alloca_tohex_sid_t(config.directory.service)); - DEBUGF("config.rhizome.api.addfile.allow_host = %s", inet_ntoa(config.rhizome.api.addfile.allow_host)); - unsigned j; - for (j = 0; j < config.mdp.iftype.ac; ++j) { - DEBUGF("config.mdp.iftype.%u", config.mdp.iftype.av[j].key); - DEBUGF(" .tick_ms = %u", config.mdp.iftype.av[j].value.tick_ms); - } - for (j = 0; j < config.dna.helper.argv.ac; ++j) { - DEBUGF("config.dna.helper.argv.%u=%s", config.dna.helper.argv.av[j].key, config.dna.helper.argv.av[j].value); - } - for (j = 0; j < config.rhizome.direct.peer.ac; ++j) { - DEBUGF("config.rhizome.direct.peer.%s", config.rhizome.direct.peer.av[j].key); - DEBUGF(" .protocol = %s", alloca_str_toprint(config.rhizome.direct.peer.av[j].value.protocol)); - DEBUGF(" .host = %s", alloca_str_toprint(config.rhizome.direct.peer.av[j].value.host)); - DEBUGF(" .port = %u", config.rhizome.direct.peer.av[j].value.port); - } - for (j = 0; j < config.interfaces.ac; ++j) { - DEBUGF("config.interfaces.%u", config.interfaces.av[j].key); - DEBUGF(" .exclude = %d", config.interfaces.av[j].value.exclude); - DEBUGF(" .match = ["); - unsigned k; - for (k = 0; k < config.interfaces.av[j].value.match.patc; ++k) - DEBUGF(" %s", alloca_str_toprint(config.interfaces.av[j].value.match.patv[k])); - DEBUGF(" ]"); - DEBUGF(" .type = %d", config.interfaces.av[j].value.type); - DEBUGF(" .port = %u", config.interfaces.av[j].value.port); - DEBUGF(" .drop_broadcasts = %d", (int) config.interfaces.av[j].value.drop_broadcasts); - DEBUGF(" .drop_unicasts = %d", (int) config.interfaces.av[j].value.drop_unicasts); - DEBUGF(" .drop_packets = %u", (unsigned) config.interfaces.av[j].value.drop_packets); - } - for (j = 0; j < config.hosts.ac; ++j) { - char sidhex[SID_STRLEN + 1]; - tohex(sidhex, SID_STRLEN, config.hosts.av[j].key.binary); - DEBUGF("config.hosts.%s", sidhex); - DEBUGF(" .interface = %s", alloca_str_toprint(config.hosts.av[j].value.interface)); - DEBUGF(" .address = %s", inet_ntoa(config.hosts.av[j].value.address)); - DEBUGF(" .port = %u", config.hosts.av[j].value.port); - } - } - exit(0); -} - -void cf_on_config_change() -{ -} diff --git a/fakeradio.c b/fakeradio.c index d3dcb1a5..9bc19a75 100644 --- a/fakeradio.c +++ b/fakeradio.c @@ -60,14 +60,7 @@ struct radio_state { #define STATE_PLUSPLUSPLUS 3 #define STATE_COMMAND 4 -int64_t gettime_ms() -{ - struct timeval nowtv; - // If gettimeofday() fails or returns an invalid value, all else is lost! - if (gettimeofday(&nowtv, NULL) == -1) - perror("gettimeofday"); - return nowtv.tv_sec * 1000LL + nowtv.tv_usec / 1000; -} +void cf_on_config_change(){} void log_time(){ struct timeval tv; diff --git a/log.c b/log.c index a7ff5338..241d8e57 100644 --- a/log.c +++ b/log.c @@ -17,6 +17,7 @@ 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 #include #include @@ -29,7 +30,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include -#include #include #include @@ -401,14 +401,6 @@ static void _log_iterator_vprintf_nl(_log_iterator *it, int level, struct __sour } } -static void _log_iterator_printf_nl(_log_iterator *it, int level, struct __sourceloc whence, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - _log_iterator_vprintf_nl(it, level, whence, fmt, ap); - va_end(ap); -} - static void _logs_vprintf_nl(int level, struct __sourceloc whence, const char *fmt, va_list ap) { _log_iterator it; @@ -688,108 +680,3 @@ void logConfigChanged() logFlush(); } -int logBacktrace(int level, struct __sourceloc whence) -{ -#ifndef NO_BACKTRACE - _log_iterator it; - _log_iterator_start(&it); - _rotate_log_file(&it); - char execpath[MAXPATHLEN]; - if (get_self_executable_path(execpath, sizeof execpath) == -1) - return WHY("cannot log backtrace: own executable path unknown"); - char tempfile[MAXPATHLEN]; - if (!FORMF_SERVAL_TMP_PATH(tempfile, "servalgdb.XXXXXX")) - return -1; - int tmpfd = mkstemp(tempfile); - if (tmpfd == -1) - return WHYF_perror("mkstemp(%s)", alloca_str_toprint(tempfile)); - if (write_str(tmpfd, "backtrace\n") == -1) { - close(tmpfd); - unlink(tempfile); - return -1; - } - if (close(tmpfd) == -1) { - WHY_perror("close"); - unlink(tempfile); - return -1; - } - char pidstr[12]; - snprintf(pidstr, sizeof pidstr, "%jd", (intmax_t)getpid()); - int stdout_fds[2]; - if (pipe(stdout_fds) == -1) - return WHY_perror("pipe"); - pid_t child_pid; - switch (child_pid = fork()) { - case -1: // error - WHY_perror("fork"); - close(stdout_fds[0]); - close(stdout_fds[1]); - return WHY("cannot log backtrace: fork failed"); - case 0: // child - if (dup2(stdout_fds[1], 1) == -1 || dup2(stdout_fds[1], 2) == -1) { - perror("dup2"); - _exit(-1); - } - close(0); - if (open("/dev/null", O_RDONLY) != 0) { - perror("open(\"/dev/null\")"); - _exit(-2); - } - close(stdout_fds[0]); - // Need the (void*) cast on Solaris because it defines NULL as 0L and gcc doesn't accept it as a - // sentinal - execlp("gdb", "gdb", "-n", "-batch", "-x", tempfile, execpath, pidstr, (void*)NULL); - perror("execlp(\"gdb\")"); - do { _exit(-3); } while (1); - break; - } - // parent - close(stdout_fds[1]); - _log_iterator_printf_nl(&it, level, whence, "GDB BACKTRACE"); - char buf[1024]; - char *const bufe = buf + sizeof buf; - char *linep = buf; - char *readp = buf; - ssize_t nr; - while ((nr = read(stdout_fds[0], readp, bufe - readp)) > 0) { - char *p = readp; - readp = readp + nr; - for (; p < readp; ++p) - if (*p == '\n' || *p == '\0') { - *p = '\0'; - _log_iterator_printf_nl(&it, level, __NOWHERE__, "GDB %s", linep); - linep = p + 1; - } - if (readp >= bufe && linep == buf) { - // Line does not fit into buffer. - char t = bufe[-1]; - bufe[-1] = '\0'; - _log_iterator_printf_nl(&it, level, __NOWHERE__, "GDB %s", buf); - buf[0] = t; - readp = buf + 1; - } else if (readp + 120 >= bufe && linep != buf) { - // Buffer low on space. - if (linep < readp) - memmove(buf, linep, readp - linep); - readp -= linep - buf; - linep = buf; - } - // Invariant: readp < bufe - } - if (nr == -1) - WHY_perror("read"); - if (readp > linep) { - *readp = '\0'; - _log_iterator_printf_nl(&it, level, __NOWHERE__, "GDB %s", linep); - } - close(stdout_fds[0]); - int status = 0; - if (waitpid(child_pid, &status, 0) == -1) - WHY_perror("waitpid"); - strbuf b = strbuf_local(buf, sizeof buf); - strbuf_append_exit_status(b, status); - _log_iterator_printf_nl(&it, level, __NOWHERE__, "gdb %s", buf); - unlink(tempfile); -#endif - return 0; -} diff --git a/log_util.c b/log_util.c index a974c86d..bdec9794 100644 --- a/log_util.c +++ b/log_util.c @@ -17,9 +17,17 @@ 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 +#include +#include +#include #include "log.h" #include "strbuf.h" #include "strbuf_helpers.h" +#include "instance.h" +#include "str.h" +#include "net.h" int logDump(int level, struct __sourceloc whence, char *name, const unsigned char *addr, size_t len) { @@ -104,3 +112,106 @@ int string_to_log_level(const char *text) if (strcasecmp(text, "silent") == 0) return LOG_LEVEL_SILENT; return LOG_LEVEL_INVALID; } + +int logBacktrace(int level, struct __sourceloc whence) +{ +#ifndef NO_BACKTRACE + char execpath[MAXPATHLEN]; + if (get_self_executable_path(execpath, sizeof execpath) == -1) + return WHY("cannot log backtrace: own executable path unknown"); + char tempfile[MAXPATHLEN]; + if (!FORMF_SERVAL_TMP_PATH(tempfile, "servalgdb.XXXXXX")) + return -1; + int tmpfd = mkstemp(tempfile); + if (tmpfd == -1) + return WHYF_perror("mkstemp(%s)", alloca_str_toprint(tempfile)); + if (write_str(tmpfd, "backtrace\n") == -1) { + close(tmpfd); + unlink(tempfile); + return -1; + } + if (close(tmpfd) == -1) { + WHY_perror("close"); + unlink(tempfile); + return -1; + } + char pidstr[12]; + snprintf(pidstr, sizeof pidstr, "%jd", (intmax_t)getpid()); + int stdout_fds[2]; + if (pipe(stdout_fds) == -1) + return WHY_perror("pipe"); + pid_t child_pid; + switch (child_pid = fork()) { + case -1: // error + WHY_perror("fork"); + close(stdout_fds[0]); + close(stdout_fds[1]); + return WHY("cannot log backtrace: fork failed"); + case 0: // child + if (dup2(stdout_fds[1], 1) == -1 || dup2(stdout_fds[1], 2) == -1) { + perror("dup2"); + _exit(-1); + } + close(0); + if (open("/dev/null", O_RDONLY) != 0) { + perror("open(\"/dev/null\")"); + _exit(-2); + } + close(stdout_fds[0]); + // Need the (void*) cast on Solaris because it defines NULL as 0L and gcc doesn't accept it as a + // sentinal + execlp("gdb", "gdb", "-n", "-batch", "-x", tempfile, execpath, pidstr, (void*)NULL); + perror("execlp(\"gdb\")"); + do { _exit(-3); } while (1); + break; + } + // parent + close(stdout_fds[1]); + logMessage(level, whence, "GDB BACKTRACE"); + char buf[1024]; + char *const bufe = buf + sizeof buf; + char *linep = buf; + char *readp = buf; + ssize_t nr; + while ((nr = read(stdout_fds[0], readp, bufe - readp)) > 0) { + char *p = readp; + readp = readp + nr; + for (; p < readp; ++p) + if (*p == '\n' || *p == '\0') { + *p = '\0'; + logMessage(level, __NOWHERE__, "GDB %s", linep); + linep = p + 1; + } + if (readp >= bufe && linep == buf) { + // Line does not fit into buffer. + char t = bufe[-1]; + bufe[-1] = '\0'; + logMessage(level, __NOWHERE__, "GDB %s", buf); + buf[0] = t; + readp = buf + 1; + } else if (readp + 120 >= bufe && linep != buf) { + // Buffer low on space. + if (linep < readp) + memmove(buf, linep, readp - linep); + readp -= linep - buf; + linep = buf; + } + // Invariant: readp < bufe + } + if (nr == -1) + WHY_perror("read"); + if (readp > linep) { + *readp = '\0'; + logMessage(level, __NOWHERE__, "GDB %s", linep); + } + close(stdout_fds[0]); + int status = 0; + if (waitpid(child_pid, &status, 0) == -1) + WHY_perror("waitpid"); + strbuf b = strbuf_local(buf, sizeof buf); + strbuf_append_exit_status(b, status); + logMessage(level, __NOWHERE__, "gdb %s", buf); + unlink(tempfile); +#endif + return 0; +} diff --git a/network_cli.c b/network_cli.c index edf1b88d..f87322b3 100644 --- a/network_cli.c +++ b/network_cli.c @@ -27,6 +27,10 @@ #include "conf.h" #include "commandline.h" #include "sighandlers.h" +#include "instance.h" +#include "serval.h" +#include "overlay_buffer.h" + DEFINE_CMD(app_mdp_ping, 0, "Attempts to ping specified node via Mesh Datagram Protocol (MDP).", @@ -530,3 +534,278 @@ static int app_network_scan(const struct cli_parsed *parsed, struct cli_context cli_put_string(context, mdp.error.message, "\n"); return mdp.error.error; } + +static void lookup_send_request(int mdp_sockfd, const sid_t *srcsid, int srcport, const sid_t *dstsid, const char *did) +{ + overlay_mdp_frame mdp; + bzero(&mdp,sizeof(mdp)); + + /* set source address to the local address and port */ + mdp.out.src.port = srcport; + mdp.out.src.sid = *srcsid; + + /* Send to destination address and DNA lookup port */ + if (dstsid) { + /* Send an encrypted unicast packet */ + mdp.packetTypeAndFlags=MDP_TX; + mdp.out.dst.sid = *dstsid; + }else{ + /* Send a broadcast packet, flooding across the local mesh network */ + mdp.packetTypeAndFlags=MDP_TX|MDP_NOCRYPT; + mdp.out.dst.sid = SID_BROADCAST; + } + mdp.out.dst.port=MDP_PORT_DNALOOKUP; + + /* put DID into packet */ + bcopy(did,&mdp.out.payload[0],strlen(did)+1); + mdp.out.payload_length=strlen(did)+1; + + overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); + + /* Also send an encrypted unicast request to a configured directory service */ + if (!dstsid){ + if (!is_sid_t_any(config.directory.service)) { + mdp.out.dst.sid = config.directory.service; + mdp.packetTypeAndFlags=MDP_TX; + overlay_mdp_send(mdp_sockfd, &mdp,0,0); + } + } +} + +DEFINE_CMD(app_dna_lookup, 0, + "Lookup the subscribers (SID) with the supplied telephone number (DID).", + "dna","lookup","","[]"); +static int app_dna_lookup(const struct cli_parsed *parsed, struct cli_context *context) +{ + int mdp_sockfd; + if (config.debug.verbose) + DEBUG_cli_parsed(parsed); + + /* Create the instance directory if it does not yet exist */ + if (create_serval_instance_dir() == -1) + return -1; + + int uri_count=0; +#define MAXREPLIES 256 +#define MAXURILEN 256 + char uris[MAXREPLIES][MAXURILEN]; + + const char *did, *delay; + if (cli_arg(parsed, "did", &did, cli_lookup_did, "*") == -1) + return -1; + if (cli_arg(parsed, "timeout", &delay, NULL, "3000") == -1) + return -1; + + int idelay=atoi(delay); + int one_reply=0; + + // Ugly hack, if timeout is negative, stop after first reply + if (idelay<0){ + one_reply=1; + idelay=-idelay; + } + + if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) + return WHY("Cannot create MDP socket"); + + /* Bind to MDP socket and await confirmation */ + sid_t srcsid; + mdp_port_t port=32768+(random()&32767); + if (overlay_mdp_getmyaddr(mdp_sockfd, 0, &srcsid)) { + overlay_mdp_client_close(mdp_sockfd); + return WHY("Could not get local address"); + } + if (overlay_mdp_bind(mdp_sockfd, &srcsid, port)) { + overlay_mdp_client_close(mdp_sockfd); + return WHY("Could not bind to MDP socket"); + } + + /* use MDP to send the lookup request to MDP_PORT_DNALOOKUP, and wait for + replies. */ + + /* Now repeatedly send resolution request and collect results until we reach + timeout. */ + time_ms_t timeout = gettime_ms() + idelay; + time_ms_t last_tx = 0; + time_ms_t now; + int interval=125; + + const char *names[]={ + "uri", + "did", + "name" + }; + cli_columns(context, 3, names); + size_t rowcount = 0; + + while (timeout > (now = gettime_ms())){ + if ((last_tx+interval)>1; + } + time_ms_t short_timeout=125; + while(short_timeout>0) { + if (overlay_mdp_client_poll(mdp_sockfd, short_timeout)){ + overlay_mdp_frame rx; + int ttl; + if (overlay_mdp_recv(mdp_sockfd, &rx, port, &ttl)==0){ + if (rx.packetTypeAndFlags==MDP_ERROR){ + WHYF(" Error message: %s", rx.error.message); + } else if ((rx.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_TX) { + /* Extract DID, Name, URI from response. */ + if (strlen((char *)rx.out.payload)<512) { + char sidhex[SID_STRLEN + 1]; + char did[DID_MAXSIZE + 1]; + char name[64]; + char uri[512]; + if ( !parseDnaReply((char *)rx.out.payload, rx.out.payload_length, sidhex, did, name, uri, NULL) + || !str_is_subscriber_id(sidhex) + || !str_is_did(did) + || !str_is_uri(uri) + ) { + WHYF("Received malformed DNA reply: %s", alloca_toprint(160, (const char *)rx.out.payload, rx.out.payload_length)); + } else { + /* Have we seen this response before? */ + int i; + for(i=0;i", "[]"); +static int app_reverse_lookup(const struct cli_parsed *parsed, struct cli_context *context) +{ + int mdp_sockfd; + if (config.debug.verbose) + DEBUG_cli_parsed(parsed); + const char *sidhex, *delay; + if (cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, "") == -1) + return -1; + if (cli_arg(parsed, "timeout", &delay, NULL, "3000") == -1) + return -1; + + mdp_port_t port=32768+(random()&0xffff); + + sid_t srcsid; + sid_t dstsid; + + if (str_to_sid_t(&dstsid, sidhex) == -1) + return WHY("str_to_sid_t() failed"); + + if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) + return WHY("Cannot create MDP socket"); + + if (overlay_mdp_getmyaddr(mdp_sockfd, 0, &srcsid)){ + overlay_mdp_client_close(mdp_sockfd); + return WHY("Unable to get my address"); + } + if (overlay_mdp_bind(mdp_sockfd, &srcsid, port)){ + overlay_mdp_client_close(mdp_sockfd); + return WHY("Unable to bind port"); + } + + time_ms_t now = gettime_ms(); + time_ms_t timeout = now + atoi(delay); + time_ms_t next_send = now; + overlay_mdp_frame mdp_reply; + + while (now < timeout){ + now=gettime_ms(); + + if (now >= next_send){ + /* Send a unicast packet to this node, asking for any did */ + lookup_send_request(mdp_sockfd, &srcsid, port, &dstsid, ""); + next_send+=125; + continue; + } + + time_ms_t poll_timeout = (next_send>timeout?timeout:next_send) - now; + if (overlay_mdp_client_poll(mdp_sockfd, poll_timeout)<=0) + continue; + + int ttl=-1; + if (overlay_mdp_recv(mdp_sockfd, &mdp_reply, port, &ttl)) + continue; + + if ((mdp_reply.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR){ + // TODO log error? + continue; + } + + if (mdp_reply.packetTypeAndFlags!=MDP_TX) { + WHYF("MDP returned an unexpected message (type=0x%x)", + mdp_reply.packetTypeAndFlags); + + if (mdp_reply.packetTypeAndFlags==MDP_ERROR) + WHYF("MDP message is return/error: %d:%s", + mdp_reply.error.error,mdp_reply.error.message); + continue; + } + + // we might receive a late response from an ealier request on the same socket, ignore it + if (cmp_sid_t(&mdp_reply.out.src.sid, &dstsid) != 0) { + WHYF("Unexpected result from SID %s", alloca_tohex_sid_t(mdp_reply.out.src.sid)); + continue; + } + + { + char sidhex[SID_STRLEN + 1]; + char did[DID_MAXSIZE + 1]; + char name[64]; + char uri[512]; + if ( !parseDnaReply((char *)mdp_reply.out.payload, mdp_reply.out.payload_length, sidhex, did, name, uri, NULL) + || !str_is_subscriber_id(sidhex) + || !str_is_did(did) + || !str_is_uri(uri) + ) { + WHYF("Received malformed DNA reply: %s", + alloca_toprint(160, (const char *)mdp_reply.out.payload, mdp_reply.out.payload_length)); + continue; + } + + /* Got a good DNA reply, copy it into place and stop polling */ + cli_field_name(context, "sid", ":"); + cli_put_string(context, sidhex, "\n"); + cli_field_name(context, "did", ":"); + cli_put_string(context, did, "\n"); + cli_field_name(context, "name", ":"); + cli_put_string(context, name, "\n"); + overlay_mdp_client_close(mdp_sockfd); + return 0; + } + } + overlay_mdp_client_close(mdp_sockfd); + return 1; +} diff --git a/overlay_address.h b/overlay_address.h index 38a5586d..0bd3b4ba 100644 --- a/overlay_address.h +++ b/overlay_address.h @@ -23,7 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "constants.h" #include "os.h" // for time_ms_t #include "socket.h" -#include "overlay_buffer.h" // for struct overlay_buffer // not reachable #define REACHABLE_NONE 0 @@ -48,6 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define BROADCAST_LEN 8 struct packet_rule; +struct overlay_buffer; // This structure supports both our own routing protocol which can store calculation details in *node // or IP4 addresses reachable via any other kind of normal layer3 routing protocol, eg olsr diff --git a/server.c b/server.c index 053aee13..fcce5958 100644 --- a/server.c +++ b/server.c @@ -55,6 +55,13 @@ static const char *_server_pidfile_path(struct __sourceloc __whence); #define server_pidfile_path() (_server_pidfile_path(__WHENCE__)) void server_shutdown_check(struct sched_ent *alarm); +void cli_cleanup(){ + /* clean up after ourselves */ + rhizome_close_db(); + free_subscribers(); + assert(keyring==NULL); +} + /** Return the PID of the currently running server process, return 0 if there is none. */ int server_pid() diff --git a/sourcefiles.mk b/sourcefiles.mk index 08a89452..047cd18c 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -50,7 +50,6 @@ SERVAL_DAEMON_SOURCES = \ rhizome_cli.c \ keyring_cli.c \ network_cli.c \ - test_cli.c \ crypto.c \ directory_client.c \ dna_helper.c \ @@ -102,9 +101,15 @@ SERVAL_DAEMON_SOURCES = \ fec-3.0.1/ccsds_tables.c \ fec-3.0.1/decode_rs_8.c \ fec-3.0.1/encode_rs_8.c \ - fec-3.0.1/init_rs_char.c \ - context1.c + fec-3.0.1/init_rs_char.c +TEST_SOURCES = \ + commandline.c \ + main.c \ + test_cli.c \ + log_stderr.c \ + context1.c + MDP_CLIENT_SOURCES = \ mdp_client.c \ mdp_net.c diff --git a/test_cli.c b/test_cli.c index 2abb2cec..e6daa8a9 100644 --- a/test_cli.c +++ b/test_cli.c @@ -17,12 +17,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include +#include +#include +#include +#include +#include +#include + #include "serval_types.h" #include "dataformats.h" #include "os.h" #include "cli.h" #include "conf.h" #include "commandline.h" +#include "mem.h" + +void cli_cleanup(){} +void cf_on_config_change(){} DEFINE_CMD(app_byteorder_test, 0, "Run byte order handling test", @@ -260,3 +272,80 @@ static int app_mem_test(const struct cli_parsed *UNUSED(parsed), struct cli_cont return 0; } +DEFINE_CMD(app_config_test, 0, + "Load a test config file and log various fields", + "config","test",""); +static int app_config_test(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context)) +{ + const char *filename; + if (cli_arg(parsed, "file", &filename, NULL, NULL)==-1) + return -1; + + int fd = open(filename, O_RDONLY); + if (fd == -1) + return WHY_perror("open"); + struct stat st; + fstat(fd, &st); + char *buf = emalloc(st.st_size); + if (!buf) + return -1; + if (read(fd, buf, st.st_size) != st.st_size) + return WHY_perror("read"); + struct cf_om_node *root = NULL; + int ret = cf_om_parse(filename, buf, st.st_size, &root); + close(fd); + DEBUGF("ret = %s", strbuf_str(strbuf_cf_flags(strbuf_alloca(128), ret))); + //cf_dump_node(root, 0); + struct config_main config; + memset(&config, 0, sizeof config); + cf_dfl_config_main(&config); + int result = root ? cf_opt_config_main(&config, root) : CFEMPTY; + cf_om_free_node(&root); + free(buf); + DEBUGF("result = %s", strbuf_str(strbuf_cf_flags(strbuf_alloca(128), result))); + DEBUGF("config.log.file.path = %s", alloca_str_toprint(config.log.file.path)); + DEBUGF("config.log.file.show_pid = %d", config.log.file.show_pid); + DEBUGF("config.log.file.show_time = %d", config.log.file.show_time); + DEBUGF("config.server.chdir = %s", alloca_str_toprint(config.server.chdir)); + DEBUGF("config.debug.verbose = %d", config.debug.verbose); + DEBUGF("config.directory.service = %s", alloca_tohex_sid_t(config.directory.service)); + DEBUGF("config.rhizome.api.addfile.allow_host = %s", inet_ntoa(config.rhizome.api.addfile.allow_host)); + unsigned j; + for (j = 0; j < config.mdp.iftype.ac; ++j) { + DEBUGF("config.mdp.iftype.%u", config.mdp.iftype.av[j].key); + DEBUGF(" .tick_ms = %u", config.mdp.iftype.av[j].value.tick_ms); + } + for (j = 0; j < config.dna.helper.argv.ac; ++j) { + DEBUGF("config.dna.helper.argv.%u=%s", config.dna.helper.argv.av[j].key, config.dna.helper.argv.av[j].value); + } + for (j = 0; j < config.rhizome.direct.peer.ac; ++j) { + DEBUGF("config.rhizome.direct.peer.%s", config.rhizome.direct.peer.av[j].key); + DEBUGF(" .protocol = %s", alloca_str_toprint(config.rhizome.direct.peer.av[j].value.protocol)); + DEBUGF(" .host = %s", alloca_str_toprint(config.rhizome.direct.peer.av[j].value.host)); + DEBUGF(" .port = %u", config.rhizome.direct.peer.av[j].value.port); + } + for (j = 0; j < config.interfaces.ac; ++j) { + DEBUGF("config.interfaces.%u", config.interfaces.av[j].key); + DEBUGF(" .exclude = %d", config.interfaces.av[j].value.exclude); + DEBUGF(" .match = ["); + unsigned k; + for (k = 0; k < config.interfaces.av[j].value.match.patc; ++k) + DEBUGF(" %s", alloca_str_toprint(config.interfaces.av[j].value.match.patv[k])); + DEBUGF(" ]"); + DEBUGF(" .type = %d", config.interfaces.av[j].value.type); + DEBUGF(" .port = %u", config.interfaces.av[j].value.port); + DEBUGF(" .drop_broadcasts = %d", (int) config.interfaces.av[j].value.drop_broadcasts); + DEBUGF(" .drop_unicasts = %d", (int) config.interfaces.av[j].value.drop_unicasts); + DEBUGF(" .drop_packets = %u", (unsigned) config.interfaces.av[j].value.drop_packets); + } + for (j = 0; j < config.hosts.ac; ++j) { + char sidhex[SID_STRLEN + 1]; + tohex(sidhex, SID_STRLEN, config.hosts.av[j].key.binary); + DEBUGF("config.hosts.%s", sidhex); + DEBUGF(" .interface = %s", alloca_str_toprint(config.hosts.av[j].value.interface)); + DEBUGF(" .address = %s", inet_ntoa(config.hosts.av[j].value.address)); + DEBUGF(" .port = %u", config.hosts.av[j].value.port); + } + return 0; +} +