summaryrefslogtreecommitdiff
path: root/node/Network.cpp
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@zerotier.com>2014-01-27 23:13:36 -0800
committerAdam Ierymenko <adam.ierymenko@zerotier.com>2014-01-27 23:13:36 -0800
commitf80ec871f6f4c63a28b9b8192477114b7aac696d (patch)
treeb2b02a40d9d9e0ee9f0dd0478fe192e966e274bc /node/Network.cpp
parente0cb5caef21243cf045cecc25ed064869d1594d4 (diff)
downloadinfinitytier-f80ec871f6f4c63a28b9b8192477114b7aac696d.tar.gz
infinitytier-f80ec871f6f4c63a28b9b8192477114b7aac696d.zip
Make EthernetTap creation occur in a background thread in Network since it's a time consuming operation on Windows. This fixes one of the last remaining Windows problems.
Diffstat (limited to 'node/Network.cpp')
-rw-r--r--node/Network.cpp82
1 files changed, 61 insertions, 21 deletions
diff --git a/node/Network.cpp b/node/Network.cpp
index 37d93b99..8ba597ba 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -46,6 +46,7 @@ const char *Network::statusString(const Status s)
throw()
{
switch(s) {
+ case NETWORK_INITIALIZING: return "INITIALIZING";
case NETWORK_WAITING_FOR_FIRST_AUTOCONF: return "WAITING_FOR_FIRST_AUTOCONF";
case NETWORK_OK: return "OK";
case NETWORK_ACCESS_DENIED: return "ACCESS_DENIED";
@@ -56,6 +57,8 @@ const char *Network::statusString(const Status s)
Network::~Network()
{
+ Thread::join(_setupThread);
+
std::string devPersistentId(_tap->persistentId());
delete _tap;
@@ -73,46 +76,50 @@ Network::~Network()
SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t id)
{
- // Tag to identify tap device -- used on some OSes like Windows
- char tag[32];
- Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)id);
-
- // We construct Network via a static method to ensure that it is immediately
- // wrapped in a SharedPtr<>. Otherwise if there is traffic on the Ethernet
- // tap device, a SharedPtr<> wrap can occur in the Ethernet frame handler
- // that then causes the Network instance to be deleted before it is finished
- // being constructed. C++ edge cases, how I love thee.
+ /* We construct Network via a static method to ensure that it is immediately
+ * wrapped in a SharedPtr<>. Otherwise if there is traffic on the Ethernet
+ * tap device, a SharedPtr<> wrap can occur in the Ethernet frame handler
+ * that then causes the Network instance to be deleted before it is finished
+ * being constructed. C++ edge cases, how I love thee. */
+
SharedPtr<Network> nw(new Network());
nw->_id = id;
- nw->_ready = false; // disable handling of Ethernet frames during construct
+ nw->_mac = renv->identity.address().toMAC();
nw->_r = renv;
- nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
+ nw->_tap = (EthernetTap *)0;
nw->_lastConfigUpdate = 0;
- nw->_status = NETWORK_WAITING_FOR_FIRST_AUTOCONF;
nw->_destroyOnDelete = false;
+ nw->_netconfFailure = NETCONF_FAILURE_NONE;
+
if (nw->controller() == renv->identity.address()) // netconf masters can't really join networks
throw std::runtime_error("cannot join a network for which I am the netconf master");
- nw->_restoreState();
- nw->_ready = true; // enable handling of Ethernet frames
- nw->requestConfiguration();
+
+ nw->_setupThread = Thread::start<Network>(nw.ptr());
return nw;
}
-void Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
+bool Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
{
+ Mutex::Lock _l(_lock);
+
+ EthernetTap *t = _tap;
+ if (!t) {
+ TRACE("BUG: setConfiguration() called while tap is null!");
+ return false; // can't accept config in initialization state
+ }
+
try {
SharedPtr<NetworkConfig> newConfig(new NetworkConfig(conf));
if ((newConfig->networkId() == _id)&&(newConfig->issuedTo() == _r->identity.address())) {
- Mutex::Lock _l(_lock);
_config = newConfig;
if (newConfig->staticIps().size())
- _tap->setIps(newConfig->staticIps());
- _tap->setDisplayName((std::string("ZeroTier One [") + newConfig->name() + "]").c_str());
+ t->setIps(newConfig->staticIps());
+ t->setDisplayName((std::string("ZeroTier One [") + newConfig->name() + "]").c_str());
_lastConfigUpdate = Utils::now();
- _status = NETWORK_OK;
+ _netconfFailure = NETCONF_FAILURE_NONE;
if (saveToDisk) {
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".conf");
@@ -122,6 +129,8 @@ void Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
Utils::lockDownFile(confPath.c_str(),false);
}
}
+
+ return true;
} else {
LOG("ignored invalid configuration for network %.16llx (configuration contains mismatched network ID or issued-to address)",(unsigned long long)_id);
}
@@ -130,10 +139,15 @@ void Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
} catch ( ... ) {
LOG("ignored invalid configuration for network %.16llx (unknown exception)",(unsigned long long)_id);
}
+
+ return false;
}
void Network::requestConfiguration()
{
+ if (!_tap)
+ return; // don't bother requesting until we are initialized
+
if (controller() == _r->identity.address()) {
// netconf master cannot be a member of its own nets
LOG("unable to request network configuration for network %.16llx: I am the network master, cannot query self",(unsigned long long)_id);
@@ -190,6 +204,7 @@ bool Network::isAllowed(const Address &peer) const
void Network::clean()
{
Mutex::Lock _l(_lock);
+
if ((_config)&&(_config->isOpen())) {
// Open (public) networks do not track certs or cert pushes at all.
_membershipCertificates.clear();
@@ -215,7 +230,7 @@ void Network::clean()
void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data)
{
- if (!((Network *)arg)->isUp())
+ if (((Network *)arg)->status() != NETWORK_OK)
return;
const RuntimeEnvironment *_r = ((Network *)arg)->_r;
@@ -250,6 +265,31 @@ void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t
}
}
+void Network::threadMain()
+{
+ try {
+ // Setup thread -- this exits when tap is constructed. It's here
+ // because opening the tap can take some time on some platforms.
+ char tag[32];
+ Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)_id);
+ _tap = new EthernetTap(_r,tag,_mac,ZT_IF_MTU,&_CBhandleTapData,this);
+ } catch (std::exception &exc) {
+ LOG("network %.16llx failed to initialize: %s",_id,exc.what());
+ _netconfFailure = NETCONF_FAILURE_INIT_FAILED;
+ } catch ( ... ) {
+ LOG("network %.16llx failed to initialize: unknown error",_id);
+ _netconfFailure = NETCONF_FAILURE_INIT_FAILED;
+ }
+
+ try {
+ _restoreState();
+ requestConfiguration();
+ } catch ( ... ) {
+ TRACE("BUG: exception in network setup thread in _restoreState() or requestConfiguration()!");
+ _lastConfigUpdate = 0; // call requestConfiguration() again
+ }
+}
+
void Network::_restoreState()
{
if (!_id)