diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-04-08 17:10:21 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-04-08 17:10:21 -0700 |
commit | e34bc961dbf85bb7a1d0a12637f306fe81c9aef6 (patch) | |
tree | ca71708c3d754382b52d93e0c52f6fc1ba8a177d | |
parent | 0751eaabd8f6d857507754b4548911d870393059 (diff) | |
download | infinitytier-e34bc961dbf85bb7a1d0a12637f306fe81c9aef6.tar.gz infinitytier-e34bc961dbf85bb7a1d0a12637f306fe81c9aef6.zip |
Add awareness of online status, and put old OS-dep utils in OSUtils.
-rw-r--r-- | node/Constants.hpp | 2 | ||||
-rw-r--r-- | node/Node.cpp | 18 | ||||
-rw-r--r-- | node/Node.hpp | 20 | ||||
-rw-r--r-- | osdep/OSUtils.cpp | 210 | ||||
-rw-r--r-- | osdep/OSUtils.hpp | 223 |
5 files changed, 466 insertions, 7 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp index 15a1f70d..4baa1ae7 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -280,7 +280,7 @@ /** * Timeout for overall peer activity (measured from last receive) */ -#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 2) + ZT_PING_CHECK_INVERVAL) +#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_DIRECT_PING_DELAY + (ZT_PING_CHECK_INVERVAL * 3)) /** * Stop relaying via peers that have not responded to direct sends diff --git a/node/Node.cpp b/node/Node.cpp index 32b1a2eb..59b8091a 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -76,6 +76,7 @@ Node::Node( _newestVersionSeen[0] = ZEROTIER_ONE_VERSION_MAJOR; _newestVersionSeen[1] = ZEROTIER_ONE_VERSION_MINOR; _newestVersionSeen[2] = ZEROTIER_ONE_VERSION_REVISION; + _online = false; std::string idtmp(dataStoreGet("identity.secret")); if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { @@ -187,19 +188,19 @@ class _PingPeersThatNeedPing { public: _PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now) : - lastReceiveFromSupernode(0), + lastReceiveFromUpstream(0), RR(renv), _now(now), _supernodes(RR->topology->supernodeAddresses()) {} - uint64_t lastReceiveFromSupernode; + uint64_t lastReceiveFromUpstream; inline void operator()(Topology &t,const SharedPtr<Peer> &p) { if (std::find(_supernodes.begin(),_supernodes.end(),p->address()) != _supernodes.end()) { p->doPingAndKeepalive(RR,_now); - if (p->lastReceive() > lastReceiveFromSupernode) - lastReceiveFromSupernode = p->lastReceive(); + if (p->lastReceive() > lastReceiveFromUpstream) + lastReceiveFromUpstream = p->lastReceive(); } else if (p->alive(_now)) { p->doPingAndKeepalive(RR,_now); } @@ -218,6 +219,8 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,uint64_t *nextBackgroun if ((now - _lastPingCheck) >= ZT_PING_CHECK_INVERVAL) { _lastPingCheck = now; + // This is used as a floor for the desperation and online status + // calculations if we just started up or have been asleep. if ((now - _startTimeAfterInactivity) > (ZT_PING_CHECK_INVERVAL * 3)) _startTimeAfterInactivity = now; @@ -225,7 +228,12 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,uint64_t *nextBackgroun _PingPeersThatNeedPing pfunc(RR,now); RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); - _coreDesperation = (unsigned int)((now - std::max(_startTimeAfterInactivity,pfunc.lastReceiveFromSupernode)) / (ZT_PING_CHECK_INVERVAL * ZT_CORE_DESPERATION_INCREMENT)); + const uint64_t lastActivityAgo = now - std::max(_startTimeAfterInactivity,pfunc.lastReceiveFromUpstream); + _coreDesperation = (unsigned int)(lastActivityAgo / (ZT_PING_CHECK_INVERVAL * ZT_CORE_DESPERATION_INCREMENT)); + bool oldOnline = _online; + _online = (lastActivityAgo < ZT_PEER_ACTIVITY_TIMEOUT); + if (oldOnline != _online) + postEvent(_online ? ZT1_EVENT_ONLINE : ZT1_EVENT_OFFLINE); } catch ( ... ) { return ZT1_RESULT_FATAL_ERROR_INTERNAL; } diff --git a/node/Node.hpp b/node/Node.hpp index 21d4567f..e16061b0 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -172,7 +172,19 @@ public: } /** - * @return Overall system level of desperation based on how long it's been since an upstream node (supernode) has talked to us + * Get an overall current level of desperation + * + * The current level of desperation is based on how recently an upstream + * (a.k.a. supernode) peer has spoken to us. As such, it will change and + * return to 0 once something like tunneling (higher desperation link) is + * active. As a result, actual link desperation for outgoing messages + * should be the max of either this or the most recent link desperation + * for an incoming message from a given address. See Path.hpp and Peer.hpp. + * + * In other words think of this as 'the desperation we should try to + * escalate to right now.' + * + * @return Overall system level of desperation */ inline unsigned int coreDesperation() const throw() { return _coreDesperation; } @@ -199,6 +211,11 @@ public: inline int configureVirtualNetworkPort(uint64_t nwid,ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast<ZT1_Node *>(this),nwid,op,nc); } /** + * @return True if we appear to be online + */ + inline bool online() const throw() { return _online; } + + /** * If this version is newer than the newest we've seen, post a new version seen event */ void postNewerVersionIfNewer(unsigned int major,unsigned int minor,unsigned int rev); @@ -231,6 +248,7 @@ private: uint64_t _lastHousekeepingRun; unsigned int _coreDesperation; unsigned int _newestVersionSeen[3]; // major, minor, revision + bool _online; }; } // namespace ZeroTier diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp new file mode 100644 index 00000000..f98f7e03 --- /dev/null +++ b/osdep/OSUtils.cpp @@ -0,0 +1,210 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, 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 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/ + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/stat.h> + +#include "../node/Constants.hpp" + +#ifdef __UNIX_LIKE__ +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include <dirent.h> +#endif + +#ifdef __WINDOWS__ +#include <wincrypt.h> +#endif + +#include "OSUtils.hpp" + +namespace ZeroTier { + +#ifdef __UNIX_LIKE__ +bool OSUtils::redirectUnixOutputs(const char *stdoutPath,const char *stderrPath) + throw() +{ + int fdout = ::open(stdoutPath,O_WRONLY|O_CREAT,0600); + if (fdout > 0) { + int fderr; + if (stderrPath) { + fderr = ::open(stderrPath,O_WRONLY|O_CREAT,0600); + if (fderr <= 0) { + ::close(fdout); + return false; + } + } else fderr = fdout; + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + ::dup2(fdout,STDOUT_FILENO); + ::dup2(fderr,STDERR_FILENO); + return true; + } + return false; +} +#endif // __UNIX_LIKE__ + +std::map<std::string,bool> OSUtils::listDirectory(const char *path) +{ + std::map<std::string,bool> r; + +#ifdef __WINDOWS__ + HANDLE hFind; + WIN32_FIND_DATAA ffd; + if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { + do { + if ((strcmp(ffd.cFileName,"."))&&(strcmp(ffd.cFileName,".."))) + r[std::string(ffd.cFileName)] = ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); + } while (FindNextFileA(hFind,&ffd)); + FindClose(hFind); + } +#else + struct dirent de; + struct dirent *dptr; + + DIR *d = opendir(path); + if (!d) + return r; + + dptr = (struct dirent *)0; + for(;;) { + if (readdir_r(d,&de,&dptr)) + break; + if (dptr) { + if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))) + r[std::string(dptr->d_name)] = (dptr->d_type == DT_DIR); + } else break; + } +#endif + + return r; +} + +void OSUtils::lockDownFile(const char *path,bool isDir) +{ +#ifdef __UNIX_LIKE__ + chmod(path,isDir ? 0700 : 0600); +#else +#ifdef __WINDOWS__ + { + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInfo; + + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo,0,sizeof(STARTUPINFOA)); + memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); + if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } + + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo,0,sizeof(STARTUPINFOA)); + memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); + if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } + } +#endif +#endif +} + +uint64_t OSUtils::getLastModified(const char *path) +{ + struct stat s; + if (stat(path,&s)) + return 0; + return (((uint64_t)s.st_mtime) * 1000ULL); +} + +bool OSUtils::fileExists(const char *path,bool followLinks) +{ + struct stat s; +#ifdef __UNIX_LIKE__ + if (!followLinks) + return (lstat(path,&s) == 0); +#endif + return (stat(path,&s) == 0); +} + +int64_t OSUtils::getFileSize(const char *path) +{ + struct stat s; + if (stat(path,&s)) + return -1; +#ifdef __WINDOWS__ + return s.st_size; +#else + if (S_ISREG(s.st_mode)) + return s.st_size; +#endif + return -1; +} + +bool OSUtils::readFile(const char *path,std::string &buf) +{ + char tmp[4096]; + FILE *f = fopen(path,"rb"); + if (f) { + for(;;) { + long n = (long)fread(tmp,1,sizeof(tmp),f); + if (n > 0) + buf.append(tmp,n); + else break; + } + fclose(f); + return true; + } + return false; +} + +bool OSUtils::writeFile(const char *path,const void *buf,unsigned int len) +{ + FILE *f = fopen(path,"wb"); + if (f) { + if ((long)fwrite(buf,1,len,f) != (long)len) { + fclose(f); + return false; + } else { + fclose(f); + return true; + } + } + return false; +} + +} // namespace ZeroTier diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp new file mode 100644 index 00000000..2f7499ba --- /dev/null +++ b/osdep/OSUtils.hpp @@ -0,0 +1,223 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, 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 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_OSUTILS_HPP +#define ZT_OSUTILS_HPP + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <time.h> + +#include <string> +#include <stdexcept> +#include <vector> +#include <map> + +#include "../node/Constants.hpp" + +#ifdef __WINDOWS__ +#include <WinSock2.h> +#include <Windows.h> +#else +#include <unistd.h> +#include <sys/time.h> +#include <arpa/inet.h> +#endif + +namespace ZeroTier { + +/** + * Miscellaneous utility functions and global constants + */ +class OSUtils +{ +public: +#ifdef __UNIX_LIKE__ + /** + * Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path + * + * This can be called after fork() and prior to exec() to suppress output + * from a subprocess, such as auto-update. + * + * @param stdoutPath Path to file to use for stdout + * @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default) + * @return True on success + */ + static bool redirectUnixOutputs(const char *stdoutPath,const char *stderrPath = (const char *)0) + throw(); +#endif // __UNIX_LIKE__ + + /** + * Delete a file + * + * @param path Path to delete + * @return True if delete was successful + */ + static inline bool rm(const char *path) + throw() + { +#ifdef __WINDOWS__ + return (DeleteFileA(path) != FALSE); +#else + return (unlink(path) == 0); +#endif + } + static inline bool rm(const std::string &path) throw() { return rm(path.c_str()); } + + /** + * List a directory's contents + * + * Keys in returned map are filenames only and don't include the leading + * path. Pseudo-paths like . and .. are not returned. Values are true if + * the item is a directory, false if it's a file. More detailed attributes + * aren't supported since the code that uses this doesn't need them. + * + * @param path Path to list + * @return Map of entries and whether or not they are also directories (empty on failure) + */ + static std::map<std::string,bool> listDirectory(const char *path); + + /** + * Set modes on a file to something secure + * + * This locks a file so that only the owner can access it. What it actually + * does varies by platform. + * + * @param path Path to lock + * @param isDir True if this is a directory + */ + static void lockDownFile(const char *path,bool isDir); + + /** + * Get file last modification time + * + * Resolution is often only second, not millisecond, but the return is + * always in ms for comparison against now(). + * + * @param path Path to file to get time + * @return Last modification time in ms since epoch or 0 if not found + */ + static uint64_t getLastModified(const char *path); + + /** + * @param path Path to check + * @param followLinks Follow links (on platforms with that concept) + * @return True if file or directory exists at path location + */ + static bool fileExists(const char *path,bool followLinks = true); + + /** + * @param path Path to file + * @return File size or -1 if nonexistent or other failure + */ + static int64_t getFileSize(const char *path); + + /** + * @return Current time in milliseconds since epoch + */ + static inline uint64_t now() + throw() + { +#ifdef __WINDOWS__ + FILETIME ft; + SYSTEMTIME st; + ULARGE_INTEGER tmp; + GetSystemTime(&st); + SystemTimeToFileTime(&st,&ft); + tmp.LowPart = ft.dwLowDateTime; + tmp.HighPart = ft.dwHighDateTime; + return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds ); +#else + struct timeval tv; + gettimeofday(&tv,(struct timezone *)0); + return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) ); +#endif + }; + + /** + * @return Current time in seconds since epoch, to the highest available resolution + */ + static inline double nowf() + throw() + { +#ifdef __WINDOWS__ + FILETIME ft; + SYSTEMTIME st; + ULARGE_INTEGER tmp; + GetSystemTime(&st); + SystemTimeToFileTime(&st,&ft); + tmp.LowPart = ft.dwLowDateTime; + tmp.HighPart = ft.dwHighDateTime; + return (((double)(tmp.QuadPart - 116444736000000000ULL)) / 10000000.0); +#else + struct timeval tv; + gettimeofday(&tv,(struct timezone *)0); + return ( ((double)tv.tv_sec) + (((double)tv.tv_usec) / 1000000.0) ); +#endif + } + + /** + * Read the full contents of a file into a string buffer + * + * The buffer isn't cleared, so if it already contains data the file's data will + * be appended. + * + * @param path Path of file to read + * @param buf Buffer to fill + * @return True if open and read successful + */ + static bool readFile(const char *path,std::string &buf); + + /** + * Write a block of data to disk, replacing any current file contents + * + * @param path Path to write + * @param buf Buffer containing data + * @param len Length of buffer + * @return True if entire file was successfully written + */ + static bool writeFile(const char *path,const void *buf,unsigned int len); + + /** + * Write a block of data to disk, replacing any current file contents + * + * @param path Path to write + * @param s Data to write + * @return True if entire file was successfully written + */ + static inline bool writeFile(const char *path,const std::string &s) + { + return writeFile(path,s.data(),(unsigned int)s.length()); + } +}; + +} // namespace ZeroTier + +#endif + |