Browse Source

Windows now builds and runs selftest correctly, and fixed a Windows (and possibly other platforms) issue in Phy<>.

Adam Ierymenko 10 years ago
parent
commit
f5848972f9
12 changed files with 223 additions and 112 deletions
  1. 1 1
      node/IncomingPacket.cpp
  2. 1 1
      node/Network.cpp
  3. 3 3
      node/Node.cpp
  4. 7 7
      osdep/Http.cpp
  5. 1 1
      osdep/Http.hpp
  6. 7 0
      osdep/OSUtils.hpp
  7. 15 7
      osdep/Phy.hpp
  8. 1 1
      osdep/Thread.hpp
  9. 137 56
      osdep/WindowsEthernetTap.cpp
  10. 21 19
      osdep/WindowsEthernetTap.hpp
  11. 6 1
      selftest.cpp
  12. 23 15
      service/OneService.cpp

+ 1 - 1
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());

+ 1 - 1
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();

+ 3 - 3
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<ZT1_Node *>(this),_uPtr,name,buf,sizeof(buf),r.length(),&olen);
+		long n = _dataStoreGetFunction(reinterpret_cast<ZT1_Node *>(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')

+ 7 - 7
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<HttpPhyHandler *>(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<HttpPhyHandler *>(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;i<length;++i)
 		hh->currentHeaderField.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<HttpPhyHandler *>(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<HttpPhyHandler *>(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;
 

+ 1 - 1
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,

+ 7 - 0
osdep/OSUtils.hpp

@@ -45,6 +45,7 @@
 #ifdef __WINDOWS__
 #include <WinSock2.h>
 #include <Windows.h>
+#include <Shlwapi.h>
 #else
 #include <unistd.h>
 #include <errno.h>
@@ -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()); }
 

+ 15 - 7
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<PhySocketImpl *>(sock));
+#if defined(_WIN32) || defined(_WIN64)
+		return ((long)::sendto(sws.sock,reinterpret_cast<const char *>(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<PhySocketImpl *>(sock));
-		long n = (long)::send(sws.sock,data,len,0);
 #if defined(_WIN32) || defined(_WIN64)
+		long n = (long)::send(sws.sock,reinterpret_cast<const char *>(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<PhySocketImpl>::iterator s(_socks.begin()),nexts;s!=_socks.end();s=nexts) {
+		bool atEnd = false;
+		for(typename std::list<PhySocketImpl>::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)) {

+ 1 - 1
osdep/Thread.hpp

@@ -37,7 +37,7 @@
 #include <WinSock2.h>
 #include <Windows.h>
 #include <string.h>
-#include "Mutex.hpp"
+#include "../node/Mutex.hpp"
 
 namespace ZeroTier {
 

+ 137 - 56
osdep/WindowsEthernetTap.cpp

@@ -44,42 +44,71 @@
 #include <nldef.h>
 
 #include <iostream>
+#include <set>
 
 #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<InetAddress> haveIps(ips());
+	std::vector<InetAddress> 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<std::string> 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<InetAddress> WindowsEthernetTap::ips() const
+std::vector<InetAddress> WindowsEthernetTap::ips() const
 {
 	static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it?
-	std::set<InetAddress> addrs;
+	std::vector<InetAddress> addrs;
 
 	if (!_initialized)
 		return addrs;
@@ -419,12 +444,12 @@ std::set<InetAddress> 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<InetAddress> 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<MulticastGroup> &groups)
+void WindowsEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
 {
 	if (!_initialized)
-		return false;
+		return;
 	HANDLE t = _tap;
 	if (t == INVALID_HANDLE_VALUE)
-		return false;
-
-	std::set<MulticastGroup> newGroups;
+		return;
 
-	// 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<InetAddress> ipaddrs(ips());
-	for(std::set<InetAddress>::const_iterator i(ipaddrs.begin());i!=ipaddrs.end();++i)
-		newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
+	std::vector<MulticastGroup> 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<MulticastGroup> &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<InetAddress> allIps(ips());
+	for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
+		newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
 
-	for(std::set<MulticastGroup>::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<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
+		if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
+			added.push_back(*m);
 	}
-	for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
-		if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
-			groups.erase(mg++);
-			changed = true;
-		} else ++mg;
+	for(std::vector<MulticastGroup>::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<std::string> 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<std::string>::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

+ 21 - 19
osdep/WindowsEthernetTap.hpp

@@ -37,42 +37,38 @@
 #include <queue>
 #include <stdexcept>
 
-#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<InetAddress> 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<MulticastGroup> &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<InetAddress> 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<MulticastGroup> &added,std::vector<MulticastGroup> &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<std::string> _getRegistryIPv4Value(const char *regKey);
 	void _setRegistryIPv4Value(const char *regKey,const std::vector<std::string> &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<MulticastGroup> _multicastGroups;
+
 	std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending;
 	Mutex _injectPending_m;
 

+ 6 - 1
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.

+ 23 - 15
service/OneService.cpp

@@ -53,6 +53,10 @@
 #include "OneService.hpp"
 #include "ControlPlane.hpp"
 
+#ifdef __WINDOWS__
+#include <ShlObj.h>
+#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<HttpConnection *>(*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<HttpConnection *>(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<HttpConnection *>(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<HttpConnection *>(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<HttpConnection *>(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;i<length;++i)
 		htc->currentHeaderField.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<HttpConnection *>(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<HttpConnection *>(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);