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 "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 {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
109
node/Node.cpp
109
node/Node.cpp
@ -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
|
||||||
|
@ -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)";
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
|
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/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 \
|
||||||
|
Loading…
Reference in New Issue
Block a user