|
|
|
|
@ -25,7 +25,166 @@
|
|
|
|
|
* LLC. Start here: http://www.zerotier.com/
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#ifndef __WINDOWS__ |
|
|
|
|
#include <dlfcn.h> |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#include "Utils.hpp" |
|
|
|
|
#include "RuntimeEnvironment.hpp" |
|
|
|
|
#include "RPC.hpp" |
|
|
|
|
#include "Switch.hpp" |
|
|
|
|
#include "Topology.hpp" |
|
|
|
|
|
|
|
|
|
namespace ZeroTier { |
|
|
|
|
|
|
|
|
|
RPC::LocalService::LocalService(const char *dllPath) |
|
|
|
|
throw(std::invalid_argument) : |
|
|
|
|
_handle((void *)0), |
|
|
|
|
_init((void *)0), |
|
|
|
|
_do((void *)0), |
|
|
|
|
_free((void *)0), |
|
|
|
|
_destroy((void *)0) |
|
|
|
|
{ |
|
|
|
|
_handle = dlopen(dllPath,RTLD_LAZY|RTLD_LOCAL); |
|
|
|
|
if (!_handle) |
|
|
|
|
throw std::invalid_argument("Unable to load DLL: dlopen() failed"); |
|
|
|
|
|
|
|
|
|
_init = dlsym(_handle,"ZeroTierPluginInit"); |
|
|
|
|
if (!_init) { |
|
|
|
|
dlclose(_handle); |
|
|
|
|
throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginInit in DLL"); |
|
|
|
|
} |
|
|
|
|
_do = dlsym(_handle,"ZeroTierPluginDo"); |
|
|
|
|
if (!_do) { |
|
|
|
|
dlclose(_handle); |
|
|
|
|
throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginDo in DLL"); |
|
|
|
|
} |
|
|
|
|
_free = dlsym(_handle,"ZeroTierPluginFree"); |
|
|
|
|
if (!_free) { |
|
|
|
|
dlclose(_handle); |
|
|
|
|
throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginFree in DLL"); |
|
|
|
|
} |
|
|
|
|
_destroy = dlsym(_handle,"ZeroTierPluginDestroy"); |
|
|
|
|
if (!_destroy) { |
|
|
|
|
dlclose(_handle); |
|
|
|
|
throw std::invalid_argument("Unable to resolve symbol ZeroTierPluginDestroy in DLL"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (((int (*)())_init)() < 0) { |
|
|
|
|
dlclose(_handle); |
|
|
|
|
throw std::invalid_argument("ZeroTierPluginInit() returned error"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RPC::LocalService::~LocalService() |
|
|
|
|
{ |
|
|
|
|
if (_handle) { |
|
|
|
|
if (_destroy) |
|
|
|
|
((void (*)())_destroy)(); |
|
|
|
|
dlclose(_handle); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::pair< int,std::vector<std::string> > RPC::LocalService::operator()(const std::vector<std::string> &args) |
|
|
|
|
{ |
|
|
|
|
unsigned int alengths[4096]; |
|
|
|
|
const void *argptrs[4096]; |
|
|
|
|
const unsigned int *rlengths = (const unsigned int *)0; |
|
|
|
|
const void **resultptrs = (const void **)0; |
|
|
|
|
std::vector<std::string> results; |
|
|
|
|
|
|
|
|
|
if (args.size() > 4096) |
|
|
|
|
throw std::runtime_error("args[] too long"); |
|
|
|
|
|
|
|
|
|
for(unsigned int i=0;i<args.size();++i) { |
|
|
|
|
alengths[i] = args[i].length(); |
|
|
|
|
argptrs[i] = (const void *)args[i].data(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int rcount = ((int (*)(unsigned int,const unsigned int *,const void **,const unsigned int **,const void ***))_do)((unsigned int)args.size(),alengths,argptrs,&rlengths,&resultptrs); |
|
|
|
|
|
|
|
|
|
for(int i=0;i<rcount;++i) |
|
|
|
|
results.push_back(std::string((const char *)resultptrs[i],rlengths[i])); |
|
|
|
|
|
|
|
|
|
((void (*)(int,const unsigned int *,const void **))_free)(rcount,rlengths,resultptrs); |
|
|
|
|
|
|
|
|
|
return std::pair< int,std::vector<std::string> >(rcount,results); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RPC::RPC(const RuntimeEnvironment *renv) : |
|
|
|
|
_r(renv) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RPC::~RPC() |
|
|
|
|
{ |
|
|
|
|
for(std::map<uint64_t,RemoteCallOutstanding>::iterator co(_remoteCallsOutstanding.begin());co!=_remoteCallsOutstanding.end();++co) { |
|
|
|
|
if (co->second.handler) |
|
|
|
|
co->second.handler(co->second.arg,co->first,co->second.peer,ZT_RPC_ERROR_CANCELLED,std::vector<std::string>()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(std::map<std::string,LocalService *>::iterator s(_rpcServices.begin());s!=_rpcServices.end();++s) |
|
|
|
|
delete s->second; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::pair< int,std::vector<std::string> > RPC::callLocal(const std::string &name,const std::vector<std::string> &args) |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_rpcServices_m); |
|
|
|
|
std::map<std::string,LocalService *>::iterator s(_rpcServices.find(name)); |
|
|
|
|
if (s == _rpcServices.end()) |
|
|
|
|
return std::pair< int,std::vector<std::string> >(ZT_RPC_ERROR_NOT_FOUND,std::vector<std::string>()); |
|
|
|
|
return ((*(s->second))(args)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint64_t RPC::callRemote( |
|
|
|
|
const Address &peer, |
|
|
|
|
const std::string &name, |
|
|
|
|
const std::vector<std::string> &args, |
|
|
|
|
void (*handler)(void *,uint64_t,const Address &,int,const std::vector<std::string> &), |
|
|
|
|
void *arg) |
|
|
|
|
throw(std::invalid_argument,std::out_of_range) |
|
|
|
|
{ |
|
|
|
|
Packet outp(peer,_r->identity.address(),Packet::VERB_RPC); |
|
|
|
|
|
|
|
|
|
if (name.length() > 0xffff) |
|
|
|
|
throw std::invalid_argument("function name too long"); |
|
|
|
|
outp.append((uint16_t)name.length()); |
|
|
|
|
outp.append(name); |
|
|
|
|
for(std::vector<std::string>::const_iterator a(args.begin());a!=args.end();++a) { |
|
|
|
|
if (a->length() > 0xffff) |
|
|
|
|
throw std::invalid_argument("argument too long"); |
|
|
|
|
outp.append((uint16_t)a->length()); |
|
|
|
|
outp.append(*a); |
|
|
|
|
} |
|
|
|
|
outp.compress(); |
|
|
|
|
|
|
|
|
|
uint64_t id = outp.packetId(); |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_remoteCallsOutstanding_m); |
|
|
|
|
RemoteCallOutstanding &rc = _remoteCallsOutstanding[id]; |
|
|
|
|
rc.callTime = Utils::now(); |
|
|
|
|
rc.peer = peer; |
|
|
|
|
rc.handler = handler; |
|
|
|
|
rc.arg = arg; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_r->sw->send(outp,true); |
|
|
|
|
|
|
|
|
|
return id; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RPC::clean() |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_remoteCallsOutstanding_m); |
|
|
|
|
uint64_t now = Utils::now(); |
|
|
|
|
for(std::map<uint64_t,RemoteCallOutstanding>::iterator co(_remoteCallsOutstanding.begin());co!=_remoteCallsOutstanding.end();) { |
|
|
|
|
if ((now - co->second.callTime) >= ZT_RPC_TIMEOUT) { |
|
|
|
|
if (co->second.handler) |
|
|
|
|
co->second.handler(co->second.arg,co->first,co->second.peer,ZT_RPC_ERROR_EXPIRED_NO_RESPONSE,std::vector<std::string>()); |
|
|
|
|
_remoteCallsOutstanding.erase(co++); |
|
|
|
|
} else ++co; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace ZeroTier
|
|
|
|
|
|