Refactor HttpClient a bit.

This commit is contained in:
Adam Ierymenko 2014-08-16 09:08:52 -07:00
parent aa59cfd545
commit 4f0fcc582e
7 changed files with 184 additions and 99 deletions

View File

@ -27,17 +27,17 @@
#include "Constants.hpp" #include "Constants.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <WinSock2.h> #include <WinSock2.h>
#include <Windows.h> #include <Windows.h>
#include <winhttp.h> #include <winhttp.h>
#include <locale> #include <locale>
#include <codecvt> #include <codecvt>
#endif #endif // __WINDOWS__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#include <unistd.h> #include <unistd.h>
@ -48,7 +48,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif // __UNIX_LIKE__
#include <vector> #include <vector>
#include <utility> #include <utility>
@ -62,8 +62,6 @@
namespace ZeroTier { namespace ZeroTier {
const std::map<std::string,std::string> HttpClient::NO_HEADERS;
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
// The *nix implementation calls 'curl' externally rather than linking to it. // The *nix implementation calls 'curl' externally rather than linking to it.
@ -76,27 +74,36 @@ const std::map<std::string,std::string> HttpClient::NO_HEADERS;
#endif #endif
// Paths where "curl" may be found on the system // Paths where "curl" may be found on the system
#define NUM_CURL_PATHS 5 #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" }; 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 // Maximum message length
#define CURL_MAX_MESSAGE_LENGTH (1024 * 1024 * 64) #define CURL_MAX_MESSAGE_LENGTH (1024 * 1024 * 64)
// Internal private thread class that performs request, notifies handler, // Internal private thread class that performs request, notifies handler,
// and then commits suicide by deleting itself. // and then commits suicide by deleting itself.
class P_Req : NonCopyable class HttpClient_Private_Request : NonCopyable
{ {
public: public:
P_Req(const char *method,const std::string &url,const std::map<std::string,std::string> &headers,unsigned int timeout,void (*handler)(void *,int,const std::string &,bool,const std::string &),void *arg) : HttpClient_Private_Request(HttpClient *parent,const char *method,const std::string &url,const std::map<std::string,std::string> &headers,unsigned int timeout,void (*handler)(void *,int,const std::string &,const std::string &),void *arg) :
_url(url), _url(url),
_headers(headers), _headers(headers),
_timeout(timeout), _timeout(timeout),
_handler(handler), _handler(handler),
_arg(arg) _arg(arg),
_parent(parent),
_pid(0),
_cancelled(false)
{ {
_myThread = Thread::start(this); _myThread = Thread::start(this);
} }
~HttpClient_Private_Request()
{
Mutex::Lock _l(_parent->_requests_m);
_parent->_requests.erase((HttpClient::Request)this);
}
void threadMain() void threadMain()
{ {
char *curlArgs[1024]; char *curlArgs[1024];
@ -111,14 +118,14 @@ public:
break; break;
} }
} }
if (!curlPath.length()) { if (!curlPath.length()) {
_handler(_arg,-1,_url,false,"unable to locate 'curl' binary in /usr/bin, /bin, /usr/local/bin, /usr/sbin, or /sbin"); _doH(_arg,-1,_url,"unable to locate 'curl' binary in /usr/bin, /bin, /usr/local/bin, /usr/sbin, or /sbin");
delete this; delete this;
return; return;
} }
if (!_url.length()) { if (!_url.length()) {
_handler(_arg,-1,_url,false,"cannot fetch empty URL"); _doH(_arg,-1,_url,"cannot fetch empty URL");
delete this; delete this;
return; return;
} }
@ -147,17 +154,17 @@ public:
::pipe(curlStdout); ::pipe(curlStdout);
::pipe(curlStderr); ::pipe(curlStderr);
long pid = (long)vfork(); _pid = (long)vfork();
if (pid < 0) { if (_pid < 0) {
// fork() failed // fork() failed
::close(curlStdout[0]); ::close(curlStdout[0]);
::close(curlStdout[1]); ::close(curlStdout[1]);
::close(curlStderr[0]); ::close(curlStderr[0]);
::close(curlStderr[1]); ::close(curlStderr[1]);
_handler(_arg,-1,_url,false,"unable to fork()"); _doH(_arg,-1,_url,"unable to fork()");
delete this; delete this;
return; return;
} else if (pid > 0) { } else if (_pid > 0) {
// fork() succeeded, in parent process // fork() succeeded, in parent process
::close(curlStdout[1]); ::close(curlStdout[1]);
::close(curlStderr[1]); ::close(curlStderr[1]);
@ -189,7 +196,7 @@ public:
} else if (n < 0) } else if (n < 0)
break; break;
if (_body.length() > CURL_MAX_MESSAGE_LENGTH) { if (_body.length() > CURL_MAX_MESSAGE_LENGTH) {
::kill(pid,SIGKILL); ::kill(_pid,SIGKILL);
tooLong = true; tooLong = true;
break; break;
} }
@ -200,12 +207,12 @@ public:
break; break;
if (Utils::now() >= timesOutAt) { if (Utils::now() >= timesOutAt) {
::kill(pid,SIGKILL); ::kill(_pid,SIGKILL);
timedOut = true; timedOut = true;
break; break;
} }
if (waitpid(pid,&exitCode,WNOHANG) > 0) { if (waitpid(_pid,&exitCode,WNOHANG) > 0) {
for(;;) { for(;;) {
// Drain output... // Drain output...
int n = (int)::read(curlStdout[0],buf,sizeof(buf)); int n = (int)::read(curlStdout[0],buf,sizeof(buf));
@ -219,23 +226,24 @@ public:
} }
} }
} }
pid = 0; _pid = 0;
break; break;
} }
} }
if (pid > 0) if (_pid > 0)
waitpid(pid,&exitCode,0); waitpid(_pid,&exitCode,0);
_pid = 0;
::close(curlStdout[0]); ::close(curlStdout[0]);
::close(curlStderr[0]); ::close(curlStderr[0]);
if (timedOut) if (timedOut)
_handler(_arg,-1,_url,false,"connection timed out"); _doH(_arg,-1,_url,"connection timed out");
else if (tooLong) else if (tooLong)
_handler(_arg,-1,_url,false,"response too long"); _doH(_arg,-1,_url,"response too long");
else if (exitCode) else if (exitCode)
_handler(_arg,-1,_url,false,"connection failed (curl returned non-zero exit code)"); _doH(_arg,-1,_url,"connection failed (curl returned non-zero exit code)");
else { else {
unsigned long idx = 0; unsigned long idx = 0;
@ -254,7 +262,7 @@ public:
headers.back().push_back(c); headers.back().push_back(c);
} }
if (headers.empty()||(!headers.front().length())) { if (headers.empty()||(!headers.front().length())) {
_handler(_arg,-1,_url,false,"HTTP response empty"); _doH(_arg,-1,_url,"HTTP response empty");
delete this; delete this;
return; return;
} }
@ -262,24 +270,24 @@ public:
// Parse first line -- HTTP status code and response // Parse first line -- HTTP status code and response
size_t scPos = headers.front().find(' '); size_t scPos = headers.front().find(' ');
if (scPos == std::string::npos) { if (scPos == std::string::npos) {
_handler(_arg,-1,_url,false,"invalid HTTP response (no status line)"); _doH(_arg,-1,_url,"invalid HTTP response (no status line)");
delete this; delete this;
return; return;
} }
++scPos; ++scPos;
unsigned int rcode = Utils::strToUInt(headers.front().substr(scPos,3).c_str()); unsigned int rcode = Utils::strToUInt(headers.front().substr(scPos,3).c_str());
if ((!rcode)||(rcode > 999)) { if ((!rcode)||(rcode > 999)) {
_handler(_arg,-1,_url,false,"invalid HTTP response (invalid response code)"); _doH(_arg,-1,_url,"invalid HTTP response (invalid response code)");
delete this; delete this;
return; return;
} }
// Serve up the resulting data to the handler // Serve up the resulting data to the handler
if (rcode == 200) if (rcode == 200)
_handler(_arg,rcode,_url,false,_body.substr(idx)); _doH(_arg,rcode,_url,_body.substr(idx));
else if ((scPos + 4) < headers.front().length()) else if ((scPos + 4) < headers.front().length())
_handler(_arg,rcode,_url,false,headers.front().substr(scPos+4)); _doH(_arg,rcode,_url,headers.front().substr(scPos+4));
else _handler(_arg,rcode,_url,false,"(no status message from server)"); else _doH(_arg,rcode,_url,"(no status message from server)");
} }
delete this; delete this;
@ -295,27 +303,41 @@ public:
} }
} }
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; const std::string _url;
std::string _body; std::string _body;
std::map<std::string,std::string> _headers; std::map<std::string,std::string> _headers;
unsigned int _timeout; unsigned int _timeout;
void (*_handler)(void *,int,const std::string &,bool,const std::string &); void (*_handler)(void *,int,const std::string &,const std::string &);
void *_arg; void *_arg;
HttpClient *_parent;
long _pid;
volatile bool _cancelled;
Mutex _cancelled_m;
Thread _myThread; Thread _myThread;
}; };
HttpClient::Request HttpClient::_do( #endif // __UNIX_LIKE__
const char *method,
const std::string &url,
const std::map<std::string,std::string> &headers,
unsigned int timeout,
void (*handler)(void *,int,const std::string &,bool,const std::string &),
void *arg)
{
return (HttpClient::Request)(new P_Req(method,url,headers,timeout,handler,arg));
}
#endif
#ifdef __WINDOWS__ #ifdef __WINDOWS__
@ -323,10 +345,10 @@ HttpClient::Request HttpClient::_do(
// Internal private thread class that performs request, notifies handler, // Internal private thread class that performs request, notifies handler,
// and then commits suicide by deleting itself. // and then commits suicide by deleting itself.
class P_Req : NonCopyable class HttpClient_Private_Request : NonCopyable
{ {
public: public:
P_Req(const char *method,const std::string &url,const std::map<std::string,std::string> &headers,unsigned int timeout,void (*handler)(void *,int,const std::string &,bool,const std::string &),void *arg) : HttpClient_Private_Request(const char *method,const std::string &url,const std::map<std::string,std::string> &headers,unsigned int timeout,void (*handler)(void *,int,const std::string &,const std::string &),void *arg) :
_url(url), _url(url),
_headers(headers), _headers(headers),
_timeout(timeout), _timeout(timeout),
@ -449,22 +471,52 @@ closeAndReturnFromHttp:
std::string _body; std::string _body;
std::map<std::string,std::string> _headers; std::map<std::string,std::string> _headers;
unsigned int _timeout; unsigned int _timeout;
void (*_handler)(void *,int,const std::string &,bool,const std::string &); void (*_handler)(void *,int,const std::string &,const std::string &);
void *_arg; void *_arg;
Thread _myThread; Thread _myThread;
}; };
#endif // __WINDOWS__
const std::map<std::string,std::string> HttpClient::NO_HEADERS;
HttpClient::HttpClient()
{
}
HttpClient::~HttpClient()
{
std::set<Request> reqs;
{
Mutex::Lock _l(_requests_m);
reqs = _requests;
}
for(std::set<Request>::iterator r(reqs.begin());r!=reqs.end();++r)
this->cancel(*r);
}
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( HttpClient::Request HttpClient::_do(
const char *method, const char *method,
const std::string &url, const std::string &url,
const std::map<std::string,std::string> &headers, const std::map<std::string,std::string> &headers,
unsigned int timeout, unsigned int timeout,
void (*handler)(void *,int,const std::string &,bool,const std::string &), void (*handler)(void *,int,const std::string &,const std::string &),
void *arg) void *arg)
{ {
return (HttpClient::Request)(new P_Req(method,url,headers,timeout,handler,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;
} }
#endif
} // namespace ZeroTier } // namespace ZeroTier

View File

@ -30,11 +30,15 @@
#include <string> #include <string>
#include <map> #include <map>
#include <set>
#include "Constants.hpp" #include "Constants.hpp"
#include "Mutex.hpp"
namespace ZeroTier { namespace ZeroTier {
class HttpClient_Private_Request;
/** /**
* HTTP client that does queries in the background * HTTP client that does queries in the background
* *
@ -55,8 +59,12 @@ namespace ZeroTier {
class HttpClient class HttpClient
{ {
public: public:
friend class HttpClient_Private_Request;
typedef void * Request; typedef void * Request;
HttpClient();
~HttpClient();
/** /**
* Empty map for convenience use * Empty map for convenience use
*/ */
@ -65,24 +73,37 @@ public:
/** /**
* Request a URL using the GET method * Request a URL using the GET method
*/ */
static inline Request GET( inline Request GET(
const std::string &url, const std::string &url,
const std::map<std::string,std::string> &headers, const std::map<std::string,std::string> &headers,
unsigned int timeout, unsigned int timeout,
void (*handler)(void *,int,const std::string &,bool,const std::string &), void (*handler)(void *,int,const std::string &,const std::string &),
void *arg) void *arg)
{ {
return _do("GET",url,headers,timeout,handler,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: private:
static Request _do( Request _do(
const char *method, const char *method,
const std::string &url, const std::string &url,
const std::map<std::string,std::string> &headers, const std::map<std::string,std::string> &headers,
unsigned int timeout, unsigned int timeout,
void (*handler)(void *,int,const std::string &,bool,const std::string &), void (*handler)(void *,int,const std::string &,const std::string &),
void *arg); void *arg);
std::set<Request> _requests;
Mutex _requests_m;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View File

@ -250,6 +250,7 @@ struct _NodeImpl
delete renv.sw; renv.sw = (Switch *)0; // order matters less from here down delete renv.sw; renv.sw = (Switch *)0; // order matters less from here down
delete renv.mc; renv.mc = (Multicaster *)0; delete renv.mc; renv.mc = (Multicaster *)0;
delete renv.antiRec; renv.antiRec = (AntiRecursion *)0; delete renv.antiRec; renv.antiRec = (AntiRecursion *)0;
delete renv.http; renv.http = (HttpClient *)0;
delete renv.prng; renv.prng = (CMWC4096 *)0; delete renv.prng; renv.prng = (CMWC4096 *)0;
delete renv.log; renv.log = (Logger *)0; // but stop logging last of all delete renv.log; renv.log = (Logger *)0; // but stop logging last of all
@ -408,7 +409,7 @@ static void _CBztTraffic(const SharedPtr<Socket> &fromSock,void *arg,const InetA
_r->sw->onRemotePacket(fromSock,from,data); _r->sw->onRemotePacket(fromSock,from,data);
} }
static void _cbHandleGetRootTopology(void *arg,int code,const std::string &url,bool onDisk,const std::string &body) static void _cbHandleGetRootTopology(void *arg,int code,const std::string &url,const std::string &body)
{ {
RuntimeEnvironment *_r = (RuntimeEnvironment *)arg; RuntimeEnvironment *_r = (RuntimeEnvironment *)arg;
if (_r->shutdownInProgress) if (_r->shutdownInProgress)
@ -524,6 +525,7 @@ Node::ReasonForTermination Node::run()
} }
Utils::lockDownFile(configAuthTokenPath.c_str(),false); Utils::lockDownFile(configAuthTokenPath.c_str(),false);
_r->http = new HttpClient();
_r->antiRec = new AntiRecursion(); _r->antiRec = new AntiRecursion();
_r->mc = new Multicaster(); _r->mc = new Multicaster();
_r->sw = new Switch(_r); _r->sw = new Switch(_r);
@ -757,7 +759,7 @@ Node::ReasonForTermination Node::run()
if ((now - lastRootTopologyFetch) >= ZT_UPDATE_ROOT_TOPOLOGY_CHECK_INTERVAL) { if ((now - lastRootTopologyFetch) >= ZT_UPDATE_ROOT_TOPOLOGY_CHECK_INTERVAL) {
lastRootTopologyFetch = now; lastRootTopologyFetch = now;
HttpClient::GET(ZT_DEFAULTS.rootTopologyUpdateURL,HttpClient::NO_HEADERS,60,&_cbHandleGetRootTopology,_r); _r->http->GET(ZT_DEFAULTS.rootTopologyUpdateURL,HttpClient::NO_HEADERS,60,&_cbHandleGetRootTopology,_r);
} }
// Sleep for loop interval or until something interesting happens. // Sleep for loop interval or until something interesting happens.

View File

@ -48,6 +48,7 @@ class SocketManager;
class AntiRecursion; class AntiRecursion;
class EthernetTapFactory; class EthernetTapFactory;
class RoutingTable; class RoutingTable;
class HttpClient;
/** /**
* Holds global state for an instance of ZeroTier::Node * Holds global state for an instance of ZeroTier::Node
@ -73,6 +74,7 @@ public:
routingTable((RoutingTable *)0), routingTable((RoutingTable *)0),
log((Logger *)0), log((Logger *)0),
prng((CMWC4096 *)0), prng((CMWC4096 *)0),
http((HttpClient *)0),
antiRec((AntiRecursion *)0), antiRec((AntiRecursion *)0),
mc((Multicaster *)0), mc((Multicaster *)0),
sw((Switch *)0), sw((Switch *)0),
@ -119,6 +121,7 @@ public:
Logger *log; // null if logging is disabled Logger *log; // null if logging is disabled
CMWC4096 *prng; CMWC4096 *prng;
HttpClient *http;
AntiRecursion *antiRec; AntiRecursion *antiRec;
Multicaster *mc; Multicaster *mc;
Switch *sw; Switch *sw;

View File

@ -33,6 +33,7 @@
#include "../version.h" #include "../version.h"
#include "Constants.hpp"
#include "SoftwareUpdater.hpp" #include "SoftwareUpdater.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "C25519.hpp" #include "C25519.hpp"
@ -42,6 +43,7 @@
#include "Thread.hpp" #include "Thread.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "HttpClient.hpp"
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#include <unistd.h> #include <unistd.h>
@ -85,6 +87,32 @@ void SoftwareUpdater::cleanOldUpdates()
} }
} }
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;
_r->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;
_r->http->GET(ZT_DEFAULTS.updateLatestNfoURL,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionInfo,this);
}
}
const char *SoftwareUpdater::parseNfo( const char *SoftwareUpdater::parseNfo(
const char *nfoText, const char *nfoText,
unsigned int &vMajor, unsigned int &vMajor,
@ -127,7 +155,7 @@ bool SoftwareUpdater::validateUpdate(
return updateAuthority->second.verify(data,len,signature.data(),(unsigned int)signature.length()); return updateAuthority->second.verify(data,len,signature.data(),(unsigned int)signature.length());
} }
void SoftwareUpdater::_cbHandleGetLatestVersionInfo(void *arg,int code,const std::string &url,bool onDisk,const std::string &body) void SoftwareUpdater::_cbHandleGetLatestVersionInfo(void *arg,int code,const std::string &url,const std::string &body)
{ {
SoftwareUpdater *upd = (SoftwareUpdater *)arg; SoftwareUpdater *upd = (SoftwareUpdater *)arg;
const RuntimeEnvironment *_r = (const RuntimeEnvironment *)upd->_r; const RuntimeEnvironment *_r = (const RuntimeEnvironment *)upd->_r;
@ -175,14 +203,14 @@ void SoftwareUpdater::_cbHandleGetLatestVersionInfo(void *arg,int code,const std
upd->_signedBy = signedBy; upd->_signedBy = signedBy;
upd->_signature = signature; upd->_signature = signature;
HttpClient::GET(url,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionBinary,arg); _r->http->GET(url,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionBinary,arg);
} catch ( ... ) { } catch ( ... ) {
LOG("software update check failed: .nfo file invalid or missing field(s)"); LOG("software update check failed: .nfo file invalid or missing field(s)");
upd->_status = UPDATE_STATUS_IDLE; upd->_status = UPDATE_STATUS_IDLE;
} }
} }
void SoftwareUpdater::_cbHandleGetLatestVersionBinary(void *arg,int code,const std::string &url,bool onDisk,const std::string &body) void SoftwareUpdater::_cbHandleGetLatestVersionBinary(void *arg,int code,const std::string &url,const std::string &body)
{ {
SoftwareUpdater *upd = (SoftwareUpdater *)arg; SoftwareUpdater *upd = (SoftwareUpdater *)arg;
const RuntimeEnvironment *_r = (const RuntimeEnvironment *)upd->_r; const RuntimeEnvironment *_r = (const RuntimeEnvironment *)upd->_r;

View File

@ -35,7 +35,6 @@
#include "Constants.hpp" #include "Constants.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "HttpClient.hpp"
#include "Defaults.hpp" #include "Defaults.hpp"
#include "Address.hpp" #include "Address.hpp"
@ -66,21 +65,7 @@ public:
* @param vmin Peer's minor version * @param vmin Peer's minor version
* @param rev Peer's revision * @param rev Peer's revision
*/ */
inline void sawRemoteVersion(unsigned int vmaj,unsigned int vmin,unsigned int rev) void 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;
HttpClient::GET(ZT_DEFAULTS.updateLatestNfoURL,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionInfo,this);
}
}
}
}
/** /**
* Check for updates now regardless of last check time or version * Check for updates now regardless of last check time or version
@ -88,15 +73,7 @@ public:
* This only starts a check if one is not in progress. Otherwise it does * This only starts a check if one is not in progress. Otherwise it does
* nothing. * nothing.
*/ */
inline void checkNow() void checkNow();
{
Mutex::Lock _l(_lock);
if (_status == UPDATE_STATUS_IDLE) {
_lastUpdateAttempt = Utils::now();
_status = UPDATE_STATUS_GETTING_NFO;
HttpClient::GET(ZT_DEFAULTS.updateLatestNfoURL,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionInfo,this);
}
}
/** /**
* Check for updates now if it's been longer than ZT_UPDATE_MAX_INTERVAL * Check for updates now if it's been longer than ZT_UPDATE_MAX_INTERVAL
@ -167,8 +144,8 @@ public:
const std::string &signature); const std::string &signature);
private: private:
static void _cbHandleGetLatestVersionInfo(void *arg,int code,const std::string &url,bool onDisk,const std::string &body); 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,bool onDisk,const std::string &body); static void _cbHandleGetLatestVersionBinary(void *arg,int code,const std::string &url,const std::string &body);
const RuntimeEnvironment *_r; const RuntimeEnvironment *_r;
const uint64_t _myVersion; const uint64_t _myVersion;

View File

@ -67,7 +67,7 @@ static unsigned char fuzzbuf[1048576];
static volatile bool webDone = false; static volatile bool webDone = false;
static std::string webSha512ShouldBe; static std::string webSha512ShouldBe;
static void testHttpHandler(void *arg,int code,const std::string &url,bool onDisk,const std::string &body) static void testHttpHandler(void *arg,int code,const std::string &url,const std::string &body)
{ {
unsigned char sha[64]; unsigned char sha[64];
if (code == 200) { if (code == 200) {
@ -81,46 +81,48 @@ static void testHttpHandler(void *arg,int code,const std::string &url,bool onDis
static int testHttp() static int testHttp()
{ {
HttpClient http;
webSha512ShouldBe = "221b348c8278ad2063c158fb15927c35dc6bb42880daf130d0574025f88ec350811c34fae38a014b576d3ef5c98af32bb540e68204810db87a51fa9b239ea567"; webSha512ShouldBe = "221b348c8278ad2063c158fb15927c35dc6bb42880daf130d0574025f88ec350811c34fae38a014b576d3ef5c98af32bb540e68204810db87a51fa9b239ea567";
std::cout << "[http] fetching http://download.zerotier.com/dev/1k ... "; std::cout.flush(); std::cout << "[http] fetching http://download.zerotier.com/dev/1k ... "; std::cout.flush();
webDone = false; webDone = false;
HttpClient::GET("http://download.zerotier.com/dev/1k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0); http.GET("http://download.zerotier.com/dev/1k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
while (!webDone) Thread::sleep(500); while (!webDone) Thread::sleep(500);
webSha512ShouldBe = "342e1a058332aad2d7a5412c1d9cd4ad02b4038178ca0c3ed9d34e3cf0905c118b684e5d2a935a158195d453d7d69e9c6e201e252620fb53f29611794a5d4b0c"; webSha512ShouldBe = "342e1a058332aad2d7a5412c1d9cd4ad02b4038178ca0c3ed9d34e3cf0905c118b684e5d2a935a158195d453d7d69e9c6e201e252620fb53f29611794a5d4b0c";
std::cout << "[http] fetching http://download.zerotier.com/dev/2k ... "; std::cout.flush(); std::cout << "[http] fetching http://download.zerotier.com/dev/2k ... "; std::cout.flush();
webDone = false; webDone = false;
HttpClient::GET("http://download.zerotier.com/dev/2k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0); http.GET("http://download.zerotier.com/dev/2k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
while (!webDone) Thread::sleep(500); while (!webDone) Thread::sleep(500);
webSha512ShouldBe = "439562e1471dd6bdb558cb680f38dd7742e521497e280cb1456a31f74b9216b7d98145b3896c2f68008e6ac0c1662a4cb70562caeac294c5d01f378b22a21292"; webSha512ShouldBe = "439562e1471dd6bdb558cb680f38dd7742e521497e280cb1456a31f74b9216b7d98145b3896c2f68008e6ac0c1662a4cb70562caeac294c5d01f378b22a21292";
std::cout << "[http] fetching http://download.zerotier.com/dev/4k ... "; std::cout.flush(); std::cout << "[http] fetching http://download.zerotier.com/dev/4k ... "; std::cout.flush();
webDone = false; webDone = false;
HttpClient::GET("http://download.zerotier.com/dev/4k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0); http.GET("http://download.zerotier.com/dev/4k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
while (!webDone) Thread::sleep(500); while (!webDone) Thread::sleep(500);
webSha512ShouldBe = "fbd3901a9956158b9d290efa1af4fff459d8c03187c98b0e630d10a19fab61940e668652257763973f6cde34f2aa81574f9a50b1979b675b45ddd18d69a4ceb8"; webSha512ShouldBe = "fbd3901a9956158b9d290efa1af4fff459d8c03187c98b0e630d10a19fab61940e668652257763973f6cde34f2aa81574f9a50b1979b675b45ddd18d69a4ceb8";
std::cout << "[http] fetching http://download.zerotier.com/dev/8k ... "; std::cout.flush(); std::cout << "[http] fetching http://download.zerotier.com/dev/8k ... "; std::cout.flush();
webDone = false; webDone = false;
HttpClient::GET("http://download.zerotier.com/dev/8k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0); http.GET("http://download.zerotier.com/dev/8k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
while (!webDone) Thread::sleep(500); while (!webDone) Thread::sleep(500);
webSha512ShouldBe = "098ae593f8c3a962f385f9f008ec2116ad22eea8bc569fc88a06a0193480fdfb27470345c427116d19179fb2a74df21d95fe5f1df575a9f2d10d99595708b765"; webSha512ShouldBe = "098ae593f8c3a962f385f9f008ec2116ad22eea8bc569fc88a06a0193480fdfb27470345c427116d19179fb2a74df21d95fe5f1df575a9f2d10d99595708b765";
std::cout << "[http] fetching http://download.zerotier.com/dev/4m ... "; std::cout.flush(); std::cout << "[http] fetching http://download.zerotier.com/dev/4m ... "; std::cout.flush();
webDone = false; webDone = false;
HttpClient::GET("http://download.zerotier.com/dev/4m",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0); http.GET("http://download.zerotier.com/dev/4m",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
while (!webDone) Thread::sleep(500); while (!webDone) Thread::sleep(500);
webSha512ShouldBe = ""; webSha512ShouldBe = "";
std::cout << "[http] fetching http://download.zerotier.com/dev/NOEXIST ... "; std::cout.flush(); std::cout << "[http] fetching http://download.zerotier.com/dev/NOEXIST ... "; std::cout.flush();
webDone = false; webDone = false;
HttpClient::GET("http://download.zerotier.com/dev/NOEXIST",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0); http.GET("http://download.zerotier.com/dev/NOEXIST",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
while (!webDone) Thread::sleep(500); while (!webDone) Thread::sleep(500);
webSha512ShouldBe = ""; webSha512ShouldBe = "";
std::cout << "[http] fetching http://1.1.1.1/SHOULD_TIME_OUT ... "; std::cout.flush(); std::cout << "[http] fetching http://1.1.1.1/SHOULD_TIME_OUT ... "; std::cout.flush();
webDone = false; webDone = false;
HttpClient::GET("http://1.1.1.1/SHOULD_TIME_OUT",HttpClient::NO_HEADERS,4,&testHttpHandler,(void *)0); http.GET("http://1.1.1.1/SHOULD_TIME_OUT",HttpClient::NO_HEADERS,4,&testHttpHandler,(void *)0);
while (!webDone) Thread::sleep(500); while (!webDone) Thread::sleep(500);
return 0; return 0;