diff options
author | Grant Limberg <glimberg@gmail.com> | 2015-05-13 20:52:23 -0700 |
---|---|---|
committer | Grant Limberg <glimberg@gmail.com> | 2015-05-13 20:52:23 -0700 |
commit | 4a0280686c7a74b58a060375ffce385554d90040 (patch) | |
tree | addbccc48f967f5e80ff31641f530c9d282766a2 /osdep | |
parent | da45840e5ad87aa86f67fbe20d0cb003d982b0f0 (diff) | |
parent | a8835cd8b33903440f372ed66f4e3b49745ea68f (diff) | |
download | infinitytier-4a0280686c7a74b58a060375ffce385554d90040.tar.gz infinitytier-4a0280686c7a74b58a060375ffce385554d90040.zip |
Merge branch 'adamierymenko-dev' into android-jni
Diffstat (limited to 'osdep')
-rw-r--r-- | osdep/WindowsEthernetTap.cpp | 185 |
1 files changed, 89 insertions, 96 deletions
diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 220516ab..4a5d32a4 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -53,7 +53,7 @@ #include "WindowsEthernetTap.hpp" #include "OSUtils.hpp" -#include "..\windows\TapDriver\tap-windows.h" +#include "..\windows\TapDriver6\tap-windows.h" // ff:ff:ff:ff:ff:ff with no ADI //static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); @@ -89,11 +89,14 @@ public: }; static const WindowsEthernetTapEnv WINENV; -} // anonymous namespace - // Only create or delete devices one at a time static Mutex _systemTapInitLock; +// Incrementing this causes everyone currently open to close and reopen +static volatile int _systemTapResetStatus = 0; + +} // anonymous namespace + WindowsEthernetTap::WindowsEthernetTap( const char *hp, const MAC &mac, @@ -124,11 +127,14 @@ WindowsEthernetTap::WindowsEthernetTap( Mutex::Lock _l(_systemTapInitLock); - std::string tapDriverPath(_pathToHelpers + WINENV.tapDriverNdis6); - const char *tapDriverName = "zttap300"; + // Use NDIS5 if it's installed, since we don't want to switch out the driver on + // pre-existing installs (yet). We won't ship NDIS5 anymore so new installs will + // use NDIS6. + std::string tapDriverPath(_pathToHelpers + WINENV.tapDriverNdis5); + const char *tapDriverName = "zttap200"; if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) { - tapDriverPath = _pathToHelpers + WINENV.tapDriverNdis5; - tapDriverName = "zttap200"; + tapDriverPath = _pathToHelpers + WINENV.tapDriverNdis6; + tapDriverName = "zttap300"; if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) { throw std::runtime_error("no tap driver available: cannot find zttap300.inf (NDIS6) or zttap200.inf (NDIS5) under home path"); } @@ -198,7 +204,7 @@ WindowsEthernetTap::WindowsEthernetTap( if (devconLog != INVALID_HANDLE_VALUE) SetFilePointer(devconLog,0,0,FILE_END); - // Execute devcon to install an instance of the Microsoft Loopback Adapter + // Execute devcon to create a new tap device STARTUPINFOA startupInfo; startupInfo.cb = sizeof(startupInfo); if (devconLog != INVALID_HANDLE_VALUE) { @@ -262,6 +268,12 @@ WindowsEthernetTap::WindowsEthernetTap( } } else break; // no more keys or error occurred } + + // When we create a new tap device from scratch, existing taps for + // some reason go into 'unplugged' state. This can be fixed by + // closing and re-opening them. Incrementing this causes all + // existing tap threads to do this. + ++_systemTapResetStatus; } if (_netCfgInstanceId.length() > 0) { @@ -306,15 +318,15 @@ WindowsEthernetTap::WindowsEthernetTap( if (ConvertInterfaceGuidToLuid(&_deviceGuid,&_deviceLuid) != NO_ERROR) throw std::runtime_error("unable to convert device interface GUID to LUID"); + // Certain functions can now work (e.g. ips()) + _initialized = true; + if (friendlyName) setFriendlyName(friendlyName); // Start background thread that actually performs I/O _injectSemaphore = CreateSemaphore(NULL,0,1,NULL); _thread = Thread::start(this); - - // Certain functions can now work (e.g. ips()) - _initialized = true; } WindowsEthernetTap::~WindowsEthernetTap() @@ -566,38 +578,26 @@ void WindowsEthernetTap::threadMain() HANDLE wait4[3]; char *tapReadBuf = (char *)0; - // Shouldn't be needed, but Windows does not overcommit. This Windows - // tap code is defensive to schizoid paranoia degrees. + if (!_enableTapDevice()) { + _enabled = false; + return; // only happens if devcon is missing or totally fails + } + + /* No idea why I did this. I did it a long time ago and there was only a + * a snarky comment. But I'd never do crap like this without a reason, so + * I am leaving it alone with a more descriptive snarky comment. */ while (!tapReadBuf) { tapReadBuf = (char *)::malloc(ZT_IF_MTU + 32); if (!tapReadBuf) Sleep(1000); } - // Tap is in this weird Windows global pseudo file space Utils::snprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str()); - - /* More insanity: repetatively try to enable/disable tap device. The first - * time we succeed, close it and do it again. This is to fix a driver init - * bug that seems to be extremely non-deterministic and to only occur after - * headless MSI upgrade. It cannot be reproduced in any other circumstance. - * - * Eventually when ZeroTier has actual money we will have someone create an - * NDIS6 tap driver. Yes, we'll likely be cool and open source it. */ - bool throwOneAway = true; + int prevTapResetStatus = _systemTapResetStatus; while (_run) { - _disableTapDevice(); - Sleep(250); - if (!_enableTapDevice()) { - ::free(tapReadBuf); - _enabled = false; - return; // only happens if devcon is missing or totally fails - } - Sleep(250); - _tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL); if (_tap == INVALID_HANDLE_VALUE) { - Sleep(500); + fprintf(stderr,"Error opening %s -- retrying.\r\n",tapPath); continue; } @@ -605,8 +605,6 @@ void WindowsEthernetTap::threadMain() uint32_t tmpi = 1; DWORD bytesReturned = 0; DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL); - bytesReturned = 0; - DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL); } { @@ -688,74 +686,69 @@ void WindowsEthernetTap::threadMain() #endif } - if (throwOneAway) { - throwOneAway = false; - CloseHandle(_tap); - _tap = INVALID_HANDLE_VALUE; - Sleep(1000); - continue; - } else break; - } - - memset(&tapOvlRead,0,sizeof(tapOvlRead)); - tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); - memset(&tapOvlWrite,0,sizeof(tapOvlWrite)); - tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); - - wait4[0] = _injectSemaphore; - wait4[1] = tapOvlRead.hEvent; - wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true - - // Start overlapped read, which is always active - ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead); - bool writeInProgress = false; - - for(;;) { - if (!_run) break; - DWORD r = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,5000,TRUE); - if (!_run) break; - - if ((r == WAIT_TIMEOUT)||(r == WAIT_FAILED)) - continue; - - if (HasOverlappedIoCompleted(&tapOvlRead)) { - DWORD bytesRead = 0; - if (GetOverlappedResult(_tap,&tapOvlRead,&bytesRead,FALSE)) { - if ((bytesRead > 14)&&(_enabled)) { - MAC to(tapReadBuf,6); - MAC from(tapReadBuf + 6,6); - unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); - try { - // TODO: decode vlans - _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); - } catch ( ... ) {} // handlers should not throw + memset(&tapOvlRead,0,sizeof(tapOvlRead)); + tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + memset(&tapOvlWrite,0,sizeof(tapOvlWrite)); + tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + wait4[0] = _injectSemaphore; + wait4[1] = tapOvlRead.hEvent; + wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true + + ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead); + bool writeInProgress = false; + while (_run) { + if (prevTapResetStatus != _systemTapResetStatus) { + prevTapResetStatus = _systemTapResetStatus; + break; // this will cause us to close and reopen the tap + } + DWORD r = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE); + if (!_run) break; // will also break outer while(_run) + + if ((r == WAIT_TIMEOUT)||(r == WAIT_FAILED)) + continue; + + if (HasOverlappedIoCompleted(&tapOvlRead)) { + DWORD bytesRead = 0; + if (GetOverlappedResult(_tap,&tapOvlRead,&bytesRead,FALSE)) { + if ((bytesRead > 14)&&(_enabled)) { + MAC to(tapReadBuf,6); + MAC from(tapReadBuf + 6,6); + unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); + try { + // TODO: decode vlans + _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); + } catch ( ... ) {} // handlers should not throw + } } + ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead); } - ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead); - } - if (writeInProgress) { - if (HasOverlappedIoCompleted(&tapOvlWrite)) { - writeInProgress = false; - _injectPending_m.lock(); - _injectPending.pop(); - } else continue; // still writing, so skip code below and wait - } else _injectPending_m.lock(); - - if (!_injectPending.empty()) { - WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&tapOvlWrite); - writeInProgress = true; + if (writeInProgress) { + if (HasOverlappedIoCompleted(&tapOvlWrite)) { + writeInProgress = false; + _injectPending_m.lock(); + _injectPending.pop(); + } else continue; // still writing, so skip code below and wait + } else _injectPending_m.lock(); + + if (!_injectPending.empty()) { + WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&tapOvlWrite); + writeInProgress = true; + } + + _injectPending_m.unlock(); } - _injectPending_m.unlock(); - } + CancelIo(_tap); - CancelIo(_tap); + CloseHandle(tapOvlRead.hEvent); + CloseHandle(tapOvlWrite.hEvent); + CloseHandle(_tap); + _tap = INVALID_HANDLE_VALUE; - CloseHandle(tapOvlRead.hEvent); - CloseHandle(tapOvlWrite.hEvent); - CloseHandle(_tap); - _tap = INVALID_HANDLE_VALUE; + // We will restart and re-open the tap unless _run == false + } ::free(tapReadBuf); } |