summaryrefslogtreecommitdiffhomepage
path: root/windows/winnet
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2019-10-24 14:13:13 +0200
committerDavid Lönnhager <david.l@mullvad.net>2019-10-30 14:58:41 +0100
commitf3b73543cae5d14fbd2cd321d85e4d22d030e6fc (patch)
tree1520f1801e5756ba3dc7f40980626643d645ed2d /windows/winnet
parentc8264165a9117eff7d03b48123762f38e1766adc (diff)
downloadmullvadvpn-f3b73543cae5d14fbd2cd321d85e4d22d030e6fc.tar.xz
mullvadvpn-f3b73543cae5d14fbd2cd321d85e4d22d030e6fc.zip
Refactor NetMonitor
Diffstat (limited to 'windows/winnet')
-rw-r--r--windows/winnet/src/winnet/netmonitor.cpp394
-rw-r--r--windows/winnet/src/winnet/netmonitor.h65
-rw-r--r--windows/winnet/src/winnet/networkadaptermonitor.cpp325
-rw-r--r--windows/winnet/src/winnet/networkadaptermonitor.h126
-rw-r--r--windows/winnet/src/winnet/offlinemonitor.cpp207
-rw-r--r--windows/winnet/src/winnet/offlinemonitor.h35
-rw-r--r--windows/winnet/src/winnet/winnet.cpp20
-rw-r--r--windows/winnet/src/winnet/winnet.h5
-rw-r--r--windows/winnet/src/winnet/winnet.vcxproj92
-rw-r--r--windows/winnet/src/winnet/winnet.vcxproj.filters6
10 files changed, 797 insertions, 478 deletions
diff --git a/windows/winnet/src/winnet/netmonitor.cpp b/windows/winnet/src/winnet/netmonitor.cpp
deleted file mode 100644
index bf6636fcd1..0000000000
--- a/windows/winnet/src/winnet/netmonitor.cpp
+++ /dev/null
@@ -1,394 +0,0 @@
-#include "stdafx.h"
-#include "netmonitor.h"
-#include <libcommon/error.h>
-#include <libcommon/memory.h>
-#include <libcommon/string.h>
-#include <sstream>
-
-namespace
-{
-
-bool ValidInterfaceType(const MIB_IF_ROW2 &iface)
-{
- switch (iface.InterfaceLuid.Info.IfType)
- {
- case IF_TYPE_SOFTWARE_LOOPBACK:
- case IF_TYPE_TUNNEL:
- {
- return false;
- }
- }
-
- //
- // (Windows 10, and possibly others.)
- // The BT adapter is erronously not marked as representing hardware.
- // By filtering on this we currently do not support BT tethering.
- //
-
- if (FALSE == iface.InterfaceAndOperStatusFlags.HardwareInterface
- || FALSE != iface.InterfaceAndOperStatusFlags.FilterInterface
- || 0 == iface.PhysicalAddressLength
- || FALSE != iface.InterfaceAndOperStatusFlags.EndPointInterface)
- {
- return false;
- }
-
- return true;
-}
-
-} // anonymous namespace
-
-NetMonitor::NetMonitor
-(
- std::shared_ptr<common::logging::ILogSink> logSink,
- NetMonitor::Notifier notifier,
- bool &currentConnectivity
-)
- : m_logSink(logSink)
- , m_notifier(notifier)
- , m_connected(false)
- , m_notificationHandle(nullptr)
-{
- m_cache = CreateCache();
- updateConnectivity();
-
- currentConnectivity = m_connected;
-
- const auto status = NotifyIpInterfaceChange(AF_UNSPEC, Callback, this, FALSE, &m_notificationHandle);
-
- THROW_UNLESS(NO_ERROR, status, "Register interface change notification");
-
- if (false == m_connected)
- {
- LogOfflineState(m_logSink);
- }
-}
-
-NetMonitor::~NetMonitor()
-{
- CancelMibChangeNotify2(m_notificationHandle);
-}
-
-// static
-bool NetMonitor::CheckConnectivity(std::shared_ptr<common::logging::ILogSink> logSink)
-{
- static bool loggedOffline = false;
-
- const auto connected = CheckConnectivity(CreateCache());
-
- if (connected)
- {
- loggedOffline = false;
- }
- else if (false == loggedOffline)
- {
- LogOfflineState(logSink);
- loggedOffline = true;
- }
-
- return connected;
-}
-
-// static
-NetMonitor::Cache NetMonitor::CreateCache()
-{
- MIB_IF_TABLE2 *table;
-
- const auto status = GetIfTable2(&table);
-
- THROW_UNLESS(NO_ERROR, status, "Acquire network interface table");
-
- common::memory::ScopeDestructor sd;
-
- sd += [table]()
- {
- FreeMibTable(table);
- };
-
- std::map<uint64_t, CacheEntry> cache;
-
- for (ULONG i = 0; i < table->NumEntries; ++i)
- {
- AddCacheEntry(cache, table->Table[i]);
- }
-
- return cache;
-}
-
-// static
-void NetMonitor::AddCacheEntry(Cache &cache, const MIB_IF_ROW2 &iface)
-{
- CacheEntry e;
-
- if (ValidInterfaceType(iface))
- {
- e.luid = iface.InterfaceLuid.Value;
- e.valid = true;
- e.connected =
- (
- NET_IF_ADMIN_STATUS_UP == iface.AdminStatus
- && IfOperStatusUp == iface.OperStatus
- && MediaConnectStateConnected == iface.MediaConnectState
- );
- }
- else
- {
- e.luid = iface.InterfaceLuid.Value;
- e.valid = false;
- e.connected = false;
- }
-
- cache.insert(std::make_pair(e.luid, e));
-}
-
-// static
-bool NetMonitor::CheckConnectivity(const Cache &cache)
-{
- for (const auto cacheEntryIter : cache)
- {
- const auto entry = cacheEntryIter.second;
-
- if (entry.valid && entry.connected)
- {
- return true;
- }
- }
-
- return false;
-}
-
-void NetMonitor::updateConnectivity()
-{
- m_connected = NetMonitor::CheckConnectivity(m_cache);
-}
-
-//static
-void __stdcall NetMonitor::Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType)
-{
- auto nm = reinterpret_cast<NetMonitor *>(context);
-
- try
- {
- nm->callback(hint, updateType);
- }
- catch (const std::exception &err)
- {
- nm->m_logSink->error(err.what());
- }
- catch (...)
- {
- nm->m_logSink->error("Unspecified error in NetMonitor::Callback()");
- }
-}
-
-void NetMonitor::callback(MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType)
-{
- std::scoped_lock<std::mutex> processingLock(m_processingMutex);
-
- switch (updateType)
- {
- case MibAddInstance:
- {
- MIB_IF_ROW2 iface = { 0 };
- iface.InterfaceLuid = hint->InterfaceLuid;
-
- const auto status = GetIfEntry2(&iface);
-
- if (NO_ERROR != status)
- {
- std::stringstream ss;
-
- ss << "GetIfEntry2() failed for LUID 0x" << std::hex << iface.InterfaceLuid.Value
- << " during processing of MibAddInstance, error: 0x" << status;
-
- throw std::runtime_error(ss.str());
- }
-
- //
- // The reason for removing an existing entry is that enabling
- // an interface on the adapter might change the overall properties in the
- // "row" which is merely an abstraction over all interfaces.
- //
-
- m_cache.erase(iface.InterfaceLuid.Value);
- AddCacheEntry(m_cache, iface);
-
- break;
- }
- case MibDeleteInstance:
- {
- m_cache.erase(hint->InterfaceLuid.Value);
-
- MIB_IF_ROW2 iface = { 0 };
- iface.InterfaceLuid = hint->InterfaceLuid;
-
- const auto status = GetIfEntry2(&iface);
-
- if (NO_ERROR == status)
- {
- AddCacheEntry(m_cache, iface);
- }
-
- break;
- }
- case MibParameterNotification:
- {
- MIB_IF_ROW2 iface = { 0 };
- iface.InterfaceLuid = hint->InterfaceLuid;
-
- const auto status = GetIfEntry2(&iface);
-
- if (NO_ERROR != status)
- {
- //
- // Only update the cache if we can look up the interface details.
- // This way, if the interface was connected and continues to be so, we don't
- // mistakenly switch the status to "offline".
- //
-
- std::stringstream ss;
-
- ss << "GetIfEntry2() failed for LUID 0x" << std::hex << iface.InterfaceLuid.Value
- << " during processing of MibParameterNotification, error: 0x" << status;
-
- throw std::runtime_error(ss.str());
- }
-
- m_cache.erase(iface.InterfaceLuid.Value);
- AddCacheEntry(m_cache, iface);
-
- break;
- }
- }
-
- const auto previousConnectivity = m_connected;
-
- updateConnectivity();
-
- if (previousConnectivity != m_connected)
- {
- m_notifier(m_connected);
-
- if (false == m_connected)
- {
- LogOfflineState(m_logSink);
- }
- }
-}
-
-//static
-void NetMonitor::LogOfflineState(std::shared_ptr<common::logging::ILogSink> logSink)
-{
- //
- // There is a race condition here because logging is not done using the
- // same data set that the online/offline logic processes.
- //
- // Not much of a problem really, this is temporary logging.
- //
-
- logSink->info("Machine is offline");
-
- MIB_IF_TABLE2 *table;
-
- const auto status = GetIfTable2(&table);
-
- if (NO_ERROR != status)
- {
- logSink->error("Failed to acquire list of network interfaces. Aborting detailed logging");
- return;
- }
-
- common::memory::ScopeDestructor sd;
-
- sd += [table]()
- {
- FreeMibTable(table);
- };
-
- logSink->info("Begin detailed listing of network interfaces");
-
- for (ULONG i = 0; i < table->NumEntries; ++i)
- {
- const auto &iface = table->Table[i];
-
- //
- // Don't flood the log with garbage.
- //
- const auto blacklist = std::vector<std::wstring>
- {
- L"WFP Native MAC Layer LightWeight Filter",
- L"QoS Packet Scheduler",
- L"WFP 802.3 MAC Layer LightWeight Filter",
- L"Microsoft Kernel Debug Network Adapter",
- L"Software Loopback Interface",
- L"Microsoft Teredo Tunneling Adapter",
- L"Microsoft IP-HTTPS Platform Adapter",
- L"Microsoft 6to4 Adapter",
- L"WAN Miniport",
- L"WiFi Filter Driver",
- L"Microsoft Wi-Fi Direct Virtual Adapter",
- };
-
- bool blacklisted = false;
-
- for (const auto &black : blacklist)
- {
- if (nullptr != wcsstr(iface.Description, black.c_str()))
- {
- blacklisted = true;
- break;
- }
- }
-
- if (blacklisted)
- {
- continue;
- }
-
- std::stringstream ss;
-
- ss << "Detailed interface logging" << std::endl;
- ss << "Interface ordinal " << i << std::endl;
-
- {
- const auto s = std::wstring(L" Alias: ").append(iface.Alias);
- ss << common::string::ToAnsi(s) << std::endl;
- }
-
- {
- const auto s = std::wstring(L" Description: ").append(iface.Description);
- ss << common::string::ToAnsi(s) << std::endl;
- }
-
- ss << " PhysicalAddressLength: " << iface.PhysicalAddressLength << std::endl;
- ss << " Type: " << iface.Type << std::endl;
- ss << " MediaType: " << iface.MediaType << std::endl;
- ss << " PhysicalMediumType: " << iface.PhysicalMediumType << std::endl;
- ss << " AccessType: " << iface.AccessType << std::endl;
-
- //
- // Bool cast prevents idiot stream from inserting literal 0/1.
- //
-
- ss << " InterfaceAndOperStatusFlags.HardwareInterface: " << (bool)iface.InterfaceAndOperStatusFlags.HardwareInterface << std::endl;
- ss << " InterfaceAndOperStatusFlags.FilterInterface: " << (bool)iface.InterfaceAndOperStatusFlags.FilterInterface << std::endl;
- ss << " InterfaceAndOperStatusFlags.ConnectorPresent: " << (bool)iface.InterfaceAndOperStatusFlags.ConnectorPresent << std::endl;
- ss << " InterfaceAndOperStatusFlags.NotAuthenticated: " << (bool)iface.InterfaceAndOperStatusFlags.NotAuthenticated << std::endl;
- ss << " InterfaceAndOperStatusFlags.NotMediaConnected: " << (bool)iface.InterfaceAndOperStatusFlags.NotMediaConnected << std::endl;
- ss << " InterfaceAndOperStatusFlags.Paused: " << (bool)iface.InterfaceAndOperStatusFlags.Paused << std::endl;
- ss << " InterfaceAndOperStatusFlags.LowPower: " << (bool)iface.InterfaceAndOperStatusFlags.LowPower << std::endl;
- ss << " InterfaceAndOperStatusFlags.EndPointInterface: " << (bool)iface.InterfaceAndOperStatusFlags.EndPointInterface << std::endl;
-
- ss << " OperStatus: " << iface.OperStatus << std::endl;
- ss << " AdminStatus: " << iface.AdminStatus << std::endl;
- ss << " MediaConnectState: " << iface.MediaConnectState << std::endl;
- ss << " TransmitLinkSpeed: " << iface.TransmitLinkSpeed << std::endl;
-
- ss << " ReceiveLinkSpeed: " << iface.ReceiveLinkSpeed << std::endl;
- ss << " InUcastPkts:" << iface.InUcastPkts;
-
- logSink->info(ss.str().c_str());
- }
-
- logSink->info("End detailed listing of network interfaces");
-}
diff --git a/windows/winnet/src/winnet/netmonitor.h b/windows/winnet/src/winnet/netmonitor.h
deleted file mode 100644
index a3e0a28281..0000000000
--- a/windows/winnet/src/winnet/netmonitor.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-#include <libcommon/logging/ilogsink.h>
-#include <memory>
-#include <map>
-#include <string>
-#include <cstdint>
-#include <mutex>
-#include <functional>
-#include <winsock2.h>
-#include <ws2ipdef.h>
-#include <iphlpapi.h>
-#include <windows.h>
-
-class NetMonitor
-{
-public:
-
- //
- // Connectivity changed.
- // true = connected, false = disconnected.
- //
- using Notifier = std::function<void(bool)>;
-
- NetMonitor(std::shared_ptr<common::logging::ILogSink> logSink, Notifier notifier, bool &currentConnectivity);
- ~NetMonitor();
-
- static bool CheckConnectivity(std::shared_ptr<common::logging::ILogSink> logSink);
-
-private:
-
- std::shared_ptr<common::logging::ILogSink> m_logSink;
- Notifier m_notifier;
-
- struct CacheEntry
- {
- // Unique interface identifier.
- uint64_t luid;
-
- // Whether this is a physical adapter or not.
- bool valid;
-
- // Last known state.
- bool connected;
- };
-
- using Cache = std::map<uint64_t, CacheEntry>;
-
- std::mutex m_processingMutex;
- Cache m_cache;
- bool m_connected;
-
- HANDLE m_notificationHandle;
-
- static Cache CreateCache();
- static void AddCacheEntry(Cache &cache, const MIB_IF_ROW2 &iface);
- static bool CheckConnectivity(const Cache &cache);
-
- void updateConnectivity();
-
- static void __stdcall Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType);
- void callback(MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType);
-
- static void LogOfflineState(std::shared_ptr<common::logging::ILogSink> logSink);
-};
diff --git a/windows/winnet/src/winnet/networkadaptermonitor.cpp b/windows/winnet/src/winnet/networkadaptermonitor.cpp
new file mode 100644
index 0000000000..8a03012f4a
--- /dev/null
+++ b/windows/winnet/src/winnet/networkadaptermonitor.cpp
@@ -0,0 +1,325 @@
+#include "stdafx.h"
+
+#include "networkadaptermonitor.h"
+#include <libcommon/memory.h>
+#include <sstream>
+#include <cstring>
+
+using namespace std::placeholders;
+
+
+NetworkAdapterMonitor::NetworkAdapterMonitor(
+ std::shared_ptr<common::logging::ILogSink> logSink,
+ UpdateSinkType updateSink,
+ FilterType filter,
+ std::shared_ptr<IDataProvider> dataProvider
+)
+ : m_logSink(logSink)
+ , m_notificationHandle(nullptr)
+ , m_updateSink(updateSink)
+ , m_filter(filter)
+ , m_dataProvider(dataProvider)
+{
+ //
+ // Initialize adapters
+ //
+
+ MIB_IF_TABLE2 *table;
+
+ const auto status = m_dataProvider->getIfTable2(&table);
+
+ THROW_UNLESS(NO_ERROR, status, "Acquire network interface table");
+
+ common::memory::ScopeDestructor sd;
+
+ sd += [this, table]()
+ {
+ m_dataProvider->freeMibTable(table);
+ };
+
+ for (ULONG i = 0; i < table->NumEntries; ++i)
+ {
+ m_adapters[table->Table[i].InterfaceLuid.Value] = table->Table[i];
+
+ if (filter(table->Table[i]))
+ {
+ m_filteredAdapters.push_back(table->Table[i]);
+ }
+ }
+
+ //
+ // Send initial notification
+ //
+
+ if (!m_filteredAdapters.empty())
+ {
+ m_updateSink(m_filteredAdapters, nullptr, UpdateType::Add);
+ }
+
+ //
+ // Listen to adapter events
+ //
+
+ const auto statusCb = m_dataProvider->notifyIpInterfaceChange(
+ AF_UNSPEC,
+ Callback,
+ this,
+ FALSE,
+ &m_notificationHandle
+ );
+
+ THROW_UNLESS(NO_ERROR, statusCb, "Register interface change notification");
+}
+
+NetworkAdapterMonitor::NetworkAdapterMonitor(
+ std::shared_ptr<common::logging::ILogSink> logSink
+ , UpdateSinkType updateSink
+ , FilterType filter
+) : NetworkAdapterMonitor(logSink, updateSink, filter, std::make_shared<SystemDataProvider>())
+{
+}
+
+NetworkAdapterMonitor::~NetworkAdapterMonitor()
+{
+ if (nullptr != m_notificationHandle)
+ {
+ m_dataProvider->cancelMibChangeNotify2(m_notificationHandle);
+ m_notificationHandle = nullptr;
+ }
+}
+
+bool NetworkAdapterMonitor::hasIPv4Interface(NET_LUID luid) const
+{
+ MIB_IPINTERFACE_ROW iprow = { 0 };
+ iprow.InterfaceLuid = luid;
+ iprow.Family = AF_INET;
+
+ const auto status = m_dataProvider->getIpInterfaceEntry(&iprow);
+
+ if (NO_ERROR == status)
+ {
+ return true;
+ }
+ else if (ERROR_NOT_FOUND != status)
+ {
+ common::error::Throw("Resolve IPv4 interface", status);
+ }
+ return false;
+}
+
+bool NetworkAdapterMonitor::hasIPv6Interface(NET_LUID luid) const
+{
+ MIB_IPINTERFACE_ROW iprow = { 0 };
+ iprow.InterfaceLuid = luid;
+ iprow.Family = AF_INET6;
+
+ const auto status = m_dataProvider->getIpInterfaceEntry(&iprow);
+
+ if (NO_ERROR == status)
+ {
+ return true;
+ }
+ else if (ERROR_NOT_FOUND != status)
+ {
+ common::error::Throw("Resolve IPv6 interface", status);
+ }
+ return false;
+}
+
+std::vector<MIB_IF_ROW2>::iterator NetworkAdapterMonitor::findFilteredAdapter(const MIB_IF_ROW2 &adapter)
+{
+ return std::find_if(m_filteredAdapters.begin(), m_filteredAdapters.end(), [&adapter](const MIB_IF_ROW2 &elem)
+ {
+ return elem.InterfaceLuid.Value == adapter.InterfaceLuid.Value;
+ });
+}
+
+MIB_IF_ROW2 NetworkAdapterMonitor::getAdapter(NET_LUID luid) const
+{
+ MIB_IF_ROW2 rowOut;
+ rowOut.InterfaceLuid = luid;
+ const auto status = m_dataProvider->getIfEntry2(&rowOut);
+
+ if (NO_ERROR == status)
+ {
+ return rowOut;
+ }
+
+ std::stringstream ss;
+
+ ss << "GetIfEntry2() failed for LUID 0x" << std::hex << rowOut.InterfaceLuid.Value
+ << " in NetworkAdapterMonitor::getAdapter(), error: 0x" << status;
+
+ throw std::runtime_error(ss.str());
+}
+
+void NetworkAdapterMonitor::callback(const MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE)
+{
+ MIB_IF_ROW2 iface = getAdapter(hint->InterfaceLuid);
+
+ bool adapterEnabled = NET_IF_ADMIN_STATUS_UP == iface.AdminStatus
+ && (hasIPv4Interface(iface.InterfaceLuid)
+ || hasIPv6Interface(iface.InterfaceLuid));
+
+ const auto adapterIt = m_adapters.find(hint->InterfaceLuid.Value);
+
+ if (adapterEnabled)
+ {
+ //
+ // Check if the adapter has been added or updated
+ //
+
+ bool fieldsChanged;
+
+ if (m_adapters.end() == adapterIt)
+ {
+ const auto pair = m_adapters.emplace(
+ iface.InterfaceLuid.Value,
+ iface
+ );
+ fieldsChanged = true;
+ }
+ else
+ {
+ //
+ // Only send an Update event if the fields have changed
+ //
+ fieldsChanged = std::memcmp(
+ &adapterIt->second,
+ &iface,
+ sizeof(MIB_IF_ROW2)
+ ) != 0;
+
+ // update stored adapter
+ adapterIt->second = iface;
+ }
+
+ if (m_filter(iface))
+ {
+ //
+ // Report Add event if this is new
+ //
+ if (m_filteredAdapters.end() == findFilteredAdapter(iface))
+ {
+ m_filteredAdapters.push_back(iface);
+ m_updateSink(m_filteredAdapters, &iface, UpdateType::Add);
+ }
+ else if (fieldsChanged)
+ {
+ m_updateSink(m_filteredAdapters, &iface, UpdateType::Update);
+ }
+ }
+ else
+ {
+ //
+ // Synthesize a Delete event if we're no longer interested
+ // in this adapter
+ //
+ const auto filteredIt = findFilteredAdapter(iface);
+
+ if (m_filteredAdapters.end() != filteredIt)
+ {
+ m_filteredAdapters.erase(filteredIt);
+ m_updateSink(
+ m_filteredAdapters,
+ &iface,
+ UpdateType::Delete
+ );
+ }
+ }
+ }
+ else
+ {
+ if (m_adapters.end() == adapterIt)
+ {
+ return;
+ }
+
+ //
+ // Remove the adapter
+ //
+
+ m_adapters.erase(adapterIt);
+
+ const auto filteredIt = findFilteredAdapter(iface);
+
+ if (m_filteredAdapters.end() != filteredIt)
+ {
+ m_filteredAdapters.erase(filteredIt);
+
+ if (m_filter(iface))
+ {
+ m_updateSink(
+ m_filteredAdapters,
+ &iface,
+ UpdateType::Delete
+ );
+ }
+ }
+ }
+}
+
+//static
+void __stdcall NetworkAdapterMonitor::Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType)
+{
+ auto inst = reinterpret_cast<NetworkAdapterMonitor *>(context);
+
+ try
+ {
+ inst->callback(hint, updateType);
+ }
+ catch (const std::exception &err)
+ {
+ inst->m_logSink->error(err.what());
+ }
+ catch (...)
+ {
+ inst->m_logSink->error("Unspecified error in NetworkAdapterMonitor::Callback()");
+ }
+}
+
+//
+// SystemDataProvider
+//
+
+DWORD NetworkAdapterMonitor::SystemDataProvider::notifyIpInterfaceChange(
+ ADDRESS_FAMILY Family,
+ PIPINTERFACE_CHANGE_CALLBACK Callback,
+ PVOID CallerContext,
+ BOOLEAN InitialNotification,
+ HANDLE *NotificationHandle
+)
+{
+ return NotifyIpInterfaceChange(
+ Family,
+ Callback,
+ CallerContext,
+ InitialNotification,
+ NotificationHandle
+ );
+}
+
+DWORD NetworkAdapterMonitor::SystemDataProvider::cancelMibChangeNotify2(HANDLE NotificationHandle)
+{
+ return CancelMibChangeNotify2(NotificationHandle);
+}
+
+DWORD NetworkAdapterMonitor::SystemDataProvider::getIfEntry2(PMIB_IF_ROW2 Row)
+{
+ return GetIfEntry2(Row);
+}
+
+DWORD NetworkAdapterMonitor::SystemDataProvider::getIfTable2(PMIB_IF_TABLE2 *Table)
+{
+ return GetIfTable2(Table);
+}
+
+DWORD NetworkAdapterMonitor::SystemDataProvider::getIpInterfaceEntry(PMIB_IPINTERFACE_ROW Row)
+{
+ return GetIpInterfaceEntry(Row);
+}
+
+void NetworkAdapterMonitor::SystemDataProvider::freeMibTable(PVOID Memory)
+{
+ FreeMibTable(Memory);
+}
diff --git a/windows/winnet/src/winnet/networkadaptermonitor.h b/windows/winnet/src/winnet/networkadaptermonitor.h
new file mode 100644
index 0000000000..fe78bb7e2d
--- /dev/null
+++ b/windows/winnet/src/winnet/networkadaptermonitor.h
@@ -0,0 +1,126 @@
+#pragma once
+
+#include <libcommon/logging/ilogsink.h>
+#include <libcommon/error.h>
+#include <map>
+#include <winsock2.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+#include <windows.h>
+#include <functional>
+#include <vector>
+
+
+class NetworkAdapterMonitor
+{
+public:
+
+ enum class UpdateType
+ {
+ Add,
+ Delete,
+ Update
+ };
+
+ using FilterType = std::function<bool(const MIB_IF_ROW2 &adapter)>;
+
+ //
+ // An event may apply to a specific adapter, or it may apply to all adapters.
+ // In the latter case, 'adapter' will be set to nullptr.
+ //
+ using UpdateSinkType = std::function<void(const std::vector<MIB_IF_ROW2> &adapters, const MIB_IF_ROW2 *adapter, UpdateType updateType)>;
+
+ struct IDataProvider;
+ class SystemDataProvider;
+
+ NetworkAdapterMonitor(
+ std::shared_ptr<common::logging::ILogSink> logSink
+ , UpdateSinkType updateSink
+ , FilterType filter
+ , std::shared_ptr<IDataProvider> dataProvider
+ );
+ NetworkAdapterMonitor(
+ std::shared_ptr<common::logging::ILogSink> logSink
+ , UpdateSinkType updateSink
+ , FilterType filter
+ );
+ ~NetworkAdapterMonitor();
+
+ NetworkAdapterMonitor(const NetworkAdapterMonitor &) = delete;
+ NetworkAdapterMonitor& operator=(const NetworkAdapterMonitor &) = delete;
+ NetworkAdapterMonitor(NetworkAdapterMonitor &&) = delete;
+ NetworkAdapterMonitor& operator=(NetworkAdapterMonitor &&) = delete;
+
+private:
+
+ std::shared_ptr<common::logging::ILogSink> m_logSink;
+ UpdateSinkType m_updateSink;
+ FilterType m_filter;
+
+ std::shared_ptr<IDataProvider> m_dataProvider;
+
+ MIB_IF_ROW2 getAdapter(NET_LUID luid) const;
+
+ bool hasIPv4Interface(NET_LUID luid) const;
+ bool hasIPv6Interface(NET_LUID luid) const;
+
+ std::map<ULONG64, MIB_IF_ROW2> m_adapters;
+ std::vector<MIB_IF_ROW2> m_filteredAdapters;
+
+ std::vector<MIB_IF_ROW2>::iterator findFilteredAdapter(const MIB_IF_ROW2 &adapter);
+
+ HANDLE m_notificationHandle;
+ static void __stdcall Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType);
+ virtual void callback(const MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType);
+};
+
+
+struct NetworkAdapterMonitor::IDataProvider
+{
+ virtual ~IDataProvider() = 0
+ {
+ }
+
+ virtual DWORD notifyIpInterfaceChange(
+ ADDRESS_FAMILY Family,
+ PIPINTERFACE_CHANGE_CALLBACK Callback,
+ PVOID CallerContext,
+ BOOLEAN InitialNotification,
+ HANDLE *NotificationHandle
+ ) = 0;
+ virtual DWORD cancelMibChangeNotify2(HANDLE NotificationHandle) = 0;
+
+ virtual DWORD getIfTable2(PMIB_IF_TABLE2 *Table) = 0;
+ virtual void freeMibTable(PVOID Memory) = 0;
+
+ virtual DWORD getIfEntry2(PMIB_IF_ROW2 Row) = 0;
+ virtual DWORD getIpInterfaceEntry(PMIB_IPINTERFACE_ROW Row) = 0;
+};
+
+class NetworkAdapterMonitor::SystemDataProvider : public IDataProvider
+{
+public:
+
+ SystemDataProvider() = default;
+ virtual ~SystemDataProvider() = default;
+
+ SystemDataProvider(const SystemDataProvider&) = delete;
+ SystemDataProvider(SystemDataProvider&&) = delete;
+ SystemDataProvider& operator=(const SystemDataProvider&) = delete;
+ SystemDataProvider& operator=(const SystemDataProvider&&) = delete;
+
+ DWORD notifyIpInterfaceChange(
+ ADDRESS_FAMILY Family,
+ PIPINTERFACE_CHANGE_CALLBACK Callback,
+ PVOID CallerContext,
+ BOOLEAN InitialNotification,
+ HANDLE *NotificationHandle
+ ) override;
+ DWORD cancelMibChangeNotify2(HANDLE NotificationHandle) override;
+
+ DWORD getIfTable2(PMIB_IF_TABLE2 *Table) override;
+ void freeMibTable(PVOID Memory) override;
+
+ DWORD getIfEntry2(PMIB_IF_ROW2 Row) override;
+ DWORD getIpInterfaceEntry(PMIB_IPINTERFACE_ROW Row) override;
+};
diff --git a/windows/winnet/src/winnet/offlinemonitor.cpp b/windows/winnet/src/winnet/offlinemonitor.cpp
new file mode 100644
index 0000000000..4f93a01def
--- /dev/null
+++ b/windows/winnet/src/winnet/offlinemonitor.cpp
@@ -0,0 +1,207 @@
+#include "stdafx.h"
+#include "offlinemonitor.h"
+#include <libcommon/error.h>
+#include <libcommon/memory.h>
+#include <libcommon/string.h>
+#include <sstream>
+
+
+using namespace std::placeholders; // for _1, _2 etc.
+
+namespace
+{
+
+bool IsConnectedAdapter(const MIB_IF_ROW2 &iface)
+{
+ switch (iface.InterfaceLuid.Info.IfType)
+ {
+ case IF_TYPE_SOFTWARE_LOOPBACK:
+ case IF_TYPE_TUNNEL:
+ {
+ return false;
+ }
+ }
+
+ //
+ // (Windows 10, and possibly others.)
+ // The BT adapter is erronously not marked as representing hardware.
+ // By filtering on this we currently do not support BT tethering.
+ //
+
+ if (FALSE == iface.InterfaceAndOperStatusFlags.HardwareInterface
+ || FALSE != iface.InterfaceAndOperStatusFlags.FilterInterface
+ || 0 == iface.PhysicalAddressLength
+ || FALSE != iface.InterfaceAndOperStatusFlags.EndPointInterface)
+ {
+ return false;
+ }
+
+ bool connected = (
+ IfOperStatusUp == iface.OperStatus
+ && MediaConnectStateConnected == iface.MediaConnectState
+ );
+ return connected;
+}
+
+} // anonymous namespace
+
+
+OfflineMonitor::OfflineMonitor
+(
+ std::shared_ptr<common::logging::ILogSink> logSink,
+ Notifier notifier,
+ std::shared_ptr<NetworkAdapterMonitor::IDataProvider> dataProvider
+)
+ : m_logSink(logSink)
+ , m_notifier(notifier)
+ , m_connected(false)
+ , m_netAdapterMonitor(
+ m_logSink,
+ std::bind(&OfflineMonitor::callback, this, _1, _2, _3),
+ IsConnectedAdapter,
+ dataProvider
+ )
+{
+}
+
+
+OfflineMonitor::OfflineMonitor
+(
+ std::shared_ptr<common::logging::ILogSink> logSink,
+ Notifier notifier
+) : OfflineMonitor(logSink, notifier, std::make_shared<NetworkAdapterMonitor::SystemDataProvider>())
+{
+}
+
+
+void OfflineMonitor::callback(const std::vector<MIB_IF_ROW2> &adapters, const MIB_IF_ROW2 *, NetworkAdapterMonitor::UpdateType)
+{
+ const auto previousConnectivity = m_connected;
+ m_connected = !adapters.empty();
+
+ if (previousConnectivity != m_connected)
+ {
+ m_notifier(m_connected);
+
+ if (false == m_connected)
+ {
+ LogOfflineState();
+ }
+ }
+}
+
+void OfflineMonitor::LogOfflineState()
+{
+ //
+ // There is a race condition here because logging is not done using the
+ // same data set that the online/offline logic processes.
+ //
+ // Not much of a problem really, this is temporary logging.
+ //
+
+ m_logSink->info("Machine is offline");
+
+ MIB_IF_TABLE2 *table;
+
+ const auto status = GetIfTable2(&table);
+
+ if (NO_ERROR != status)
+ {
+ m_logSink->error("Failed to acquire list of network interfaces. Aborting detailed logging");
+ return;
+ }
+
+ common::memory::ScopeDestructor sd;
+
+ sd += [table]()
+ {
+ FreeMibTable(table);
+ };
+
+ m_logSink->info("Begin detailed listing of network interfaces");
+
+ for (ULONG i = 0; i < table->NumEntries; ++i)
+ {
+ const auto &iface = table->Table[i];
+
+ //
+ // Don't flood the log with garbage.
+ //
+ const auto blacklist = std::vector<std::wstring>
+ {
+ L"WFP Native MAC Layer LightWeight Filter",
+ L"QoS Packet Scheduler",
+ L"WFP 802.3 MAC Layer LightWeight Filter",
+ L"Microsoft Kernel Debug Network Adapter",
+ L"Software Loopback Interface",
+ L"Microsoft Teredo Tunneling Adapter",
+ L"Microsoft IP-HTTPS Platform Adapter",
+ L"Microsoft 6to4 Adapter",
+ L"WAN Miniport",
+ L"WiFi Filter Driver",
+ L"Microsoft Wi-Fi Direct Virtual Adapter",
+ };
+
+ bool blacklisted = false;
+
+ for (const auto &black : blacklist)
+ {
+ if (nullptr != wcsstr(iface.Description, black.c_str()))
+ {
+ blacklisted = true;
+ break;
+ }
+ }
+
+ if (blacklisted)
+ {
+ continue;
+ }
+
+ std::stringstream ss;
+
+ ss << "Detailed interface logging" << std::endl;
+ ss << "Interface ordinal " << i << std::endl;
+
+ {
+ const auto s = std::wstring(L" Alias: ").append(iface.Alias);
+ ss << common::string::ToAnsi(s) << std::endl;
+ }
+
+ {
+ const auto s = std::wstring(L" Description: ").append(iface.Description);
+ ss << common::string::ToAnsi(s) << std::endl;
+ }
+
+ ss << " PhysicalAddressLength: " << iface.PhysicalAddressLength << std::endl;
+ ss << " Type: " << iface.Type << std::endl;
+ ss << " MediaType: " << iface.MediaType << std::endl;
+ ss << " PhysicalMediumType: " << iface.PhysicalMediumType << std::endl;
+ ss << " AccessType: " << iface.AccessType << std::endl;
+
+ //
+ // Bool cast prevents idiot stream from inserting literal 0/1.
+ //
+
+ ss << " InterfaceAndOperStatusFlags.HardwareInterface: " << (bool)iface.InterfaceAndOperStatusFlags.HardwareInterface << std::endl;
+ ss << " InterfaceAndOperStatusFlags.FilterInterface: " << (bool)iface.InterfaceAndOperStatusFlags.FilterInterface << std::endl;
+ ss << " InterfaceAndOperStatusFlags.ConnectorPresent: " << (bool)iface.InterfaceAndOperStatusFlags.ConnectorPresent << std::endl;
+ ss << " InterfaceAndOperStatusFlags.NotAuthenticated: " << (bool)iface.InterfaceAndOperStatusFlags.NotAuthenticated << std::endl;
+ ss << " InterfaceAndOperStatusFlags.NotMediaConnected: " << (bool)iface.InterfaceAndOperStatusFlags.NotMediaConnected << std::endl;
+ ss << " InterfaceAndOperStatusFlags.Paused: " << (bool)iface.InterfaceAndOperStatusFlags.Paused << std::endl;
+ ss << " InterfaceAndOperStatusFlags.LowPower: " << (bool)iface.InterfaceAndOperStatusFlags.LowPower << std::endl;
+ ss << " InterfaceAndOperStatusFlags.EndPointInterface: " << (bool)iface.InterfaceAndOperStatusFlags.EndPointInterface << std::endl;
+
+ ss << " OperStatus: " << iface.OperStatus << std::endl;
+ ss << " AdminStatus: " << iface.AdminStatus << std::endl;
+ ss << " MediaConnectState: " << iface.MediaConnectState << std::endl;
+ ss << " TransmitLinkSpeed: " << iface.TransmitLinkSpeed << std::endl;
+
+ ss << " ReceiveLinkSpeed: " << iface.ReceiveLinkSpeed << std::endl;
+ ss << " InUcastPkts:" << iface.InUcastPkts;
+
+ m_logSink->info(ss.str().c_str());
+ }
+
+ m_logSink->info("End detailed listing of network interfaces");
+}
diff --git a/windows/winnet/src/winnet/offlinemonitor.h b/windows/winnet/src/winnet/offlinemonitor.h
new file mode 100644
index 0000000000..230fef48d7
--- /dev/null
+++ b/windows/winnet/src/winnet/offlinemonitor.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <libcommon/logging/ilogsink.h>
+#include <mutex>
+#include "networkadaptermonitor.h"
+
+class OfflineMonitor
+{
+public:
+
+ //
+ // Connectivity changed.
+ // true = connected, false = disconnected.
+ //
+ using Notifier = std::function<void(bool)>;
+
+ OfflineMonitor(
+ std::shared_ptr<common::logging::ILogSink> logSink,
+ Notifier notifier,
+ std::shared_ptr<NetworkAdapterMonitor::IDataProvider> dataProvider
+ );
+ OfflineMonitor(std::shared_ptr<common::logging::ILogSink> logSink, Notifier notifier);
+
+private:
+
+ std::shared_ptr<common::logging::ILogSink> m_logSink;
+ Notifier m_notifier;
+
+ bool m_connected;
+ NetworkAdapterMonitor m_netAdapterMonitor;
+
+ void LogOfflineState();
+
+ void callback(const std::vector<MIB_IF_ROW2> &adapters, const MIB_IF_ROW2 *adapter, NetworkAdapterMonitor::UpdateType type);
+};
diff --git a/windows/winnet/src/winnet/winnet.cpp b/windows/winnet/src/winnet/winnet.cpp
index 329002d4f9..4b006964a6 100644
--- a/windows/winnet/src/winnet/winnet.cpp
+++ b/windows/winnet/src/winnet/winnet.cpp
@@ -2,7 +2,7 @@
#include "winnet.h"
#include "NetworkInterfaces.h"
#include "interfaceutils.h"
-#include "netmonitor.h"
+#include "offlinemonitor.h"
#include "../../shared/logsinkadapter.h"
#include <libcommon/error.h>
#include <cstdint>
@@ -12,7 +12,7 @@
namespace
{
-NetMonitor *g_NetMonitor = nullptr;
+OfflineMonitor *g_OfflineMonitor = nullptr;
void UnwindAndLog(MullvadLogSink logSink, void *logSinkContext, const std::exception &err)
{
@@ -152,14 +152,13 @@ WINNET_API
WinNet_ActivateConnectivityMonitor(
WinNetConnectivityMonitorCallback callback,
void *callbackContext,
- bool *currentConnectivity,
MullvadLogSink logSink,
void *logSinkContext
)
{
try
{
- if (nullptr != g_NetMonitor)
+ if (nullptr != g_OfflineMonitor)
{
throw std::runtime_error("Cannot activate connectivity monitor twice");
}
@@ -169,16 +168,9 @@ WinNet_ActivateConnectivityMonitor(
callback(connected, callbackContext);
};
- bool connected = false;
-
auto logger = std::make_shared<shared::LogSinkAdapter>(logSink, logSinkContext);
- g_NetMonitor = new NetMonitor(logger, forwarder, connected);
-
- if (nullptr != currentConnectivity)
- {
- *currentConnectivity = connected;
- }
+ g_OfflineMonitor = new OfflineMonitor(logger, forwarder);
return true;
}
@@ -202,8 +194,8 @@ WinNet_DeactivateConnectivityMonitor(
{
try
{
- delete g_NetMonitor;
- g_NetMonitor = nullptr;
+ delete g_OfflineMonitor;
+ g_OfflineMonitor = nullptr;
}
catch (...)
{
diff --git a/windows/winnet/src/winnet/winnet.h b/windows/winnet/src/winnet/winnet.h
index c56faad951..9b1af52e36 100644
--- a/windows/winnet/src/winnet/winnet.h
+++ b/windows/winnet/src/winnet/winnet.h
@@ -3,11 +3,15 @@
#include "../../shared/logsink.h"
#include <stdbool.h>
+#ifndef WINNET_STATIC
#ifdef WINNET_EXPORTS
#define WINNET_LINKAGE __declspec(dllexport)
#else
#define WINNET_LINKAGE __declspec(dllimport)
#endif
+#else
+#define WINNET_LINKAGE
+#endif
#define WINNET_API __stdcall
@@ -75,7 +79,6 @@ WINNET_API
WinNet_ActivateConnectivityMonitor(
WinNetConnectivityMonitorCallback callback,
void *callbackContext,
- bool *currentConnectivity,
MullvadLogSink logSink,
void *logSinkContext
);
diff --git a/windows/winnet/src/winnet/winnet.vcxproj b/windows/winnet/src/winnet/winnet.vcxproj
index fd10ec40fd..141c992c4e 100644
--- a/windows/winnet/src/winnet/winnet.vcxproj
+++ b/windows/winnet/src/winnet/winnet.vcxproj
@@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug Static|Win32">
+ <Configuration>Debug Static</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug Static|x64">
+ <Configuration>Debug Static</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
@@ -19,18 +27,20 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="networkadaptermonitor.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="InterfacePair.cpp" />
<ClCompile Include="interfaceutils.cpp" />
- <ClCompile Include="netmonitor.cpp" />
+ <ClCompile Include="offlinemonitor.cpp" />
<ClCompile Include="NetworkInterfaces.cpp" />
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="winnet.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="networkadaptermonitor.h" />
<ClInclude Include="InterfacePair.h" />
<ClInclude Include="interfaceutils.h" />
- <ClInclude Include="netmonitor.h" />
+ <ClInclude Include="offlinemonitor.h" />
<ClInclude Include="NetworkInterfaces.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
@@ -56,6 +66,12 @@
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@@ -69,6 +85,12 @@
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
@@ -84,12 +106,18 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
@@ -99,11 +127,23 @@
<OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)\bin\$(Platform)-Debug\</OutDir>
+ <IntDir>$(SolutionDir)\bin\temp\$(Platform)-Debug\$(ProjectName)\</IntDir>
+ <TargetName>$(ProjectName)-static</TargetName>
+ </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)\bin\$(Platform)-Debug\</OutDir>
+ <IntDir>$(SolutionDir)\bin\temp\$(Platform)-Debug\$(ProjectName)\</IntDir>
+ <TargetName>$(ProjectName)-static</TargetName>
+ </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir>
@@ -134,6 +174,30 @@
<AdditionalDependencies>libcommon.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Create</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WINNET_STATIC;WIN32;_DEBUG;WINNET_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ <AdditionalIncludeDirectories>$(ProjectDir)..\..\..\windows-libraries\src\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ModuleDefinitionFile>winnet.def</ModuleDefinitionFile>
+ <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libcommon.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Lib>
+ <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-Debug</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libcommon.lib;Iphlpapi.lib</AdditionalDependencies>
+ </Lib>
+ </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Create</PrecompiledHeader>
@@ -154,6 +218,30 @@
<ModuleDefinitionFile>winnet.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Create</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WINNET_STATIC;_DEBUG;WINNET_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ <AdditionalIncludeDirectories>$(ProjectDir)..\..\..\windows-libraries\src\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>libcommon.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories>
+ <ModuleDefinitionFile>winnet.def</ModuleDefinitionFile>
+ </Link>
+ <Lib>
+ <AdditionalDependencies>libcommon.lib;Iphlpapi.lib</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-Debug</AdditionalLibraryDirectories>
+ </Lib>
+ </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Create</PrecompiledHeader>
diff --git a/windows/winnet/src/winnet/winnet.vcxproj.filters b/windows/winnet/src/winnet/winnet.vcxproj.filters
index 3ac5a14717..9a901d3203 100644
--- a/windows/winnet/src/winnet/winnet.vcxproj.filters
+++ b/windows/winnet/src/winnet/winnet.vcxproj.filters
@@ -7,7 +7,8 @@
<ClCompile Include="NetworkInterfaces.cpp" />
<ClCompile Include="InterfacePair.cpp" />
<ClCompile Include="interfaceutils.cpp" />
- <ClCompile Include="netmonitor.cpp" />
+ <ClCompile Include="networkadaptermonitor.cpp" />
+ <ClCompile Include="offlinemonitor.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
@@ -16,7 +17,8 @@
<ClInclude Include="NetworkInterfaces.h" />
<ClInclude Include="InterfacePair.h" />
<ClInclude Include="interfaceutils.h" />
- <ClInclude Include="netmonitor.h" />
+ <ClInclude Include="networkadaptermonitor.h" />
+ <ClInclude Include="offlinemonitor.h" />
</ItemGroup>
<ItemGroup>
<None Include="winnet.def" />