2 #include "ClientConnection.hpp"
3 #include "Connection.hpp"
4 #include "ConnectionHandler.hpp"
9 #include "../app/init.hpp"
10 #include "../world/World.hpp"
20 constexpr size_t Packet::Ping::MAX_LEN;
21 constexpr size_t Packet::Login::MAX_LEN;
22 constexpr size_t Packet::Join::MAX_LEN;
23 constexpr size_t Packet::Part::MAX_LEN;
27 UDPsocket client_bind(Uint16 port) {
28 UDPsocket sock = SDLNet_UDP_Open(port);
30 throw NetError("SDLNet_UDP_Open");
35 IPaddress client_resolve(const char *host, Uint16 port) {
37 if (SDLNet_ResolveHost(&addr, host, port) != 0) {
38 throw NetError("SDLNet_ResolveHost");
45 Client::Client(const Config &conf)
46 : conn(client_resolve(conf.host.c_str(), conf.port))
47 , client_sock(client_bind(0))
48 , client_pack{ -1, nullptr, 0 } {
49 client_pack.data = new Uint8[sizeof(Packet)];
50 client_pack.maxlen = sizeof(Packet);
51 // establish connection
56 delete[] client_pack.data;
57 SDLNet_UDP_Close(client_sock);
61 void Client::Handle() {
62 int result = SDLNet_UDP_Recv(client_sock, &client_pack);
64 HandlePacket(client_pack);
65 result = SDLNet_UDP_Recv(client_sock, &client_pack);
69 throw NetError("SDLNet_UDP_Recv");
73 void Client::HandlePacket(const UDPpacket &udp_pack) {
74 if (!conn.Matches(udp_pack.address)) {
75 // packet came from somewhere else, drop
78 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
79 if (pack.header.tag != Packet::TAG) {
80 // mistagged packet, drop
84 conn.Received(udp_pack);
87 void Client::Update(int dt) {
89 if (conn.ShouldPing()) {
94 uint16_t Client::SendPing() {
95 return conn.SendPing(client_pack, client_sock);
98 uint16_t Client::SendLogin(const string &name) {
99 auto pack = Packet::Make<Packet::Login>(client_pack);
100 pack.WritePlayerName(name);
101 return conn.Send(client_pack, client_sock);
105 ClientConnection::ClientConnection(Server &server, const IPaddress &addr)
109 conn.SetHandler(this);
112 ClientConnection::~ClientConnection() {
116 void ClientConnection::Update(int dt) {
118 if (Disconnected()) {
119 cout << "disconnect from " << conn.Address() << endl;
120 } else if (conn.ShouldPing()) {
121 conn.SendPing(server.GetPacket(), server.GetSocket());
125 void ClientConnection::AttachPlayer(Entity &new_player) {
127 player = &new_player;
131 void ClientConnection::DetachPlayer() {
138 void ClientConnection::On(const Packet::Login &pack) {
140 pack.ReadPlayerName(name);
142 Entity *new_player = server.GetWorld().AddPlayer(name);
146 AttachPlayer(*new_player);
147 cout << "accepted login from player \"" << name << '"' << endl;
148 auto response = Packet::Make<Packet::Join>(server.GetPacket());
149 response.WritePlayer(*new_player);
150 response.WriteWorldName(server.GetWorld().Name());
151 conn.Send(server.GetPacket(), server.GetSocket());
154 cout << "rejected login from player \"" << name << '"' << endl;
155 Packet::Make<Packet::Part>(server.GetPacket());
156 conn.Send(server.GetPacket(), server.GetSocket());
161 void ClientConnection::On(const Packet::Part &) {
166 Connection::Connection(const IPaddress &addr)
171 , ctrl_out{ 0, 0xFFFF, 0xFFFFFFFF }
172 , ctrl_in{ 0, 0xFFFF, 0xFFFFFFFF }
178 bool Connection::Matches(const IPaddress &remote) const noexcept {
179 return memcmp(&addr, &remote, sizeof(IPaddress)) == 0;
182 void Connection::FlagSend() noexcept {
186 void Connection::FlagRecv() noexcept {
190 bool Connection::ShouldPing() const noexcept {
191 return !closed && send_timer.HitOnce();
194 bool Connection::TimedOut() const noexcept {
195 return recv_timer.HitOnce();
198 void Connection::Update(int dt) {
199 send_timer.Update(dt);
200 recv_timer.Update(dt);
204 Handler().OnTimeout();
210 uint16_t Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
211 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
212 pack.header.ctrl = ctrl_out;
213 uint16_t seq = ctrl_out.seq++;
215 udp_pack.address = addr;
216 if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
217 throw NetError("SDLNet_UDP_Send");
224 void Connection::Received(const UDPpacket &udp_pack) {
225 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
228 int16_t diff = int16_t(pack.header.ctrl.seq) - int16_t(ctrl_out.ack);
233 ctrl_out.hist <<= diff;
234 ctrl_out.hist |= 1 << (diff - 1);
236 } else if (diff < 0 && diff >= -32) {
237 ctrl_out.hist |= 1 << (-diff - 1);
239 ctrl_out.ack = pack.header.ctrl.seq;
246 Packet::TControl ctrl_new = pack.header.ctrl;
247 Handler().Handle(udp_pack);
250 // if the packet holds more recent information
251 // check if remote failed to ack one of our packets
252 diff = int16_t(ctrl_new.ack) - int16_t(ctrl_in.ack);
253 // should always be true, but you never know…
255 for (int i = 0; i < diff; ++i) {
256 if (i > 32 || (i < 32 && (ctrl_in.hist & (1 << (31 - i))) == 0)) {
257 Handler().OnPacketLost(ctrl_in.ack - 32 + i);
265 uint16_t Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
266 Packet::Make<Packet::Ping>(udp_pack);
267 return Send(udp_pack, sock);
271 ostream &operator <<(ostream &out, const IPaddress &addr) {
272 const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
274 << '.' << int(host[1])
275 << '.' << int(host[2])
276 << '.' << int(host[3]);
278 out << ':' << SDLNet_Read16(&addr.port);
284 const char *Packet::Type2String(uint8_t t) noexcept {
300 void Packet::Payload::Write(const T &src, size_t off) noexcept {
301 if ((length - off) < sizeof(T)) {
302 // dismiss out of bounds write
305 *reinterpret_cast<T *>(&data[off]) = src;
309 void Packet::Payload::Read(T &dst, size_t off) const noexcept {
310 if ((length - off) < sizeof(T)) {
311 // dismiss out of bounds read
314 dst = *reinterpret_cast<T *>(&data[off]);
317 void Packet::Payload::WriteString(const string &src, size_t off, size_t maxlen) noexcept {
318 uint8_t *dst = &data[off];
319 size_t len = min(maxlen, length - off);
320 if (src.size() < len) {
321 memset(dst, '\0', len);
322 memcpy(dst, src.c_str(), src.size());
324 memcpy(dst, src.c_str(), len);
328 void Packet::Payload::ReadString(string &dst, size_t off, size_t maxlen) const noexcept {
329 size_t len = min(maxlen, length - off);
332 for (size_t i = 0; i < len && data[off + i] != '\0'; ++i) {
333 dst.push_back(data[off + i]);
338 void Packet::Login::WritePlayerName(const string &name) noexcept {
339 WriteString(name, 0, 32);
342 void Packet::Login::ReadPlayerName(string &name) const noexcept {
343 ReadString(name, 0, 32);
346 void Packet::Join::WritePlayer(const Entity &player) noexcept {
347 Write(player.ID(), 0);
348 Write(player.ChunkCoords(), 4);
349 Write(player.Position(), 16);
350 Write(player.Velocity(), 28);
351 Write(player.Orientation(), 40);
352 Write(player.AngularVelocity(), 56);
355 void Packet::Join::ReadPlayerID(uint32_t &id) const noexcept {
359 void Packet::Join::ReadPlayer(Entity &player) const noexcept {
360 glm::ivec3 chunk_coords(0);
366 Read(chunk_coords, 4);
372 player.Position(chunk_coords, pos);
373 player.Velocity(vel);
374 player.Orientation(rot);
375 player.AngularVelocity(ang);
378 void Packet::Join::WriteWorldName(const string &name) noexcept {
379 WriteString(name, 68, 32);
382 void Packet::Join::ReadWorldName(string &name) const noexcept {
383 ReadString(name, 68, 32);
387 void ConnectionHandler::Handle(const UDPpacket &udp_pack) {
388 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
389 switch (pack.Type()) {
390 case Packet::Ping::TYPE:
391 On(Packet::As<Packet::Ping>(udp_pack));
393 case Packet::Login::TYPE:
394 On(Packet::As<Packet::Login>(udp_pack));
396 case Packet::Join::TYPE:
397 On(Packet::As<Packet::Join>(udp_pack));
399 case Packet::Part::TYPE:
400 On(Packet::As<Packet::Part>(udp_pack));
403 // drop unknown or unhandled packets
409 Server::Server(const Config &conf, World &world)
411 , serv_pack{ -1, nullptr, 0 }
414 serv_sock = SDLNet_UDP_Open(conf.port);
416 throw NetError("SDLNet_UDP_Open");
419 serv_pack.data = new Uint8[sizeof(Packet)];
420 serv_pack.maxlen = sizeof(Packet);
424 delete[] serv_pack.data;
425 SDLNet_UDP_Close(serv_sock);
429 void Server::Handle() {
430 int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
432 HandlePacket(serv_pack);
433 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
436 // a boo boo happened
437 throw NetError("SDLNet_UDP_Recv");
441 void Server::HandlePacket(const UDPpacket &udp_pack) {
442 if (udp_pack.len < int(sizeof(Packet::Header))) {
443 // packet too small, drop
446 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
447 if (pack.header.tag != Packet::TAG) {
448 // mistagged packet, drop
452 ClientConnection &client = GetClient(udp_pack.address);
453 client.GetConnection().Received(udp_pack);
456 ClientConnection &Server::GetClient(const IPaddress &addr) {
457 for (ClientConnection &client : clients) {
458 if (client.Matches(addr)) {
462 clients.emplace_back(*this, addr);
463 return clients.back();
466 void Server::Update(int dt) {
467 for (list<ClientConnection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
469 if (client->Disconnected()) {
470 client = clients.erase(client);