Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix CLI/Network: Detached thread made trouble #88

Merged
merged 5 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion include/GEngine/libdev/Systems.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
#pragma once

#include "GEngine/libdev/systems/AutoKiller.hpp"
#include "GEngine/libdev/systems/CLI.hpp"
#include "GEngine/libdev/systems/Collisions.hpp"
#include "GEngine/libdev/systems/Logger.hpp"
#include "GEngine/libdev/systems/MainLoop.hpp"
#include "GEngine/libdev/systems/Motions.hpp"

/* TODO: Thomas: these includes should never exists, it should be the developer to get them individually */
namespace gengine::system {
class CLI;
}

namespace geg::system {
using AutoKiller = gengine::system::AutoKiller;

Expand Down
13 changes: 13 additions & 0 deletions include/GEngine/libdev/systems/CLI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#include "GEngine/libdev/systems/events/CLI.hpp"
#include "GEngine/libdev/systems/events/MainLoop.hpp"
#include "GEngine/libdev/systems/events/Native.hpp"
#include "GEngine/net/events/socket_event.hpp"
#include "GEngine/net/net_socket_system.hpp"
#include "GEngine/net/net_wait.hpp"

#include <atomic>
#include <chrono>
Expand All @@ -36,10 +39,20 @@ class CLI : public gengine::System<CLI> {
private:
void getInputs(void);
std::vector<std::string> splitInput(const std::string &input);
void processOutput(void);

Network::NetWait m_wait;
Network::Event::SocketEvent m_socketEventStop;
Network::SocketSTD m_socketSTD;

std::thread m_inputThread;
std::atomic_bool m_stopReading;
std::atomic_bool m_stopProgram; /* due to EOF */
std::vector<std::string> m_userInputHistory;
mutable std::mutex m_historyMutex;

#ifdef NET_USE_HANDLE
DWORD m_dwMod;
#endif
};
} // namespace gengine::system
4 changes: 4 additions & 0 deletions include/GEngine/net/net.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ class NET {
return mg_client.getRecord();
}

static NetWait &getWaitHandler(void) {
return mg_wait;
}

public:
/* todo : temp*/
static SocketUDP &getSocketUdp(void) {
Expand Down
2 changes: 1 addition & 1 deletion include/GEngine/net/net_event.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct Info : public InfoHeader {
*/
class Manager {
public:
Manager() = default;
Manager();
~Manager() = default;

template <typename T>
Expand Down
45 changes: 45 additions & 0 deletions include/GEngine/net/net_socket_system.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
** EPITECH PROJECT, 2024
** GameEngine
** File description:
** net_system_socket
*/

#pragma once

#include "net_socket.hpp"

#include <string>

namespace Network {

#ifdef _WIN32
#define STD_IN STD_INPUT_HANDLE
#define STD_OUT STD_OUTPUT_HANDLE
#define STD_ERR STD_ERROR_HANDLE
#else
#define STD_IN STDIN_FILENO
#define STD_OUT STDOUT_FILENO
#define STD_ERR STDERR_FILENO
#endif

class SocketSTD : public ASocket {
public:
SocketSTD() = default;
SocketSTD(int stdNumber);
SocketSTD(const SocketSTD &other) = delete;
SocketSTD &operator=(const SocketSTD &) = delete;
SocketSTD(SocketSTD &&other);
SocketSTD &operator=(SocketSTD &&other);
~SocketSTD() = default;

int read(std::string &buffer) const;
int write(const std::string &buffer) const;

int socketClose(void) override final {
return socketCloseAdv(false);
}

void setStd(int stdNumber);
};
} // namespace Network
23 changes: 13 additions & 10 deletions include/GEngine/net/net_wait.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class NetWaitSet {
m_resIndex = res;
}

bool applyCallback(void) const;
bool applyCallback(bool shouldReset = true) const;

private:
static constexpr size_t MAX_SOCKETS = MAXIMUM_WAIT_OBJECTS;
Expand Down Expand Up @@ -90,24 +90,27 @@ class NetWait {
NetWait();
virtual ~NetWait() = default;

/**
* @brief Waits for a specified amount of time or until an event occurs in the NetWaitSet.
*
* @param ms The maximum number of milliseconds to wait.
* @param set The NetWaitSet to monitor for events.
* @return true if an event occurred within the specified time, false if the timeout was reached.
*/
bool wait(uint32_t ms, NetWaitSet &set);

public:
static void addSocketPool(ASocket &socket);
static void removeSocketPool(const ASocket &socket);
void addSocketPool(ASocket &socket);
void removeSocketPool(const ASocket &socket);

#ifdef NET_USE_HANDLE

#else
public:
static SOCKET getHighestSocket(void) {
SOCKET getHighestSocket(void) {
return m_highFd;
}

private:
static fd_set m_fdSet;
static SOCKET m_highFd;
#endif
fd_set m_fdSet;
SOCKET m_highFd = -1;
};

} // namespace Network
81 changes: 74 additions & 7 deletions source/GEngine/libdev/systems/CLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

#include "GEngine/libdev/systems/CLI.hpp"

#include "GEngine/net/events/socket_event.hpp"
#include "GEngine/net/net_socket_system.hpp"
#include "GEngine/net/net_wait.hpp"

namespace gengine::system {

CLI::CLI()
: m_stopReading(false) {
}
Expand All @@ -19,32 +24,94 @@ void CLI::init(void) {
}

void CLI::onStartEngine(gengine::system::event::StartEngine &e [[maybe_unused]]) {
m_socketSTD.setStd(STD_IN);
#ifndef NET_USE_HANDLE
m_wait.addSocketPool(m_socketSTD);
m_wait.addSocketPool(m_socketEventStop);
#endif
m_inputThread = std::thread(&CLI::getInputs, this);
m_inputThread.detach();
}

void CLI::onStopEngine(gengine::system::event::StopEngine &e [[maybe_unused]]) {
m_stopReading = true;

m_socketEventStop.signal();

#ifdef NET_USE_HANDLE
SetConsoleMode(m_socketSTD.getHandle(), m_dwMod);
#endif

if (m_inputThread.joinable())
m_inputThread.join();
}

void CLI::onMainLoop(gengine::system::event::MainLoop &e [[maybe_unused]]) {
std::lock_guard<std::mutex> lock(m_historyMutex);
if (m_stopProgram) {
publishEvent(gengine::system::event::StopMainLoop());
return;
}

for (const auto &entry : m_userInputHistory)
publishEvent(gengine::system::event::CLINewInput(splitInput(entry)));
m_userInputHistory.clear();
}

void CLI::getInputs(void) {
void CLI::processOutput(void) {
std::string input;

auto &res = std::getline(std::cin, input);
if (res.eof()) {
m_stopProgram = true;
m_stopReading = true;
return;
}

if (!input.empty()) {
std::lock_guard<std::mutex> lock(m_historyMutex);
m_userInputHistory.push_back(input);
}

/* ugly way of output a > once it's printed */
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

void CLI::getInputs(void) {
#ifdef NET_USE_HANDLE
GetConsoleMode(m_socketSTD.getHandle(), &m_dwMod);

DWORD fdwMode = m_dwMod & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
SetConsoleMode(m_socketSTD.getHandle(), fdwMode);

/* flush to remove existing events */
FlushConsoleInputBuffer(m_socketSTD.getHandle());
#endif
while (!m_stopReading) {
Network::NetWaitSet set;

set.setAlert(m_socketEventStop, [this]() {
/* do nothing, just loopback since the thread must be killed */
return true;
});

set.setAlert(m_socketSTD, [this]() {
processOutput();
return true;
});

std::cout << "> " << std::flush;
if (std::getline(std::cin, input)) {
std::lock_guard<std::mutex> lock(m_historyMutex);
m_userInputHistory.push_back(input);
} else
bool hasActivity = m_wait.wait(1000000000, set);
if (!hasActivity)
continue;

#ifdef NET_USE_HANDLE
set.applyCallback(false);
#else
if (set.isSignaled(m_socketEventStop)) /**/
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (set.isSignaled(m_socketSTD))
processOutput();
#endif
}
}

Expand Down
3 changes: 2 additions & 1 deletion source/GEngine/libdev/systems/driver/output/VoIPAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ void VoIPAudio::processSoundInput(void) {

VoIPAudio::~VoIPAudio() {
m_running = false;
m_soundThread.join();
if (m_soundThread.joinable())
m_soundThread.join();

auto err = Pa_StopStream(playbackStream);
err = Pa_CloseStream(playbackStream);
Expand Down
16 changes: 8 additions & 8 deletions source/GEngine/net/cl_net_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,17 +211,17 @@ void CLNetClient::getPingResponse(const UDPMessage &msg, const Address &addr) {
msg.readData<UDPSV_PingResponse>(data);

std::unique_ptr<Address> addrPtr;
if (addr.getType() == AT_IPV4)
uint16_t port = -1;
if (addr.getType() == AT_IPV4) {
addrPtr = std::make_unique<AddressV4>(static_cast<const AddressV4 &>(addr));
else if (addr.getType() == AT_IPV6)
port = data.tcpv4Port;
} else if (addr.getType() == AT_IPV6) {
addrPtr = std::make_unique<AddressV6>(static_cast<const AddressV6 &>(addr));
port = data.tcpv6Port;
}

Event::PingInfo pinginfo = {addrPtr->toString(),
addrPtr->getPort(),
data.currentPlayers,
data.maxPlayers,
data.os,
Time::Clock::milliseconds() - m_pingSendTime};
Event::PingInfo pinginfo = {addrPtr->toString(), port, data.currentPlayers,
data.maxPlayers, data.os, Time::Clock::milliseconds() - m_pingSendTime};
NET::getEventManager().invokeCallbacks(Event::CT_OnPingResult, pinginfo);

m_pingedServers.push_back({data, std::move(addrPtr)});
Expand Down
3 changes: 1 addition & 2 deletions source/GEngine/net/events/net_socket_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#include "GEngine/net/events/socket_event.hpp"
#include "GEngine/net/net_exception.hpp"
#include "GEngine/net/net_wait.hpp"

#include <stdexcept>

Expand Down Expand Up @@ -44,7 +43,7 @@ SocketEvent::SocketEvent() {
if (m_sock == -1)
throw NetException("Failed to create eventfd", EL_ERR_SOCKET);
#endif
NetWait::addSocketPool(*this);

#else
m_handle = CreateEvent(NULL, TRUE, FALSE, NULL);
#endif
Expand Down
7 changes: 5 additions & 2 deletions source/GEngine/net/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ namespace Network {

/* Global vars */

NetWait NET::mg_wait;

SocketUDP NET::mg_socketUdp;
SocketTCPMaster NET::mg_socketListenTcp;
SocketUDP NET::mg_socketUdpV6;
SocketTCPMaster NET::mg_socketListenTcpV6;

NetWait NET::mg_wait;
Event::Manager NET::mg_eventManager;
NetServer NET::mg_server(mg_socketUdp, mg_socketUdpV6);
CLNetClient NET::mg_client(CVar::net_ipv6.getIntValue() ? mg_socketUdpV6 : mg_socketUdp,
Expand Down Expand Up @@ -156,7 +157,9 @@ void NET::stop(void) {

auto &eventManager = NET::getEventManager();
eventManager.getSocketEvent().signal();
mg_networkThread.join();
if (mg_networkThread.joinable())
mg_networkThread.join();

/* end of network thread */

NET::mg_server.stop();
Expand Down
6 changes: 6 additions & 0 deletions source/GEngine/net/net_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
#include "GEngine/net/net.hpp"

namespace Network::Event {
Manager::Manager() {
#ifndef NET_USE_HANDLE
NET::getWaitHandler().addSocketPool(m_socketEvent);
#endif
}

void Manager::createSets(NetWaitSet &set) {
set.setAlert(m_socketEvent, [this]() { return handleEvent(); });
}
Expand Down
Loading