diff --git a/Makefile b/Makefile index f39c5c2..a87b4ae 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ CXXSRC=\ src/ChunkManager.cpp\ src/BuddyManager.cpp\ src/GroupManager.cpp\ + src/Monitor.cpp\ # headers (for timestamp purposes) CHDR=\ @@ -88,6 +89,7 @@ CXXHDR=\ src/ChunkManager.hpp\ src/BuddyManager.hpp\ src/GroupManager.hpp\ + src/Monitor.hpp\ COBJ=$(CSRC:.c=.o) CXXOBJ=$(CXXSRC:.cpp=.o) diff --git a/src/Monitor.cpp b/src/Monitor.cpp new file mode 100644 index 0000000..6058933 --- /dev/null +++ b/src/Monitor.cpp @@ -0,0 +1,127 @@ +#include "CNShardServer.hpp" +#include "PlayerManager.hpp" +#include "CNStructs.hpp" +#include "Monitor.hpp" + +#include + +static int listener; +static std::mutex sockLock; // guards socket list +static std::list sockets; +static sockaddr_in address; + +// runs during init +void Monitor::init() { + listener = socket(AF_INET, SOCK_STREAM, 0); + if (listener < 0) { + perror("socket"); + exit(1); + } + + int opt = 1; + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + perror("setsockopt"); + exit(1); + } + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(8003); + + if (bind(listener, (struct sockaddr*)&address, sizeof(address)) < 0) { + perror("bind"); + exit(1); + } + + if (listen(listener, SOMAXCONN) < 0) { + perror("listen"); + exit(1); + } + + std::cout << "[INFO] Monitor listening on *:8003" << std::endl; + + REGISTER_SHARD_TIMER(tick, 5000); +} + +// XXX +static bool transmit(std::list::iterator it, char *buff, int len) { + int n = 0; + int sock = *it; + + while (n < len) { + n = send(sock, buff+n, len-n, 0); + if (n < 0) { + perror("send"); + close(sock); + it = sockets.erase(it); + return false; + } + } + + return true; +} + +// runs in shard thread +void Monitor::tick(CNServer *serv, time_t delta) { + std::lock_guard lock(sockLock); + char buff[256]; + int n; + + auto it = sockets.begin(); + while (it != sockets.end()) { + int sock = *it; + + n = send(sock, "begin\n", 6, 0); + if (n < 0) { + perror("send"); + close(sock); + it = sockets.erase(it); + continue; + } + + for (auto& pair : PlayerManager::players) { + n = std::snprintf(buff, sizeof(buff), "player %d %d %s\n", + pair.second->x, pair.second->y, + PlayerManager::getPlayerName(pair.second, false).c_str()); + + n = send(sock, buff, n, 0); + if (n < 0) { + perror("send"); + close(sock); + it = sockets.erase(it); + continue; + } + } + + n = send(sock, "end\n", 4, 0); + if (n < 0) { + perror("send"); + close(sock); + it = sockets.erase(it); + continue; + } + + it++; + } +} + +// runs in monitor thread +void Monitor::start(void *unused) { + socklen_t len = sizeof(address); + + for (;;) { + int sock = accept(listener, (struct sockaddr*)&address, &len); + if (sock < 0) { + perror("accept"); + continue; + } + + std::cout << "[INFO] New monitor connection from " << inet_ntoa(address.sin_addr) << std::endl; + + { + std::lock_guard lock(sockLock); + + sockets.push_back(sock); + } + } +} diff --git a/src/Monitor.hpp b/src/Monitor.hpp new file mode 100644 index 0000000..c654b5a --- /dev/null +++ b/src/Monitor.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "CNProtocol.hpp" + +#include +#include + +namespace Monitor { + void init(); + void tick(CNServer *, time_t); + void start(void *); +}; diff --git a/src/main.cpp b/src/main.cpp index f00dadd..ee9220f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "TableData.hpp" #include "ChunkManager.hpp" #include "GroupManager.hpp" +#include "Monitor.hpp" #include "settings.hpp" @@ -37,6 +38,8 @@ CNShardServer *shardServer = nullptr; std::thread *shardThread = nullptr; +std::thread *monitorThread = nullptr; + void startShard(CNShardServer* server) { server->start(); } @@ -101,6 +104,7 @@ int main() { TransportManager::init(); BuddyManager::init(); GroupManager::init(); + Monitor::init(); Database::open(); switch (settings::EVENTMODE) { @@ -119,6 +123,7 @@ int main() { shardServer = new CNShardServer(settings::SHARDPORT); shardThread = new std::thread(startShard, (CNShardServer*)shardServer); + monitorThread = new std::thread(Monitor::start, nullptr); loginServer.start();