6 changed files with 446 additions and 1 deletions
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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/
|
||||
*/ |
||||
|
||||
/*
|
||||
* This is the netconf service. It's currently used only by netconf nodes that |
||||
* are run by ZeroTier itself. There is nothing to prevent you from running |
||||
* your own if you wanted to create your own networks outside our system. |
||||
* |
||||
* That being said, we'd like to charge for private networks to support |
||||
* ZeroTier One and future development efforts. So while this software is |
||||
* open source and we're not going to stop you from sidestepping this, we |
||||
* do ask -- honor system here -- that you pay for private networks if you |
||||
* are going to use them for any commercial purpose such as a business VPN |
||||
* alternative. |
||||
* |
||||
* This will at the moment only build on Linux and requires the mysql++ |
||||
* library, which is available here: |
||||
* |
||||
* http://tangentsoft.net/mysql++/
|
||||
* |
||||
* (Packages are available for CentOS via EPEL and for any Debian distro.) |
||||
* |
||||
* This program must be built and installed in the services.d subfolder of |
||||
* the ZeroTier One home folder of the node designated to act as a master |
||||
* for networks. Doing so will enable the NETWORK_CONFIG_REQUEST protocol |
||||
* verb. |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
|
||||
#include <iostream> |
||||
#include <string> |
||||
#include <map> |
||||
#include <list> |
||||
#include <vector> |
||||
#include <algorithm> |
||||
|
||||
#include <mysql++.h> |
||||
|
||||
#include "../node/Dictionary.hpp" |
||||
|
||||
using namespace ZeroTier; |
||||
using namespace mysqlpp; |
||||
|
||||
static Connection *dbCon = (Connection *)0; |
||||
|
||||
static void connectOrReconnect() |
||||
{ |
||||
if (dbCon) |
||||
delete dbCon; |
||||
dbCon = new Connection(mysqlDatabase,mysqlHost,mysqlUser,mysqlPassword,(unsigned int)strtol(mysqlPort,(char **)0,10)); |
||||
if (dbCon->connected()) |
||||
break; |
||||
else { |
||||
fprintf(stderr,"Unable to connect to database server.\n"); |
||||
usleep(1000); |
||||
} |
||||
} |
||||
|
||||
int main(int argc,char **argv) |
||||
{ |
||||
char mysqlHost[64],mysqlPort[64],mysqlDatabase[64],mysqlUser[64],mysqlPassword[64]; |
||||
|
||||
{ |
||||
char *ee = getenv("ZT_NETCONF_MYSQL_HOST"); |
||||
if (!ee) { |
||||
fprintf(stderr,"Missing environment variable: ZT_NETCONF_MYSQL_HOST\n"); |
||||
return -1; |
||||
} |
||||
strcpy(mysqlHost,ee); |
||||
ee = getenv("ZT_NETCONF_MYSQL_PORT"); |
||||
if (ee == null) |
||||
strcpy(mysqlPort,"3306"); |
||||
else strcpy(mysqlPort,ee); |
||||
ee = getenv("ZT_NETCONF_MYSQL_DATABASE"); |
||||
if (!ee) { |
||||
fprintf(stderr,"Missing environment variable: ZT_NETCONF_MYSQL_DATABASE\n"); |
||||
return -1; |
||||
} |
||||
strcpy(mysqlDatabase,ee); |
||||
ee = getenv("ZT_NETCONF_MYSQL_USER"); |
||||
if (!ee) { |
||||
fprintf(stderr,"Missing environment variable: ZT_NETCONF_MYSQL_USER\n"); |
||||
return -1; |
||||
} |
||||
strcpy(mysqlUser,ee); |
||||
ee = getenv("ZT_NETCONF_MYSQL_PASSWORD"); |
||||
if (!ee) { |
||||
fprintf(stderr,"Missing environment variable: ZT_NETCONF_MYSQL_PASSWORD\n"); |
||||
return -1; |
||||
} |
||||
strcpy(mysqlPassword,ee); |
||||
} |
||||
|
||||
connectOrReconnect(); |
||||
for(;;) { |
||||
if (!dbCon->connected()) |
||||
connectOrReconnect(); |
||||
} |
||||
} |
||||
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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/
|
||||
*/ |
||||
|
||||
#include "Constants.hpp" |
||||
|
||||
#ifndef __WINDOWS__ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <signal.h> |
||||
#include <time.h> |
||||
#include <fcntl.h> |
||||
#include <sys/time.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/select.h> |
||||
#include <sys/wait.h> |
||||
|
||||
#include "Service.hpp" |
||||
#include "RuntimeEnvironment.hpp" |
||||
#include "Utils.hpp" |
||||
#include "Logger.hpp" |
||||
|
||||
namespace ZeroTier { |
||||
|
||||
Service::Service(const RuntimeEnvironment *renv,const char *name,const char *path,void (*handler)(void *,Service &,const Dictionary &),void *arg) : |
||||
_r(renv), |
||||
_path(path), |
||||
_name(name), |
||||
_arg(arg), |
||||
_handler(handler), |
||||
_pid(-1), |
||||
_childStdin(0), |
||||
_childStdout(0), |
||||
_childStderr(0), |
||||
_run(true) |
||||
{ |
||||
start(); |
||||
} |
||||
|
||||
Service::~Service() |
||||
{ |
||||
_run = false; |
||||
long pid = _pid; |
||||
if (pid > 0) { |
||||
int st = 0; |
||||
::kill(pid,SIGTERM); |
||||
for(int i=0;i<20;++i) { |
||||
if (waitpid(pid,&st,WNOHANG) == pid) { |
||||
pid = 0; |
||||
break; |
||||
} |
||||
Thread::sleep(100); |
||||
} |
||||
if (pid > 0) { |
||||
::kill(pid,SIGKILL); |
||||
waitpid(pid,&st,0); |
||||
} |
||||
} |
||||
join(); |
||||
} |
||||
|
||||
bool Service::send(const Dictionary &msg) |
||||
{ |
||||
if (_childStdin <= 0) |
||||
return false; |
||||
|
||||
std::string mser = msg.toString(); |
||||
if (mser.length() > ZT_SERVICE_MAX_MESSAGE_SIZE) |
||||
return false; |
||||
|
||||
// This can technically block. We'll fix this if it ends up being a
|
||||
// problem.
|
||||
uint32_t len = Utils::hton((uint32_t)mser.length()); |
||||
if (write(_childStdin,&len,4) != 4) |
||||
return false; |
||||
if ((int)write(_childStdin,mser.data(),mser.length()) != (int)mser.length()) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void Service::main() |
||||
throw() |
||||
{ |
||||
fd_set readfds,writefds,exceptfds; |
||||
struct timeval tv; |
||||
|
||||
while (_run) { |
||||
if (_pid <= 0) { |
||||
LOG("launching service %s...",_name.c_str()); |
||||
|
||||
int in[2],out[2],err[2]; |
||||
pipe(in); |
||||
pipe(out); |
||||
pipe(err); |
||||
|
||||
long pid = fork(); |
||||
if (pid < 0) { |
||||
LOG("service %s terminating: could not fork!",_name.c_str()); |
||||
return; |
||||
} else if (pid) { |
||||
close(in[1]); |
||||
close(out[0]); |
||||
close(err[0]); |
||||
Thread::sleep(500); // give child time to start
|
||||
_childStdin = in[1]; |
||||
_childStdout = out[0]; |
||||
_childStderr = err[0]; |
||||
} else { |
||||
dup2(in[0],STDIN_FILENO); |
||||
dup2(out[1],STDOUT_FILENO); |
||||
dup2(err[1],STDERR_FILENO); |
||||
execl(_path.c_str(),_path.c_str(),_r->homePath.c_str(),(const char *)0); |
||||
exit(-1); |
||||
} |
||||
} else { |
||||
int st = 0; |
||||
if (waitpid(_pid,&st,WNOHANG) == _pid) { |
||||
if (_childStdin > 0) close(_childStdin); |
||||
_childStdin = 0; |
||||
if (_childStdout > 0) close(_childStdout); |
||||
if (_childStderr > 0) close(_childStderr); |
||||
_pid = 0; |
||||
|
||||
if (!_run) |
||||
return; |
||||
|
||||
LOG("service %s exited with exit code: %d, delaying 1s to attempt relaunch",_name.c_str(),st); |
||||
|
||||
Thread::sleep(1000); // wait to relaunch
|
||||
continue; |
||||
} |
||||
} |
||||
|
||||
FD_ZERO(&readfds); |
||||
FD_ZERO(&writefds); |
||||
FD_ZERO(&exceptfds); |
||||
|
||||
FD_SET(_childStdout,&readfds); |
||||
FD_SET(_childStderr,&readfds); |
||||
|
||||
tv.tv_sec = 1; |
||||
tv.tv_usec = 0; |
||||
select(std::max(_childStdout,_childStderr)+1,&readfds,&writefds,&exceptfds,&tv); |
||||
|
||||
if (!_run) { |
||||
if (_childStdin > 0) close(_childStdin); |
||||
_childStdin = 0; |
||||
if (_childStdout > 0) close(_childStdout); |
||||
if (_childStderr > 0) close(_childStderr); |
||||
return; |
||||
} |
||||
|
||||
if ((_childStderr > 0)&&(FD_ISSET(_childStderr,&readfds))) { |
||||
} |
||||
|
||||
if ((_childStdout > 0)&&(FD_ISSET(_childStdout,&readfds))) { |
||||
} |
||||
} |
||||
} |
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif // __WINDOWS__
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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_SERVICE_HPP |
||||
#define _ZT_SERVICE_HPP |
||||
|
||||
#include <string> |
||||
#include <stdexcept> |
||||
|
||||
#include "Constants.hpp" |
||||
#include "Dictionary.hpp" |
||||
#include "Thread.hpp" |
||||
#include "Mutex.hpp" |
||||
|
||||
/**
|
||||
* Maximum size of a service message in bytes (sanity limit) |
||||
*/ |
||||
#define ZT_SERVICE_MAX_MESSAGE_SIZE 131072 |
||||
|
||||
namespace ZeroTier { |
||||
|
||||
class RuntimeEnvironment; |
||||
|
||||
#ifndef __WINDOWS__ |
||||
/**
|
||||
* A subprocess that communicates with the host via a simple protocol |
||||
* |
||||
* This is currently only supported on *nix systems, and is used to implement |
||||
* special plugins that are used by supernodes and network configuration |
||||
* master nodes. Users will probably have no use for it. |
||||
* |
||||
* The simple binary protocol consists of a bidirectional stream of string- |
||||
* serialized Dictionaries prefixed by a 32-bit message length. Input |
||||
* messages are sent to the subprocess via its stdin, and output is read |
||||
* from its stdout. Messages printed by the subprocess on its stderr are |
||||
* logged via the standard Logger instance. If the subprocess dies, an |
||||
* attempt is made to restart it every second. |
||||
*/ |
||||
class Service : protected Thread |
||||
{ |
||||
public: |
||||
/**
|
||||
* Create and launch a new service |
||||
* |
||||
* @param renv Runtime environment |
||||
* @param name Name of service |
||||
* @param path Path to service binary |
||||
* @param handler Handler function to call when service generates output |
||||
* @param arg First argument to service |
||||
*/ |
||||
Service(const RuntimeEnvironment *renv,const char *name,const char *path,void (*handler)(void *,Service &,const Dictionary &),void *arg); |
||||
|
||||
virtual ~Service(); |
||||
|
||||
/**
|
||||
* Send a message to service subprocess |
||||
* |
||||
* @param msg Message in key/value dictionary form |
||||
* @return True if message was sent |
||||
*/ |
||||
bool send(const Dictionary &msg); |
||||
|
||||
/**
|
||||
* @return Name of service |
||||
*/ |
||||
inline const char *name() const |
||||
throw() |
||||
{ |
||||
return _name.c_str(); |
||||
} |
||||
|
||||
/**
|
||||
* @return True if subprocess is running |
||||
*/ |
||||
inline bool running() const |
||||
throw() |
||||
{ |
||||
return (_pid > 0); |
||||
} |
||||
|
||||
protected: |
||||
virtual void main() |
||||
throw(); |
||||
|
||||
private: |
||||
const RuntimeEnvironment *_r; |
||||
std::string _path; |
||||
std::string _name; |
||||
void *_arg; |
||||
void (*_handler)(void *,Service &,const Dictionary &); |
||||
long _pid; |
||||
int _childStdin; |
||||
int _childStdout; |
||||
int _childStderr; |
||||
volatile bool _run; |
||||
}; |
||||
#endif // __WINDOWS__
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif |
||||
Loading…
Reference in new issue