mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-12-23 04:10:06 +00:00
[refactor] Move files to core/ and servers/ subdirectories
CNProtocol, CNShared, CNStructs and Defines are now in core/. CNLoginServer, CNShardServer and Monitor are now in servers/. core/Core.hpp wraps all the core headers except for CNShared.hpp. Defines.cpp has been renamed to Packets.cpp, and so has its corresponding namespace, but not the header file. This is in preparation for upcoming changes.
This commit is contained in:
166
src/servers/Monitor.cpp
Normal file
166
src/servers/Monitor.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "servers/CNShardServer.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "Chat.hpp"
|
||||
#include "servers/Monitor.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
static SOCKET listener;
|
||||
static std::mutex sockLock; // guards socket list
|
||||
static std::list<SOCKET> sockets;
|
||||
static sockaddr_in address;
|
||||
|
||||
static bool transmit(std::list<SOCKET>::iterator& it, char *buff, int len) {
|
||||
int n = 0;
|
||||
int sock = *it;
|
||||
|
||||
while (n < len) {
|
||||
n += send(sock, buff+n, len-n, 0);
|
||||
if (SOCKETERROR(n)) {
|
||||
printSocketError("send");
|
||||
|
||||
#ifdef _WIN32
|
||||
shutdown(sock, SD_BOTH);
|
||||
closesocket(sock);
|
||||
#else
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
#endif
|
||||
|
||||
std::cout << "[INFO] Disconnected a monitor" << std::endl;
|
||||
|
||||
it = sockets.erase(it);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void tick(CNServer *serv, time_t delta) {
|
||||
std::lock_guard<std::mutex> lock(sockLock);
|
||||
char buff[256];
|
||||
int n;
|
||||
|
||||
auto it = sockets.begin();
|
||||
outer:
|
||||
while (it != sockets.end()) {
|
||||
if (!transmit(it, (char*)"begin\n", 6))
|
||||
continue;
|
||||
|
||||
// player
|
||||
for (auto& pair : PlayerManager::players) {
|
||||
if (pair.second->hidden)
|
||||
continue;
|
||||
|
||||
n = std::snprintf(buff, sizeof(buff), "player %d %d %s\n",
|
||||
pair.second->x, pair.second->y,
|
||||
PlayerManager::getPlayerName(pair.second, false).c_str());
|
||||
|
||||
if (!transmit(it, buff, n))
|
||||
goto outer;
|
||||
}
|
||||
|
||||
// chat
|
||||
for (auto& str : Chat::dump) {
|
||||
n = std::snprintf(buff, sizeof(buff), "chat %s\n", str.c_str());
|
||||
|
||||
if (!transmit(it, buff, n))
|
||||
goto outer;
|
||||
}
|
||||
|
||||
if (!transmit(it, (char*)"end\n", 4))
|
||||
continue;
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
Chat::dump.clear();
|
||||
}
|
||||
|
||||
bool Monitor::acceptConnection(SOCKET fd, uint16_t revents) {
|
||||
socklen_t len = sizeof(address);
|
||||
|
||||
if (!settings::MONITORENABLED)
|
||||
return false;
|
||||
|
||||
if (fd != listener)
|
||||
return false;
|
||||
|
||||
if (revents & ~POLLIN) {
|
||||
std::cout << "[FATAL] Error on monitor listener?" << std::endl;
|
||||
terminate(0);
|
||||
}
|
||||
|
||||
int sock = accept(listener, (struct sockaddr*)&address, &len);
|
||||
if (SOCKETERROR(sock)) {
|
||||
printSocketError("accept");
|
||||
return true;
|
||||
}
|
||||
|
||||
setSockNonblocking(listener, sock);
|
||||
|
||||
std::cout << "[INFO] New monitor connection from " << inet_ntoa(address.sin_addr) << std::endl;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(sockLock);
|
||||
|
||||
sockets.push_back(sock);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SOCKET Monitor::init() {
|
||||
listener = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (SOCKETERROR(listener)) {
|
||||
std::cout << "Failed to create monitor socket" << std::endl;
|
||||
printSocketError("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const char opt = 1;
|
||||
#else
|
||||
int opt = 1;
|
||||
#endif
|
||||
if (SOCKETERROR(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))) {
|
||||
std::cout << "Failed to set SO_REUSEADDR on monitor socket" << std::endl;
|
||||
printSocketError("setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(settings::MONITORPORT);
|
||||
|
||||
if (SOCKETERROR(bind(listener, (struct sockaddr*)&address, sizeof(address)))) {
|
||||
std::cout << "Failed to bind to monitor port" << std::endl;
|
||||
printSocketError("bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (SOCKETERROR(listen(listener, SOMAXCONN))) {
|
||||
std::cout << "Failed to listen on monitor port" << std::endl;
|
||||
printSocketError("listen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned long mode = 1;
|
||||
if (ioctlsocket(listener, FIONBIO, &mode) != 0) {
|
||||
#else
|
||||
if (fcntl(listener, F_SETFL, (fcntl(listener, F_GETFL, 0) | O_NONBLOCK)) != 0) {
|
||||
#endif
|
||||
std::cerr << "[FATAL] OpenFusion: fcntl failed" << std::endl;
|
||||
printSocketError("fcntl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::cout << "Monitor listening on *:" << settings::MONITORPORT << std::endl;
|
||||
|
||||
REGISTER_SHARD_TIMER(tick, settings::MONITORINTERVAL);
|
||||
|
||||
return listener;
|
||||
}
|
||||
Reference in New Issue
Block a user