From af8fcac0fcfd64600a442dc4d633601e29e611ea Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 25 Jul 2013 15:19:35 -0400 Subject: RPC infrastructure work in progress. --- node/RPC.cpp | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) (limited to 'node/RPC.cpp') diff --git a/node/RPC.cpp b/node/RPC.cpp index 2c69033e..e6591d7d 100644 --- a/node/RPC.cpp +++ b/node/RPC.cpp @@ -25,7 +25,166 @@ * LLC. Start here: http://www.zerotier.com/ */ +#ifndef __WINDOWS__ +#include +#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 > RPC::LocalService::operator()(const std::vector &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 results; + + if (args.size() > 4096) + throw std::runtime_error("args[] too long"); + + for(unsigned int i=0;i >(rcount,results); +} + +RPC::RPC(const RuntimeEnvironment *renv) : + _r(renv) +{ +} + +RPC::~RPC() +{ + for(std::map::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()); + } + + for(std::map::iterator s(_rpcServices.begin());s!=_rpcServices.end();++s) + delete s->second; +} + +std::pair< int,std::vector > RPC::callLocal(const std::string &name,const std::vector &args) +{ + Mutex::Lock _l(_rpcServices_m); + std::map::iterator s(_rpcServices.find(name)); + if (s == _rpcServices.end()) + return std::pair< int,std::vector >(ZT_RPC_ERROR_NOT_FOUND,std::vector()); + return ((*(s->second))(args)); +} + +uint64_t RPC::callRemote( + const Address &peer, + const std::string &name, + const std::vector &args, + void (*handler)(void *,uint64_t,const Address &,int,const std::vector &), + 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::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::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()); + _remoteCallsOutstanding.erase(co++); + } else ++co; + } +} + +} // namespace ZeroTier -- cgit v1.2.3