diff --git a/BUILDING.txt b/BUILDING.txt index a5e4226b3..21bbfe54d 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -2,6 +2,10 @@ Building ZeroTier One on different platforms: (See RUNNING.txt for what to do next.) +Developers note: there is currently no management of dependencies on *nix +platforms, so you should make clean ; make if you change a header. Will +do this eventually. + -- MacOS make -f Makefile.mac diff --git a/main.cpp b/main.cpp index 44f935227..13379ad60 100644 --- a/main.cpp +++ b/main.cpp @@ -70,12 +70,18 @@ static void sighandlerQuit(int sig) static void sighandlerUsr(int sig) { } +static void sighandlerHup(int sig) +{ + Node *n = node; + if (n) + n->updateStatusNow(); +} #endif int main(int argc,char **argv) { #ifndef _WIN32 - signal(SIGHUP,SIG_IGN); + signal(SIGHUP,&sighandlerHup); signal(SIGPIPE,SIG_IGN); signal(SIGUSR1,&sighandlerUsr); signal(SIGUSR2,&sighandlerUsr); diff --git a/node/Constants.hpp b/node/Constants.hpp index 641b25bb7..394c89eb2 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -253,6 +253,11 @@ error_no_ZT_ARCH */ #define ZT_AUTOCONFIGURE_CHECK_DELAY 15000 +/** + * Delay between updates of status file in home directory + */ +#define ZT_STATUS_OUTPUT_PERIOD 120000 + /** * Minimum delay in Node service loop * diff --git a/node/Node.cpp b/node/Node.cpp index 830ee354b..85029e819 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -74,8 +74,9 @@ struct _NodeImpl RuntimeEnvironment renv; std::string reasonForTerminationStr; Node::ReasonForTermination reasonForTermination; - bool started; - bool running; + volatile bool started; + volatile bool running; + volatile bool updateStatusNow; volatile bool terminateNow; // Helper used to rapidly terminate from run() @@ -104,6 +105,7 @@ Node::Node(const char *hp,const char *urlPrefix,const char *configAuthorityIdent impl->reasonForTermination = Node::NODE_RUNNING; impl->started = false; impl->running = false; + impl->updateStatusNow = false; impl->terminateNow = false; } @@ -236,6 +238,8 @@ Node::ReasonForTermination Node::run() } try { + std::string statusPath(_r->homePath + ZT_PATH_SEPARATOR_S + "status"); + uint64_t lastPingCheck = 0; uint64_t lastTopologyClean = Utils::now(); // don't need to do this immediately uint64_t lastNetworkFingerprintCheck = 0; @@ -243,6 +247,7 @@ Node::ReasonForTermination Node::run() uint64_t networkConfigurationFingerprint = _r->sysEnv->getNetworkConfigurationFingerprint(); uint64_t lastMulticastCheck = 0; uint64_t lastMulticastAnnounceAll = 0; + uint64_t lastStatusUpdate = 0; long lastDelayDelta = 0; LOG("%s starting version %s",_r->identity.address().toString().c_str(),versionString()); @@ -373,6 +378,20 @@ Node::ReasonForTermination Node::run() _r->topology->clean(); // happens in background } + if (((now - lastStatusUpdate) >= ZT_STATUS_OUTPUT_PERIOD)||(impl->updateStatusNow)) { + lastStatusUpdate = now; + impl->updateStatusNow = false; + FILE *statusf = ::fopen(statusPath.c_str(),"w"); + if (statusf) { + try { + _r->topology->eachPeer(Topology::DumpPeerStatistics(statusf)); + } catch ( ... ) { + TRACE("unexpected exception updating status dump"); + } + ::fclose(statusf); + } + } + try { unsigned long delay = std::min((unsigned long)ZT_MIN_SERVICE_LOOP_INTERVAL,_r->sw->doTimerTasks()); uint64_t start = Utils::now(); @@ -391,11 +410,6 @@ Node::ReasonForTermination Node::run() return impl->terminateBecause(Node::NODE_NORMAL_TERMINATION,"normal termination"); } -/** - * Obtain a human-readable reason for node termination - * - * @return Reason for node termination or NULL if run() has not returned - */ const char *Node::reasonForTermination() const throw() { @@ -404,19 +418,18 @@ const char *Node::reasonForTermination() const return ((_NodeImpl *)_impl)->reasonForTerminationStr.c_str(); } -/** - * Cause run() to return with NODE_NORMAL_TERMINATION - * - * 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. - */ void Node::terminate() throw() { ((_NodeImpl *)_impl)->terminateNow = true; } +void Node::updateStatusNow() + throw() +{ + ((_NodeImpl *)_impl)->updateStatusNow = true; +} + class _VersionStringMaker { public: diff --git a/node/Node.hpp b/node/Node.hpp index 1cc9a746b..df6b946ff 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -98,6 +98,12 @@ public: void terminate() throw(); + /** + * Update the status file in the home directory on next service loop + */ + void updateStatusNow() + throw(); + /** * Get the ZeroTier version in major.minor.revision string format * diff --git a/node/Peer.hpp b/node/Peer.hpp index 5da194683..ef33d519d 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -232,6 +232,46 @@ public: return ((_ipv4p.isActive(now))||(_ipv6p.isActive(now))); } + /** + * @return IPv4 direct address or null InetAddress if none + */ + inline InetAddress ipv4Path() const + throw() + { + return _ipv4p.addr; + } + + /** + * @return IPv6 direct address or null InetAddress if none + */ + inline InetAddress ipv6Path() const + throw() + { + return _ipv4p.addr; + } + + /** + * @return IPv4 direct address or null InetAddress if none + */ + inline InetAddress ipv4ActivePath(uint64_t now) const + throw() + { + if (_ipv4p.isActive(now)) + return _ipv4p.addr; + return InetAddress(); + } + + /** + * @return IPv6 direct address or null InetAddress if none + */ + inline InetAddress ipv6ActivePath(uint64_t now) const + throw() + { + if (_ipv6p.isActive(now)) + return _ipv6p.addr; + return InetAddress(); + } + /** * @return 256-bit encryption key */ diff --git a/node/Topology.hpp b/node/Topology.hpp index 951244973..7baebad08 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -28,6 +28,8 @@ #ifndef _ZT_TOPOLOGY_HPP #define _ZT_TOPOLOGY_HPP +#include +#include #include #include #include @@ -292,6 +294,35 @@ public: std::vector< SharedPtr > &_v; }; + /** + * Dump peer I/O statistics to an open FILE (for status reporting and debug) + */ + class DumpPeerStatistics + { + public: + DumpPeerStatistics(FILE *out) : + _out(out), + _now(Utils::now()) + { + fprintf(_out,"Peer Direct IPv4 Direct IPv6 Latency(ms)"ZT_EOL_S); + } + + inline void operator()(Topology &t,const SharedPtr &p) + { + InetAddress v4(p->ipv4ActivePath(_now)); + InetAddress v6(p->ipv6ActivePath(_now)); + fprintf(_out,"%-10s %-21s %-51s %u"ZT_EOL_S, + p->address().toString().c_str(), + ((v4) ? v4.toString().c_str() : "(none)"), + ((v6) ? v6.toString().c_str() : "(none)"), + p->latency()); + } + + private: + FILE *_out; + uint64_t _now; + }; + protected: virtual void main() throw();