diff --git a/idtool.cpp b/idtool.cpp index 00511a0fe..66a7bafcf 100644 --- a/idtool.cpp +++ b/idtool.cpp @@ -45,8 +45,6 @@ static void printHelp(char *pn) std::cout << "\tgetpublic " << std::endl; std::cout << "\tsign " << std::endl; std::cout << "\tverify " << std::endl; - std::cout << "\tencrypt [] []" << std::endl; - std::cout << "\tdecrypt [] []" << 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 423689065..000000000 --- a/launcher-fakebin.c +++ /dev/null @@ -1,21 +0,0 @@ -/* Fake zerotier-one binary to test launcher upgrade procedure */ - -#include -#include -#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 b51d03982..000000000 --- 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 . - * - * -- - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 d99eadc88..000000000 --- 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 . - * - * -- - * - * 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 495307654..41380a2f8 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 785fc6345..96d1f87ad 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 9fb4666d2..8e9f27772 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 2cfd0cae5..bc7c35f48 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 NodeConfig::execute(const char *command) _P("200 help listnetworks"); _P("200 help join "); _P("200 help leave "); + _P("200 help terminate []"); } else if (cmd[0] == "listpeers") { _P("200 listpeers "); _r->topology->eachPeer(_DumpPeerStatistics(r)); @@ -231,6 +233,10 @@ std::vector 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 4be4f367d..f8b395972 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