From 647ce82b86a56c45f07cd69d5cabedd083179365 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 31 Mar 2015 15:23:14 -0700 Subject: Move more stuff into osdep/ -- node/ will not use threads directly. --- node/EthernetTap.hpp | 179 -------------- node/EthernetTapFactory.hpp | 98 -------- node/HttpClient.cpp | 591 -------------------------------------------- node/HttpClient.hpp | 111 --------- node/Network.hpp | 9 - node/SoftwareUpdater.cpp | 280 --------------------- node/SoftwareUpdater.hpp | 166 ------------- node/Thread.hpp | 203 --------------- 8 files changed, 1637 deletions(-) delete mode 100644 node/EthernetTap.hpp delete mode 100644 node/EthernetTapFactory.hpp delete mode 100644 node/HttpClient.cpp delete mode 100644 node/HttpClient.hpp delete mode 100644 node/SoftwareUpdater.cpp delete mode 100644 node/SoftwareUpdater.hpp delete mode 100644 node/Thread.hpp (limited to 'node') diff --git a/node/EthernetTap.hpp b/node/EthernetTap.hpp deleted file mode 100644 index 94193e0c..00000000 --- a/node/EthernetTap.hpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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 . - * - * -- - * - * 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_ETHERNETTAP_HPP -#define ZT_ETHERNETTAP_HPP - -#include -#include - -#include -#include - -#include "Constants.hpp" -#include "MAC.hpp" -#include "InetAddress.hpp" -#include "Buffer.hpp" -#include "MulticastGroup.hpp" -#include "NonCopyable.hpp" - -namespace ZeroTier { - -/** - * Base class for Ethernet tap device implementations - */ -class EthernetTap : NonCopyable -{ -protected: - EthernetTap(const char *cn,const MAC &m,unsigned int mt,unsigned int met) : - _implName(cn), - _mac(m), - _mtu(mt), - _metric(met) {} - -public: - virtual ~EthernetTap() {} - - /** - * @return Implementation class name (e.g. UnixEthernetTap) - */ - inline const char *implementationName() const { return _implName; } - - /** - * Sets whether device is 'up' - * - * This may do nothing on some platforms. - * - * @param en Is device enabled? - */ - virtual void setEnabled(bool en) = 0; - - /** - * @return Is device 'up'? - */ - virtual bool enabled() const = 0; - - /** - * @return MAC address of this interface - */ - inline const MAC &mac() const throw() { return _mac; } - - /** - * @return MTU of this interface - */ - inline unsigned int mtu() const throw() { return _mtu; } - - /** - * @return Interface metric - */ - inline unsigned int metric() const throw() { return _metric; } - - /** - * Add an IP to this interface - * - * @param ip IP and netmask (netmask stored in port field) - * @return True if IP added successfully - */ - virtual bool addIP(const InetAddress &ip) = 0; - - /** - * Remove an IP from this interface - * - * Link-local IP addresses may not be able to be removed, depending on platform and type. - * - * @param ip IP and netmask (netmask stored in port field) - * @return True if IP removed successfully - */ - virtual bool removeIP(const InetAddress &ip) = 0; - - /** - * @return All IP addresses (V4 and V6) assigned to this interface (including link-local) - */ - virtual std::set ips() const = 0; - - /** - * Put a frame, making it available to the OS for processing - * - * @param from MAC address from which frame originated - * @param to MAC address of destination (typically MAC of tap itself) - * @param etherType Ethernet protocol ID - * @param data Frame payload - * @param len Length of frame - */ - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0; - - /** - * @return OS-specific device or connection name (e.g. zt0, tap0, etc.) - */ - virtual std::string deviceName() const = 0; - - /** - * Change this device's user-visible name (if supported) - * - * @param friendlyName New name - */ - virtual void setFriendlyName(const char *friendlyName) = 0; - - /** - * Fill or modify a set to contain multicast groups for this device - * - * This populates a set or, if already populated, modifies it to contain - * only multicast groups in which this device is interested. - * - * This neither includes nor removes the broadcast (ff:ff:ff:ff:ff:ff / 0) - * group. - * - * @param groups Set to modify in place - * @return True if set was changed since last call - */ - virtual bool updateMulticastGroups(std::set &groups) = 0; - - /** - * Inject a packet as if it was sent by the host, if supported - * - * This is for testing and is typically not supported by real TAP devices. - * It's implemented by TestEthernetTap in testnet. - * - * @param from Source MAC - * @param to Destination MAC - * @param etherType Ethernet frame type - * @param data Packet data - * @param len Packet length - * @return False if not supported or packet too large - */ - virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0; - -protected: - const char *_implName; - MAC _mac; - unsigned int _mtu; - unsigned int _metric; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/EthernetTapFactory.hpp b/node/EthernetTapFactory.hpp deleted file mode 100644 index 4acb2369..00000000 --- a/node/EthernetTapFactory.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 . - * - * -- - * - * 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_ETHERNETTAPFACTORY_HPP -#define ZT_ETHERNETTAPFACTORY_HPP - -#include - -#include "MAC.hpp" -#include "NonCopyable.hpp" -#include "Buffer.hpp" - -namespace ZeroTier { - -class EthernetTap; - -/** - * Ethernet tap factory - * - * This serves up tap implementations for a given platform. It should never be - * deleted until the Node using it is shut down, since doing so may invalidate - * any tap devices it manages. - * - * Using a factory pattern will faciliatate packaging ZeroTier as a library, - * as well as moving toward a design that makes unit testing the entire app - * quite a bit easier. - */ -class EthernetTapFactory : NonCopyable -{ -public: - EthernetTapFactory() {} - virtual ~EthernetTapFactory() {} - - /** - * Create / open an Ethernet tap device - * - * On some platforms (Windows) this can be a time-consuming operation. - * - * Note that close() must be used. Do not just delete the tap instance, - * since this may leave orphaned resources or cause other problems. - * - * @param mac MAC address - * @param mtu Device MTU - * @param metric Interface metric (higher = lower priority, may not be supported on all OSes) - * @param nwid ZeroTier network ID - * @param desiredDevice Desired system device name or NULL for no preference - * @param friendlyName Friendly name of this interface or NULL for none (not used on all platforms) - * @param handler Function to call when packets are received - * @param arg First argument to provide to handler - * @return EthernetTap instance - * @throws std::runtime_error Unable to initialize tap device - */ - virtual EthernetTap *open( - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *desiredDevice, - const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg) = 0; - - /** - * Close an ethernet tap device and delete/free the tap object - * - * @param tap Tap instance - * @param destroyPersistentDevices If true, destroy persistent device (on platforms where applicable) - */ - virtual void close(EthernetTap *tap,bool destroyPersistentDevices) = 0; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/HttpClient.cpp b/node/HttpClient.cpp deleted file mode 100644 index 6b96960b..00000000 --- a/node/HttpClient.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* - * 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 . - * - * -- - * - * 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 "Constants.hpp" - -#include -#include -#include - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#include -#endif // __WINDOWS__ - -#ifdef __UNIX_LIKE__ -#include -#include -#include -#include -#include -#include -#include -#include -#endif // __UNIX_LIKE__ - -#include -#include -#include - -#include "HttpClient.hpp" -#include "Thread.hpp" -#include "Utils.hpp" -#include "NonCopyable.hpp" -#include "Defaults.hpp" - -namespace ZeroTier { - -#ifdef __UNIX_LIKE__ - -// The *nix implementation calls 'curl' externally rather than linking to it. -// This makes it an optional dependency that can be avoided in tiny systems -// provided you don't want to have automatic software updates... or want to -// do them via another method. - -#ifdef __APPLE__ -// TODO: get proxy configuration -#endif - -// Paths where "curl" may be found on the system -#define NUM_CURL_PATHS 6 -static const char *CURL_PATHS[NUM_CURL_PATHS] = { "/usr/bin/curl","/bin/curl","/usr/local/bin/curl","/usr/sbin/curl","/sbin/curl","/usr/libexec/curl" }; - -// Maximum message length -#define CURL_MAX_MESSAGE_LENGTH (1024 * 1024 * 64) - -// Internal private thread class that performs request, notifies handler, -// and then commits suicide by deleting itself. -class HttpClient_Private_Request : NonCopyable -{ -public: - HttpClient_Private_Request(HttpClient *parent,const char *method,const std::string &url,const std::map &headers,unsigned int timeout,void (*handler)(void *,int,const std::string &,const std::string &),void *arg) : - _url(url), - _headers(headers), - _timeout(timeout), - _handler(handler), - _arg(arg), - _parent(parent), - _pid(0), - _cancelled(false) - { - _myThread = Thread::start(this); - } - - ~HttpClient_Private_Request() - { - Mutex::Lock _l(_parent->_requests_m); - _parent->_requests.erase((HttpClient::Request)this); - } - - void threadMain() - { - char *curlArgs[1024]; - char buf[16384]; - fd_set readfds,writefds,errfds; - struct timeval tv; - - std::string curlPath; - for(int i=0;i(curlPath.c_str()); - curlArgs[1] = const_cast ("-D"); - curlArgs[2] = const_cast ("-"); // append headers before output - int argPtr = 3; - std::vector headerArgs; - for(std::map::const_iterator h(_headers.begin());h!=_headers.end();++h) { - headerArgs.push_back(h->first); - headerArgs.back().append(": "); - headerArgs.back().append(h->second); - } - for(std::vector::iterator h(headerArgs.begin());h!=headerArgs.end();++h) { - if (argPtr >= (1024 - 4)) // leave room for terminating NULL and URL - break; - curlArgs[argPtr++] = const_cast ("-H"); - curlArgs[argPtr++] = const_cast (h->c_str()); - } - curlArgs[argPtr++] = const_cast (_url.c_str()); - curlArgs[argPtr] = (char *)0; - - if (_cancelled) { - delete this; - return; - } - - int curlStdout[2]; - int curlStderr[2]; - ::pipe(curlStdout); - ::pipe(curlStderr); - - _pid = (long)vfork(); - if (_pid < 0) { - // fork() failed - ::close(curlStdout[0]); - ::close(curlStdout[1]); - ::close(curlStderr[0]); - ::close(curlStderr[1]); - _doH(_arg,-1,_url,"unable to fork()"); - delete this; - return; - } else if (_pid > 0) { - // fork() succeeded, in parent process - ::close(curlStdout[1]); - ::close(curlStderr[1]); - fcntl(curlStdout[0],F_SETFL,O_NONBLOCK); - fcntl(curlStderr[0],F_SETFL,O_NONBLOCK); - - int exitCode = -1; - unsigned long long timesOutAt = Utils::now() + ((unsigned long long)_timeout * 1000ULL); - bool timedOut = false; - bool tooLong = false; - - while (!_cancelled) { - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&errfds); - FD_SET(curlStdout[0],&readfds); - FD_SET(curlStderr[0],&readfds); - FD_SET(curlStdout[0],&errfds); - FD_SET(curlStderr[0],&errfds); - tv.tv_sec = 1; - tv.tv_usec = 0; - select(std::max(curlStdout[0],curlStderr[0])+1,&readfds,&writefds,&errfds,&tv); - - if (FD_ISSET(curlStdout[0],&readfds)) { - int n = (int)::read(curlStdout[0],buf,sizeof(buf)); - if (n > 0) { - _body.append(buf,n); - // Reset timeout when data is read... - timesOutAt = Utils::now() + ((unsigned long long)_timeout * 1000ULL); - } else if (n < 0) - break; - if (_body.length() > CURL_MAX_MESSAGE_LENGTH) { - tooLong = true; - break; - } - } - - if (FD_ISSET(curlStderr[0],&readfds)) - ::read(curlStderr[0],buf,sizeof(buf)); - - if (FD_ISSET(curlStdout[0],&errfds)||FD_ISSET(curlStderr[0],&errfds)) - break; - - if (Utils::now() >= timesOutAt) { - timedOut = true; - break; - } - - if (waitpid(_pid,&exitCode,WNOHANG) > 0) { - for(;;) { - // Drain output... - int n = (int)::read(curlStdout[0],buf,sizeof(buf)); - if (n <= 0) - break; - else { - _body.append(buf,n); - if (_body.length() > CURL_MAX_MESSAGE_LENGTH) { - tooLong = true; - break; - } - } - } - _pid = 0; - break; - } - } - - if (_pid > 0) { - ::kill(_pid,SIGKILL); - waitpid(_pid,&exitCode,0); - } - _pid = 0; - - ::close(curlStdout[0]); - ::close(curlStderr[0]); - - if (timedOut) - _doH(_arg,-1,_url,"connection timed out"); - else if (tooLong) - _doH(_arg,-1,_url,"response too long"); - else if (exitCode) - _doH(_arg,-1,_url,"connection failed (curl returned non-zero exit code)"); - else { - unsigned long idx = 0; - - // Grab status line and headers, which will prefix output on - // success and will end with an empty line. - std::vector headers; - headers.push_back(std::string()); - while (idx < _body.length()) { - char c = _body[idx++]; - if (c == '\n') { - if (!headers.back().length()) { - headers.pop_back(); - break; - } else headers.push_back(std::string()); - } else if (c != '\r') - headers.back().push_back(c); - } - if (headers.empty()||(!headers.front().length())) { - _doH(_arg,-1,_url,"HTTP response empty"); - delete this; - return; - } - - // Parse first line -- HTTP status code and response - size_t scPos = headers.front().find(' '); - if (scPos == std::string::npos) { - _doH(_arg,-1,_url,"invalid HTTP response (no status line)"); - delete this; - return; - } - ++scPos; - unsigned int rcode = Utils::strToUInt(headers.front().substr(scPos,3).c_str()); - if ((!rcode)||(rcode > 999)) { - _doH(_arg,-1,_url,"invalid HTTP response (invalid response code)"); - delete this; - return; - } - - // Serve up the resulting data to the handler - if (rcode == 200) - _doH(_arg,rcode,_url,_body.substr(idx)); - else if ((scPos + 4) < headers.front().length()) - _doH(_arg,rcode,_url,headers.front().substr(scPos+4)); - else _doH(_arg,rcode,_url,"(no status message from server)"); - } - - delete this; - return; - } else { - // fork() succeeded, in child process - ::dup2(curlStdout[1],STDOUT_FILENO); - ::close(curlStdout[1]); - ::dup2(curlStderr[1],STDERR_FILENO); - ::close(curlStderr[1]); - ::execv(curlPath.c_str(),curlArgs); - ::exit(-1); // only reached if execv() fails - } - } - - inline void cancel() - { - { - Mutex::Lock _l(_cancelled_m); - _cancelled = true; - if (_pid > 0) - ::kill(_pid,SIGKILL); - } - Thread::join(_myThread); - } - -private: - inline void _doH(void *arg,int code,const std::string &url,const std::string &body) - { - Mutex::Lock _l(_cancelled_m); - try { - if ((!_cancelled)&&(_handler)) - _handler(arg,code,url,body); - } catch ( ... ) {} - } - - const std::string _url; - std::string _body; - std::map _headers; - unsigned int _timeout; - void (*_handler)(void *,int,const std::string &,const std::string &); - void *_arg; - HttpClient *_parent; - long _pid; - volatile bool _cancelled; - Mutex _cancelled_m; - Thread _myThread; -}; - -#endif // __UNIX_LIKE__ - -#ifdef __WINDOWS__ - -#define WIN_MAX_MESSAGE_LENGTH (1024 * 1024 * 64) - -// Internal private thread class that performs request, notifies handler, -// and then commits suicide by deleting itself. -class HttpClient_Private_Request : NonCopyable -{ -public: - HttpClient_Private_Request(HttpClient *parent,const char *method,const std::string &url,const std::map &headers,unsigned int timeout,void (*handler)(void *,int,const std::string &,const std::string &),void *arg) : - _url(url), - _headers(headers), - _timeout(timeout), - _handler(handler), - _arg(arg), - _parent(parent), - _hRequest((HINTERNET)0) - { - _myThread = Thread::start(this); - } - - ~HttpClient_Private_Request() - { - Mutex::Lock _l(_parent->_requests_m); - _parent->_requests.erase((HttpClient::Request)this); - } - - void threadMain() - { - HINTERNET hSession = (HINTERNET)0; - HINTERNET hConnect = (HINTERNET)0; - HINTERNET hRequest = (HINTERNET)0; - - try { - hSession = WinHttpOpen(L"ZeroTier One HttpClient/1.0 (WinHttp)",WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,WINHTTP_NO_PROXY_NAME,WINHTTP_NO_PROXY_BYPASS,0); - if (!hSession) { - _handler(_arg,-1,_url,"WinHttpOpen() failed"); - goto closeAndReturnFromHttp; - } - int timeoutMs = (int)_timeout * 1000; - WinHttpSetTimeouts(hSession,timeoutMs,timeoutMs,timeoutMs,timeoutMs); - - std::wstring_convert< std::codecvt_utf8 > wcconv; - std::wstring wurl(wcconv.from_bytes(_url)); - - URL_COMPONENTS uc; - memset(&uc,0,sizeof(uc)); - uc.dwStructSize = sizeof(uc); - uc.dwSchemeLength = -1; - uc.dwHostNameLength = -1; - uc.dwUrlPathLength = -1; - uc.dwExtraInfoLength = -1; - if (!WinHttpCrackUrl(wurl.c_str(),(DWORD)wurl.length(),0,&uc)) { - _handler(_arg,-1,_url,"unable to parse URL: WinHttpCrackUrl() failed"); - goto closeAndReturnFromHttp; - } - if ((!uc.lpszHostName)||(!uc.lpszUrlPath)||(!uc.lpszScheme)||(uc.dwHostNameLength <= 0)||(uc.dwUrlPathLength <= 0)||(uc.dwSchemeLength <= 0)) { - _handler(_arg,-1,_url,"unable to parse URL: missing scheme, host name, or path"); - goto closeAndReturnFromHttp; - } - std::wstring urlScheme(uc.lpszScheme,uc.dwSchemeLength); - std::wstring urlHostName(uc.lpszHostName,uc.dwHostNameLength); - std::wstring urlPath(uc.lpszUrlPath,uc.dwUrlPathLength); - if ((uc.lpszExtraInfo)&&(uc.dwExtraInfoLength > 0)) - urlPath.append(uc.lpszExtraInfo,uc.dwExtraInfoLength); - - if (urlScheme != L"http") { - _handler(_arg,-1,_url,"only 'http' scheme is supported"); - goto closeAndReturnFromHttp; - } - - hConnect = WinHttpConnect(hSession,urlHostName.c_str(),((uc.nPort > 0) ? uc.nPort : 80),0); - if (!hConnect) { - _handler(_arg,-1,_url,"connection failed"); - goto closeAndReturnFromHttp; - } - - { - Mutex::Lock _rl(_hRequest_m); - _hRequest = WinHttpOpenRequest(hConnect,L"GET",urlPath.c_str(),NULL,WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES,0); - if (!_hRequest) { - _handler(_arg,-1,_url,"error sending request (1)"); - goto closeAndReturnFromHttp; - } - if (!WinHttpSendRequest(_hRequest,WINHTTP_NO_ADDITIONAL_HEADERS,0,WINHTTP_NO_REQUEST_DATA,0,0,0)) { - _handler(_arg,-1,_url,"error sending request (2)"); - goto closeAndReturnFromHttp; - } - hRequest = _hRequest; - } - - if (WinHttpReceiveResponse(hRequest,NULL)) { - DWORD dwStatusCode = 0; - DWORD dwTmp = sizeof(dwStatusCode); - WinHttpQueryHeaders(hRequest,WINHTTP_QUERY_STATUS_CODE| WINHTTP_QUERY_FLAG_NUMBER,NULL,&dwStatusCode,&dwTmp,NULL); - - DWORD dwSize; - do { - dwSize = 0; - if (!WinHttpQueryDataAvailable(hRequest,&dwSize)) { - _handler(_arg,-1,_url,"receive error (1)"); - goto closeAndReturnFromHttp; - } - - { - Mutex::Lock _rl(_hRequest_m); - if (!_hRequest) { - _handler(_arg,-1,_url,"request cancelled"); - goto closeAndReturnFromHttp; - } - } - - char *outBuffer = new char[dwSize]; - DWORD dwRead = 0; - if (!WinHttpReadData(hRequest,(LPVOID)outBuffer,dwSize,&dwRead)) { - _handler(_arg,-1,_url,"receive error (2)"); - goto closeAndReturnFromHttp; - } - - { - Mutex::Lock _rl(_hRequest_m); - if (!_hRequest) { - _handler(_arg,-1,_url,"request cancelled"); - goto closeAndReturnFromHttp; - } - - _body.append(outBuffer,dwRead); - delete [] outBuffer; - if (_body.length() > WIN_MAX_MESSAGE_LENGTH) { - _handler(_arg,-1,_url,"result too large"); - goto closeAndReturnFromHttp; - } - } - } while ((dwSize > 0)&&(_hRequest)); - - { - Mutex::Lock _rl(_hRequest_m); - if (!_hRequest) { - _handler(_arg,-1,_url,"request cancelled"); - goto closeAndReturnFromHttp; - } - - _handler(_arg,dwStatusCode,_url,_body); - } - } else { - _handler(_arg,-1,_url,"receive response failed"); - } - } catch ( ... ) { - _handler(_arg,-1,_url,"unexpected exception"); - } - -closeAndReturnFromHttp: - { - Mutex::Lock _rl(_hRequest_m); - if (_hRequest) { - WinHttpCloseHandle(_hRequest); - _hRequest = (HINTERNET)0; - } - } - if (hConnect) - WinHttpCloseHandle(hConnect); - if (hSession) - WinHttpCloseHandle(hSession); - delete this; - return; - } - - inline void cancel() - { - Mutex::Lock _rl(_hRequest_m); - if (_hRequest) { - WinHttpCloseHandle(_hRequest); - _hRequest = (HINTERNET)0; - } - } - - const std::string _url; - std::string _body; - std::map _headers; - unsigned int _timeout; - void (*_handler)(void *,int,const std::string &,const std::string &); - void *_arg; - HttpClient *_parent; - HINTERNET _hRequest; - Mutex _hRequest_m; - Thread _myThread; -}; - -#endif // __WINDOWS__ - -const std::map HttpClient::NO_HEADERS; - -HttpClient::HttpClient() -{ -} - -HttpClient::~HttpClient() -{ - std::set reqs; - { - Mutex::Lock _l(_requests_m); - reqs = _requests; - } - - for(std::set::iterator r(reqs.begin());r!=reqs.end();++r) - this->cancel(*r); - - for(;;) { - _requests_m.lock(); - if (_requests.empty()) { - _requests_m.unlock(); - break; - } else { - _requests_m.unlock(); - Thread::sleep(250); - } - } -} - -void HttpClient::cancel(HttpClient::Request req) -{ - Mutex::Lock _l(_requests_m); - if (_requests.count(req) == 0) - return; - ((HttpClient_Private_Request *)req)->cancel(); -} - -HttpClient::Request HttpClient::_do( - const char *method, - const std::string &url, - const std::map &headers, - unsigned int timeout, - void (*handler)(void *,int,const std::string &,const std::string &), - void *arg) -{ - HttpClient::Request r = (HttpClient::Request)(new HttpClient_Private_Request(this,method,url,headers,timeout,handler,arg)); - Mutex::Lock _l(_requests_m); - _requests.insert(r); - return r; -} - -} // namespace ZeroTier diff --git a/node/HttpClient.hpp b/node/HttpClient.hpp deleted file mode 100644 index 925ce76e..00000000 --- a/node/HttpClient.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 . - * - * -- - * - * 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_HTTPCLIENT_HPP -#define ZT_HTTPCLIENT_HPP - -#include -#include -#include - -#include "Constants.hpp" -#include "Mutex.hpp" - -namespace ZeroTier { - -class HttpClient_Private_Request; - -/** - * HTTP client that does queries in the background - * - * The handler method takes the following arguments: an arbitrary pointer, an - * HTTP response code, the URL queried, whether or not the message body was - * stored on disk, and the message body. - * - * If stored on disk, the body string contains the path and the file must be - * moved or deleted by the receiver when it's done. If an error occurs, the - * response code will be negative and the body will be the error message. - * - * All headers in the returned headers map will have their header names - * converted to lower case, e.g. "content-type". - * - * Currently only the "http" transport is guaranteed to be supported on all - * platforms. - */ -class HttpClient -{ -public: - friend class HttpClient_Private_Request; - typedef void * Request; - - HttpClient(); - ~HttpClient(); - - /** - * Empty map for convenience use - */ - static const std::map NO_HEADERS; - - /** - * Request a URL using the GET method - */ - inline Request GET( - const std::string &url, - const std::map &headers, - unsigned int timeout, - void (*handler)(void *,int,const std::string &,const std::string &), - void *arg) - { - return _do("GET",url,headers,timeout,handler,arg); - } - - /** - * Cancel a request - * - * If the request is not active, this does nothing. This may take some time - * depending on HTTP implementation. It may also not kill instantly, but - * it will prevent the handler function from ever being called and cause the - * request to die silently when complete. - */ - void cancel(Request req); - -private: - Request _do( - const char *method, - const std::string &url, - const std::map &headers, - unsigned int timeout, - void (*handler)(void *,int,const std::string &,const std::string &), - void *arg); - - std::set _requests; - Mutex _requests_m; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/Network.hpp b/node/Network.hpp index 9c4d6746..dfbe4f8b 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -54,7 +54,6 @@ #include "Multicaster.hpp" #include "NetworkConfig.hpp" #include "CertificateOfMembership.hpp" -#include "Thread.hpp" namespace ZeroTier { @@ -447,12 +446,6 @@ public: */ void destroy(); - /** - * Thread main method; do not call elsewhere - */ - void threadMain() - throw(); - private: static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data); @@ -495,8 +488,6 @@ private: NETCONF_FAILURE_INIT_FAILED } _netconfFailure; - Thread _setupThread; - Mutex _lock; AtomicCounter __refCount; diff --git a/node/SoftwareUpdater.cpp b/node/SoftwareUpdater.cpp deleted file mode 100644 index 345fc28e..00000000 --- a/node/SoftwareUpdater.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* - * 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 . - * - * -- - * - * 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 -#include -#include - -#include - -#include "../version.h" - -#include "Constants.hpp" -#include "SoftwareUpdater.hpp" -#include "Dictionary.hpp" -#include "C25519.hpp" -#include "Identity.hpp" -#include "Logger.hpp" -#include "RuntimeEnvironment.hpp" -#include "Thread.hpp" -#include "Node.hpp" -#include "Utils.hpp" -#include "HttpClient.hpp" - -#ifdef __UNIX_LIKE__ -#include -#include -#include -#include -#endif - -namespace ZeroTier { - -SoftwareUpdater::SoftwareUpdater(const RuntimeEnvironment *renv) : - RR(renv), - _myVersion(packVersion(ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION)), - _lastUpdateAttempt(0), - _status(UPDATE_STATUS_IDLE), - _die(false), - _lock() -{ -} - -SoftwareUpdater::~SoftwareUpdater() -{ - _die = true; - for(;;) { - _lock.lock(); - bool ip = (_status != UPDATE_STATUS_IDLE); - _lock.unlock(); - if (ip) - Thread::sleep(500); - else break; - } -} - -void SoftwareUpdater::cleanOldUpdates() -{ - std::string updatesDir(RR->homePath + ZT_PATH_SEPARATOR_S + "updates.d"); - std::map dl(Utils::listDirectory(updatesDir.c_str())); - for(std::map::iterator i(dl.begin());i!=dl.end();++i) { - if (!i->second) - Utils::rm((updatesDir + ZT_PATH_SEPARATOR_S + i->first).c_str()); - } -} - -void SoftwareUpdater::sawRemoteVersion(unsigned int vmaj,unsigned int vmin,unsigned int rev) -{ - const uint64_t tmp = packVersion(vmaj,vmin,rev); - if (tmp > _myVersion) { - Mutex::Lock _l(_lock); - if ((_status == UPDATE_STATUS_IDLE)&&(!_die)&&(ZT_DEFAULTS.updateLatestNfoURL.length())) { - const uint64_t now = Utils::now(); - if ((now - _lastUpdateAttempt) >= ZT_UPDATE_MIN_INTERVAL) { - _lastUpdateAttempt = now; - _status = UPDATE_STATUS_GETTING_NFO; - RR->http->GET(ZT_DEFAULTS.updateLatestNfoURL,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionInfo,this); - } - } - } -} - -void SoftwareUpdater::checkNow() -{ - Mutex::Lock _l(_lock); - if (_status == UPDATE_STATUS_IDLE) { - _lastUpdateAttempt = Utils::now(); - _status = UPDATE_STATUS_GETTING_NFO; - RR->http->GET(ZT_DEFAULTS.updateLatestNfoURL,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionInfo,this); - } -} - -const char *SoftwareUpdater::parseNfo( - const char *nfoText, - unsigned int &vMajor, - unsigned int &vMinor, - unsigned int &vRevision, - Address &signedBy, - std::string &signature, - std::string &url) -{ - try { - Dictionary nfo(nfoText); - - vMajor = Utils::strToUInt(nfo.get("vMajor").c_str()); - vMinor = Utils::strToUInt(nfo.get("vMinor").c_str()); - vRevision = Utils::strToUInt(nfo.get("vRevision").c_str()); - signedBy = nfo.get("signedBy"); - signature = Utils::unhex(nfo.get("ed25519")); - url = nfo.get("url"); - - if (signature.length() != ZT_C25519_SIGNATURE_LEN) - return "bad ed25519 signature, invalid length"; - if ((url.length() <= 7)||(url.substr(0,7) != "http://")) - return "invalid URL, must begin with http://"; - - return (const char *)0; - } catch ( ... ) { - return "invalid NFO file format or one or more required fields missing"; - } -} - -bool SoftwareUpdater::validateUpdate( - const void *data, - unsigned int len, - const Address &signedBy, - const std::string &signature) -{ - std::map< Address,Identity >::const_iterator updateAuthority = ZT_DEFAULTS.updateAuthorities.find(signedBy); - if (updateAuthority == ZT_DEFAULTS.updateAuthorities.end()) - return false; - return updateAuthority->second.verify(data,len,signature.data(),(unsigned int)signature.length()); -} - -void SoftwareUpdater::_cbHandleGetLatestVersionInfo(void *arg,int code,const std::string &url,const std::string &body) -{ - SoftwareUpdater *upd = (SoftwareUpdater *)arg; - const RuntimeEnvironment *RR = (const RuntimeEnvironment *)upd->RR; - Mutex::Lock _l(upd->_lock); - - if ((upd->_die)||(upd->_status != UPDATE_STATUS_GETTING_NFO)) { - upd->_status = UPDATE_STATUS_IDLE; - return; - } - - if (code != 200) { - LOG("software update check failed: server responded with code %d",code); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - - try { - unsigned int vMajor = 0,vMinor = 0,vRevision = 0; - Address signedBy; - std::string signature,url; - - const char *err = parseNfo(body.c_str(),vMajor,vMinor,vRevision,signedBy,signature,url); - - if (err) { - LOG("software update check aborted: .nfo file parse error: %s",err); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - - if (!ZT_DEFAULTS.updateAuthorities.count(signedBy)) { - LOG("software update check aborted: .nfo file specifies unknown signing authority"); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - -#ifndef ZT_ALWAYS_UPDATE /* for testing */ - if (packVersion(vMajor,vMinor,vRevision) <= upd->_myVersion) { - TRACE("software update check complete: version on update site is not newer than my version, no update necessary"); - upd->_status = UPDATE_STATUS_IDLE; - return; - } -#endif - - upd->_status = UPDATE_STATUS_GETTING_FILE; - upd->_signedBy = signedBy; - upd->_signature = signature; - - RR->http->GET(url,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionBinary,arg); - } catch ( ... ) { - LOG("software update check failed: .nfo file invalid or missing field(s)"); - upd->_status = UPDATE_STATUS_IDLE; - } -} - -void SoftwareUpdater::_cbHandleGetLatestVersionBinary(void *arg,int code,const std::string &url,const std::string &body) -{ - SoftwareUpdater *upd = (SoftwareUpdater *)arg; - const RuntimeEnvironment *RR = (const RuntimeEnvironment *)upd->RR; - Mutex::Lock _l(upd->_lock); - - if (!validateUpdate(body.data(),(unsigned int)body.length(),upd->_signedBy,upd->_signature)) { - LOG("software update failed: update fetched from '%s' failed signature check (image size: %u)",url.c_str(),(unsigned int)body.length()); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - - size_t lastSlash = url.rfind('/'); - if (lastSlash == std::string::npos) { // sanity check, shouldn't happen - LOG("software update failed: invalid URL"); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - std::string updatesDir(RR->homePath + ZT_PATH_SEPARATOR_S + "updates.d"); - std::string updateFilename(url.substr(lastSlash + 1)); - if ((updateFilename.length() < 3)||(updateFilename.find("..") != std::string::npos)) { - LOG("software update failed: invalid URL: filename contains invalid characters"); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - for(std::string::iterator c(updateFilename.begin());c!=updateFilename.end();++c) { - // Only allow a list of whitelisted characters to make up the filename to prevent any - // path shenanigans, esp on Windows where / is not the path separator. - if (!strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.0123456789",*c)) { - LOG("software update failed: invalid URL: filename contains invalid characters"); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - } - std::string updatePath(updatesDir + ZT_PATH_SEPARATOR_S + updateFilename); -#ifdef __WINDOWS__ - CreateDirectoryA(updatesDir.c_str(),NULL); -#else - mkdir(updatesDir.c_str(),0755); -#endif - - FILE *upf = fopen(updatePath.c_str(),"wb"); - if (!upf) { - LOG("software update failed: unable to open %s for writing",updatePath.c_str()); - upd->_status = UPDATE_STATUS_IDLE; - return; - } - if (fwrite(body.data(),body.length(),1,upf) != 1) { - LOG("software update failed: unable to write to %s",updatePath.c_str()); - upd->_status = UPDATE_STATUS_IDLE; - fclose(upf); - Utils::rm(updatePath); - return; - } - fclose(upf); - -#ifdef __UNIX_LIKE__ - ::chmod(updatePath.c_str(),0755); -#endif - - // We exit with this reason code and the path as the text. It is the - // caller's responsibility (main.c) to pick this up and do the right - // thing. - upd->_status = UPDATE_STATUS_IDLE; - RR->node->terminate(Node::NODE_RESTART_FOR_UPGRADE,updatePath.c_str()); -} - -} // namespace ZeroTier diff --git a/node/SoftwareUpdater.hpp b/node/SoftwareUpdater.hpp deleted file mode 100644 index 6c1e573a..00000000 --- a/node/SoftwareUpdater.hpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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 . - * - * -- - * - * 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_SOFTWAREUPDATER_HPP -#define ZT_SOFTWAREUPDATER_HPP - -#include - -#include - -#include "Constants.hpp" -#include "Mutex.hpp" -#include "Utils.hpp" -#include "Defaults.hpp" -#include "Address.hpp" - -namespace ZeroTier { - -class RuntimeEnvironment; - -/** - * Software updater - */ -class SoftwareUpdater -{ -public: - SoftwareUpdater(const RuntimeEnvironment *renv); - ~SoftwareUpdater(); - - /** - * Remove old updates in updates.d - */ - void cleanOldUpdates(); - - /** - * Called on each version message from a peer - * - * If a peer has a newer version, that causes an update to be started. - * - * @param vmaj Peer's major version - * @param vmin Peer's minor version - * @param rev Peer's revision - */ - void sawRemoteVersion(unsigned int vmaj,unsigned int vmin,unsigned int rev); - - /** - * Check for updates now regardless of last check time or version - * - * This only starts a check if one is not in progress. Otherwise it does - * nothing. - */ - void checkNow(); - - /** - * Check for updates now if it's been longer than ZT_UPDATE_MAX_INTERVAL - * - * This is called periodically from the main loop. - */ - inline void checkIfMaxIntervalExceeded(uint64_t now) - { - if ((now - _lastUpdateAttempt) >= ZT_UPDATE_MAX_INTERVAL) - checkNow(); - } - - /** - * Pack three-component version into a 64-bit integer - * - * @param vmaj Major version (0..65535) - * @param vmin Minor version (0..65535) - * @param rev Revision (0..65535) - * @return Version packed into an easily comparable 64-bit integer - */ - static inline uint64_t packVersion(unsigned int vmaj,unsigned int vmin,unsigned int rev) - throw() - { - return ( ((uint64_t)(vmaj & 0xffff) << 32) | ((uint64_t)(vmin & 0xffff) << 16) | (uint64_t)(rev & 0xffff) ); - } - - /** - * Parse NFO data from .nfo file on software update site - * - * The first argument is the NFO data, and all the remaining arguments are - * result parameters to be filled with results. If an error is returned the - * results in the parameters should be considered undefined. - * - * @param nfo NFO data - * @param vMajor Result: major version - * @param vMinor Result: minor version - * @param vRevision Result: revision number - * @param signedBy Result: signing identity - * @param signature Result: Ed25519 signature data - * @param url Result: URL of update binary - * @return NULL on success or error message on failure - */ - static const char *parseNfo( - const char *nfoText, - unsigned int &vMajor, - unsigned int &vMinor, - unsigned int &vRevision, - Address &signedBy, - std::string &signature, - std::string &url); - - /** - * Validate an update once downloaded - * - * This obtains the identity corresponding to the address from the compiled-in - * list of valid signing identities. - * - * @param data Update data - * @param len Length of update data - * @param signedBy Signing authority address - * @param signature Signing authority signature - * @return True on validation success, false if rejected - */ - static bool validateUpdate( - const void *data, - unsigned int len, - const Address &signedBy, - const std::string &signature); - -private: - static void _cbHandleGetLatestVersionInfo(void *arg,int code,const std::string &url,const std::string &body); - static void _cbHandleGetLatestVersionBinary(void *arg,int code,const std::string &url,const std::string &body); - - const RuntimeEnvironment *RR; - const uint64_t _myVersion; - volatile uint64_t _lastUpdateAttempt; - volatile enum { - UPDATE_STATUS_IDLE, - UPDATE_STATUS_GETTING_NFO, - UPDATE_STATUS_GETTING_FILE - } _status; - volatile bool _die; - Address _signedBy; - std::string _signature; - Mutex _lock; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/Thread.hpp b/node/Thread.hpp deleted file mode 100644 index c8c99f29..00000000 --- a/node/Thread.hpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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 . - * - * -- - * - * 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_THREAD_HPP -#define ZT_THREAD_HPP - -#include - -#include "Constants.hpp" - -#ifdef __WINDOWS__ - -#include -#include -#include -#include "Mutex.hpp" - -namespace ZeroTier { - -template -static DWORD WINAPI ___zt_threadMain(LPVOID lpParam) -{ - try { - ((C *)lpParam)->threadMain(); - } catch ( ... ) {} - return 0; -} - -class Thread -{ -public: - Thread() - throw() - { - _th = NULL; - _tid = 0; - } - - template - static inline Thread start(C *instance) - throw(std::runtime_error) - { - Thread t; - t._th = CreateThread(NULL,0,&___zt_threadMain,(LPVOID)instance,0,&t._tid); - if (t._th == NULL) - throw std::runtime_error("CreateThread() failed"); - return t; - } - - static inline void join(const Thread &t) - { - if (t._th != NULL) { - for(;;) { - DWORD ec = STILL_ACTIVE; - GetExitCodeThread(t._th,&ec); - if (ec == STILL_ACTIVE) - WaitForSingleObject(t._th,1000); - else break; - } - } - } - - static inline void sleep(unsigned long ms) - { - Sleep((DWORD)ms); - } - - // Not available on *nix platforms - static inline void cancelIO(const Thread &t) - { - if (t._th != NULL) - CancelSynchronousIo(t._th); - } - - inline operator bool() const throw() { return (_th != NULL); } - -private: - HANDLE _th; - DWORD _tid; -}; - -} // namespace ZeroTier - -#else - -#include -#include -#include -#include -#include - -namespace ZeroTier { - -template -static void *___zt_threadMain(void *instance) -{ - try { - ((C *)instance)->threadMain(); - } catch ( ... ) {} - return (void *)0; -} - -/** - * A thread identifier, and static methods to start and join threads - */ -class Thread -{ -public: - Thread() - throw() - { - memset(&_tid,0,sizeof(_tid)); - _started = false; - } - - Thread(const Thread &t) - throw() - { - memcpy(&_tid,&(t._tid),sizeof(_tid)); - _started = t._started; - } - - inline Thread &operator=(const Thread &t) - throw() - { - memcpy(&_tid,&(t._tid),sizeof(_tid)); - _started = t._started; - return *this; - } - - /** - * Start a new thread - * - * @param instance Instance whose threadMain() method gets called by new thread - * @return Thread identifier - * @throws std::runtime_error Unable to create thread - * @tparam C Class containing threadMain() - */ - template - static inline Thread start(C *instance) - throw(std::runtime_error) - { - Thread t; - t._started = true; - if (pthread_create(&t._tid,(const pthread_attr_t *)0,&___zt_threadMain,instance)) - throw std::runtime_error("pthread_create() failed, unable to create thread"); - return t; - } - - /** - * Join to a thread, waiting for it to terminate (does nothing on null Thread values) - * - * @param t Thread to join - */ - static inline void join(const Thread &t) - { - if (t._started) - pthread_join(t._tid,(void **)0); - } - - /** - * Sleep the current thread - * - * @param ms Number of milliseconds to sleep - */ - static inline void sleep(unsigned long ms) { usleep(ms * 1000); } - - inline operator bool() const throw() { return (_started); } - -private: - pthread_t _tid; - volatile bool _started; -}; - -} // namespace ZeroTier - -#endif // __WINDOWS__ / !__WINDOWS__ - -#endif -- cgit v1.2.3