Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
ServerNetwork.cpp
Go to the documentation of this file.
1
9#include "RType/Logger.hpp"
10
11namespace rtp::server {
12
14 // Public API
16
18 : _ioContext(),
19 _acceptor(_ioContext, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)),
20 _udpSocket(_ioContext, asio::ip::udp::endpoint(asio::ip::udp::v4(), port)),
21 _nextSessionId(1)
22 {
23 log::info("ServerNetwork initialized on port {}", port);
24 }
25
30
32 {
33 log::info("Starting ServerNetwork...");
34
37
38 _ioThread = std::thread([this]() {
39 try {
40 log::info("ASIO Context running...");
41 auto workGuard = asio::make_work_guard(_ioContext);
42 _ioContext.run();
43 } catch (const std::exception& e) {
44 log::error("ServerNetwork context error: {}", e.what());
45 }
46 });
47 }
48
50 {
51 if (!_ioContext.stopped()) {
52 _ioContext.stop();
53 }
54 if (_ioThread.joinable()) {
55 _ioThread.join();
56 }
57 _acceptor.close();
58 _udpSocket.close();
59 log::info("ServerNetwork stopped.");
60 }
61
62 void ServerNetwork::sendPacket(uint32_t sessionId, const net::Packet& packet, net::NetworkMode mode)
63 {
64 std::lock_guard<std::mutex> lock(_sessionsMutex);
65 auto it = _sessions.find(sessionId);
66 if (it != _sessions.end()) {
67 it->second->send(packet, mode);
68 }
69 }
70
72 {
73 std::lock_guard<std::mutex> lock(_sessionsMutex);
74 for (auto& [id, session] : _sessions) {
75 session->send(packet, mode);
76 }
77 }
78
79 std::optional<net::NetworkEvent> ServerNetwork::pollEvent()
80 {
81 std::lock_guard<std::mutex> lock(_eventQueueMutex);
82 if (_eventQueue.empty()) {
83 return std::nullopt;
84 }
85 auto event = _eventQueue.front();
86 _eventQueue.pop();
87 return event;
88 }
89
91 {
92 std::lock_guard<std::mutex> lock(_eventQueueMutex);
93 _eventQueue.push(event);
94 }
95
97 // Private Implementation
99
101 {
102 auto newSocket = std::make_shared<asio::ip::tcp::socket>(_ioContext);
103
104 _acceptor.async_accept(*newSocket, [this, newSocket](const asio::error_code& error) {
105 if (!error) {
106 uint32_t id = _nextSessionId++;
107 log::info("New connection accepted from {}. Session ID: {}",
108 newSocket->remote_endpoint().address().to_string(), id);
109
110 auto session = std::make_shared<net::Session>(
111 id,
112 std::move(*newSocket),
113 _udpSocket,
114 *this
115 );
116
117 {
118 std::lock_guard<std::mutex> lock(_sessionsMutex);
119 _sessions[id] = session;
120 }
121
122 session->start();
123
125 welcome << id;
126 session->send(welcome, net::NetworkMode::TCP);
127
128 } else {
129 log::error("Accept error: {}", error.message());
130 }
131
133 });
134 }
135
137{
138 _udpSocket.async_receive_from(
139 asio::buffer(_udpBuffer),
141 [this](const asio::error_code& error, std::size_t bytesTransferred)
142 {
143 if (error) {
144 if (error != asio::error::operation_aborted)
145 log::error("UDP receive error: {}", error.message());
147 return;
148 }
149
150 if (bytesTransferred < sizeof(net::Header)) {
152 return;
153 }
154
155 net::Header header;
156 std::memcpy(&header, _udpBuffer.data(), sizeof(header));
157
158 header.magic = net::Packet::from_network(header.magic);
161 header.ackId = net::Packet::from_network(header.ackId);
163
164 if (header.magic != net::MAGIC_NUMBER) {
166 return;
167 }
168
169 if (bytesTransferred != sizeof(net::Header) + header.bodySize) {
170 log::error("Malformed UDP packet (size mismatch) bytes={} expected={}",
171 bytesTransferred, sizeof(net::Header) + header.bodySize);
173 return;
174 }
175
176 if (header.opCode == net::OpCode::Hello) {
177 uint32_t claimedSessionId = header.sessionId;
178
179 {
180 std::lock_guard<std::mutex> lock(_sessionsMutex);
181 auto it = _sessions.find(claimedSessionId);
182 if (it != _sessions.end()) {
183 it->second->setUdpEndpoint(_udpRemoteEndpoint);
184
185 {
186 std::lock_guard<std::mutex> udpLock(_udpMapMutex);
188 }
189
190 log::info("UDP bound: session {} -> {}:{}",
191 claimedSessionId,
192 _udpRemoteEndpoint.address().to_string(),
193 _udpRemoteEndpoint.port());
194 }
195 }
196
198 return;
199 }
200
201 uint32_t realSessionId = 0;
202 {
203 std::lock_guard<std::mutex> lock(_udpMapMutex);
205 if (it == _udpEndpointToSessionId.end()) {
207 return;
208 }
209 realSessionId = it->second;
210 }
211
212 net::Packet packet;
213 header.sessionId = realSessionId;
214 packet.header = header;
215
216 if (header.bodySize > 0) {
217 packet.body.resize(header.bodySize);
218 std::memcpy(packet.body.data(),
219 _udpBuffer.data() + sizeof(net::Header),
220 header.bodySize);
221 }
222
223 publishEvent({ realSessionId, packet });
224
226 }
227 );
228}
229
230
231} // namespace rtp::server
Logger declaration with support for multiple log levels.
Network packet with header and serializable body.
Definition Packet.hpp:471
std::vector< uint8_t > body
Packet body/payload.
Definition Packet.hpp:474
Header header
Packet header.
Definition Packet.hpp:473
static T from_network(T value)
Converts a primitive type (integer, float) from Big-Endian (network) to machine endianness.
Definition Packet.hpp:532
void start(void) override
Start the network server.
void sendPacket(uint32_t sessionId, const net::Packet &packet, net::NetworkMode mode)
Send a packet to a specific session.
std::optional< net::NetworkEvent > pollEvent(void) override
Poll for a network event.
std::mutex _sessionsMutex
Mutex for protecting access to the sessions map.
uint32_t _nextSessionId
Next session ID to assign to a new connection.
std::unordered_map< asio::ip::udp::endpoint, uint32_t > _udpEndpointToSessionId
Map of UDP endpoints to session IDs.
std::mutex _udpMapMutex
Mutex for protecting access to the UDP endpoint map.
void broadcastPacket(const net::Packet &packet, net::NetworkMode mode)
Broadcast a packet to all connected sessions.
asio::ip::tcp::acceptor _acceptor
TCP acceptor for incoming connections.
std::queue< net::NetworkEvent > _eventQueue
Queue of network events to be processed.
std::unordered_map< uint32_t, std::shared_ptr< net::Session > > _sessions
Map of active sessions indexed by session ID.
ServerNetwork(uint16_t port)
Constructor for ServerNetwork.
void publishEvent(net::NetworkEvent event) override
Publish a network event to be processed.
std::array< char, 4096 > _udpBuffer
Buffer for receiving UDP packets.
std::mutex _eventQueueMutex
Mutex for protecting access to the event queue.
asio::ip::udp::endpoint _udpRemoteEndpoint
Remote endpoint for the last received UDP packet.
~ServerNetwork() override
Destructor for ServerNetwork.
asio::ip::udp::socket _udpSocket
UDP socket for receiving and sending datagrams.
void acceptConnection()
Accept incoming TCP connections.
std::thread _ioThread
Thread running the ASIO I/O context.
void receiveUdpPacket()
Receive incoming UDP packets.
asio::io_context _ioContext
ASIO I/O context for managing asynchronous operations.
void stop(void) override
Stop the network server.
void error(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an error message.
void info(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an informational message.
constexpr uint16_t MAGIC_NUMBER
Magic number for packet validation.
Definition Packet.hpp:52
@ Welcome
Server welcome response.
@ Hello
Client hello packet.
NetworkMode
Enum representing network transmission modes.
Definition INetwork.hpp:25
File : GameManager.hpp License: MIT Author : Elias Josué HAJJAR LLAUQUEN elias-josue....
Packet header with sequencing and acknowledgment support.
Definition Packet.hpp:130
uint16_t ackId
Last acknowledged packet.
Definition Packet.hpp:134
uint16_t magic
Magic number for validation.
Definition Packet.hpp:131
uint16_t sequenceId
Packet sequence number.
Definition Packet.hpp:132
uint32_t sessionId
Session identifier.
Definition Packet.hpp:137
uint32_t bodySize
Size of the packet body.
Definition Packet.hpp:133
OpCode opCode
Operation code.
Definition Packet.hpp:135
Represents a network event containing session ID and packet data.
Definition INetwork.hpp:34