mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-12 14:48:49 +00:00
fix pings?
This commit is contained in:
@@ -35,8 +35,8 @@ namespace {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Network::Type::STREAM:
|
case Network::Type::STREAM:
|
||||||
case Network::Type::SEQPACKET:
|
case Network::Type::SEQPACKET:
|
||||||
case Network::Type::RAW:
|
|
||||||
return true;
|
return true;
|
||||||
|
case Network::Type::RAW:
|
||||||
case Network::Type::DGRAM:
|
case Network::Type::DGRAM:
|
||||||
case Network::Type::RDM:
|
case Network::Type::RDM:
|
||||||
case Network::Type::Unspecified:
|
case Network::Type::Unspecified:
|
||||||
@@ -562,6 +562,7 @@ std::pair<s32, Network::Errno> BSD::SocketImpl(Network::Domain domain, Network::
|
|||||||
if ((protocol != Network::Protocol::ICMP && protocol != Network::Protocol::ICMPV6)
|
if ((protocol != Network::Protocol::ICMP && protocol != Network::Protocol::ICMPV6)
|
||||||
&& (room_member && room_member->IsConnected())) {
|
&& (room_member && room_member->IsConnected())) {
|
||||||
descriptor.socket = std::make_shared<Network::ProxySocket>();
|
descriptor.socket = std::make_shared<Network::ProxySocket>();
|
||||||
|
descriptor.socket->fd = fd;
|
||||||
} else {
|
} else {
|
||||||
descriptor.socket = std::make_shared<Network::Socket>();
|
descriptor.socket = std::make_shared<Network::Socket>();
|
||||||
}
|
}
|
||||||
@@ -573,9 +574,9 @@ std::pair<s32, Network::Errno> BSD::SocketImpl(Network::Domain domain, Network::
|
|||||||
&& (protocol == Network::Protocol::ICMP || protocol == Network::Protocol::ICMPV6)) {
|
&& (protocol == Network::Protocol::ICMP || protocol == Network::Protocol::ICMPV6)) {
|
||||||
LOG_WARNING(Network, "Using ICMP emulated socket");
|
LOG_WARNING(Network, "Using ICMP emulated socket");
|
||||||
descriptor.socket = std::make_shared<Network::IcmpSocket>();
|
descriptor.socket = std::make_shared<Network::IcmpSocket>();
|
||||||
|
descriptor.socket->fd = fd;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
descriptor.is_connection_based = IsConnectionBased(type);
|
descriptor.is_connection_based = IsConnectionBased(type);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (descriptor.is_connection_based && descriptor.socket->fd == INVALID_SOCKET) {
|
if (descriptor.is_connection_based && descriptor.socket->fd == INVALID_SOCKET) {
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include <cstdio>
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#ifdef __unix__
|
||||||
|
#include <spawn.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "core/internal_network/socket_icmp.h"
|
#include "core/internal_network/socket_icmp.h"
|
||||||
|
|
||||||
#ifdef __unix__
|
extern "C" {
|
||||||
#include <unistd.h>
|
extern char **environ;
|
||||||
#include <sys/socket.h>
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
@@ -31,8 +39,6 @@ u16 ComputeChecksum(std::span<const u8> data) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IcmpSocket::IcmpSocket() noexcept {}
|
|
||||||
|
|
||||||
IcmpSocket::~IcmpSocket() {
|
IcmpSocket::~IcmpSocket() {
|
||||||
if (fd == INVALID_SOCKET) {
|
if (fd == INVALID_SOCKET) {
|
||||||
return;
|
return;
|
||||||
@@ -61,6 +67,7 @@ std::pair<IcmpSocket::AcceptResult, Errno> IcmpSocket::Accept() {
|
|||||||
|
|
||||||
Errno IcmpSocket::Connect(Network::SockAddrIn addr_in) {
|
Errno IcmpSocket::Connect(Network::SockAddrIn addr_in) {
|
||||||
LOG_WARNING(Network, "(stubbed) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
|
connected_addr = addr_in;
|
||||||
return Errno::E_SUCCESS;
|
return Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,47 +98,69 @@ Errno IcmpSocket::Shutdown(ShutdownHow how) {
|
|||||||
|
|
||||||
std::pair<s32, Errno> IcmpSocket::Recv(int flags, std::span<u8> message) {
|
std::pair<s32, Errno> IcmpSocket::Recv(int flags, std::span<u8> message) {
|
||||||
LOG_DEBUG(Network, "(stubbed) called");
|
LOG_DEBUG(Network, "(stubbed) called");
|
||||||
return {s32(0), Errno::E_NOTCONN};
|
return connected_addr.has_value()
|
||||||
|
? RecvFrom(flags, message, nullptr)
|
||||||
|
: std::make_pair(s32(0), Errno::E_NOTCONN);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> IcmpSocket::RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) {
|
std::pair<s32, Errno> IcmpSocket::RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) {
|
||||||
LOG_DEBUG(Network, "(stubbed) called");
|
LOG_DEBUG(Network, "(stubbed) called");
|
||||||
ASSERT(flags == 0);
|
ASSERT(flags == 0);
|
||||||
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||||
|
|
||||||
#if !defined(__OPENORBIS__) && (defined(__FreeBSD__) || defined(__linux__))
|
#if !defined(__OPENORBIS__) && (defined(__FreeBSD__) || defined(__linux__))
|
||||||
if (addr) {
|
const auto rcv_timeout_ms = (s64(rcv_timeo.tv_sec) * 1000) + (s64(rcv_timeo.tv_usec) / 1000);
|
||||||
if (seq_ident.empty())
|
const auto timestamp = std::chrono::steady_clock::now();
|
||||||
return {0, Errno::E_SUCCESS};
|
while (true) {
|
||||||
// PLEASE DON'T KILL ME, I SWEAR THIS IS LEGITIMATELY THE BEST WAY TO DO IT
|
{
|
||||||
// IF YOU OPEN socket() GOOGLE WILL STRAIGHT UP IP BAN YOU AFTER 2 HOURS
|
std::lock_guard guard(pings_mutex);
|
||||||
auto rcv_time = f64(std::min<u64>(rcv_timeo.tv_sec, 600)) + f64(std::min<u64>(rcv_timeo.tv_usec, 1000000)) * f64(1.0 / 1000000.0);
|
// find ping process that is finished running
|
||||||
if (!std::isfinite(rcv_time) || std::isnan(rcv_time))
|
for (auto it = pings.begin(); it != pings.end();) {
|
||||||
rcv_time = 1.0;
|
pid_t result = waitpid(it->ping_pid, &it->ping_status, WNOHANG);
|
||||||
#ifdef __FreeBSD__
|
// ping process is still running, go to next
|
||||||
auto const cmd = fmt::format("ping -W {} -o {}.{}.{}.{}", rcv_time, addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3]);
|
if (result != it->ping_pid) {
|
||||||
#elif defined(__linux__)
|
++it;
|
||||||
auto const cmd = fmt::format("ping -W {} -c 1 {}.{}.{}.{}", rcv_time, addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3]);
|
continue;
|
||||||
#endif
|
}
|
||||||
if (::system(cmd.c_str()) == 0) {
|
// ping process is finished, remove and handle it
|
||||||
std::vector<u8> data{
|
it = pings.erase(it);
|
||||||
8,
|
if (it->ping_status == 0) {
|
||||||
0,
|
if (addr) {
|
||||||
0, //checksum
|
addr->family = it->family;
|
||||||
0,
|
addr->ip = it->ip;
|
||||||
u8(seq_ident.front() >> 24), //ident
|
addr->portno = it->portno;
|
||||||
u8(seq_ident.front() >> 16),
|
addr->len = 16;
|
||||||
u8(seq_ident.front() >> 8), // seq
|
addr->zeroes = {};
|
||||||
u8(seq_ident.front() >> 0),
|
}
|
||||||
};
|
std::array<u8, 8> data{
|
||||||
seq_ident.pop_back();
|
0,
|
||||||
auto const csum = ComputeChecksum(std::span<const u8>{data.begin(), data.end()});
|
0,
|
||||||
data[2] = u8(csum >> 8); //hi
|
0, //checksum
|
||||||
data[3] = u8(csum); //lo
|
0,
|
||||||
auto const n = (std::max)(data.size(), message.size());
|
it->seq_ident[0],
|
||||||
std::copy(data.begin(), data.begin() + n, message.begin());
|
it->seq_ident[1],
|
||||||
return {n, Errno::E_SUCCESS};
|
it->seq_ident[2],
|
||||||
|
it->seq_ident[3]
|
||||||
|
};
|
||||||
|
auto const csum = ComputeChecksum(std::span<const u8>{data.begin(), data.end()});
|
||||||
|
data[2] = u8(csum >> 8); //hi
|
||||||
|
data[3] = u8(csum); //lo
|
||||||
|
auto const n = std::min(data.size(), message.size());
|
||||||
|
std::copy(data.begin(), data.begin() + n, message.begin());
|
||||||
|
return {s32(n), Errno::E_SUCCESS};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {-1, Errno::E_TIMEDOUT};
|
|
||||||
|
if (!blocking)
|
||||||
|
return {-1, Errno::E_AGAIN};
|
||||||
|
|
||||||
|
const auto time_diff = std::chrono::steady_clock::now() - timestamp;
|
||||||
|
const auto time_diff_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
|
||||||
|
if (time_diff_ms > rcv_timeout_ms)
|
||||||
|
return {-1, Errno::E_TIMEDOUT};
|
||||||
|
|
||||||
|
std::this_thread::yield();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return {-1, Errno::E_INVAL};
|
return {-1, Errno::E_INVAL};
|
||||||
@@ -139,12 +168,8 @@ std::pair<s32, Errno> IcmpSocket::RecvFrom(int flags, std::span<u8> message, Net
|
|||||||
|
|
||||||
std::pair<s32, Errno> IcmpSocket::Send(std::span<const u8> message, int flags) {
|
std::pair<s32, Errno> IcmpSocket::Send(std::span<const u8> message, int flags) {
|
||||||
LOG_DEBUG(Network, "(stubbed) called");
|
LOG_DEBUG(Network, "(stubbed) called");
|
||||||
seq_ident.push_back(
|
if (connected_addr.has_value())
|
||||||
(u32(message[4]) << 24)
|
return SendTo(flags, message, std::addressof(connected_addr.value()));
|
||||||
| (u32(message[5]) << 16)
|
|
||||||
| (u32(message[6]) << 8)
|
|
||||||
| (u32(message[7]) << 0)
|
|
||||||
);
|
|
||||||
return {s32(0), Errno::E_NOTCONN};
|
return {s32(0), Errno::E_NOTCONN};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,8 +181,73 @@ std::pair<s32, Errno> IcmpSocket::SendTo(u32 flags, std::span<const u8> message,
|
|||||||
// 2..4 -> checksum
|
// 2..4 -> checksum
|
||||||
// 4..6 -> ident
|
// 4..6 -> ident
|
||||||
// 6..8 -> seq
|
// 6..8 -> seq
|
||||||
if (!message.empty())
|
|
||||||
|
// PLEASE DON'T KILL ME, I SWEAR THIS IS LEGITIMATELY THE BEST WAY TO DO IT
|
||||||
|
// IF YOU OPEN socket() GOOGLE WILL STRAIGHT UP IP BAN YOU AFTER 2 HOURS
|
||||||
|
#if !defined(__OPENORBIS__) && (defined(__FreeBSD__) || defined(__linux__))
|
||||||
|
const auto rcv_timeout_ms = (s64(rcv_timeo.tv_sec) * 1000) + (s64(rcv_timeo.tv_usec) / 1000);
|
||||||
|
if (!addr)
|
||||||
|
return {-1, Errno::E_DESTADDRREQ};
|
||||||
|
|
||||||
|
if (message.size() >= 8) {
|
||||||
|
std::string ip_str = fmt::format(
|
||||||
|
"{}.{}.{}.{}",
|
||||||
|
addr->ip[0],
|
||||||
|
addr->ip[1],
|
||||||
|
addr->ip[2],
|
||||||
|
addr->ip[3]
|
||||||
|
);
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
// ping -W option is a nonfractional int (milliseconds)
|
||||||
|
std::string timeout_str = fmt::format("{}", rcv_timeout_ms);
|
||||||
|
std::vector<char*> argv = {
|
||||||
|
const_cast<char*>("ping"),
|
||||||
|
const_cast<char*>("-c"),
|
||||||
|
const_cast<char*>("1"),
|
||||||
|
const_cast<char*>("-W"),
|
||||||
|
timeout_str.data(),
|
||||||
|
ip_str.data(),
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
#elif defined(__linux__)
|
||||||
|
// ping -W option is a fractional float (seconds)
|
||||||
|
auto const rcv_timeout_s = f64(rcv_timeout_ms) / 1000.0;
|
||||||
|
std::string timeout_str = fmt::format("{}", rcv_timeout_s);
|
||||||
|
std::vector<char*> argv = {
|
||||||
|
const_cast<char*>("ping"),
|
||||||
|
const_cast<char*>("-c"),
|
||||||
|
const_cast<char*>("1"),
|
||||||
|
const_cast<char*>("-W"),
|
||||||
|
timeout_str.data(),
|
||||||
|
ip_str.data(),
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
pid_t ping_pid;
|
||||||
|
// we should pass in attributes to stop stdout spam, but im too lazy to figure that out
|
||||||
|
if (posix_spawnp(&ping_pid, "ping", nullptr, nullptr, argv.data(), environ) != 0) {
|
||||||
|
LOG_ERROR(Network, "Unable to start ping process for emulated ICMP socket");
|
||||||
|
return {-1, Errno::E_INVAL};
|
||||||
|
}
|
||||||
|
std::lock_guard guard(pings_mutex);
|
||||||
|
if (pings.size() >= pings.max_size())
|
||||||
|
pings.erase(pings.begin());
|
||||||
|
pings.push_back(PingProcessData{
|
||||||
|
.ip = addr->ip,
|
||||||
|
.portno = addr->portno,
|
||||||
|
.ping_pid = ping_pid,
|
||||||
|
.ping_status = 0,
|
||||||
|
.seq_ident = {
|
||||||
|
message[4],
|
||||||
|
message[5],
|
||||||
|
message[6],
|
||||||
|
message[7]
|
||||||
|
},
|
||||||
|
.family = addr->family,
|
||||||
|
});
|
||||||
return {s32(message.size()), Errno::E_SUCCESS};
|
return {s32(message.size()), Errno::E_SUCCESS};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return {-1, Errno::E_INVAL};
|
return {-1, Errno::E_INVAL};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +270,7 @@ void IcmpSocket::HandleProxyPacket(const ProxyPacket& packet) {
|
|||||||
LOG_WARNING(Network, "(stubbed) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
}
|
}
|
||||||
Errno IcmpSocket::SetNonBlock(bool enable) {
|
Errno IcmpSocket::SetNonBlock(bool enable) {
|
||||||
|
blocking = !enable;
|
||||||
return Errno::E_SUCCESS;
|
return Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,29 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <utility>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <boost/container/static_vector.hpp>
|
||||||
#include "core/internal_network/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "core/internal_network/sockets.h"
|
#include "core/internal_network/sockets.h"
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
|
struct PingProcessData {
|
||||||
|
IPv4Address ip;
|
||||||
|
u16 portno;
|
||||||
|
pid_t ping_pid;
|
||||||
|
pid_t ping_status;
|
||||||
|
std::array<u8, 4> seq_ident;
|
||||||
|
u8 family;
|
||||||
|
};
|
||||||
|
|
||||||
class IcmpSocket : public Network::SocketBase {
|
class IcmpSocket : public Network::SocketBase {
|
||||||
public:
|
public:
|
||||||
explicit IcmpSocket() noexcept;
|
explicit IcmpSocket() noexcept = default;
|
||||||
~IcmpSocket() override;
|
~IcmpSocket() override;
|
||||||
Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
|
Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
|
||||||
Errno Close() override;
|
Errno Close() override;
|
||||||
@@ -32,8 +46,11 @@ public:
|
|||||||
void HandleProxyPacket(const ProxyPacket& packet) override;
|
void HandleProxyPacket(const ProxyPacket& packet) override;
|
||||||
Errno SetNonBlock(bool enable) override;
|
Errno SetNonBlock(bool enable) override;
|
||||||
|
|
||||||
std::vector<u32> seq_ident;
|
boost::container::static_vector<PingProcessData, 128> pings;
|
||||||
|
std::optional<SockAddrIn> connected_addr;
|
||||||
|
std::mutex pings_mutex;
|
||||||
Network::Timeval rcv_timeo;
|
Network::Timeval rcv_timeo;
|
||||||
|
bool blocking = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Network
|
} // namespace Network
|
||||||
|
|||||||
Reference in New Issue
Block a user