More work on adding testnet and user-mode capabilities for local network simulation.

This commit is contained in:
Adam Ierymenko 2014-10-03 11:59:50 -07:00
commit 67aa23530b
31 changed files with 251 additions and 39 deletions

141
node/Condition.hpp Normal file
View file

@ -0,0 +1,141 @@
/*
* ZeroTier One - Global Peer to Peer Ethernet
* Copyright (C) 2012-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_CONDITION_HPP
#define ZT_CONDITION_HPP
#include "Constants.hpp"
#include "NonCopyable.hpp"
#ifdef __WINDOWS__
#include <Windows.h>
#include <stdlib.h>
#include "Utils.hpp"
namespace ZeroTier {
class Condition : NonCopyable
{
public:
Condition()
throw()
{
_sem = CreateSemaphore(NULL,0,1,NULL);
}
~Condition()
{
CloseHandle(_sem);
}
inline void wait() const
throw()
{
WaitForSingleObject(_sem,INFINITE);
}
inline void wait(unsigned long ms) const
throw()
{
WaitForSingleObject(_sem,(DWORD)ms);
}
inline void signal() const
throw()
{
ReleaseSemaphore(_sem,1,NULL);
}
private:
HANDLE _sem;
};
} // namespace ZeroTier
#else // !__WINDOWS__
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
#include "Utils.hpp"
namespace ZeroTier {
class Condition : NonCopyable
{
public:
Condition()
throw()
{
pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0);
pthread_cond_init(&_cond,(const pthread_condattr_t *)0);
}
~Condition()
{
pthread_cond_destroy(&_cond);
pthread_mutex_destroy(&_mh);
}
inline void wait() const
throw()
{
pthread_mutex_lock(const_cast <pthread_mutex_t *>(&_mh));
pthread_cond_wait(const_cast <pthread_cond_t *>(&_cond),const_cast <pthread_mutex_t *>(&_mh));
pthread_mutex_unlock(const_cast <pthread_mutex_t *>(&_mh));
}
inline void wait(unsigned long ms) const
throw()
{
uint64_t when = Utils::now() + (uint64_t)ms;
struct timespec ts;
ts.tv_sec = (unsigned long)(when / 1000);
ts.tv_nsec = (unsigned long)(when % 1000) * 1000000;
pthread_mutex_lock(const_cast <pthread_mutex_t *>(&_mh));
pthread_cond_timedwait(const_cast <pthread_cond_t *>(&_cond),const_cast <pthread_mutex_t *>(&_mh),&ts);
pthread_mutex_unlock(const_cast <pthread_mutex_t *>(&_mh));
}
inline void signal() const
throw()
{
pthread_cond_signal(const_cast <pthread_cond_t *>(&_cond));
}
private:
pthread_cond_t _cond;
pthread_mutex_t _mh;
};
} // namespace ZeroTier
#endif // !__WINDOWS__
#endif

View file

@ -152,6 +152,21 @@ public:
*/
virtual bool updateMulticastGroups(std::set<MulticastGroup> &groups) = 0;
/**
* Inject a packet as if it was sent by the host, if supported
*
* This is for testing and is typically not supported by real TAP devices.
* It's implemented by TestEthernetTap in testnet.
*
* @param from Source MAC
* @param to Destination MAC
* @param etherType Ethernet frame type
* @param data Packet data
* @param len Packet length
* @return False if not supported or packet too large
*/
virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0;
protected:
const char *_implName;
MAC _mac;

View file

@ -93,6 +93,7 @@ struct _NodeImpl
volatile bool running;
volatile bool resynchronize;
volatile bool disableRootTopologyUpdates;
std::string overrideRootTopology;
// This function performs final node tear-down
inline Node::ReasonForTermination terminate()
@ -223,8 +224,8 @@ Node::Node(
RoutingTable *rt,
unsigned int udpPort,
unsigned int tcpPort,
bool resetIdentity)
throw() :
bool resetIdentity,
const char *overrideRootTopology) throw() :
_impl(new _NodeImpl)
{
_NodeImpl *impl = (_NodeImpl *)_impl;
@ -260,7 +261,13 @@ Node::Node(
impl->started = false;
impl->running = false;
impl->resynchronize = false;
impl->disableRootTopologyUpdates = false;
if (overrideRootTopology) {
impl->disableRootTopologyUpdates = true;
impl->overrideRootTopology = overrideRootTopology;
} else {
impl->disableRootTopologyUpdates = false;
}
}
Node::~Node()
@ -403,7 +410,7 @@ Node::ReasonForTermination Node::run()
#endif
// Initialize root topology from defaults or root-toplogy file in home path on disk
{
if (impl->overrideRootTopology.length() == 0) {
std::string rootTopologyPath(RR->homePath + ZT_PATH_SEPARATOR_S + "root-topology");
std::string rootTopology;
if (!Utils::readFile(rootTopologyPath.c_str(),rootTopology))
@ -427,6 +434,14 @@ Node::ReasonForTermination Node::run()
} catch ( ... ) {
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format");
}
} else {
try {
Dictionary rt(impl->overrideRootTopology);
RR->topology->setSupernodes(Dictionary(rt.get("supernodes","")));
impl->disableRootTopologyUpdates = true;
} catch ( ... ) {
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format");
}
}
} catch (std::bad_alloc &exc) {
return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"memory allocation failure");

View file

@ -88,6 +88,7 @@ public:
* @param udpPort UDP port or 0 to disable
* @param tcpPort TCP port or 0 to disable
* @param resetIdentity If true, delete identity before starting and regenerate
* @param overrideRootTopology Override root topology with this dictionary (in string serialized format) and do not update (default: NULL for none)
*/
Node(
const char *hp,
@ -95,7 +96,8 @@ public:
RoutingTable *rt,
unsigned int udpPort,
unsigned int tcpPort,
bool resetIdentity) throw();
bool resetIdentity,
const char *overrideRootTopology = (const char *)0) throw();
~Node();