Back out of RPC... blech. Have a better idea.

This commit is contained in:
Adam Ierymenko 2013-07-27 13:36:27 -04:00
parent 57d8730f1b
commit b0a83093ce
11 changed files with 2 additions and 476 deletions

View File

@ -324,9 +324,4 @@ error_no_ZT_ARCH_defined;
*/
#define ZT_RENDEZVOUS_NAT_T_DELAY 500
/**
* Timeout for remote RPC calls
*/
#define ZT_RPC_TIMEOUT 10000
#endif

View File

@ -50,14 +50,6 @@ class NodeConfig;
/**
* Local membership to a network
*
* Networks configure themselves via RPC by accessing the function
* com.zerotier.one.Network.bootstrap at any supernode. This returns
* a series of key/value pairs that includes the IP address
* information for this node on the network and -- for closed
* networks -- a URL to retreive the network's membership list.
* A SHA-256 hash is also included to verify the return from this
* URL query.
*/
class Network : NonCopyable
{

View File

@ -68,7 +68,6 @@
#include "Mutex.hpp"
#include "Multicaster.hpp"
#include "CMWC4096.hpp"
#include "RPC.hpp"
#include "../version.h"
@ -211,7 +210,6 @@ Node::~Node()
{
_NodeImpl *impl = (_NodeImpl *)_impl;
delete impl->renv.rpc;
delete impl->renv.sysEnv;
delete impl->renv.topology;
delete impl->renv.sw;
@ -317,7 +315,6 @@ Node::ReasonForTermination Node::run()
_r->sw = new Switch(_r);
_r->topology = new Topology(_r,(_r->homePath + ZT_PATH_SEPARATOR_S + "peer.db").c_str());
_r->sysEnv = new SysEnv(_r);
_r->rpc = new RPC(_r);
// TODO: make configurable
bool boundPort = false;
@ -341,25 +338,6 @@ Node::ReasonForTermination Node::run()
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unknown exception during initialization");
}
try {
std::map<std::string,bool> pluginsd(Utils::listDirectory((_r->homePath + ZT_PATH_SEPARATOR_S + "plugins.d").c_str()));
for(std::map<std::string,bool>::iterator ppath(pluginsd.begin());ppath!=pluginsd.end();++ppath) {
if (!ppath->second) {
try {
std::string funcName(ppath->first.substr(0,ppath->first.rfind('.')));
LOG("loading plugins.d/%s as RPC function %s",ppath->first.c_str(),funcName.c_str());
_r->rpc->loadLocal(funcName.c_str(),(_r->homePath + ZT_PATH_SEPARATOR_S + "plugins.d" + ZT_PATH_SEPARATOR_S + ppath->first).c_str());
} catch (std::exception &exc) {
LOG("failed to load plugin plugins.d/%s: %s",ppath->first.c_str(),exc.what());
} catch ( ... ) {
LOG("failed to load plugin plugins.d/%s: (unknown exception)",ppath->first.c_str());
}
}
}
} catch ( ... ) {
TRACE("unknown exception attempting to enumerate and load plugins");
}
try {
uint64_t lastPingCheck = 0;
uint64_t lastTopologyClean = Utils::now(); // don't need to do this immediately

View File

@ -42,7 +42,6 @@ const char *Packet::verbString(Verb v)
case VERB_FRAME: return "FRAME";
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
case VERB_RPC: return "RPC";
}
return "(unknown)";
}

View File

@ -463,26 +463,7 @@ public:
*
* No OK or ERROR is generated.
*/
VERB_MULTICAST_FRAME = 9,
/* Call a plugin via RPC:
* <[2] length of function name>
* <[...] function name>
* [<[2] length of argument>]
* [<[...] argument>]
* [... additional length/argument pairs ...]
*
* This generates ERROR_NOT_FOUND if the specified function was not
* found. Otherwise it generates an OK message. The OK message has
* the same format as the request, except arguments are replaced
* by results.
*
* This can be used to implement simple RPC. No retransmission or
* other guarantees are made, so it behaves like UDP-based RPC
* protocols. Plugins are typically run by supernodes and are used
* to implement network lookup and other services.
*/
VERB_RPC = 10
VERB_MULTICAST_FRAME = 9
};
/**

View File

@ -102,8 +102,6 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
return _doMULTICAST_LIKE(_r,peer);
case Packet::VERB_MULTICAST_FRAME:
return _doMULTICAST_FRAME(_r,peer);
case Packet::VERB_RPC:
return _doRPC(_r,peer);
default:
// This might be something from a new or old version of the protocol.
// Technically it passed HMAC so the packet is still valid, but we
@ -540,8 +538,4 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
return true;
}
bool PacketDecoder::_doRPC(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
{
}
} // namespace ZeroTier

View File

@ -122,7 +122,6 @@ private:
bool _doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doRPC(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
uint64_t _receiveTime;
Demarc::Port _localPort;

View File

@ -1,212 +0,0 @@
/*
* 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

View File

@ -1,196 +0,0 @@
/*
* 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 _ZT_RPC_HPP
#define _ZT_RPC_HPP
#include <stdint.h>
#include <stdexcept>
#include <map>
#include <vector>
#include <utility>
#include "Constants.hpp"
#include "NonCopyable.hpp"
#include "Mutex.hpp"
#include "Address.hpp"
namespace ZeroTier {
class RuntimeEnvironment;
/**
* Peer or method not found
*/
#define ZT_RPC_ERROR_NOT_FOUND -1
/**
* A runtime error occurred
*/
#define ZT_RPC_ERROR_RUNTIME -2
/**
* Call was expired without response from target
*/
#define ZT_RPC_ERROR_EXPIRED_NO_RESPONSE -3
/**
* Call was cancelled (or RPC is shutting down)
*/
#define ZT_RPC_ERROR_CANCELLED -4
/**
* RPC request and result handler
*/
class RPC : NonCopyable
{
public:
#ifndef __WINDOWS__
/**
* A local service accessible by RPC, non-Windows only for now
*
* Each service DLL must export these functions:
*
* int ZeroTierPluginInit();
* int ZeroTierPluginDo(unsigned int,const unsigned int *,const void **,const unsigned int **,const void ***);
* void ZeroTierPluginFree(int,const unsigned int *,const void **);
* void ZeroTierPluginDestroy();
*
* Init is called on library load, Destroy on unload. Do() may
* be called from multiple threads concurrently, so any locking
* is the responsibility of the library. These must have C
* function signatures (extern "C" in C++).
*
* Do's arguments are: the number of paramters, the size of each parameter in bytes,
* and each parameter's contents. The last two arguments are result parameters. The
* first result parameter must be set to an array of integers describing the size of
* each result. The second is set to an array of pointers to actual results. The number
* of results (size of both arrays) is returned. If Do() returns zero or negative,
* these result paremeters are not used by the caller and don't need to be set.
*
* After the caller is done with Do()'s results, it calls ZeroTierPluginFree() to
* free them. This may also be called concurrently. Free() takes the number of
* results, the array of result sizes, and the result array.
*/
class LocalService : NonCopyable
{
public:
/**
* @param dllPath Path to DLL/shared object
* @throws std::invalid_argument Unable to properly load or resolve symbol(s) in DLL
*/
LocalService(const char *dllPath)
throw(std::invalid_argument);
~LocalService();
/**
* Call the DLL, return result
*
* @param args Input arguments
* @return Results from DLL
* @throws std::runtime_error Error calling DLL
*/
std::pair< int,std::vector<std::string> > operator()(const std::vector<std::string> &args);
private:
void *_handle;
void *_init;
void *_do;
void *_free;
void *_destroy;
};
#endif
RPC(const RuntimeEnvironment *renv);
~RPC();
/**
* Used by PacketDecoder to call local RPC methods
*
* @param name Name of locally loaded method to call
* @param args Arguments to method
* @return Return value of method, and results (negative first item and empty vector means error)
*/
std::pair< int,std::vector<std::string> > callLocal(const std::string &name,const std::vector<std::string> &args);
/**
* Load a plugin
*
* @param name Name of RPC function
* @param path Path to plugin DLL
* @throws std::invalid_argument Unable to properly load or resolve symbol(s) in DLL
*/
void loadLocal(const char *name,const char *path)
throw(std::invalid_argument);
/**
* Call a remote service
*
* @param peer Peer to call on
* @param name Name of remote function
* @param args Arguments to remote function
* @param handler Handler to call on result
* @param arg First argument to handler
* @return Call ID (packet ID of sent packet)
*/
uint64_t 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);
/**
* Periodically called to clean up, such as by expiring remote calls
*/
void clean();
private:
const RuntimeEnvironment *_r;
#ifndef __WINDOWS__
std::map<std::string,LocalService *> _rpcServices;
Mutex _rpcServices_m;
#endif
struct RemoteCallOutstanding
{
uint64_t callTime;
Address peer;
void (*handler)(void *,uint64_t,const Address &,int,const std::vector<std::string> &);
void *arg;
};
std::map<uint64_t,RemoteCallOutstanding> _remoteCallsOutstanding;
Mutex _remoteCallsOutstanding_m;
};
} // namespace ZeroTier
#endif

View File

@ -42,7 +42,6 @@ class Topology;
class SysEnv;
class Multicaster;
class CMWC4096;
class RPC;
/**
* Holds global state for an instance of ZeroTier::Node
@ -67,8 +66,7 @@ public:
multicaster((Multicaster *)0),
sw((Switch *)0),
topology((Topology *)0),
sysEnv((SysEnv *)0),
rpc((RPC *)0)
sysEnv((SysEnv *)0)
{
}
@ -90,7 +88,6 @@ public:
Switch *sw;
Topology *topology;
SysEnv *sysEnv;
RPC *rpc;
};
} // namespace ZeroTier

View File

@ -21,7 +21,6 @@ OBJS=\
node/PacketDecoder.o \
node/Pack.o \
node/Peer.o \
node/RPC.o \
node/Salsa20.o \
node/Switch.o \
node/SysEnv.o \