From 883a216d2a5f3d3cbddd230796d15da0af9bfab7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 12:29:31 -0700 Subject: [PATCH 1/6] Build fixes. --- controller/SqliteNetworkController.cpp | 17 +++++++++-- controller/SqliteNetworkController.hpp | 1 + controller/controller-api-test.sh | 42 ++++++++++++++++++++++++++ service/ControlPlane.cpp | 6 ++-- service/ControlPlane.hpp | 1 + service/OneService.cpp | 2 +- 6 files changed, 63 insertions(+), 6 deletions(-) create mode 100755 controller/controller-api-test.sh diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index a2bc5fc3a..b9aebbb8a 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -178,6 +178,7 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) : ||(sqlite3_prepare_v2(_db,"INSERT INTO Network (networkId,name,creationTime,revision) VALUES (?,?,?,1)",-1,&_sCreateNetwork,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"UPDATE Network SET ? = ? WHERE networkId = ?",-1,&_sUpdateNetworkField,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"SELECT revision FROM Network WHERE id = ?",-1,&_sGetNetworkRevision,(const char **)0) != SQLITE_OK) + ||(sqlite3_prepare_v2(_db,"UPDATE Network SET revision = ? WHERE id = ?",-1,&_sSetNetworkRevision,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"SELECT ip,ipNetmaskBits,ipVersion FROM IpAssignment WHERE networkId = ? AND nodeId = ?",-1,&_sGetIpAssignmentsForNode2,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"DELETE FROM Relay WHERE networkId = ?",-1,&_sDeleteRelaysForNetwork,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"INSERT INTO Relay (networkId,nodeId,phyAddress) VALUES (?,?,?)",-1,&_sCreateRelay,(const char **)0) != SQLITE_OK) @@ -220,6 +221,7 @@ SqliteNetworkController::~SqliteNetworkController() sqlite3_finalize(_sCreateNetwork); sqlite3_finalize(_sUpdateNetworkField); sqlite3_finalize(_sGetNetworkRevision); + sqlite3_finalize(_sSetNetworkRevision); sqlite3_finalize(_sGetIpAssignmentsForNode2); sqlite3_finalize(_sDeleteRelaysForNetwork); sqlite3_finalize(_sCreateRelay); @@ -841,11 +843,17 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( int64_t revision = 0; sqlite3_reset(_sGetNetworkRevision); sqlite3_bind_text(_sGetNetworkRevision,1,nwids,16,SQLITE_STATIC); - if (sqlite3_step(_sGetNetworkRevision) == SQLITE_ROW) + bool networkExists = false; + if (sqlite3_step(_sGetNetworkRevision) == SQLITE_ROW) { + networkExists = true; revision = sqlite3_column_int64(_sGetNetworkRevision,0); + } if (path.size() >= 3) { + if (!networkExists) + return 404; + if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { uint64_t address = Utils::hexStrToU64(path[3].c_str()); char addrs[24]; @@ -856,7 +864,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( } else { - if (revision <= 0) { + if (!networkExists) { sqlite3_reset(_sCreateNetwork); sqlite3_bind_text(_sCreateNetwork,1,nwids,16,SQLITE_STATIC); sqlite3_bind_text(_sCreateNetwork,2,nwids,16,SQLITE_STATIC); // default name, will be changed below if a name is specified in JSON @@ -1081,6 +1089,11 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( json_value_free(j); } + sqlite3_reset(_sSetNetworkRevision); + sqlite3_bind_int64(_sSetNetworkRevision,1,revision += 1); + sqlite3_bind_text(_sSetNetworkRevision,2,nwids,16,SQLITE_STATIC); + sqlite3_step(_sSetNetworkRevision); + return handleControlPlaneHttpGET(path,urlArgs,headers,body,responseBody,responseContentType); } diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 72f1e2033..c61829c3a 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -113,6 +113,7 @@ private: sqlite3_stmt *_sCreateNetwork; sqlite3_stmt *_sUpdateNetworkField; sqlite3_stmt *_sGetNetworkRevision; + sqlite3_stmt *_sSetNetworkRevision; sqlite3_stmt *_sGetIpAssignmentsForNode2; sqlite3_stmt *_sDeleteRelaysForNetwork; sqlite3_stmt *_sCreateRelay; diff --git a/controller/controller-api-test.sh b/controller/controller-api-test.sh new file mode 100755 index 000000000..934685b38 --- /dev/null +++ b/controller/controller-api-test.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +if [ "$#" -ne "2" ]; then + echo 'Usage: controller-api-test.sh ' + exit 1 +fi + +network_json=$(cat <addAuthToken(authToken.c_str()); if (_master) - _controlPlane->mount("controller",_master); + _controlPlane->mount("controller",reinterpret_cast(_master)); { // Remember networks from previous session std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str())); From 54954f5b8886bd6ea49e043fa5a695fcd7608c68 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 13:35:17 -0700 Subject: [PATCH 2/6] First pass of Windows cleanup and build fixes... --- ext/json-parser/json.c | 1 + node/BandwidthAccount.hpp | 5 +- node/Constants.hpp | 2 + node/Node.cpp | 4 +- node/Node.hpp | 14 +- node/Peer.hpp | 3 +- windows/ZeroTierOne/ZeroTierOne.vcxproj | 111 ++------ .../ZeroTierOne/ZeroTierOne.vcxproj.filters | 239 ++++++------------ 8 files changed, 125 insertions(+), 254 deletions(-) diff --git a/ext/json-parser/json.c b/ext/json-parser/json.c index 6012bad7d..166cdcb60 100644 --- a/ext/json-parser/json.c +++ b/ext/json-parser/json.c @@ -33,6 +33,7 @@ #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif + #pragma warning(disable:4996) #endif const struct _json_value json_value_none; diff --git a/node/BandwidthAccount.hpp b/node/BandwidthAccount.hpp index b6ebfa3e5..3a6432c44 100644 --- a/node/BandwidthAccount.hpp +++ b/node/BandwidthAccount.hpp @@ -28,10 +28,13 @@ #ifndef ZT_BWACCOUNT_HPP #define ZT_BWACCOUNT_HPP +#include "Constants.hpp" + +#include + #include #include -#include "Constants.hpp" #include "Utils.hpp" #ifdef __WINDOWS__ diff --git a/node/Constants.hpp b/node/Constants.hpp index cefd48633..10c48c20a 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -91,7 +91,9 @@ #ifndef __WINDOWS__ #define __WINDOWS__ #endif +#ifndef NOMINMAX #define NOMINMAX +#endif #pragma warning(disable : 4290) #pragma warning(disable : 4996) #pragma warning(disable : 4101) diff --git a/node/Node.cpp b/node/Node.cpp index 2ffdeb96c..855b8266e 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -60,7 +60,7 @@ Node::Node( ZT1_EventCallback eventCallback, const char *overrideRootTopology) : RR(new RuntimeEnvironment(this)), - _uptr(uptr), + _uPtr(uptr), _dataStoreGetFunction(dataStoreGetFunction), _dataStorePutFunction(dataStorePutFunction), _wirePacketSendFunction(wirePacketSendFunction), @@ -426,7 +426,7 @@ std::string Node::dataStoreGet(const char *name) std::string r; unsigned long olen = 0; do { - long n = _dataStoreGetFunction(reinterpret_cast(this),_uptr,name,buf,sizeof(buf),r.length(),&olen); + long n = _dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),r.length(),&olen); if (n <= 0) return std::string(); r.append(buf,n); diff --git a/node/Node.hpp b/node/Node.hpp index f07776dad..396e04c0f 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -127,7 +127,7 @@ public: { return (_wirePacketSendFunction( reinterpret_cast(this), - _uptr, + _uPtr, reinterpret_cast(&addr), desperation, data, @@ -149,7 +149,7 @@ public: { _virtualNetworkFrameFunction( reinterpret_cast(this), - _uptr, + _uPtr, nwid, source.toInt(), dest.toInt(), @@ -192,9 +192,9 @@ public: */ inline unsigned int coreDesperation() const throw() { return _coreDesperation; } - inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_dataStorePutFunction(reinterpret_cast(this),_uptr,name,data,len,(int)secure) == 0); } + inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); } - inline void dataStoreDelete(const char *name) { _dataStorePutFunction(reinterpret_cast(this),_uptr,name,(const void *)0,0,0); } + inline void dataStoreDelete(const char *name) { _dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } std::string dataStoreGet(const char *name); /** @@ -203,7 +203,7 @@ public: * @param ev Event type * @param md Meta-data (default: NULL/none) */ - inline void postEvent(ZT1_Event ev,const void *md = (const void *)0) { _eventCallback(reinterpret_cast(this),_uptr,ev,md); } + inline void postEvent(ZT1_Event ev,const void *md = (const void *)0) { _eventCallback(reinterpret_cast(this),_uPtr,ev,md); } /** * Update virtual network port configuration @@ -212,7 +212,7 @@ public: * @param op Configuration operation * @param nc Network configuration */ - inline int configureVirtualNetworkPort(uint64_t nwid,ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast(this),_uptr,nwid,op,nc); } + inline int configureVirtualNetworkPort(uint64_t nwid,ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,op,nc); } /** * @return True if we appear to be online @@ -231,7 +231,7 @@ public: private: RuntimeEnvironment *RR; - void *_uptr; + void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P ZT1_DataStoreGetFunction _dataStoreGetFunction; ZT1_DataStorePutFunction _dataStorePutFunction; diff --git a/node/Peer.hpp b/node/Peer.hpp index d9ed56703..e36b0c7b6 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -30,6 +30,8 @@ #include +#include "Constants.hpp" + #include #include #include @@ -37,7 +39,6 @@ #include "../include/ZeroTierOne.h" -#include "Constants.hpp" #include "RuntimeEnvironment.hpp" #include "Path.hpp" #include "Address.hpp" diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index a651b5f73..6ee776b17 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -19,87 +19,40 @@ - - - - + + - - - - - - + - - - - - - - true - true - true - true - - - true - true - true - true - - - true - true - true - true - - - true - true - true - true - - - true - true - true - true - - - true - true - true - true - - - - + + + + + + - - - - + + @@ -114,55 +67,41 @@ - - - - + - - - + - - - - - - - - - - - - - - + + + + + + + + - - - @@ -240,7 +179,7 @@ Disabled true $(SolutionDir)\ext\bin\libcrypto\include - ZT_LOG_STDOUT;ZT_TRACE;%(PreprocessorDefinitions) + NOMINMAX;ZT_TRACE;%(PreprocessorDefinitions) true @@ -254,7 +193,7 @@ Disabled true $(SolutionDir)\ext\bin\libcrypto\include - ZT_LOG_STDOUT;ZT_TRACE;%(PreprocessorDefinitions) + NOMINMAX;ZT_TRACE;%(PreprocessorDefinitions) true @@ -270,7 +209,7 @@ true true $(SolutionDir)\ext\bin\libcrypto\include - ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;%(PreprocessorDefinitions) + ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded NoExtensions true @@ -294,7 +233,7 @@ true true $(SolutionDir)\ext\bin\libcrypto\include - ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;%(PreprocessorDefinitions) + ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded NotSet true diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index 8771af7e4..be0997454 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -16,36 +16,66 @@ {67b1c0f8-b018-4169-9c14-7032ed12c786} - - {64683235-3edd-443c-828c-c8e657d3bfd7} - - - {c8a3c54f-bb49-4c3f-b406-5177bc14a447} - - - {142d7af3-1770-44d7-bd87-d509bb25be1e} - {40761a4c-e8db-4a91-9cab-7afef332f4a8} - - {066d9967-d4f3-4b41-b9a8-b18ea763aca3} - {da3b8126-840c-45db-8abe-9d7e7976f8be} - - {173e391d-1519-41b8-960b-9b8dad083827} + + {6054dfae-4ed2-4d69-8cf5-d6f27646f2d7} - - {6f36ddd5-a2e1-48e1-9543-1ab975f91780} + + {9944293a-4a1a-40e9-b92a-eff31fe87e2c} + + + {ca21bd6b-ff4e-4f9e-bedd-c9f603d2d0d6} + + + {e1743b3c-1d18-47f1-ab5a-f5703c19f1df} + + + {71865460-d693-4c73-84f6-dbff42f49df6} + + + {17ae9a01-d39f-4c6d-a800-8f2cd0804c96} + + + {736aad7f-8d95-4602-88df-3bb970869c6f} + + + {3636527c-bc03-4852-bd3c-20ee25e56d82} + + + {7784af31-5b60-4300-b07e-44cf864c54db} + + + {29164186-10fc-45f5-b253-6d03f0ddd4db} + + + {f8a1c208-15b8-4d85-a4cb-11d2b82f2d1e} + + + {da28e961-1761-41d8-9a59-65b00dfb1302} - - Source Files + + Source Files\service - + + Source Files\service + + + Source Files\osdep + + + Source Files\osdep + + + Source Files\osdep + + Source Files @@ -60,9 +90,6 @@ Source Files\node - - Source Files\node - Source Files\node @@ -72,9 +99,6 @@ Source Files\node - - Source Files\node - Source Files\node @@ -87,9 +111,6 @@ Source Files\node - - Source Files\node - Source Files\node @@ -102,21 +123,15 @@ Source Files\node - - Source Files\node - Source Files\node - + Source Files\node Source Files\node - - Source Files\node - Source Files\node @@ -126,118 +141,49 @@ Source Files\node - - Source Files\control + + Source Files\ext\lz4 - - Source Files\control + + Source Files\ext\http-parser - - Source Files\control - - - Source Files\control - - - Source Files\osnet - - - Source Files\osnet - - - Source Files\osnet - - - Source Files\osnet - - - Source Files\testnet - - - Source Files\testnet - - - Source Files\testnet - - - Source Files\testnet - - - Source Files\testnet - - - Source Files - - - Source Files - - - Source Files - - - Source Files + + Source Files\ext\json-parser Header Files - - Header Files - - - Header Files - - - Header Files - Header Files - - Header Files\testnet - - - Header Files\testnet - - - Header Files\testnet - - - Header Files\testnet - - - Header Files\testnet - - - Header Files\testnet - Header Files\include - - Header Files\control + + Header Files\osdep - - Header Files\control + + Header Files\osdep - - Header Files\control + + Header Files\osdep - - Header Files\control + + Header Files\osdep - - Header Files\osnet + + Header Files\osdep - - Header Files\osnet + + Header Files\service - - Header Files\osnet + + Header Files\service - - Header Files\osnet + + Header Files\service Header Files\node @@ -275,15 +221,6 @@ Header Files\node - - Header Files\node - - - Header Files\node - - - Header Files\node - Header Files\node @@ -293,9 +230,6 @@ Header Files\node - - Header Files\node - Header Files\node @@ -314,10 +248,10 @@ Header Files\node - + Header Files\node - + Header Files\node @@ -338,16 +272,13 @@ Header Files\node - - Header Files\node - Header Files\node Header Files\node - + Header Files\node @@ -356,21 +287,9 @@ Header Files\node - - Header Files\node - - - Header Files\node - - - Header Files\node - Header Files\node - - Header Files\node - Header Files\node @@ -378,7 +297,13 @@ Header Files\node - Header Files + Header Files\ext\lz4 + + + Header Files\ext\json-parser + + + Header Files\ext\http-parser From f5848972f992e20093da85e91761c327e2f3d3ce Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 15:05:28 -0700 Subject: [PATCH 3/6] Windows now builds and runs selftest correctly, and fixed a Windows (and possibly other platforms) issue in Phy<>. --- node/IncomingPacket.cpp | 2 +- node/Network.cpp | 2 +- node/Node.cpp | 6 +- osdep/Http.cpp | 14 +-- osdep/Http.hpp | 2 +- osdep/OSUtils.hpp | 7 ++ osdep/Phy.hpp | 22 ++-- osdep/Thread.hpp | 2 +- osdep/WindowsEthernetTap.cpp | 193 +++++++++++++++++++++++++---------- osdep/WindowsEthernetTap.hpp | 40 ++++---- selftest.cpp | 7 +- service/OneService.cpp | 38 ++++--- 12 files changed, 223 insertions(+), 112 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5397d51c8..a8d564bb8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -685,7 +685,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append(pid); outp.append(nwid); outp.append((uint16_t)netconfStr.length()); - outp.append(netconfStr.data(),netconfStr.length()); + outp.append(netconfStr.data(),(unsigned int)netconfStr.length()); outp.compress(); if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length()); diff --git a/node/Network.cpp b/node/Network.cpp index 08856f02f..ddfb01c7f 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -437,7 +437,7 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr) void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) { Mutex::Lock _l(_lock); - unsigned long tmp = _multicastGroupsBehindMe.size(); + unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe[mg] = now; if (tmp != _multicastGroupsBehindMe.size()) _announceMulticastGroups(); diff --git a/node/Node.cpp b/node/Node.cpp index 855b8266e..e77a977eb 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -426,7 +426,7 @@ std::string Node::dataStoreGet(const char *name) std::string r; unsigned long olen = 0; do { - long n = _dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),r.length(),&olen); + long n = _dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); if (n <= 0) return std::string(); r.append(buf,n); @@ -454,14 +454,14 @@ void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) Mutex::Lock _l(traceLock); + time_t now = (time_t)(_now / 1000ULL); #ifdef __WINDOWS__ ctime_s(tmp3,sizeof(tmp3),&now); char *nowstr = tmp3; #else - time_t now = (time_t)(_now / 1000ULL); char *nowstr = ctime_r(&now,tmp3); #endif - unsigned long nowstrlen = strlen(nowstr); + unsigned long nowstrlen = (unsigned long)strlen(nowstr); if (nowstr[nowstrlen-1] == '\n') nowstr[--nowstrlen] = (char)0; if (nowstr[nowstrlen-1] == '\r') diff --git a/osdep/Http.cpp b/osdep/Http.cpp index 1abf49034..cd3cf1370 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -130,7 +130,7 @@ static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; return 0; @@ -138,13 +138,13 @@ static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) { (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; - hh->currentHeaderField.assign("",0); - hh->currentHeaderValue.assign("",0); + hh->currentHeaderField = ""; + hh->currentHeaderValue = ""; } for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); @@ -153,7 +153,7 @@ static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; hh->currentHeaderValue.append(ptr,length); @@ -169,7 +169,7 @@ static int ShttpOnHeadersComplete(http_parser *parser) static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; hh->responseBody->append(ptr,length); @@ -198,7 +198,7 @@ unsigned int Http::_do( { try { responseHeaders.clear(); - responseBody.assign("",0); + responseBody = ""; HttpPhyHandler handler; diff --git a/osdep/Http.hpp b/osdep/Http.hpp index a1882add8..86759ad20 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -89,7 +89,7 @@ public: * * @return HTTP status code or 0 on error (responseBody will contain error message) */ - static inline unsigned int DELETE( + static inline unsigned int DEL( unsigned long maxResponseSize, unsigned long timeout, const struct sockaddr *remoteAddress, diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 4422ab7d1..bfe9b68aa 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -45,6 +45,7 @@ #ifdef __WINDOWS__ #include #include +#include #else #include #include @@ -96,9 +97,15 @@ public: static inline bool mkdir(const char *path) throw() { +#ifdef __WINDOWS__ + if (::PathIsDirectoryA(path)) + return true; + return (::CreateDirectoryA(path,NULL) == TRUE); +#else if (::mkdir(path,0755) != 0) return (errno == EEXIST); return true; +#endif } static inline bool mkdir(const std::string &path) throw() { return OSUtils::mkdir(path.c_str()); } diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index 9bbfe43f1..5cebe1692 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -339,7 +339,11 @@ public: inline bool udpSend(PhySocket *sock,const struct sockaddr *remoteAddress,const void *data,unsigned long len) { PhySocketImpl &sws = *(reinterpret_cast(sock)); +#if defined(_WIN32) || defined(_WIN64) + return ((long)::sendto(sws.sock,reinterpret_cast(data),len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); +#else return ((long)::sendto(sws.sock,data,len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); +#endif } /** @@ -522,8 +526,8 @@ public: inline long tcpSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler = true) { PhySocketImpl &sws = *(reinterpret_cast(sock)); - long n = (long)::send(sws.sock,data,len,0); #if defined(_WIN32) || defined(_WIN64) + long n = (long)::send(sws.sock,reinterpret_cast(data),len,0); if (n == SOCKET_ERROR) { switch(WSAGetLastError()) { case WSAEINTR: @@ -535,6 +539,7 @@ public: } } #else // not Windows + long n = (long)::send(sws.sock,data,len,0); if (n < 0) { switch(errno) { #ifdef EAGAIN @@ -614,8 +619,10 @@ public: #endif } - for(typename std::list::iterator s(_socks.begin()),nexts;s!=_socks.end();s=nexts) { + bool atEnd = false; + for(typename std::list::iterator s(_socks.begin()),nexts;(!atEnd);s=nexts) { nexts = s; ++nexts; // we can delete the linked list item, so traverse now + atEnd = (nexts == _socks.end()); // if we delete the last element, s!=_socks.end() will no longer terminate our loop switch (s->type) { @@ -644,9 +651,10 @@ public: break; case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: - case ZT_PHY_SOCKET_TCP_IN: - if (FD_ISSET(s->sock,&rfds)) { - long n = (long)::recv(s->sock,buf,sizeof(buf),0); + case ZT_PHY_SOCKET_TCP_IN: { + ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable + if (FD_ISSET(sock,&rfds)) { + long n = (long)::recv(sock,buf,sizeof(buf),0); if (n <= 0) { this->close((PhySocket *)&(*s),true); } else { @@ -655,12 +663,12 @@ public: } catch ( ... ) {} } } - if ((FD_ISSET(s->sock,&wfds))&&(FD_ISSET(s->sock,&_writefds))) { + if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) { try { _handler->phyOnTcpWritable((PhySocket *)&(*s),&(s->uptr)); } catch ( ... ) {} } - break; + } break; case ZT_PHY_SOCKET_TCP_LISTEN: if (FD_ISSET(s->sock,&rfds)) { diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index f0dd37770..1dfb9ab57 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -37,7 +37,7 @@ #include #include #include -#include "Mutex.hpp" +#include "../node/Mutex.hpp" namespace ZeroTier { diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 682e33d70..d8fb3957e 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -44,42 +44,71 @@ #include #include +#include #include "../node/Constants.hpp" #include "../node/Utils.hpp" #include "../node/Mutex.hpp" #include "WindowsEthernetTap.hpp" +#include "OSUtils.hpp" #include "..\windows\TapDriver\tap-windows.h" // ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); +//static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); #define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE namespace ZeroTier { +namespace { + +class WindowsEthernetTapEnv +{ +public: + WindowsEthernetTapEnv() + { +#ifdef _WIN64 + is64Bit = TRUE; + devcon = "\\devcon_x64.exe"; + tapDriver = "\\tap-windows\\x64\\zttap200.inf"; +#else + is64Bit = FALSE; + IsWow64Process(GetCurrentProcess(),&is64Bit); + devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); + tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf"); +#endif + } + + BOOL is64Bit; + std::string devcon; + std::string tapDriver; +}; + +static const WindowsEthernetTapEnv WINENV; + +} // anonymous namespace + // Only create or delete devices one at a time static Mutex _systemTapInitLock; WindowsEthernetTap::WindowsEthernetTap( - const char *pathToHelpers, + const char *hp, const MAC &mac, unsigned int mtu, unsigned int metric, uint64_t nwid, - const char *desiredDevice, const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), + void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : - EthernetTap("WindowsEthernetTap",mac,mtu,metric), _handler(handler), _arg(arg), + _mac(mac), _nwid(nwid), _tap(INVALID_HANDLE_VALUE), _injectSemaphore(INVALID_HANDLE_VALUE), - _pathToHelpers(pathToHelpers), + _pathToHelpers(hp), _run(true), _initialized(false), _enabled(true) @@ -169,11 +198,11 @@ WindowsEthernetTap::WindowsEthernetTap( PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" install \"" + _pathToHelpers + WindowsEthernetTapFactory::WINENV.tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" install \"" + _pathToHelpers + WINENV.tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { RegCloseKey(nwAdapters); if (devconLog != INVALID_HANDLE_VALUE) CloseHandle(devconLog); - throw std::runtime_error(std::string("unable to find or execute devcon at ") + WindowsEthernetTapFactory::WINENV.devcon); + throw std::runtime_error(std::string("unable to find or execute devcon at ") + WINENV.devcon); } WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); @@ -296,18 +325,18 @@ bool WindowsEthernetTap::enabled() const return _enabled; } -bool WindowsEthernetTap::addIP(const InetAddress &ip) +bool WindowsEthernetTap::addIp(const InetAddress &ip) { if (!_initialized) return false; if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT? return false; - std::set haveIps(ips()); + std::vector haveIps(ips()); try { // Add IP to interface at the netlink level if not already assigned. - if (!haveIps.count(ip)) { + if (!std::binary_search(haveIps.begin(),haveIps.end(),ip)) { MIB_UNICASTIPADDRESS_ROW ipr; InitializeUnicastIpAddressEntry(&ipr); @@ -333,11 +362,8 @@ bool WindowsEthernetTap::addIP(const InetAddress &ip) ipr.InterfaceLuid = _deviceLuid; ipr.InterfaceIndex = _getDeviceIndex(); - if (CreateUnicastIpAddressEntry(&ipr) == NO_ERROR) { - haveIps.insert(ip); - } else { + if (CreateUnicastIpAddressEntry(&ipr) != NO_ERROR) return false; - } } std::vector regIps(_getRegistryIPv4Value("IPAddress")); @@ -348,14 +374,13 @@ bool WindowsEthernetTap::addIP(const InetAddress &ip) _setRegistryIPv4Value("IPAddress",regIps); _setRegistryIPv4Value("SubnetMask",regSubnetMasks); } - //_syncIpsWithRegistry(haveIps,_netCfgInstanceId); } catch ( ... ) { return false; } return true; } -bool WindowsEthernetTap::removeIP(const InetAddress &ip) +bool WindowsEthernetTap::removeIp(const InetAddress &ip) { if (!_initialized) return false; @@ -371,7 +396,7 @@ bool WindowsEthernetTap::removeIP(const InetAddress &ip) break; case AF_INET6: addr.set(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); - if (addr.isLinkLocal()) + if (addr.ipScope() == InetAddress::IP_SCOPE_LINK_LOCAL) continue; // can't remove link-local IPv6 addresses break; } @@ -402,10 +427,10 @@ bool WindowsEthernetTap::removeIP(const InetAddress &ip) return false; } -std::set WindowsEthernetTap::ips() const +std::vector WindowsEthernetTap::ips() const { static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it? - std::set addrs; + std::vector addrs; if (!_initialized) return addrs; @@ -419,12 +444,12 @@ std::set WindowsEthernetTap::ips() const case AF_INET: { InetAddress ip(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength); if (ip != InetAddress::LO4) - addrs.insert(ip); + addrs.push_back(ip); } break; case AF_INET6: { InetAddress ip(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); if ((ip != linkLocalLoopback)&&(ip != InetAddress::LO6)) - addrs.insert(ip); + addrs.push_back(ip); } break; } } @@ -433,6 +458,9 @@ std::set WindowsEthernetTap::ips() const } } catch ( ... ) {} // sanity check, shouldn't happen unless out of memory + std::sort(addrs.begin(),addrs.end()); + std::unique(addrs.begin(),addrs.end()); + return addrs; } @@ -472,23 +500,15 @@ void WindowsEthernetTap::setFriendlyName(const char *dn) } } -bool WindowsEthernetTap::updateMulticastGroups(std::set &groups) +void WindowsEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) { if (!_initialized) - return false; + return; HANDLE t = _tap; if (t == INVALID_HANDLE_VALUE) - return false; + return; - std::set newGroups; - - // Ensure that groups are added for each IP... this handles the MAC:ADI - // groups that are created from IPv4 addresses. Some of these may end - // up being duplicates of what the IOCTL returns but that's okay since - // the set<> will filter that. - std::set ipaddrs(ips()); - for(std::set::const_iterator i(ipaddrs.begin());i!=ipaddrs.end();++i) - newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); + std::vector newGroups; // The ZT1 tap driver supports an IOCTL to get multicast memberships at the L2 // level... something Windows does not seem to expose ordinarily. This lets @@ -503,32 +523,28 @@ bool WindowsEthernetTap::updateMulticastGroups(std::set &groups) i += 6; if ((mac.isMulticast())&&(!mac.isBroadcast())) { // exclude the nulls that may be returned or any other junk Windows puts in there - newGroups.insert(MulticastGroup(mac,0)); + newGroups.push_back(MulticastGroup(mac,0)); } } } - bool changed = false; + std::vector allIps(ips()); + for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - for(std::set::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { - if (!groups.count(*mg)) { - groups.insert(*mg); - changed = true; - } + std::sort(newGroups.begin(),newGroups.end()); + std::unique(newGroups.begin(),newGroups.end()); + + for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { + if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) + added.push_back(*m); } - for(std::set::iterator mg(groups.begin());mg!=groups.end();) { - if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) { - groups.erase(mg++); - changed = true; - } else ++mg; + for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { + if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) + removed.push_back(*m); } - return changed; -} - -bool WindowsEthernetTap::injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - return false; + _multicastGroups.swap(newGroups); } void WindowsEthernetTap::threadMain() @@ -699,8 +715,8 @@ void WindowsEthernetTap::threadMain() MAC from(tapReadBuf + 6,6); unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); try { - Buffer<4096> tmp(tapReadBuf + 14,bytesRead - 14); - _handler(_arg,from,to,etherType,tmp); + // TODO: decode vlans + _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); } catch ( ... ) {} // handlers should not throw } } @@ -733,6 +749,49 @@ void WindowsEthernetTap::threadMain() ::free(tapReadBuf); } +void WindowsEthernetTap::destroyAllPersistentTapDevices(const char *pathToHelpers) +{ + char subkeyName[4096]; + char subkeyClass[4096]; + char data[4096]; + + std::set instanceIdPathsToRemove; + { + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) + return; + + for(DWORD subkeyIndex=0;;++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; + if (!strnicmp(data,"zttap",5)) { + std::string instanceIdPath; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) + instanceIdPath.assign(data,dataLen); + if (instanceIdPath.length() != 0) + instanceIdPathsToRemove.insert(instanceIdPath); + } + } + } else break; // end of list or failure + } + + RegCloseKey(nwAdapters); + } + + for(std::set::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) + _deletePersistentTapDevice(pathToHelpers,iidp->c_str()); +} + bool WindowsEthernetTap::_disableTapDevice() { HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); @@ -748,7 +807,7 @@ bool WindowsEthernetTap::_disableTapDevice() PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" disable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" disable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { if (devconLog != INVALID_HANDLE_VALUE) CloseHandle(devconLog); return false; @@ -778,7 +837,7 @@ bool WindowsEthernetTap::_enableTapDevice() PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" enable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" enable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { if (devconLog != INVALID_HANDLE_VALUE) CloseHandle(devconLog); return false; @@ -863,4 +922,26 @@ void WindowsEthernetTap::_setRegistryIPv4Value(const char *regKey,const std::vec } } +void WindowsEthernetTap::_deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId) +{ + HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + STARTUPINFOA startupInfo; + startupInfo.cb = sizeof(startupInfo); + if (devconLog != INVALID_HANDLE_VALUE) { + SetFilePointer(devconLog,0,0,FILE_END); + startupInfo.hStdOutput = devconLog; + startupInfo.hStdError = devconLog; + } + PROCESS_INFORMATION processInfo; + memset(&startupInfo,0,sizeof(STARTUPINFOA)); + memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); + if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } + if (devconLog != INVALID_HANDLE_VALUE) + CloseHandle(devconLog); +} + } // namespace ZeroTier diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 9c513a5db..7ec8cf19c 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -37,42 +37,38 @@ #include #include -#include "EthernetTap.hpp" - #include "../node/Constants.hpp" #include "../node/Mutex.hpp" -#include "../node/Thread.hpp" #include "../node/Array.hpp" #include "../node/MulticastGroup.hpp" +#include "../osdep/Thread.hpp" namespace ZeroTier { -class WindowsEthernetTap : public EthernetTap +class WindowsEthernetTap { public: WindowsEthernetTap( - const char *pathToHelpers, + const char *hp, const MAC &mac, unsigned int mtu, unsigned int metric, uint64_t nwid, - const char *desiredDevice, const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), + void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); - virtual ~WindowsEthernetTap(); + ~WindowsEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIP(const InetAddress &ip); - virtual bool removeIP(const InetAddress &ip); - virtual std::set ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual bool updateMulticastGroups(std::set &groups); - virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + void setEnabled(bool en); + bool enabled() const; + bool addIp(const InetAddress &ip); + bool removeIp(const InetAddress &ip); + std::vector ips() const; + void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + std::string deviceName() const; + void setFriendlyName(const char *friendlyName); + void scanMulticastGroups(std::vector &added,std::vector &removed); inline const NET_LUID &luid() const { return _deviceLuid; } inline const GUID &guid() const { return _deviceGuid; } @@ -81,15 +77,19 @@ public: void threadMain() throw(); + static void destroyAllPersistentTapDevices(const char *pathToHelpers); + private: bool _disableTapDevice(); bool _enableTapDevice(); NET_IFINDEX _getDeviceIndex(); // throws on failure std::vector _getRegistryIPv4Value(const char *regKey); void _setRegistryIPv4Value(const char *regKey,const std::vector &value); + static void _deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId); - void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &); + void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; + MAC _mac; uint64_t _nwid; Thread _thread; @@ -101,6 +101,8 @@ private: std::string _netCfgInstanceId; // NetCfgInstanceId, a GUID std::string _deviceInstanceId; // DeviceInstanceID, another kind of "instance ID" + std::vector _multicastGroups; + std::queue< std::pair< Array,unsigned int > > _injectPending; Mutex _injectPending_m; diff --git a/selftest.cpp b/selftest.cpp index ea90813e5..319271f32 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -628,7 +628,7 @@ struct TestPhyHandlers { std::string *testMessage = (std::string *)*uptr; if ((testMessage)&&(testMessage->length() > 0)) { - long sent = testPhyInstance->tcpSend(sock,(const void *)testMessage->data(),testMessage->length(),true); + long sent = testPhyInstance->tcpSend(sock,(const void *)testMessage->data(),(unsigned long)testMessage->length(),true); if (sent > 0) testMessage->erase(0,sent); } @@ -804,6 +804,11 @@ int main(int argc,char **argv) { int r = 0; +#ifdef __WINDOWS__ + WSADATA wsaData; + WSAStartup(MAKEWORD(2,2),&wsaData); +#endif + // Code to generate the C25519 test vectors -- did this once and then // put these up top so that we can ensure that every platform produces // the same result. diff --git a/service/OneService.cpp b/service/OneService.cpp index 2c67dbf1d..c32fb7927 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -53,6 +53,10 @@ #include "OneService.hpp" #include "ControlPlane.hpp" +#ifdef __WINDOWS__ +#include +#endif + // Include the right tap device driver for this platform -- add new platforms here #ifdef __APPLE__ #include "../osdep/OSXEthernetTap.hpp" @@ -62,6 +66,10 @@ namespace ZeroTier { typedef OSXEthernetTap EthernetTap; } #include "../osdep/LinuxEthernetTap.hpp" namespace ZeroTier { typedef LinuxEthernetTap EthernetTap; } #endif +#ifdef __WINDOWS__ +#include "../osdep/WindowsEthernetTap.hpp" +namespace ZeroTier { typedef WindowsEthernetTap EthernetTap; } +#endif // Sanity limits for HTTP #define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 8) @@ -384,7 +392,7 @@ public: inline void phyOnTcpWritable(PhySocket *sock,void **uptr) { HttpConnection *htc = reinterpret_cast(*uptr); - long sent = _phy.tcpSend(sock,htc->body.data() + htc->writePtr,htc->body.length() - htc->writePtr,true); + long sent = _phy.tcpSend(sock,htc->body.data() + htc->writePtr,(unsigned long)htc->body.length() - htc->writePtr,true); if (sent < 0) { return; // close handler will have been called, so everything's dead } else { @@ -395,7 +403,7 @@ public: if (htc->shouldKeepAlive) { htc->writing = false; htc->writePtr = 0; - htc->body.assign("",0); + htc->body = ""; } else { _phy.close(sock); // will call close handler to delete from _httpConnections } @@ -417,7 +425,7 @@ public: _homePath.c_str(), MAC(nwc->mac), nwc->mtu, - ZT_IF_METRIC, + (unsigned int)ZT_IF_METRIC, nwid, friendlyName, StapFrameHandler, @@ -683,19 +691,19 @@ static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC static int ShttpOnMessageBegin(http_parser *parser) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->currentHeaderField.assign("",0); - htc->currentHeaderValue.assign("",0); + htc->currentHeaderField = ""; + htc->currentHeaderValue = ""; htc->messageSize = 0; - htc->url.assign("",0); - htc->status.assign("",0); + htc->url = ""; + htc->status = ""; htc->headers.clear(); - htc->body.assign("",0); + htc->body = ""; return 0; } static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->url.append(ptr,length); @@ -704,7 +712,7 @@ static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->status.append(ptr,length); @@ -713,13 +721,13 @@ static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; if ((htc->currentHeaderField.length())&&(htc->currentHeaderValue.length())) { htc->headers[htc->currentHeaderField] = htc->currentHeaderValue; - htc->currentHeaderField.assign("",0); - htc->currentHeaderValue.assign("",0); + htc->currentHeaderField = ""; + htc->currentHeaderValue = ""; } for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); @@ -728,7 +736,7 @@ static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->currentHeaderValue.append(ptr,length); @@ -744,7 +752,7 @@ static int ShttpOnHeadersComplete(http_parser *parser) static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->body.append(ptr,length); From 0e315513497832874192a3f44fcb4404c65df275 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 15:15:14 -0700 Subject: [PATCH 4/6] Take winhttp out of lib list, since we don't use it anymore. --- windows/ZeroTierOne/ZeroTierOne.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 6ee776b17..2dfc4433e 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -183,7 +183,7 @@ true - wsock32.lib;ws2_32.lib;newdev.lib;winhttp.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -197,7 +197,7 @@ true - wsock32.lib;ws2_32.lib;newdev.lib;winhttp.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -221,7 +221,7 @@ true true true - wsock32.lib;ws2_32.lib;newdev.lib;winhttp.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -245,7 +245,7 @@ true true true - wsock32.lib;ws2_32.lib;newdev.lib;winhttp.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false From e2c65bf16a9b6f30daf023a9cfc270354d351387 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 15:44:39 -0700 Subject: [PATCH 5/6] Bring Windows service code up to date and into sync. --- one.cpp | 11 +-- windows/ZeroTierOne/ZeroTierOne.vcxproj | 14 +++- .../ZeroTierOne/ZeroTierOne.vcxproj.filters | 33 +++++++++ windows/ZeroTierOne/ZeroTierOneService.cpp | 71 ++++++++++++++----- windows/ZeroTierOne/ZeroTierOneService.h | 8 +-- 5 files changed, 109 insertions(+), 28 deletions(-) diff --git a/one.cpp b/one.cpp index c75542e4c..54145d037 100644 --- a/one.cpp +++ b/one.cpp @@ -32,6 +32,8 @@ #include #include +#include "node/Constants.hpp" + #ifdef __WINDOWS__ #include #include @@ -60,7 +62,6 @@ #include "ext/json-parser/json.h" -#include "node/Constants.hpp" #include "node/Identity.hpp" #include "node/CertificateOfMembership.hpp" #include "node/Utils.hpp" @@ -499,7 +500,7 @@ static int cli(int argc,char **argv) cliPrintHelp(argv[0],stderr); return 2; } - unsigned int scode = Http::DELETE( + unsigned int scode = Http::DEL( 1024 * 1024 * 16, 60000, (const struct sockaddr *)&addr, @@ -731,9 +732,9 @@ static BOOL WINAPI _winConsoleCtrlHandler(DWORD dwCtrlType) case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: case CTRL_SHUTDOWN_EVENT: - Node *n = node; - if (n) - n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal"); + OneService *s = zt1Service; + if (s) + s->terminate(); return TRUE; } return FALSE; diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 2dfc4433e..796c30d94 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -43,12 +43,21 @@ + - + + true + true + true + true + + + + @@ -102,6 +111,9 @@ + + + diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index be0997454..7ed585ad5 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -58,6 +58,18 @@ {da28e961-1761-41d8-9a59-65b00dfb1302} + + {43f75f84-c70d-4d44-a0ef-28a7a399abd4} + + + {0da07a2f-8922-4827-ac51-29ca3f30f881} + + + {b74916eb-bb6c-4449-a2a2-fa0b17f60121} + + + {bf604491-14c4-4a74-81a6-6105d07c5c7c} + @@ -150,6 +162,18 @@ Source Files\ext\json-parser + + Source Files + + + Source Files\windows\ZeroTierOne + + + Source Files\windows\ZeroTierOne + + + Source Files\windows\ZeroTierOne + @@ -305,6 +329,15 @@ Header Files\ext\http-parser + + Header Files\windows\ZeroTierOne + + + Header Files\windows\ZeroTierOne + + + Header Files\windows\ZeroTierOne + diff --git a/windows/ZeroTierOne/ZeroTierOneService.cpp b/windows/ZeroTierOne/ZeroTierOneService.cpp index abae3affc..e5426dc27 100644 --- a/windows/ZeroTierOne/ZeroTierOneService.cpp +++ b/windows/ZeroTierOne/ZeroTierOneService.cpp @@ -34,15 +34,13 @@ #include "ZeroTierOneService.h" -#include "../../node/Defaults.hpp" +#include "../../version.h" +#include "../../include/ZeroTierOne.h" + +#include "../../node/Constants.hpp" #include "../../node/Utils.hpp" - -#include "../../control/NodeControlClient.hpp" -#include "../../control/NodeControlService.hpp" - -#include "../../osdep/WindowsEthernetTapFactory.hpp" -#include "../../osdep/WindowsRoutingTable.hpp" -#include "../../osdep/NativeSocketManager.hpp" +#include "../../osdep/OSUtils.hpp" +#include "../../service/OneService.hpp" #pragma endregion // Includes @@ -53,7 +51,7 @@ ZeroTier::Mutex SVCDBGfile_m; ZeroTierOneService::ZeroTierOneService() : CServiceBase(ZT_SERVICE_NAME,TRUE,TRUE,FALSE), - _node((ZeroTier::Node *)0) + _service((ZeroTier::OneService *)0) { #ifdef ZT_DEBUG_SERVICE SVCDBGfile_m.lock(); @@ -86,6 +84,41 @@ void ZeroTierOneService::threadMain() restart_node: try { + { + ZeroTier::Mutex::Lock _l(_lock); + delete _service; + _service = (ZeroTier::OneService *)0; // in case newInstance() fails + _service = ZeroTier::OneService::newInstance( + ZeroTier::OneService::platformDefaultHomePath().c_str(), + ZT1_DEFAULT_PORT); + } + switch(_service->run()) { + case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR: { + std::string err("ZeroTier One encountered an unrecoverable error: "); + err.append(_service->fatalErrorMessage()); + err.append(" (restarting in 5 seconds)"); + WriteEventLogEntry(const_cast (err.c_str()),EVENTLOG_ERROR_TYPE); + Sleep(5000); + } goto restart_node; + + case ZeroTier::OneService::ONE_IDENTITY_COLLISION: { + std::string homeDir(ZeroTier::OneService::platformDefaultHomePath()); + delete _service; + _service = (ZeroTier::OneService *)0; + std::string oldid; + ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); + if (oldid.length()) { + ZeroTier::OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); + ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); + ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); + } + } goto restart_node; + + default: // normal termination + break; + } + +#if 0 std::string authToken(ZeroTier::NodeControlClient::getAuthToken((ZeroTier::ZT_DEFAULTS.defaultHomePath + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),true)); ZeroTier::WindowsEthernetTapFactory tapFactory(ZeroTier::ZT_DEFAULTS.defaultHomePath.c_str()); @@ -154,6 +187,7 @@ restart_node: break; } +#endif } catch ( ... ) { // sanity check, shouldn't happen since Node::run() should catch all its own errors // could also happen if we're out of memory though! @@ -164,17 +198,19 @@ restart_node: { ZeroTier::Mutex::Lock _l(_lock); - delete _node; - _node = (ZeroTier::Node *)0; + delete _service; + _service = (ZeroTier::OneService *)0; } } bool ZeroTierOneService::doStartUpgrade(const std::string &msiPath) { - std::string msiLog(ZeroTier::ZT_DEFAULTS.defaultHomePath + "\\LastUpdateLog.txt"); - ZeroTier::Utils::rm(msiLog); + std::string homePath(ZeroTier::OneService::platformDefaultHomePath()); - std::string bat(ZeroTier::ZT_DEFAULTS.defaultHomePath + "\\InstallAndRestartService.bat"); + std::string msiLog(homePath + "\\LastUpdateLog.txt"); + ZeroTier::OSUtils::rm(msiLog); + + std::string bat(homePath + "\\InstallAndRestartService.bat"); FILE *batf = fopen(bat.c_str(),"wb"); if (!batf) return false; @@ -210,10 +246,11 @@ void ZeroTierOneService::OnStop() ZT_SVCDBG("ZeroTierOneService::OnStop()\r\n"); _lock.lock(); - ZeroTier::Node *n = _node; + ZeroTier::OneService *s = _service; _lock.unlock(); - if (n) { - n->terminate(ZeroTier::Node::NODE_NORMAL_TERMINATION,"Windows service stopped"); + + if (s) { + s->terminate(); ZeroTier::Thread::join(_thread); } } diff --git a/windows/ZeroTierOne/ZeroTierOneService.h b/windows/ZeroTierOne/ZeroTierOneService.h index bfc835f27..1b97fd46e 100644 --- a/windows/ZeroTierOne/ZeroTierOneService.h +++ b/windows/ZeroTierOne/ZeroTierOneService.h @@ -33,11 +33,9 @@ #include -#include "../../node/Node.hpp" -#include "../../node/Defaults.hpp" -#include "../../node/Thread.hpp" #include "../../node/Mutex.hpp" -#include "../../node/Utils.hpp" +#include "../../osdep/Thread.hpp" +#include "../../service/OneService.hpp" // Uncomment to make debugging Windows services suck slightly less hard. //#define ZT_DEBUG_SERVICE "C:\\ZeroTierOneServiceDebugLog.txt" @@ -79,7 +77,7 @@ protected: virtual void OnShutdown(); private: - ZeroTier::Node *volatile _node; + ZeroTier::OneService *volatile _service; ZeroTier::Mutex _lock; ZeroTier::Thread _thread; }; From ce09e363dc95d801e8707a29a0d585089d6c3d09 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 16:31:19 -0700 Subject: [PATCH 6/6] Destroy tap devices on Windows 'leave'. --- osdep/WindowsEthernetTap.cpp | 46 ++++++++++++++++++------------------ osdep/WindowsEthernetTap.hpp | 2 +- service/OneService.cpp | 7 ++++++ 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index d8fb3957e..a0999b3da 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -789,7 +789,29 @@ void WindowsEthernetTap::destroyAllPersistentTapDevices(const char *pathToHelper } for(std::set::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) - _deletePersistentTapDevice(pathToHelpers,iidp->c_str()); + deletePersistentTapDevice(pathToHelpers,iidp->c_str()); +} + +void WindowsEthernetTap::deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId) +{ + HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + STARTUPINFOA startupInfo; + startupInfo.cb = sizeof(startupInfo); + if (devconLog != INVALID_HANDLE_VALUE) { + SetFilePointer(devconLog,0,0,FILE_END); + startupInfo.hStdOutput = devconLog; + startupInfo.hStdError = devconLog; + } + PROCESS_INFORMATION processInfo; + memset(&startupInfo,0,sizeof(STARTUPINFOA)); + memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); + if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } + if (devconLog != INVALID_HANDLE_VALUE) + CloseHandle(devconLog); } bool WindowsEthernetTap::_disableTapDevice() @@ -922,26 +944,4 @@ void WindowsEthernetTap::_setRegistryIPv4Value(const char *regKey,const std::vec } } -void WindowsEthernetTap::_deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId) -{ - HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - SetFilePointer(devconLog,0,0,FILE_END); - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); -} - } // namespace ZeroTier diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 7ec8cf19c..670467633 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -78,6 +78,7 @@ public: throw(); static void destroyAllPersistentTapDevices(const char *pathToHelpers); + static void deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId); private: bool _disableTapDevice(); @@ -85,7 +86,6 @@ private: NET_IFINDEX _getDeviceIndex(); // throws on failure std::vector _getRegistryIPv4Value(const char *regKey); void _setRegistryIPv4Value(const char *regKey,const std::vector &value); - static void _deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId); void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; diff --git a/service/OneService.cpp b/service/OneService.cpp index c32fb7927..bff705007 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -461,9 +461,16 @@ public: case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY: if (t != _taps.end()) { +#ifdef __WINDOWS__ + std::string winInstanceId(t->second->instanceId()); +#endif delete t->second; _taps.erase(t); _tapAssignedIps.erase(nwid); +#ifdef __WINDOWS__ + if ((op == ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY)&&(winInstanceId.length() > 0)) + WindowsEthernetTap::deletePersistentTapDevice(_homePath.c_str(),winInstanceId.c_str()); +#endif } break; }