mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-18 10:46:33 +00:00
Strip out old Service code, add new service message type.
This commit is contained in:
parent
95e303d6f3
commit
56cfe1d603
@ -39,7 +39,6 @@
|
||||
#include "Switch.hpp"
|
||||
#include "Peer.hpp"
|
||||
#include "NodeConfig.hpp"
|
||||
#include "Service.hpp"
|
||||
#include "SoftwareUpdater.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
@ -85,7 +84,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
|
||||
case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,peer);
|
||||
case Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return _doNETWORK_MEMBERSHIP_CERTIFICATE(RR,peer);
|
||||
case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer);
|
||||
case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer);
|
||||
case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer);
|
||||
case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer);
|
||||
}
|
||||
@ -714,43 +712,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
|
||||
{
|
||||
try {
|
||||
uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
if (RR->netconfService) {
|
||||
char tmp[128];
|
||||
unsigned int dictLen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN);
|
||||
|
||||
Dictionary request;
|
||||
if (dictLen)
|
||||
request["meta"] = std::string((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,dictLen),dictLen);
|
||||
request["type"] = "netconf-request";
|
||||
request["peerId"] = peer->identity().toString(false);
|
||||
Utils::snprintf(tmp,sizeof(tmp),"%.16llx",(unsigned long long)nwid);
|
||||
request["nwid"] = tmp;
|
||||
Utils::snprintf(tmp,sizeof(tmp),"%.16llx",(unsigned long long)packetId());
|
||||
request["requestId"] = tmp;
|
||||
if (!hops())
|
||||
request["from"] = _remoteAddress.toString();
|
||||
//TRACE("to netconf:\n%s",request.toString().c_str());
|
||||
RR->netconfService->send(request);
|
||||
} else {
|
||||
#endif // !__WINDOWS__
|
||||
|
||||
// Send unsupported operation if there is no netconf service
|
||||
// configured on this node (or if this is a Windows machine,
|
||||
// which doesn't support that at all).
|
||||
Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
|
||||
outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
|
||||
outp.append(packetId());
|
||||
outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
|
||||
outp.append(nwid);
|
||||
outp.armor(peer->key(),true);
|
||||
_fromSock->send(_remoteAddress,outp.data(),outp.size());
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
}
|
||||
#endif // !__WINDOWS__
|
||||
|
||||
peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,Utils::now());
|
||||
} catch (std::exception &exc) {
|
||||
TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
|
||||
@ -760,27 +721,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
|
||||
while ((ptr + sizeof(uint64_t)) <= size()) {
|
||||
uint64_t nwid = at<uint64_t>(ptr); ptr += sizeof(uint64_t);
|
||||
SharedPtr<Network> nw(RR->nc->network(nwid));
|
||||
if ((nw)&&(source() == nw->controller())) { // only respond to requests from controller
|
||||
TRACE("NETWORK_CONFIG_REFRESH from %s, refreshing network %.16llx",source().toString().c_str(),nwid);
|
||||
nw->requestConfiguration();
|
||||
}
|
||||
}
|
||||
peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,Utils::now());
|
||||
} catch (std::exception &exc) {
|
||||
TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
|
||||
} catch ( ... ) {
|
||||
TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
|
@ -125,7 +125,6 @@ private:
|
||||
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
|
||||
|
109
node/Node.cpp
109
node/Node.cpp
@ -71,7 +71,6 @@
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Multicaster.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "Service.hpp"
|
||||
#include "SoftwareUpdater.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "AntiRecursion.hpp"
|
||||
@ -101,9 +100,6 @@ struct _NodeImpl
|
||||
|
||||
running = false;
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
delete renv.netconfService;
|
||||
#endif
|
||||
delete renv.updater; renv.updater = (SoftwareUpdater *)0;
|
||||
delete renv.nc; renv.nc = (NodeConfig *)0; // shut down all networks, close taps, etc.
|
||||
delete renv.topology; renv.topology = (Topology *)0; // now we no longer need routing info
|
||||
@ -125,93 +121,6 @@ struct _NodeImpl
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef __WINDOWS__ // "services" are not supported on Windows
|
||||
static void _netconfServiceMessageHandler(void *renv,Service &svc,const Dictionary &msg)
|
||||
{
|
||||
if (!renv)
|
||||
return; // sanity check
|
||||
const RuntimeEnvironment *RR = (const RuntimeEnvironment *)renv;
|
||||
|
||||
try {
|
||||
//TRACE("from netconf:\n%s",msg.toString().c_str());
|
||||
const std::string &type = msg.get("type");
|
||||
if (type == "ready") {
|
||||
LOG("received 'ready' from netconf.service, sending netconf-init with identity information...");
|
||||
Dictionary initMessage;
|
||||
initMessage["type"] = "netconf-init";
|
||||
initMessage["netconfId"] = RR->identity.toString(true);
|
||||
RR->netconfService->send(initMessage);
|
||||
} else if (type == "netconf-response") {
|
||||
uint64_t inRePacketId = strtoull(msg.get("requestId").c_str(),(char **)0,16);
|
||||
uint64_t nwid = strtoull(msg.get("nwid").c_str(),(char **)0,16);
|
||||
Address peerAddress(msg.get("peer").c_str());
|
||||
|
||||
if (peerAddress) {
|
||||
if (msg.contains("error")) {
|
||||
Packet::ErrorCode errCode = Packet::ERROR_INVALID_REQUEST;
|
||||
const std::string &err = msg.get("error");
|
||||
if (err == "OBJ_NOT_FOUND")
|
||||
errCode = Packet::ERROR_OBJ_NOT_FOUND;
|
||||
else if (err == "ACCESS_DENIED")
|
||||
errCode = Packet::ERROR_NETWORK_ACCESS_DENIED_;
|
||||
|
||||
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_ERROR);
|
||||
outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
|
||||
outp.append(inRePacketId);
|
||||
outp.append((unsigned char)errCode);
|
||||
outp.append(nwid);
|
||||
RR->sw->send(outp,true);
|
||||
} else if (msg.contains("netconf")) {
|
||||
const std::string &netconf = msg.get("netconf");
|
||||
if (netconf.length() < 2048) { // sanity check
|
||||
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_OK);
|
||||
outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
|
||||
outp.append(inRePacketId);
|
||||
outp.append(nwid);
|
||||
outp.append((uint16_t)netconf.length());
|
||||
outp.append(netconf.data(),netconf.length());
|
||||
outp.compress();
|
||||
RR->sw->send(outp,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type == "netconf-push") {
|
||||
if (msg.contains("to")) {
|
||||
Dictionary to(msg.get("to")); // key: peer address, value: comma-delimited network list
|
||||
for(Dictionary::iterator t(to.begin());t!=to.end();++t) {
|
||||
Address ztaddr(t->first);
|
||||
if (ztaddr) {
|
||||
Packet outp(ztaddr,RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REFRESH);
|
||||
|
||||
char *saveptr = (char *)0;
|
||||
// Note: this loop trashes t->second, which is quasi-legal C++ but
|
||||
// shouldn't break anything as long as we don't try to use 'to'
|
||||
// for anything interesting after doing this.
|
||||
for(char *p=Utils::stok(const_cast<char *>(t->second.c_str()),",",&saveptr);(p);p=Utils::stok((char *)0,",",&saveptr)) {
|
||||
uint64_t nwid = Utils::hexStrToU64(p);
|
||||
if (nwid) {
|
||||
if ((outp.size() + sizeof(uint64_t)) >= ZT_UDP_DEFAULT_PAYLOAD_MTU) {
|
||||
RR->sw->send(outp,true);
|
||||
outp.reset(ztaddr,RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REFRESH);
|
||||
}
|
||||
outp.append(nwid);
|
||||
}
|
||||
}
|
||||
|
||||
if (outp.payloadLength())
|
||||
RR->sw->send(outp,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (std::exception &exc) {
|
||||
LOG("unexpected exception parsing response from netconf service: %s",exc.what());
|
||||
} catch ( ... ) {
|
||||
LOG("unexpected exception parsing response from netconf service: unknown exception");
|
||||
}
|
||||
}
|
||||
#endif // !__WINDOWS__
|
||||
|
||||
Node::Node(
|
||||
const char *hp,
|
||||
EthernetTapFactory *tf,
|
||||
@ -450,24 +359,6 @@ Node::ReasonForTermination Node::run()
|
||||
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unknown exception during initialization");
|
||||
}
|
||||
|
||||
// Start external service subprocesses, which is only used by special nodes
|
||||
// right now and isn't available on Windows.
|
||||
#ifndef __WINDOWS__
|
||||
try {
|
||||
std::string netconfServicePath(RR->homePath + ZT_PATH_SEPARATOR_S + "services.d" + ZT_PATH_SEPARATOR_S + "netconf.service");
|
||||
if (Utils::fileExists(netconfServicePath.c_str())) {
|
||||
LOG("netconf.d/netconf.service appears to exist, starting...");
|
||||
RR->netconfService = new Service(RR,"netconf",netconfServicePath.c_str(),&_netconfServiceMessageHandler,RR);
|
||||
Dictionary initMessage;
|
||||
initMessage["type"] = "netconf-init";
|
||||
initMessage["netconfId"] = RR->identity.toString(true);
|
||||
RR->netconfService->send(initMessage);
|
||||
}
|
||||
} catch ( ... ) {
|
||||
LOG("unexpected exception attempting to start services");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Core I/O loop
|
||||
try {
|
||||
/* Shut down if this file exists but fails to open. This is used on Mac to
|
||||
|
@ -50,6 +50,7 @@ const char *Packet::verbString(Verb v)
|
||||
case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";
|
||||
case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
|
||||
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
|
||||
case VERB_SERVICE_MESSAGE: return "SERVICE_MESSAGE";
|
||||
}
|
||||
return "(unknown)";
|
||||
}
|
||||
|
@ -55,7 +55,7 @@
|
||||
* 3 - 0.5.0 ... 0.6.0
|
||||
* * Yet another multicast redesign
|
||||
* * New crypto completely changes key agreement cipher
|
||||
* 4 - 0.6.0 ... 0.9.2
|
||||
* 4 - 0.6.0 ... CURRENT
|
||||
* * New identity format based on hashcash design
|
||||
*
|
||||
* This isn't going to change again for a long time unless your
|
||||
@ -722,17 +722,7 @@ public:
|
||||
*/
|
||||
VERB_NETWORK_CONFIG_REQUEST = 11,
|
||||
|
||||
/* Network configuration refresh request:
|
||||
* <[...] array of 64-bit network IDs>
|
||||
*
|
||||
* This message can be sent by the network configuration master node
|
||||
* to request that nodes refresh their network configuration. It can
|
||||
* thus be used to "push" updates so that network config changes will
|
||||
* take effect quickly.
|
||||
*
|
||||
* It does not generate an OK or ERROR message, and is treated only as
|
||||
* a hint to refresh now.
|
||||
*/
|
||||
/* DEPRECATED -- was never actually used */
|
||||
VERB_NETWORK_CONFIG_REFRESH = 12,
|
||||
|
||||
/* Request endpoints for multicast distribution:
|
||||
@ -812,7 +802,40 @@ public:
|
||||
* <[6] multicast group MAC>
|
||||
* <[4] 32-bit multicast group ADI>
|
||||
*/
|
||||
VERB_MULTICAST_FRAME = 14
|
||||
VERB_MULTICAST_FRAME = 14,
|
||||
|
||||
/* Message or query to a service:
|
||||
* <[8] 64-bit service identifier>
|
||||
* <[1] flags>
|
||||
* [<[...] payload to service>]
|
||||
*
|
||||
* Flags are currently unused and must be zero.
|
||||
*
|
||||
* Services allow out-of-band extensions to be added to the
|
||||
* ZeroTier peer-to-peer network without having to mix them
|
||||
* with the Ethernet virtualization layer. Right now this
|
||||
* includes the network configuration (netconf) service, and
|
||||
* in the future could include things like DHTs, caching,
|
||||
* mesh net functionality, extensions to cryptographic or
|
||||
* authentication services, remote administration, remote
|
||||
* debugging, etc.
|
||||
*
|
||||
* Service identifiers less than or equal to 0xffff (65535)
|
||||
* are reserved for use by ZeroTier Networks, with ID 0 being
|
||||
* the netconf service that provisions and configures virtual
|
||||
* networks. These IDs should not be used by third party
|
||||
* developers. IDs above 65535 can be used, and should be
|
||||
* assigned using something like a cryptographic random number
|
||||
* generator to minimize the potential for collisions.
|
||||
*
|
||||
* OK responses to this message contain the same fields as
|
||||
* above, and their meaning is service-dependent.
|
||||
*
|
||||
* ERROR_UNSUPPORTED_OPERATION may optionally be returned if
|
||||
* the queried service ID is not available on this node.
|
||||
* Payload consists of the 64-bit service ID queried.
|
||||
*/
|
||||
VERB_SERVICE_MESSAGE = 15
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -40,7 +40,6 @@ class Logger;
|
||||
class Switch;
|
||||
class Topology;
|
||||
class CMWC4096;
|
||||
class Service;
|
||||
class Node;
|
||||
class SoftwareUpdater;
|
||||
class SocketManager;
|
||||
@ -85,9 +84,6 @@ public:
|
||||
nc((NodeConfig *)0),
|
||||
node((Node *)0),
|
||||
updater((SoftwareUpdater *)0)
|
||||
#ifndef __WINDOWS__
|
||||
,netconfService((Service *)0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
@ -133,9 +129,6 @@ public:
|
||||
NodeConfig *nc;
|
||||
Node *node;
|
||||
SoftwareUpdater *updater; // null if software updates are not enabled
|
||||
#ifndef __WINDOWS__
|
||||
Service *netconfService; // null if no netconf service running
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
222
node/Service.cpp
222
node/Service.cpp
@ -1,222 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Global Peer to Peer Ethernet
|
||||
* Copyright (C) 2011-2014 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 <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#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) :
|
||||
RR(renv),
|
||||
_path(path),
|
||||
_name(name),
|
||||
_arg(arg),
|
||||
_handler(handler),
|
||||
_pid(-1),
|
||||
_childStdin(0),
|
||||
_childStdout(0),
|
||||
_childStderr(0),
|
||||
_run(true)
|
||||
{
|
||||
_thread = Thread::start(this);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Thread::join(_thread);
|
||||
}
|
||||
|
||||
bool Service::send(const Dictionary &msg)
|
||||
{
|
||||
if (_childStdin <= 0)
|
||||
return false;
|
||||
std::string mser(msg.toString());
|
||||
mser.append(ZT_EOL_S);
|
||||
return ((long)::write(_childStdin,mser.data(),mser.length()) == (long)mser.length());
|
||||
}
|
||||
|
||||
void Service::threadMain()
|
||||
throw()
|
||||
{
|
||||
char buf[16384];
|
||||
fd_set readfds,writefds,exceptfds;
|
||||
struct timeval tv;
|
||||
int eolsInARow = 0;
|
||||
std::string stderrBuf,stdoutBuf;
|
||||
|
||||
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 = vfork();
|
||||
if (pid < 0) {
|
||||
LOG("service %s terminating: could not fork!",_name.c_str());
|
||||
return;
|
||||
} else if (pid) {
|
||||
// Parent
|
||||
close(in[0]);
|
||||
close(out[1]);
|
||||
close(err[1]);
|
||||
Thread::sleep(500); // give child time to start
|
||||
_childStdin = in[1];
|
||||
_childStdout = out[0];
|
||||
_childStderr = err[0];
|
||||
fcntl(_childStdout,F_SETFL,O_NONBLOCK);
|
||||
fcntl(_childStderr,F_SETFL,O_NONBLOCK);
|
||||
_pid = pid;
|
||||
} else {
|
||||
// Child
|
||||
close(in[1]);
|
||||
close(out[0]);
|
||||
close(err[0]);
|
||||
dup2(in[0],STDIN_FILENO);
|
||||
dup2(out[1],STDOUT_FILENO);
|
||||
dup2(err[1],STDERR_FILENO);
|
||||
setenv("ZT_HOME",RR->homePath.c_str(),1);
|
||||
chdir(RR->homePath.c_str());
|
||||
execl(_path.c_str(),_path.c_str(),RR->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;
|
||||
}
|
||||
}
|
||||
|
||||
// If we've made it here, _pid is running last we checked.
|
||||
|
||||
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))) {
|
||||
int n = (int)::read(_childStderr,buf,sizeof(buf));
|
||||
for(int i=0;i<n;++i) {
|
||||
if ((buf[i] == '\r')||(buf[i] == '\n')) {
|
||||
stderrBuf = Utils::trim(stderrBuf);
|
||||
if (stderrBuf.length())
|
||||
LOG("service %s: %s",_name.c_str(),stderrBuf.c_str());
|
||||
stderrBuf = "";
|
||||
} else stderrBuf.push_back(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((_childStdout > 0)&&(FD_ISSET(_childStdout,&readfds))) {
|
||||
int n = (int)::read(_childStdout,buf,sizeof(buf));
|
||||
for(int i=0;i<n;++i) {
|
||||
if ((buf[i] == '\n')||(buf[i] == '\r')) {
|
||||
if (buf[i] == '\n')
|
||||
++eolsInARow;
|
||||
} else eolsInARow = 0;
|
||||
|
||||
if (eolsInARow >= 2) {
|
||||
// Two CRs in a row ends a message
|
||||
try {
|
||||
_handler(_arg,*this,Dictionary(stdoutBuf));
|
||||
stdoutBuf = "";
|
||||
} catch ( ... ) {} // handlers should not throw
|
||||
} else stdoutBuf.push_back(buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif // __WINDOWS__
|
||||
|
122
node/Service.hpp
122
node/Service.hpp
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Global Peer to Peer Ethernet
|
||||
* Copyright (C) 2011-2014 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"
|
||||
|
||||
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
|
||||
{
|
||||
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);
|
||||
|
||||
~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); }
|
||||
|
||||
/**
|
||||
* Thread main method; do not call elsewhere
|
||||
*/
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
const RuntimeEnvironment *RR;
|
||||
|
||||
Thread _thread;
|
||||
|
||||
std::string _path;
|
||||
std::string _name;
|
||||
void *_arg;
|
||||
void (*_handler)(void *,Service &,const Dictionary &);
|
||||
volatile long _pid;
|
||||
|
||||
volatile int _childStdin;
|
||||
volatile int _childStdout;
|
||||
volatile int _childStderr;
|
||||
|
||||
volatile bool _run;
|
||||
};
|
||||
#endif // __WINDOWS__
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -25,7 +25,6 @@ OBJS=\
|
||||
node/Poly1305.o \
|
||||
node/RoutingTable.o \
|
||||
node/Salsa20.o \
|
||||
node/Service.o \
|
||||
node/SoftwareUpdater.o \
|
||||
node/SHA512.o \
|
||||
node/Switch.o \
|
||||
|
Loading…
Reference in New Issue
Block a user