Browse Source

Wire up RPC plugin loading to Node.

Adam Ierymenko 12 years ago
parent
commit
57d8730f1b
6 changed files with 102 additions and 3 deletions
  1. 22 0
      node/Node.cpp
  2. 22 0
      node/RPC.cpp
  3. 12 0
      node/RPC.hpp
  4. 8 1
      node/RuntimeEnvironment.hpp
  5. 27 2
      node/Utils.cpp
  6. 11 0
      node/Utils.hpp

+ 22 - 0
node/Node.cpp

@@ -68,6 +68,7 @@
 #include "Mutex.hpp"
 #include "Multicaster.hpp"
 #include "CMWC4096.hpp"
+#include "RPC.hpp"
 
 #include "../version.h"
 
@@ -210,6 +211,7 @@ Node::~Node()
 {
 	_NodeImpl *impl = (_NodeImpl *)_impl;
 
+	delete impl->renv.rpc;
 	delete impl->renv.sysEnv;
 	delete impl->renv.topology;
 	delete impl->renv.sw;
@@ -315,6 +317,7 @@ 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;
@@ -338,6 +341,25 @@ 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

+ 22 - 0
node/RPC.cpp

@@ -37,6 +37,8 @@
 
 namespace ZeroTier {
 
+#ifndef __WINDOWS__
+
 RPC::LocalService::LocalService(const char *dllPath)
 	throw(std::invalid_argument) :
 	_handle((void *)0),
@@ -111,6 +113,8 @@ std::pair< int,std::vector<std::string> > RPC::LocalService::operator()(const st
 	return std::pair< int,std::vector<std::string> >(rcount,results);
 }
 
+#endif // __WINDOWS__
+
 RPC::RPC(const RuntimeEnvironment *renv) :
 	_r(renv)
 {
@@ -123,17 +127,35 @@ RPC::~RPC()
 			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(

+ 12 - 0
node/RPC.hpp

@@ -139,6 +139,16 @@ public:
 	 */
 	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
 	 *
@@ -165,8 +175,10 @@ public:
 private:
 	const RuntimeEnvironment *_r;
 
+#ifndef __WINDOWS__
 	std::map<std::string,LocalService *> _rpcServices;
 	Mutex _rpcServices_m;
+#endif
 
 	struct RemoteCallOutstanding
 	{

+ 8 - 1
node/RuntimeEnvironment.hpp

@@ -42,6 +42,7 @@ class Topology;
 class SysEnv;
 class Multicaster;
 class CMWC4096;
+class RPC;
 
 /**
  * Holds global state for an instance of ZeroTier::Node
@@ -65,7 +66,9 @@ public:
 		demarc((Demarc *)0),
 		multicaster((Multicaster *)0),
 		sw((Switch *)0),
-		topology((Topology *)0)
+		topology((Topology *)0),
+		sysEnv((SysEnv *)0),
+		rpc((RPC *)0)
 	{
 	}
 
@@ -76,6 +79,9 @@ public:
 
 	Identity identity;
 
+	// Order matters a bit here. These are constructed in this order
+	// and then deleted in the opposite order on Node exit.
+
 	Logger *log; // may be null
 	CMWC4096 *prng;
 	NodeConfig *nc;
@@ -84,6 +90,7 @@ public:
 	Switch *sw;
 	Topology *topology;
 	SysEnv *sysEnv;
+	RPC *rpc;
 };
 
 } // namespace ZeroTier

+ 27 - 2
node/Utils.cpp

@@ -29,14 +29,13 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include "Utils.hpp"
-#include "Mutex.hpp"
 
 #if defined(__APPLE__) || defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <dirent.h>
 #endif
 
 #ifdef _WIN32
@@ -46,6 +45,9 @@
 #include <sys/stat.h>
 #include <openssl/rand.h>
 
+#include "Utils.hpp"
+#include "Mutex.hpp"
+
 namespace ZeroTier {
 
 const char Utils::HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
@@ -214,6 +216,29 @@ const char Utils::base64DecMap[128] = {
 static const char *DAY_NAMES[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
 static const char *MONTH_NAMES[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
 
+std::map<std::string,bool> Utils::listDirectory(const char *path)
+{
+	struct dirent de;
+	struct dirent *dptr;
+	std::map<std::string,bool> r;
+
+	DIR *d = opendir(path);
+	if (!d)
+		return r;
+
+	dptr = (struct dirent *)0;
+	for(;;) {
+		if (readdir_r(d,&de,&dptr))
+			break;
+		if (dptr) {
+			if ((!strcmp(dptr->d_name,"."))&&(!strcmp(dptr->d_name,"..")))
+				r[std::string(dptr->d_name)] = (dptr->d_type == DT_DIR);
+		} else break;
+	}
+
+	return r;
+}
+
 std::string Utils::base64Encode(const void *data,unsigned int len)
 {
 	if (!len)

+ 11 - 0
node/Utils.hpp

@@ -38,6 +38,7 @@
 #include <string>
 #include <stdexcept>
 #include <vector>
+#include <map>
 
 #include "../ext/lz4/lz4.h"
 #include "../ext/lz4/lz4hc.h"
@@ -58,6 +59,16 @@ namespace ZeroTier {
 class Utils
 {
 public:
+	/**
+	 * List a directory's contents
+	 *
+	 * @param path Path to list
+	 * @param files Set to fill with files
+	 * @param directories Set to fill with directories
+	 * @return Map of entries and whether or not they are also directories (empty on failure)
+	 */
+	static std::map<std::string,bool> listDirectory(const char *path);
+
 	/**
 	 * @param data Data to convert to hex
 	 * @param len Length of data