| 1 | // Copyright (C) Microsoft Corporation. All rights reserved. |
| 2 | |
| 3 | #include "precomp.h" |
| 4 | #include "socket.hpp" |
| 5 | #include "GnsPortTrackerChannel.h" |
| 6 | |
| 7 | using wsl::core::GnsPortTrackerChannel; |
| 8 | |
| 9 | GnsPortTrackerChannel::GnsPortTrackerChannel( |
| 10 | wil::unique_socket&& Socket, |
| 11 | const std::function<int(const SOCKADDR_INET&, int, bool)>& Callback, |
| 12 | const std::function<void(const std::string&, bool)>& InterfaceStateCallback) : |
| 13 | m_callback(Callback), |
| 14 | m_interfaceStateCallback(InterfaceStateCallback), |
| 15 | m_channel(std::move(Socket), "GNSPortTracker", {m_stopEvent.get()}) |
| 16 | { |
| 17 | m_thread = std::thread{std::bind(&GnsPortTrackerChannel::Run, this)}; |
| 18 | } |
| 19 | |
| 20 | GnsPortTrackerChannel::~GnsPortTrackerChannel() |
| 21 | { |
| 22 | LOG_IF_WIN32_BOOL_FALSE(SetEvent(m_stopEvent.get())); |
| 23 | |
| 24 | if (m_thread.joinable()) |
| 25 | { |
| 26 | m_thread.join(); |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | void GnsPortTrackerChannel::Run() |
| 31 | { |
| 32 | try |
| 33 | { |
| 34 | for (;;) |
| 35 | { |
| 36 | auto transaction = m_channel.ReceiveTransaction(); |
| 37 | auto [header, range] = transaction.ReceiveOrClosed<MESSAGE_HEADER>(); |
| 38 | if (header == nullptr) |
| 39 | { |
| 40 | return; |
| 41 | } |
| 42 | |
| 43 | switch (header->MessageType) |
| 44 | { |
| 45 | case LxGnsMessagePortMappingRequest: |
| 46 | { |
| 47 | const auto* message = gslhelpers::try_get_struct<LX_GNS_PORT_ALLOCATION_REQUEST>(range); |
| 48 | THROW_HR_IF_MSG(E_UNEXPECTED, !message, "Unexpected message size: %i", header->MessageSize); |
| 49 | |
| 50 | transaction.SendResultMessage<int32_t>( |
| 51 | m_callback(ConvertPortRequestToSockAddr(message), message->Protocol, message->Allocate)); |
| 52 | } |
| 53 | break; |
| 54 | case LxGnsMessageIfStateChangeRequest: |
| 55 | { |
| 56 | const auto* message = gslhelpers::try_get_struct<LX_GNS_TUN_BRIDGE_REQUEST>(range); |
| 57 | THROW_HR_IF_MSG(E_UNEXPECTED, !message, "Unexpected message size: %i", header->MessageSize); |
| 58 | |
| 59 | m_interfaceStateCallback(message->InterfaceName, message->InterfaceUp); |
| 60 | transaction.SendResultMessage<int32_t>(0); |
| 61 | } |
| 62 | break; |
| 63 | default: |
| 64 | THROW_HR_MSG(E_UNEXPECTED, "Unexpected message type: %i", header->MessageType); |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | CATCH_LOG() |
| 69 | } |
| 70 | |
| 71 | SOCKADDR_INET GnsPortTrackerChannel::ConvertPortRequestToSockAddr(_In_ const LX_GNS_PORT_ALLOCATION_REQUEST* portAllocationRequest) |
| 72 | { |
| 73 | SOCKADDR_INET address{}; |
| 74 | |
| 75 | address.si_family = static_cast<uint16_t>(portAllocationRequest->Af); |
| 76 | |
| 77 | if (portAllocationRequest->Af == AF_INET) |
| 78 | { |
| 79 | IN_ADDR ipv4Addr{}; |
| 80 | ipv4Addr.S_un.S_addr = portAllocationRequest->Address32[0]; |
| 81 | IN4ADDR_SETSOCKADDR(&address.Ipv4, &ipv4Addr, portAllocationRequest->Port); |
| 82 | } |
| 83 | else |
| 84 | { |
| 85 | IN6_ADDR ipv6Addr{}; |
| 86 | // Copy 16 bytes that represent IPv6 address |
| 87 | memcpy(&ipv6Addr.u, portAllocationRequest->Address32, sizeof(portAllocationRequest->Address32)); |
| 88 | IN6ADDR_SETSOCKADDR(&address.Ipv6, &ipv6Addr, SCOPEID_UNSPECIFIED_INIT, portAllocationRequest->Port); |
| 89 | } |
| 90 | |
| 91 | return address; |
| 92 | } |