123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /*
- * ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2013 ZeroTier Networks LLC
- *
- * 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 __WINDOWS__
- #include <dlfcn.h>
- #endif
- #include "Utils.hpp"
- #include "RuntimeEnvironment.hpp"
- #include "RPC.hpp"
- #include "Switch.hpp"
- #include "Topology.hpp"
- namespace ZeroTier {
- #ifndef __WINDOWS__
- 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);
- }
- #endif // __WINDOWS__
- 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>());
- }
- #ifndef __WINDOWS__
- for(std::map<std::string,LocalService *>::iterator s(_rpcServices.begin());s!=_rpcServices.end();++s)
- delete s->second;
- #endif
- }
- std::pair< int,std::vector<std::string> > RPC::callLocal(const std::string &name,const std::vector<std::string> &args)
- {
- #ifdef __WINDOWS__
- return std::pair< int,std::vector<std::string> >(ZT_RPC_ERROR_NOT_FOUND,std::vector<std::string>());
- #else
- 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));
- #endif
- }
- void RPC::loadLocal(const char *name,const char *path)
- throw(std::invalid_argument)
- {
- #ifdef __WINDOWS__
- throw std::invalid_argument("RPC plugins not supported on Windows (yet?)");
- #else
- LocalService *s = new LocalService(path);
- Mutex::Lock _l(_rpcServices_m);
- _rpcServices[std::string(name)] = s;
- #endif
- }
- 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
|