/* Copyright 2016-2024 melonDS team This file is part of melonDS. melonDS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. melonDS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with melonDS. If not, see http://www.gnu.org/licenses/. */ #ifndef NET_PCAP_H #define NET_PCAP_H #include #include #include #include #include #include #include "types.h" #include "Platform.h" #include "NetDriver.h" namespace melonDS { struct AdapterData { char DeviceName[128]; char FriendlyName[128]; char Description[128]; u8 MAC[6]; u8 IP_v4[4]; /// The flags on the pcap_if_t that was used to populate this struct u32 Flags; }; typedef int (*pcap_findalldevs_t)(pcap_if_t** alldevs, char* errbuf); typedef void (*pcap_freealldevs_t)(pcap_if_t* alldevs); typedef pcap_t* (*pcap_open_live_t)(const char* src, int snaplen, int flags, int readtimeout, char* errbuf); typedef void (*pcap_close_t)(pcap_t* dev); typedef int (*pcap_setnonblock_t)(pcap_t* dev, int nonblock, char* errbuf); typedef int (*pcap_sendpacket_t)(pcap_t* dev, const u_char* data, int len); typedef int (*pcap_dispatch_t)(pcap_t* dev, int num, pcap_handler callback, u_char* data); typedef const u_char* (*pcap_next_t)(pcap_t* dev, struct pcap_pkthdr* hdr); class Net_PCap; class LibPCap { public: static std::optional New() noexcept; LibPCap(const LibPCap&) = delete; LibPCap& operator=(const LibPCap&) = delete; LibPCap(LibPCap&&) noexcept; LibPCap& operator=(LibPCap&&) noexcept; ~LibPCap() noexcept = default; [[nodiscard]] std::unique_ptr Open(std::string_view devicename, const Platform::SendPacketCallback& handler) const noexcept; [[nodiscard]] std::unique_ptr Open(const AdapterData& device, const Platform::SendPacketCallback& handler) const noexcept; // so that Net_PCap objects can safely outlive LibPCap // (because the actual DLL will be kept loaded until no shared_ptrs remain) std::shared_ptr PCapLib = nullptr; pcap_findalldevs_t findalldevs = nullptr; pcap_freealldevs_t freealldevs = nullptr; pcap_open_live_t open_live = nullptr; pcap_close_t close = nullptr; pcap_setnonblock_t setnonblock = nullptr; pcap_sendpacket_t sendpacket = nullptr; pcap_dispatch_t dispatch = nullptr; pcap_next_t next = nullptr; [[nodiscard]] bool IsValid() const noexcept { return PCapLib != nullptr && findalldevs != nullptr && freealldevs != nullptr && open_live != nullptr && close != nullptr && setnonblock != nullptr && sendpacket != nullptr && dispatch != nullptr && next != nullptr ; } /// @return List of all network interfaces available at the time of the call [[nodiscard]] std::vector GetAdapters() const noexcept; private: static bool TryLoadPCap(LibPCap& pcap, Platform::DynamicLibrary *lib) noexcept; LibPCap() noexcept = default; }; class Net_PCap : public NetDriver { public: Net_PCap() noexcept = default; ~Net_PCap() noexcept override; Net_PCap(const Net_PCap&) = delete; Net_PCap& operator=(const Net_PCap&) = delete; Net_PCap(Net_PCap&& other) noexcept; Net_PCap& operator=(Net_PCap&& other) noexcept; int SendPacket(u8* data, int len) noexcept override; void RecvCheck() noexcept override; private: friend class LibPCap; static void RXCallback(u_char* userdata, const pcap_pkthdr* header, const u_char* data) noexcept; pcap_t* PCapAdapter = nullptr; Platform::SendPacketCallback Callback; // To avoid undefined behavior in case the original LibPCap object is destroyed // before this interface is cleaned up std::shared_ptr PCapLib = nullptr; pcap_close_t close = nullptr; pcap_sendpacket_t sendpacket = nullptr; pcap_dispatch_t dispatch = nullptr; }; } #endif // NET_PCAP_H