From 388fc53380083424fdc1d7d2ebc3c608a642ca8a Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 7 Dec 2021 11:17:20 -0500 Subject: [PATCH] match io loop event order on windows/apple to match linux. on win32/apple reading packets from the interface does not count as an io operation. manually trigger pump on win32/apple to pretend that it is an io event. add platform quark function MaybeWakeUpperLayers on vpn::Interface to manaully wake up the other components on platforms that need that (ones on which packet io is not done via io events). on non linux platforms, use uv_prepare_t instead of uv_check_t as the former triggers before blocking for io, instead of after. this better matches linux's order of operations in libuv. --- cmake/win32.cmake | 5 +++-- llarp/apple/vpn_interface.cpp | 16 ++++++++++++++-- llarp/apple/vpn_interface.hpp | 10 +++++++++- llarp/apple/vpn_platform.cpp | 5 +++-- llarp/apple/vpn_platform.hpp | 3 ++- llarp/config/config.cpp | 4 ++-- llarp/config/config.hpp | 2 +- llarp/ev/ev_libuv.cpp | 11 +++++++++-- llarp/ev/vpn.hpp | 9 +++++++-- llarp/handlers/exit.cpp | 2 +- llarp/handlers/tun.cpp | 2 +- llarp/net/sock_addr.hpp | 5 ----- llarp/router/router.cpp | 6 +----- llarp/vpn/android.hpp | 2 +- llarp/vpn/linux.hpp | 2 +- llarp/vpn/win32.hpp | 21 ++++++++++++++++----- pybind/llarp/config.cpp | 4 ++-- 17 files changed, 73 insertions(+), 36 deletions(-) diff --git a/cmake/win32.cmake b/cmake/win32.cmake index 2a4af72a0..73cda29b3 100644 --- a/cmake/win32.cmake +++ b/cmake/win32.cmake @@ -15,8 +15,9 @@ if(NOT MSVC_VERSION) # to .r[o]data section one after the other! add_compile_options(-fno-ident -Wa,-mbig-obj) link_libraries( -lws2_32 -lshlwapi -ldbghelp -luser32 -liphlpapi -lpsapi -luserenv) - # zmq requires windows xp or higher - add_definitions(-DWINVER=0x0501 -D_WIN32_WINNT=0x0501) + # the minimum windows version, set to 6 rn because supporting older windows is hell + set(_winver 0x0600) + add_definitions(-DWINVER=${_winver} -D_WIN32_WINNT=${_winver}) endif() if(EMBEDDED_CFG) diff --git a/llarp/apple/vpn_interface.cpp b/llarp/apple/vpn_interface.cpp index 079e24aa9..c54cef00a 100644 --- a/llarp/apple/vpn_interface.cpp +++ b/llarp/apple/vpn_interface.cpp @@ -1,12 +1,18 @@ #include "vpn_interface.hpp" #include "context.hpp" +#include namespace llarp::apple { VPNInterface::VPNInterface( - Context& ctx, packet_write_callback packet_writer, on_readable_callback on_readable) - : m_PacketWriter{std::move(packet_writer)}, m_OnReadable{std::move(on_readable)} + Context& ctx, + packet_write_callback packet_writer, + on_readable_callback on_readable, + AbstractRouter* router) + : m_PacketWriter{std::move(packet_writer)} + , m_OnReadable{std::move(on_readable)} + , _router{router} { ctx.loop->call_soon([this] { m_OnReadable(*this); }); } @@ -21,6 +27,12 @@ namespace llarp::apple return true; } + void + VPNInterface::MaybeWakeUpperLayers() const + { + _router->TriggerPump(); + } + int VPNInterface::PollFD() const { diff --git a/llarp/apple/vpn_interface.hpp b/llarp/apple/vpn_interface.hpp index c1dff8dbf..762227f91 100644 --- a/llarp/apple/vpn_interface.hpp +++ b/llarp/apple/vpn_interface.hpp @@ -17,7 +17,10 @@ namespace llarp::apple using on_readable_callback = std::function; explicit VPNInterface( - Context& ctx, packet_write_callback packet_writer, on_readable_callback on_readable); + Context& ctx, + packet_write_callback packet_writer, + on_readable_callback on_readable, + AbstractRouter* router); // Method to call when a packet has arrived to deliver the packet to lokinet bool @@ -35,6 +38,9 @@ namespace llarp::apple bool WritePacket(net::IPPacket pkt) override; + void + MaybeWakeUpperLayers() const override; + private: // Function for us to call when we have a packet to emit. Should return true if the packet was // handed off to the OS successfully. @@ -46,6 +52,8 @@ namespace llarp::apple static inline constexpr auto PacketQueueSize = 1024; thread::Queue m_ReadQueue{PacketQueueSize}; + + AbstractRouter* const _router; }; } // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.cpp b/llarp/apple/vpn_platform.cpp index b11c0b05b..1d1eafb8e 100644 --- a/llarp/apple/vpn_platform.cpp +++ b/llarp/apple/vpn_platform.cpp @@ -15,8 +15,9 @@ namespace llarp::apple , m_OnReadable{std::move(on_readable)} {} - std::shared_ptr VPNPlatform::ObtainInterface(vpn::InterfaceInfo) + std::shared_ptr + VPNPlatform::ObtainInterface(vpn::InterfaceInfo, AbstractRouter* router) { - return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); + return std::make_shared(m_Context, m_PacketWriter, m_OnReadable, router); } } // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp index 04ce75646..0cf7f469b 100644 --- a/llarp/apple/vpn_platform.hpp +++ b/llarp/apple/vpn_platform.hpp @@ -16,7 +16,8 @@ namespace llarp::apple llarp_route_callbacks route_callbacks, void* callback_context); - std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override; + std::shared_ptr + ObtainInterface(vpn::InterfaceInfo, AbstractRouter*) override; vpn::IRouteManager& RouteManager() override diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 3a2719343..047427631 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -798,12 +798,12 @@ namespace llarp const IpAddress addr{value}; if (not addr.hasPort()) throw std::invalid_argument("no port provided in link address"); - info.interface = addr.toHost(); + info.m_interface = addr.toHost(); info.port = *addr.getPort(); } else { - info.interface = std::string{name}; + info.m_interface = std::string{name}; std::vector splits = split(value, ","); for (std::string_view str : splits) diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 03f7a000c..b738bdfb2 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -147,7 +147,7 @@ namespace llarp { struct LinkInfo { - std::string interface; + std::string m_interface; int addressFamily = -1; uint16_t port = -1; }; diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index b491f42b0..c7356f432 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -241,8 +241,11 @@ namespace llarp::uv using event_t = uvw::PollEvent; auto handle = m_Impl->resource(netif->PollFD()); #else - using event_t = uvw::CheckEvent; - auto handle = m_Impl->resource(); + // we use a uv_prepare_t because it fires before blocking for new io events unconditionally + // we want to match what linux does, using a uv_check_t does not suffice as the order of + // operations is not what we need. + using event_t = uvw::PrepareEvent; + auto handle = m_Impl->resource(); #endif if (!handle) return false; @@ -254,6 +257,10 @@ namespace llarp::uv LogDebug("got packet ", pkt.sz); if (handler) handler(std::move(pkt)); + // on windows/apple, vpn packet io does not happen as an io action that wakes up the event + // loop thus, we must manually wake up the event loop when we get a packet on our interface. + // on linux this is a nop + netif->MaybeWakeUpperLayers(); } }); diff --git a/llarp/ev/vpn.hpp b/llarp/ev/vpn.hpp index c3346fcdd..ede6b0acd 100644 --- a/llarp/ev/vpn.hpp +++ b/llarp/ev/vpn.hpp @@ -9,7 +9,8 @@ namespace llarp { struct Context; -} + struct AbstractRouter; +} // namespace llarp namespace llarp::vpn { @@ -59,6 +60,10 @@ namespace llarp::vpn /// returns false if we dropped it virtual bool WritePacket(net::IPPacket pkt) = 0; + + /// idempotently wake up the upper layers as needed (platform dependant) + virtual void + MaybeWakeUpperLayers() const {}; }; class IRouteManager @@ -112,7 +117,7 @@ namespace llarp::vpn /// get a new network interface fully configured given the interface info /// blocks until ready, throws on error virtual std::shared_ptr - ObtainInterface(InterfaceInfo info) = 0; + ObtainInterface(InterfaceInfo info, AbstractRouter* router) = 0; /// get owned ip route manager for managing routing table virtual IRouteManager& diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 8c88c3753..7dc80f65a 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -443,7 +443,7 @@ namespace llarp info.ifname = m_ifname; info.addrs.emplace(m_OurRange); - m_NetIf = GetRouter()->GetVPNPlatform()->ObtainInterface(std::move(info)); + m_NetIf = GetRouter()->GetVPNPlatform()->ObtainInterface(std::move(info), m_Router); if (not m_NetIf) { llarp::LogError("Could not create interface"); diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 5677fc12b..8736f2125 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -908,7 +908,7 @@ namespace llarp try { - m_NetIf = Router()->GetVPNPlatform()->ObtainInterface(std::move(info)); + m_NetIf = Router()->GetVPNPlatform()->ObtainInterface(std::move(info), Router()); } catch (std::exception& ex) { diff --git a/llarp/net/sock_addr.hpp b/llarp/net/sock_addr.hpp index 2e18451a2..3c25e8914 100644 --- a/llarp/net/sock_addr.hpp +++ b/llarp/net/sock_addr.hpp @@ -7,11 +7,6 @@ #include #include #include -extern "C" const char* -inet_ntop(int af, const void* src, char* dst, size_t size); -extern "C" int -inet_pton(int af, const char* src, void* dst); -#define inet_aton(x, y) inet_pton(AF_INET, x, y) #endif #include diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 8729bf0a0..87816e7ae 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -709,7 +709,7 @@ namespace llarp util::memFn(&AbstractRouter::TriggerPump, this), util::memFn(&AbstractRouter::QueueWork, this)); - const std::string& key = serverConfig.interface; + const std::string& key = serverConfig.m_interface; int af = serverConfig.addressFamily; uint16_t port = serverConfig.port; if (!server->Configure(this, key, af, port)) @@ -1241,10 +1241,6 @@ namespace llarp LogInfo("have ", _nodedb->NumLoaded(), " routers"); -#ifdef _WIN32 - // windows uses proactor event loop so we need to constantly pump - _loop->add_ticker([this] { PumpLL(); }); -#endif _loop->call_every(ROUTER_TICK_INTERVAL, weak_from_this(), [this] { Tick(); }); _running.store(true); _startedAt = Now(); diff --git a/llarp/vpn/android.hpp b/llarp/vpn/android.hpp index c9792a009..043249b0d 100644 --- a/llarp/vpn/android.hpp +++ b/llarp/vpn/android.hpp @@ -92,7 +92,7 @@ namespace llarp::vpn {} std::shared_ptr - ObtainInterface(InterfaceInfo info) override + ObtainInterface(InterfaceInfo info, AbstractRouter*) override { return std::make_shared(std::move(info), fd); } diff --git a/llarp/vpn/linux.hpp b/llarp/vpn/linux.hpp index 0f47636e9..b682ae15b 100644 --- a/llarp/vpn/linux.hpp +++ b/llarp/vpn/linux.hpp @@ -448,7 +448,7 @@ namespace llarp::vpn public: std::shared_ptr - ObtainInterface(InterfaceInfo info) override + ObtainInterface(InterfaceInfo info, AbstractRouter*) override { return std::make_shared(std::move(info)); }; diff --git a/llarp/vpn/win32.hpp b/llarp/vpn/win32.hpp index 9ecd15e79..172fb0b94 100644 --- a/llarp/vpn/win32.hpp +++ b/llarp/vpn/win32.hpp @@ -6,6 +6,7 @@ #include #include #include +#include // DDK macros #define CTL_CODE(DeviceType, Function, Method, Access) \ @@ -177,6 +178,8 @@ namespace llarp::vpn InterfaceInfo m_Info; + AbstractRouter* const _router; + static std::wstring get_win_sys_path() { @@ -220,7 +223,8 @@ namespace llarp::vpn return converter.to_bytes(wcmd); } - Win32Interface(InterfaceInfo info) : m_ReadQueue{1024}, m_Info{std::move(info)} + Win32Interface(InterfaceInfo info, AbstractRouter* router) + : m_ReadQueue{1024}, m_Info{std::move(info)}, _router{router} { DWORD len; @@ -401,6 +405,12 @@ namespace llarp::vpn thread.join(); } + virtual void + MaybeWakeUpperLayers() const override + { + _router->TriggerPump(); + } + int PollFD() const override { @@ -541,8 +551,8 @@ namespace llarp::vpn Execute(RouteCommand() + " " + cmd + " c000::/2 " + ipv6.ToString()); ifname.back()++; - Execute(RouteCommand() + " " + cmd + " 0.0.0.0 MASK 128.0.0.0 " + ifname); - Execute(RouteCommand() + " " + cmd + " 128.0.0.0 MASK 128.0.0.0 " + ifname); + Execute(RouteCommand() + " " + cmd + " 0.0.0.0 MASK 128.0.0.0 " + ifname + " METRIC 2"); + Execute(RouteCommand() + " " + cmd + " 128.0.0.0 MASK 128.0.0.0 " + ifname + " METRIC 2"); } void @@ -629,12 +639,13 @@ namespace llarp::vpn public: std::shared_ptr - ObtainInterface(InterfaceInfo info) override + ObtainInterface(InterfaceInfo info, AbstractRouter* router) override { - auto netif = std::make_shared(std::move(info)); + auto netif = std::make_shared(std::move(info), router); netif->Start(); return netif; }; + IRouteManager& RouteManager() override { diff --git a/pybind/llarp/config.cpp b/pybind/llarp/config.cpp index 3ca6fe306..c0d15cdfe 100644 --- a/pybind/llarp/config.cpp +++ b/pybind/llarp/config.cpp @@ -77,7 +77,7 @@ namespace llarp "setOutboundLink", [](LinksConfig& self, std::string interface, int family, uint16_t port) { LinksConfig::LinkInfo info; - info.interface = std::move(interface); + info.m_interface = std::move(interface); info.addressFamily = family; info.port = port; self.m_OutboundLink = std::move(info); @@ -86,7 +86,7 @@ namespace llarp "addInboundLink", [](LinksConfig& self, std::string interface, int family, uint16_t port) { LinksConfig::LinkInfo info; - info.interface = std::move(interface); + info.m_interface = std::move(interface); info.addressFamily = family; info.port = port; self.m_InboundLinks.push_back(info);