Strip out old Service code, add new service message type.

This commit is contained in:
Adam Ierymenko 2015-01-05 11:47:22 -08:00
parent 95e303d6f3
commit 56cfe1d603
9 changed files with 37 additions and 535 deletions

View File

@ -39,7 +39,6 @@
#include "Switch.hpp" #include "Switch.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "NodeConfig.hpp" #include "NodeConfig.hpp"
#include "Service.hpp"
#include "SoftwareUpdater.hpp" #include "SoftwareUpdater.hpp"
namespace ZeroTier { 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_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,peer);
case Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return _doNETWORK_MEMBERSHIP_CERTIFICATE(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_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_GATHER: return _doMULTICAST_GATHER(RR,peer);
case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(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 { try {
uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); 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()); peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,Utils::now());
} catch (std::exception &exc) { } 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()); 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; 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) bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
{ {
try { try {

View File

@ -125,7 +125,6 @@ private:
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer); bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doNETWORK_MEMBERSHIP_CERTIFICATE(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_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_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);

View File

@ -71,7 +71,6 @@
#include "MulticastGroup.hpp" #include "MulticastGroup.hpp"
#include "Multicaster.hpp" #include "Multicaster.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "Service.hpp"
#include "SoftwareUpdater.hpp" #include "SoftwareUpdater.hpp"
#include "Buffer.hpp" #include "Buffer.hpp"
#include "AntiRecursion.hpp" #include "AntiRecursion.hpp"
@ -101,9 +100,6 @@ struct _NodeImpl
running = false; running = false;
#ifndef __WINDOWS__
delete renv.netconfService;
#endif
delete renv.updater; renv.updater = (SoftwareUpdater *)0; delete renv.updater; renv.updater = (SoftwareUpdater *)0;
delete renv.nc; renv.nc = (NodeConfig *)0; // shut down all networks, close taps, etc. 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 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( Node::Node(
const char *hp, const char *hp,
EthernetTapFactory *tf, EthernetTapFactory *tf,
@ -450,24 +359,6 @@ Node::ReasonForTermination Node::run()
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unknown exception during initialization"); 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 // Core I/O loop
try { try {
/* Shut down if this file exists but fails to open. This is used on Mac to /* Shut down if this file exists but fails to open. This is used on Mac to

View File

@ -50,6 +50,7 @@ const char *Packet::verbString(Verb v)
case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH"; case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";
case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
case VERB_SERVICE_MESSAGE: return "SERVICE_MESSAGE";
} }
return "(unknown)"; return "(unknown)";
} }

View File

@ -55,7 +55,7 @@
* 3 - 0.5.0 ... 0.6.0 * 3 - 0.5.0 ... 0.6.0
* * Yet another multicast redesign * * Yet another multicast redesign
* * New crypto completely changes key agreement cipher * * 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 * * New identity format based on hashcash design
* *
* This isn't going to change again for a long time unless your * This isn't going to change again for a long time unless your
@ -722,17 +722,7 @@ public:
*/ */
VERB_NETWORK_CONFIG_REQUEST = 11, VERB_NETWORK_CONFIG_REQUEST = 11,
/* Network configuration refresh request: /* DEPRECATED -- was never actually used */
* <[...] 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.
*/
VERB_NETWORK_CONFIG_REFRESH = 12, VERB_NETWORK_CONFIG_REFRESH = 12,
/* Request endpoints for multicast distribution: /* Request endpoints for multicast distribution:
@ -812,7 +802,40 @@ public:
* <[6] multicast group MAC> * <[6] multicast group MAC>
* <[4] 32-bit multicast group ADI> * <[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
}; };
/** /**

View File

@ -40,7 +40,6 @@ class Logger;
class Switch; class Switch;
class Topology; class Topology;
class CMWC4096; class CMWC4096;
class Service;
class Node; class Node;
class SoftwareUpdater; class SoftwareUpdater;
class SocketManager; class SocketManager;
@ -85,9 +84,6 @@ public:
nc((NodeConfig *)0), nc((NodeConfig *)0),
node((Node *)0), node((Node *)0),
updater((SoftwareUpdater *)0) updater((SoftwareUpdater *)0)
#ifndef __WINDOWS__
,netconfService((Service *)0)
#endif
{ {
} }
@ -133,9 +129,6 @@ public:
NodeConfig *nc; NodeConfig *nc;
Node *node; Node *node;
SoftwareUpdater *updater; // null if software updates are not enabled SoftwareUpdater *updater; // null if software updates are not enabled
#ifndef __WINDOWS__
Service *netconfService; // null if no netconf service running
#endif
}; };
} // namespace ZeroTier } // namespace ZeroTier

View File

@ -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__

View File

@ -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

View File

@ -25,7 +25,6 @@ OBJS=\
node/Poly1305.o \ node/Poly1305.o \
node/RoutingTable.o \ node/RoutingTable.o \
node/Salsa20.o \ node/Salsa20.o \
node/Service.o \
node/SoftwareUpdater.o \ node/SoftwareUpdater.o \
node/SHA512.o \ node/SHA512.o \
node/Switch.o \ node/Switch.o \