Zappy Server
C++ game server: world, rules, scheduler, network
Loading...
Searching...
No Matches
ClientManager.cpp
Go to the documentation of this file.
2
3#include <sys/socket.h>
4
5#include <cerrno>
6#include <cstring>
7#include <stdexcept>
8
9ClientManager::ClientManager(Listener& listener) : _listener(listener) {}
10
12{
13 _pollFds.clear();
14 _fdToId.clear();
15 _pollFds.push_back({_listener.fd(), POLLIN, 0});
16 for (auto& [id, conn] : _connections) {
17 short events = POLLIN | (conn.hasPendingWrite() ? POLLOUT : 0);
18 _pollFds.push_back({conn.fd(), events, 0});
19 _fdToId[conn.fd()] = id;
20 }
21}
22
24{
26
27 int ret = ::poll(_pollFds.data(), static_cast<nfds_t>(_pollFds.size()), timeoutMs);
28
29 if (ret < 0 && errno == EINTR) return {};
30 if (ret < 0) throw std::runtime_error(std::string("poll() failed: ") + strerror(errno));
31
32 PollResult result;
33 if (_pollFds[0].revents & POLLIN) _acceptNew(result);
34 for (size_t i = 1; i < _pollFds.size(); ++i) _handleEvents(_pollFds[i], result);
35 return result;
36}
37
39{
40 int fd = _listener.accept();
41 if (fd < 0) return;
42 int id = _nextId++;
43 _connections.emplace(std::piecewise_construct, std::forward_as_tuple(id),
44 std::forward_as_tuple(fd));
45 result.newConnections.push_back(id);
46 for (auto* obs : _observers) obs->onClientConnected(id);
47}
48
49void ClientManager::_handleEvents(const pollfd& pfd, PollResult& result)
50{
51 if (!pfd.revents) return;
52
53 int id = _fdToId.at(pfd.fd);
54 auto& conn = _connections.at(id);
55
56 if (pfd.revents & POLLIN) {
57 char buf[4096];
58 ssize_t n = ::recv(pfd.fd, buf, sizeof(buf), 0);
59 if (n <= 0) {
60 result.disconnectedIds.push_back(id);
61 return;
62 }
63 conn.appendRead({buf, static_cast<size_t>(n)});
64 while (auto line = conn.nextLine()) {
65 for (auto* obs : _observers) obs->onLineReceived(id, *line);
66 result.lines.emplace_back(id, std::move(*line));
67 }
68 }
69 if (pfd.revents & (POLLHUP | POLLERR)) {
70 result.disconnectedIds.push_back(id);
71 return;
72 }
73 if (pfd.revents & POLLOUT) conn.flushWrite();
74}
75
76void ClientManager::send(int connectionId, const std::string& msg)
77{
78 auto it = _connections.find(connectionId);
79 if (it != _connections.end()) it->second.queueWrite(msg);
80 for (auto* obs : _observers) obs->onLineSent(connectionId, msg);
81}
82
83void ClientManager::disconnect(int connectionId)
84{
85 auto it = _connections.find(connectionId);
86 if (it == _connections.end()) return;
87 it->second.flushWrite();
88 _connections.erase(it);
89 for (auto* obs : _observers) obs->onClientDisconnected(connectionId);
90}
91
93{
94 auto it = _connections.find(connectionId);
95 if (it == _connections.end())
96 throw std::out_of_range("ClientManager::getConnection: unknown id");
97 return it->second;
98}
99
101{
102 _observers.push_back(observer);
103}
static std::string id(int n)
Definition Serializer.cpp:3
static std::string n(int v)
Definition Serializer.cpp:4
void send(int connectionId, const std::string &msg)
Queue msg to be sent to a client (flushed during poll()).
std::unordered_map< int, Connection > _connections
void _acceptNew(PollResult &result)
Connection & getConnection(int connectionId)
Access the underlying Connection (e.g. to set its type/playerId).
void disconnect(int connectionId)
Close a client and drop its connection.
std::vector< INetworkObserver * > _observers
void _handleEvents(const pollfd &pfd, PollResult &result)
Listener & _listener
std::vector< pollfd > _pollFds
PollResult poll(int timeoutMs)
Run one poll cycle (blocks up to timeoutMs); returns this cycle's events.
std::unordered_map< int, int > _fdToId
ClientManager(Listener &listener)
void addNetworkObserver(INetworkObserver *observer)
Subscribe an observer to connect/disconnect/line events.
One client socket plus its read/write buffers.
Observer hooks for raw socket events (Observer pattern).
The server's listening socket.
Definition Listener.hpp:31
int fd() const
The listening socket fd (to register in poll()).
Definition Listener.cpp:43
int accept() const
Accept one pending client; returns its new socket fd.
Definition Listener.cpp:45
std::vector< int > disconnectedIds
std::vector< int > newConnections
std::vector< std::pair< int, std::string > > lines