summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-08-30 15:02:12 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-08-30 15:02:12 -0400
commit4875eb49f851d7919587cbc2059ff552a24bcfc1 (patch)
tree5e3080f1f264fa678d0223184db74db8d805c11d
parent11774f7d5fe14226e99118f95346deda51baa254 (diff)
downloadinfinitytier-4875eb49f851d7919587cbc2059ff552a24bcfc1.tar.gz
infinitytier-4875eb49f851d7919587cbc2059ff552a24bcfc1.zip
Remove old launcher code, fix build error in idtool, add terminate command to control bus.
-rw-r--r--idtool.cpp126
-rw-r--r--launcher-fakebin.c21
-rw-r--r--launcher.c279
-rw-r--r--launcher.h71
-rw-r--r--main.cpp20
-rw-r--r--node/Node.cpp30
-rw-r--r--node/Node.hpp10
-rw-r--r--node/NodeConfig.cpp6
-rw-r--r--node/RuntimeEnvironment.hpp3
9 files changed, 37 insertions, 529 deletions
diff --git a/idtool.cpp b/idtool.cpp
index 00511a0f..66a7bafc 100644
--- a/idtool.cpp
+++ b/idtool.cpp
@@ -45,8 +45,6 @@ static void printHelp(char *pn)
std::cout << "\tgetpublic <identity.secret>" << std::endl;
std::cout << "\tsign <identity.secret> <file>" << std::endl;
std::cout << "\tverify <identity.secret/public> <file> <signature>" << std::endl;
- std::cout << "\tencrypt <identity.secret> <identity.public (recipient)> [<file>] [<outfile>]" << std::endl;
- std::cout << "\tdecrypt <identity.secret> <identity.public (sender)> [<file>] [<outfile>]" << std::endl;
}
static Identity getIdFromArg(char *arg)
@@ -165,130 +163,6 @@ int main(int argc,char **argv)
std::cerr << argv[3] << " signature check FAILED" << std::endl;
return -1;
}
- } else if (!strcmp(argv[1],"encrypt")) {
- if (argc < 4) {
- printHelp(argv[0]);
- return -1;
- }
-
- Identity from = getIdFromArg(argv[2]);
- if (!from) {
- std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
- return -1;
- }
- if (!from.hasPrivate()) {
- std::cerr << argv[2] << " must contain a secret key" << std::endl;
- return -1;
- }
-
- Identity to = getIdFromArg(argv[3]);
- if (!to) {
- std::cerr << "Identity argument invalid or file unreadable: " << argv[3] << std::endl;
- return -1;
- }
-
- FILE *inf;
- if (argc > 4) {
- inf = fopen(argv[4],"r");
- if (!inf) {
- std::cerr << "Could not open input file " << argv[4] << std::endl;
- return -1;
- }
- } else inf = stdin;
- int inbuflen = 131072;
- char *inbuf = (char *)malloc(inbuflen);
- if (!inbuf) {
- std::cerr << "Could not malloc()" << std::endl;
- return -1;
- }
- int inlen = 0;
- int n;
- while ((n = (int)fread(inbuf + inlen,1,inbuflen - inlen,inf)) > 0) {
- inlen += n;
- if ((inbuflen - inlen) < 1024) {
- inbuf = (char *)realloc(inbuf,inbuflen += 131072);
- if (!inbuf) {
- std::cerr << "Could not malloc()" << std::endl;
- return -1;
- }
- }
- }
- if (inf != stdin)
- fclose(inf);
-
- std::string crypted(from.encrypt(to,inbuf,inlen));
- if (!crypted.length()) {
- std::cerr << "Failure encrypting data, check from/to identities" << std::endl;
- return -1;
- }
-
- if (argc > 5)
- Utils::writeFile(argv[5],crypted.data(),crypted.length());
- else fwrite(crypted.data(),1,crypted.length(),stdout);
-
- free(inbuf);
- } else if (!strcmp(argv[1],"decrypt")) {
- if (argc < 4) {
- printHelp(argv[0]);
- return -1;
- }
-
- Identity to = getIdFromArg(argv[2]);
- if (!to) {
- std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
- return -1;
- }
-
- if (!to.hasPrivate()) {
- std::cerr << argv[2] << " must contain a secret key" << std::endl;
- return -1;
- }
-
- Identity from = getIdFromArg(argv[3]);
- if (!from) {
- std::cerr << "Identity argument invalid or file unreadable: " << argv[3] << std::endl;
- return -1;
- }
-
- FILE *inf;
- if (argc > 4) {
- inf = fopen(argv[4],"r");
- if (!inf) {
- std::cerr << "Could not open input file " << argv[4] << std::endl;
- return -1;
- }
- } else inf = stdin;
- int inbuflen = 131072;
- char *inbuf = (char *)malloc(inbuflen);
- if (!inbuf) {
- std::cerr << "Could not malloc()" << std::endl;
- return -1;
- }
- int inlen = 0;
- int n;
- while ((n = (int)fread(inbuf + inlen,1,inbuflen - inlen,inf)) > 0) {
- inlen += n;
- if ((inbuflen - inlen) < 1024) {
- inbuf = (char *)realloc(inbuf,inbuflen += 131072);
- if (!inbuf) {
- std::cerr << "Could not malloc()" << std::endl;
- return -1;
- }
- }
- }
- if (inf != stdin)
- fclose(inf);
-
- std::string dec(to.decrypt(from,inbuf,inlen));
- free(inbuf);
- if (!dec.length()) {
- std::cerr << "Failure decrypting data, check from/to identities" << std::endl;
- return -1;
- }
-
- if (argc > 5)
- Utils::writeFile(argv[5],dec.data(),dec.length());
- else fwrite(dec.data(),1,dec.length(),stdout);
} else {
printHelp(argv[0]);
return -1;
diff --git a/launcher-fakebin.c b/launcher-fakebin.c
deleted file mode 100644
index 42368906..00000000
--- a/launcher-fakebin.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Fake zerotier-one binary to test launcher upgrade procedure */
-
-#include <stdio.h>
-#include <unistd.h>
-#include "launcher.h"
-
-const unsigned char EMBEDDED_VERSION_STAMP[20] = {
- 0x6d,0xfe,0xff,0x01,0x90,0xfa,0x89,0x57,0x88,0xa1,0xaa,0xdc,0xdd,0xde,0xb0,0x33,
- ZEROTIER_FAKE_VERSION_MAJOR,
- ZEROTIER_FAKE_VERSION_MINOR,
- (unsigned char)(((unsigned int)ZEROTIER_FAKE_VERSION_REVISION) & 0xff), /* little-endian */
- (unsigned char)((((unsigned int)ZEROTIER_FAKE_VERSION_REVISION) >> 8) & 0xff)
-};
-
-int main(int argc,char **argv)
-{
- fprintf(stderr,"Fake ZeroTier binary version %d.%d.%d\n",ZEROTIER_FAKE_VERSION_MAJOR,ZEROTIER_FAKE_VERSION_MINOR,ZEROTIER_FAKE_VERSION_REVISION);
- sleep(5);
- fprintf(stderr," (exiting)\n");
- return ZEROTIER_EXEC_RETURN_VALUE_TERMINATED_FOR_UPGRADE;
-}
diff --git a/launcher.c b/launcher.c
deleted file mode 100644
index b51d0398..00000000
--- a/launcher.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2013 ZeroTier Networks LLC
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-/* Launcher for Linux/Unix/Mac */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include "launcher.h"
-
-/* Must match first 16 bytes of EMBEDDED_VERSION_STAMP in Node.cpp */
-static const unsigned char EMBEDDED_VERSION_STAMP_KEY[16] = { 0x6d,0xfe,0xff,0x01,0x90,0xfa,0x89,0x57,0x88,0xa1,0xaa,0xdc,0xdd,0xde,0xb0,0x33 };
-
-const unsigned char EMBEDDED_LAUNCHER_VERSION_STAMP[20] = {
- 0x96,0xf0,0x00,0x08,0x18,0xff,0xc9,0xde,0xad,0xf0,0x0f,0xbe,0xef,0x30,0xce,0xa1, /* key */
- ZT_LAUNCHER_VERSION_MAJOR,
- ZT_LAUNCHER_VERSION_MINOR,
- (unsigned char)(((unsigned int)ZT_LAUNCHER_VERSION_REVISION) & 0xff), /* little-endian */
- (unsigned char)((((unsigned int)ZT_LAUNCHER_VERSION_REVISION) >> 8) & 0xff)
-};
-
-#define ZT_BINARY_NAME "zerotier-one"
-#define ZT_BINARY_UPDATE_PREFIX "zerotier-one_update."
-
-#define ZT_LAUNCHER_PIDFILE "zerotier-launcher.pid"
-#define ZT_ONE_PIDFILE "zerotier-one.pid"
-
-/* Load a file into newly malloc()'ed memory, len set to size */
-static unsigned char *loadFile(const char *path,unsigned long *len)
-{
- unsigned char *fbuf = (unsigned char *)0;
- FILE *f = fopen(path,"rb");
- if (f) {
- if (!fseek(f,0,SEEK_END)) {
- long l = ftell(f);
- if (l > 0) {
- fseek(f,0,SEEK_SET);
- fbuf = malloc(l);
- if (fbuf) {
- if (fread(fbuf,l,1,f) != 1) {
- free(fbuf);
- fbuf = (unsigned char *)0;
- } else *len = (unsigned long)l;
- }
- }
- }
- fclose(f);
- }
- return fbuf;
-}
-
-/* Scans a ZeroTier binary and determines its version from its embedded version code */
-static int findVersion(const unsigned char *bin,unsigned long len,unsigned int *major,unsigned int *minor,unsigned int *revision)
-{
- unsigned long i;
-
- if (len > 20) {
- for(i=0;i<(len - 20);++i) {
- if ((bin[i] == EMBEDDED_VERSION_STAMP_KEY[0])&&(!memcmp(bin + i,EMBEDDED_VERSION_STAMP_KEY,16))) {
- *major = bin[i + 16];
- *minor = bin[i + 17];
- *revision = ((unsigned int)bin[i + 18] & 0xff) | (((unsigned int)bin[i + 19] << 8) & 0xff00);
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-/* Scan for updates and, if found, replace the main binary if possible */
-static int doUpdateBinaryIfNewer()
-{
- long pfxLen = strlen(ZT_BINARY_UPDATE_PREFIX);
- struct dirent dbuf,*d;
- int needUpdate;
- unsigned int major = 0,minor = 0,revision = 0;
- unsigned int existingMajor = 0,existingMinor = 0,existingRevision = 0;
- unsigned long binLen;
- unsigned char *bin;
- char oldname[1024];
- DIR *dir;
-
- binLen = 0;
- bin = loadFile(ZT_BINARY_NAME,&binLen);
- if (!((bin)&&(binLen)&&(findVersion(bin,binLen,&existingMajor,&existingMinor,&existingRevision)))) {
- if (bin)
- free(bin);
- return 0;
- }
- free(bin);
-
- dir = opendir(".");
- if (!dir)
- return 0;
- while (!readdir_r(dir,&dbuf,&d)) {
- if (!d) break;
- if (!strncasecmp(d->d_name,ZT_BINARY_UPDATE_PREFIX,pfxLen)) {
- binLen = 0;
- unsigned char *bin = loadFile(d->d_name,&binLen);
- if ((bin)&&(binLen)&&(findVersion(bin,binLen,&major,&minor,&revision))) {
- needUpdate = 0;
- if (major > existingMajor)
- needUpdate = 1;
- else if (major == existingMajor) {
- if (minor > existingMinor)
- needUpdate = 1;
- else if (minor == existingMinor) {
- if (revision > existingRevision)
- needUpdate = 1;
- }
- }
- free(bin);
- if (needUpdate) {
- /* fprintf(stderr,"zerotier-launcher: replacing %s with %s\n",ZT_BINARY_NAME,d->d_name); */
- sprintf(oldname,"%s.OLD",ZT_BINARY_NAME);
- if (!rename(ZT_BINARY_NAME,oldname)) {
- /* fprintf(stderr,"zerotier-launcher: %s -> %s\n",ZT_BINARY_NAME,oldname); */
- if (!rename(d->d_name,ZT_BINARY_NAME)) {
- /* fprintf(stderr,"zerotier-launcher: %s -> %s\nzerotier-launcher: delete %s\n",d->d_name,ZT_BINARY_NAME,oldname); */
- chmod(ZT_BINARY_NAME,0755);
- unlink(oldname);
- return 1;
- }
- }
- break;
- }
- }
- if (bin)
- free(bin);
- }
- }
- closedir(dir);
-
- return 0;
-}
-
-static volatile long childPid = 0;
-
-static void sigRepeater(int sig)
-{
- if (childPid > 0)
- kill(childPid,sig);
-}
-
-int main(int argc,char **argv)
-{
- const char *zerotierHome = ZT_DEFAULT_HOME;
- FILE *pidf;
- int status,exitCode;
- unsigned long timeStart;
- unsigned int numSubTwoSecondRuns;
-
- /* Pass on certain signals transparently to the subprogram to do with as it will */
- signal(SIGHUP,&sigRepeater);
- signal(SIGPIPE,SIG_IGN);
- signal(SIGUSR1,&sigRepeater);
- signal(SIGUSR2,&sigRepeater);
- signal(SIGALRM,SIG_IGN);
- signal(SIGURG,SIG_IGN);
- signal(SIGTERM,&sigRepeater);
- signal(SIGQUIT,&sigRepeater);
-
- if (argc == 2)
- zerotierHome = argv[1];
-
- if (chdir(zerotierHome)) {
- fprintf(stderr,"%s: fatal error: could not chdir to %s\n",argv[0],zerotierHome);
- return ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
- }
-
- pidf = fopen(ZT_LAUNCHER_PIDFILE,"w");
- if (pidf) {
- fprintf(pidf,"%d",(int)getpid());
- fclose(pidf);
- }
-
- numSubTwoSecondRuns = 0;
- exitCode = ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION;
-
-restart_subprogram:
- /* We actually do this on every loop, which is fine. It picks up any
- * newer versions that are waiting and swaps them out for the current
- * running binary. */
- doUpdateBinaryIfNewer();
-
- timeStart = time(0);
- childPid = fork();
- if (childPid < 0) {
- fprintf(stderr,"%s: fatal error: could not fork(): %s\n",argv[0],strerror(errno));
- return ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
- } else if (childPid) {
- pidf = fopen(ZT_ONE_PIDFILE,"w");
- if (pidf) {
- fprintf(pidf,"%d",(int)childPid);
- fclose(pidf);
- }
-
- status = ZT_EXEC_RETURN_VALUE_NO_BINARY;
-wait_for_subprogram_exit:
- if ((long)waitpid(childPid,&status,0) >= 0) {
- if (WIFEXITED(status)) {
- unlink(ZT_ONE_PIDFILE);
-
- if ((time(0) - timeStart) < 2) {
- /* Terminate abnormally if we appear to be looping in a tight loop
- * to avoid fork bombing if one exits abnormally without an abnormal
- * exit code. */
- if (++numSubTwoSecondRuns >= 16) {
- fprintf(stderr,"%s: fatal error: program exiting immediately in infinite loop\n",argv[0]);
- return ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
- }
- }
-
- switch(WEXITSTATUS(status)) {
- case ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION:
- exitCode = ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION;
- goto exit_launcher;
- case ZT_EXEC_RETURN_VALUE_NO_BINARY:
- fprintf(stderr,"%s: fatal error: binary zerotier-one not found at %s\n",argv[0],zerotierHome);
- exitCode = ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
- goto exit_launcher;
- case ZT_EXEC_RETURN_VALUE_TERMINATED_FOR_UPGRADE:
- case ZT_EXEC_RETURN_VALUE_PLEASE_RESTART:
- goto restart_subprogram;
- default:
- exitCode = status;
- goto exit_launcher;
- }
- }
- } else if (errno != EINTR) {
- fprintf(stderr,"%s: fatal error: waitpid() failed: %s\n",argv[0],strerror(errno));
- exitCode = ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
- goto exit_launcher;
- } else {
- goto wait_for_subprogram_exit;
- }
- } else {
- execl(ZT_BINARY_NAME,ZT_BINARY_NAME,zerotierHome,(char *)0);
- exit(ZT_EXEC_RETURN_VALUE_NO_BINARY); /* only reached if execl succeeds */
- }
-
-exit_launcher:
- unlink(ZT_LAUNCHER_PIDFILE);
- return exitCode;
-}
diff --git a/launcher.h b/launcher.h
deleted file mode 100644
index d99eadc8..00000000
--- a/launcher.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2013 ZeroTier Networks LLC
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef _ZT_LAUNCHER_H
-#define _ZT_LAUNCHER_H
-
-#define ZT_LAUNCHER_VERSION_MAJOR 0
-#define ZT_LAUNCHER_VERSION_MINOR 0
-#define ZT_LAUNCHER_VERSION_REVISION 1
-
-/**
- * Normal termination
- *
- * This causes the launcher too to exit normally.
- */
-#define ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION 0
-
-/**
- * Terminated for upgrade
- *
- * This tells the launcher that an upgrade may be available, so a scan for
- * newer executables should be performed followed by a restart.
- */
-#define ZT_EXEC_RETURN_VALUE_TERMINATED_FOR_UPGRADE 1
-
-/**
- * Terminated but should be restarted
- *
- * This simply tells the launcher to restart the executable. Possible
- * reasons include the need to change a config parameter that requires restart.
- */
-#define ZT_EXEC_RETURN_VALUE_PLEASE_RESTART 2
-
-/**
- * Unrecoverable error
- *
- * This tells the launcher to exit after possibly sending an error report to
- * ZeroTier if the user has this option enabled.
- */
-#define ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR 3
-
-/**
- * Used on Unix systems to return from forked sub-process if exec fails
- */
-#define ZT_EXEC_RETURN_VALUE_NO_BINARY 4
-
-#endif
diff --git a/main.cpp b/main.cpp
index 49530765..41380a2f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -56,8 +56,6 @@
#include "node/Utils.hpp"
#include "node/Node.hpp"
-#include "launcher.h"
-
using namespace ZeroTier;
// ---------------------------------------------------------------------------
@@ -102,7 +100,7 @@ static void sighandlerQuit(int sig)
{
Node *n = node;
if (n)
- n->terminate();
+ n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal");
else exit(0);
}
#endif
@@ -117,7 +115,7 @@ static BOOL WINAPI _handlerRoutine(DWORD dwCtrlType)
case CTRL_SHUTDOWN_EVENT:
Node *n = node;
if (n)
- n->terminate();
+ n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal");
return TRUE;
}
return FALSE;
@@ -157,12 +155,12 @@ int main(int argc,char **argv)
case '?':
default:
printHelp(argv[0],stderr);
- return ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION;
+ return 0;
}
} else {
if (homeDir) {
printHelp(argv[0],stderr);
- return ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION;
+ return 0;
}
homeDir = argv[i];
break;
@@ -176,22 +174,16 @@ int main(int argc,char **argv)
mkdir(homeDir,0755); // will fail if it already exists
#endif
- int exitCode = ZT_EXEC_RETURN_VALUE_NORMAL_TERMINATION;
+ int exitCode = 0;
node = new Node(homeDir);
const char *termReason = (char *)0;
switch(node->run()) {
- case Node::NODE_RESTART_FOR_RECONFIGURATION:
- exitCode = ZT_EXEC_RETURN_VALUE_PLEASE_RESTART;
- break;
case Node::NODE_UNRECOVERABLE_ERROR:
- exitCode = ZT_EXEC_RETURN_VALUE_UNRECOVERABLE_ERROR;
+ exitCode = -1;
termReason = node->reasonForTermination();
fprintf(stderr,"%s: abnormal termination: %s\n",argv[0],(termReason) ? termReason : "(unknown reason)");
break;
- case Node::NODE_NEW_VERSION_AVAILABLE:
- exitCode = ZT_EXEC_RETURN_VALUE_TERMINATED_FOR_UPGRADE;
- break;
default:
break;
}
diff --git a/node/Node.cpp b/node/Node.cpp
index 785fc634..96d1f87a 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -183,20 +183,20 @@ struct _NodeImpl
{
RuntimeEnvironment renv;
std::string reasonForTerminationStr;
- Node::ReasonForTermination reasonForTermination;
+ volatile Node::ReasonForTermination reasonForTermination;
volatile bool started;
volatile bool running;
- volatile bool terminateNow;
- // run() calls this on all return paths
- inline Node::ReasonForTermination terminateBecause(Node::ReasonForTermination r,const char *rstr)
+ inline Node::ReasonForTermination terminate()
{
RuntimeEnvironment *_r = &renv;
- LOG("terminating: %s",rstr);
+ LOG("terminating: %s",reasonForTerminationStr.c_str());
renv.shutdownInProgress = true;
Thread::sleep(500);
+ running = false;
+
#ifndef __WINDOWS__
delete renv.netconfService;
#endif
@@ -209,11 +209,14 @@ struct _NodeImpl
delete renv.prng;
delete renv.log;
+ return reasonForTermination;
+ }
+
+ inline Node::ReasonForTermination terminateBecause(Node::ReasonForTermination r,const char *rstr)
+ {
reasonForTerminationStr = rstr;
reasonForTermination = r;
- running = false;
-
- return r;
+ return terminate();
}
};
@@ -279,7 +282,6 @@ Node::Node(const char *hp)
impl->reasonForTermination = Node::NODE_RUNNING;
impl->started = false;
impl->running = false;
- impl->terminateNow = false;
}
Node::~Node()
@@ -377,6 +379,7 @@ Node::ReasonForTermination Node::run()
// One is running.
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,(std::string("another instance of ZeroTier One appears to be running, or local control UDP port cannot be bound: ") + exc.what()).c_str());
}
+ _r->node = this;
// TODO: make configurable
bool boundPort = false;
@@ -424,7 +427,7 @@ Node::ReasonForTermination Node::run()
LOG("%s starting version %s",_r->identity.address().toString().c_str(),versionString());
- while (!impl->terminateNow) {
+ while (impl->reasonForTermination == NODE_RUNNING) {
uint64_t now = Utils::now();
bool resynchronize = false;
@@ -562,7 +565,7 @@ Node::ReasonForTermination Node::run()
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unexpected exception during outer main I/O loop");
}
- return impl->terminateBecause(Node::NODE_NORMAL_TERMINATION,"normal termination");
+ return impl->terminate();
}
const char *Node::reasonForTermination() const
@@ -573,10 +576,11 @@ const char *Node::reasonForTermination() const
return ((_NodeImpl *)_impl)->reasonForTerminationStr.c_str();
}
-void Node::terminate()
+void Node::terminate(ReasonForTermination reason,const char *reasonText)
throw()
{
- ((_NodeImpl *)_impl)->terminateNow = true;
+ ((_NodeImpl *)_impl)->reasonForTermination = reason;
+ ((_NodeImpl *)_impl)->reasonForTerminationStr = ((reasonText) ? reasonText : "");
((_NodeImpl *)_impl)->renv.mainLoopWaitCondition.signal();
}
diff --git a/node/Node.hpp b/node/Node.hpp
index 9fb4666d..8e9f2777 100644
--- a/node/Node.hpp
+++ b/node/Node.hpp
@@ -86,8 +86,7 @@ public:
NODE_RUNNING = 0,
NODE_NORMAL_TERMINATION = 1,
NODE_RESTART_FOR_RECONFIGURATION = 2,
- NODE_UNRECOVERABLE_ERROR = 3,
- NODE_NEW_VERSION_AVAILABLE = 4
+ NODE_UNRECOVERABLE_ERROR = 3
};
/**
@@ -124,13 +123,16 @@ public:
throw();
/**
- * Cause run() to return with NODE_NORMAL_TERMINATION
+ * Cause run() to return
*
* This can be called from a signal handler or another thread to signal a
* running node to shut down. Shutdown may take a few seconds, so run()
* may not return instantly. Multiple calls are ignored.
+ *
+ * @param reason Reason for termination
+ * @param reasonText Text to be returned by reasonForTermination()
*/
- void terminate()
+ void terminate(ReasonForTermination reason,const char *reasonText)
throw();
/**
diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp
index 2cfd0cae..bc7c35f4 100644
--- a/node/NodeConfig.cpp
+++ b/node/NodeConfig.cpp
@@ -55,6 +55,7 @@
#include "Peer.hpp"
#include "Salsa20.hpp"
#include "HMAC.hpp"
+#include "Node.hpp"
#ifdef __WINDOWS__
#define strtoull _strtoui64
@@ -170,6 +171,7 @@ std::vector<std::string> NodeConfig::execute(const char *command)
_P("200 help listnetworks");
_P("200 help join <network ID>");
_P("200 help leave <network ID>");
+ _P("200 help terminate [<reason>]");
} else if (cmd[0] == "listpeers") {
_P("200 listpeers <ztaddr> <ipv4> <ipv6> <latency> <version>");
_r->topology->eachPeer(_DumpPeerStatistics(r));
@@ -231,6 +233,10 @@ std::vector<std::string> NodeConfig::execute(const char *command)
} else {
_P("400 leave requires a network ID (>0) in hexadecimal format");
}
+ } else if (cmd[0] == "terminate") {
+ if (cmd.size() > 1)
+ _r->node->terminate(Node::NODE_NORMAL_TERMINATION,cmd[1].c_str());
+ else _r->node->terminate(Node::NODE_NORMAL_TERMINATION,(const char *)0);
} else {
_P("404 %s No such command. Use 'help' for help.",cmd[0].c_str());
}
diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp
index 4be4f367..f8b39597 100644
--- a/node/RuntimeEnvironment.hpp
+++ b/node/RuntimeEnvironment.hpp
@@ -44,6 +44,7 @@ class SysEnv;
class Multicaster;
class CMWC4096;
class Service;
+class Node;
/**
* Holds global state for an instance of ZeroTier::Node
@@ -96,7 +97,7 @@ public:
Topology *topology;
SysEnv *sysEnv;
NodeConfig *nc;
-
+ Node *node;
#ifndef __WINDOWS__
Service *netconfService; // may be null
#endif