Refactor network implementations to be more reusable and less buggy (#2107)

encapsulate network interfaces
This commit is contained in:
Jesse Talavera
2024-08-01 16:02:45 -04:00
committed by GitHub
parent c6bf5d5181
commit 327ce45124
20 changed files with 715 additions and 439 deletions

View File

@ -19,13 +19,20 @@
#ifndef NET_PCAP_H
#define NET_PCAP_H
#include <functional>
#include <memory>
#include <optional>
#include <string_view>
#include <vector>
#include <pcap/pcap.h>
#include "types.h"
#include "Platform.h"
#include "NetDriver.h"
namespace Net_PCap
namespace melonDS
{
using namespace melonDS;
struct AdapterData
{
char DeviceName[128];
@ -34,19 +41,95 @@ struct AdapterData
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);
extern AdapterData* Adapters;
extern int NumAdapters;
class Net_PCap;
class LibPCap
{
public:
static std::optional<LibPCap> New() noexcept;
LibPCap(const LibPCap&) = delete;
LibPCap& operator=(const LibPCap&) = delete;
LibPCap(LibPCap&&) noexcept;
LibPCap& operator=(LibPCap&&) noexcept;
~LibPCap() noexcept = default;
bool InitAdapterList();
bool Init(std::string_view devicename);
void DeInit();
[[nodiscard]] std::unique_ptr<Net_PCap> Open(std::string_view devicename, const Platform::SendPacketCallback& handler) const noexcept;
[[nodiscard]] std::unique_ptr<Net_PCap> Open(const AdapterData& device, const Platform::SendPacketCallback& handler) const noexcept;
int SendPacket(u8* data, int len);
void RecvCheck();
// 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<Platform::DynamicLibrary> 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<AdapterData> 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<Platform::DynamicLibrary> PCapLib = nullptr;
pcap_close_t close = nullptr;
pcap_sendpacket_t sendpacket = nullptr;
pcap_dispatch_t dispatch = nullptr;
};
}