2 #include "Connection.hpp"
3 #include "ConnectionHandler.hpp"
8 #include "../app/init.hpp"
9 #include "../world/World.hpp"
19 constexpr size_t Packet::Ping::MAX_LEN;
20 constexpr size_t Packet::Login::MAX_LEN;
21 constexpr size_t Packet::Join::MAX_LEN;
22 constexpr size_t Packet::Part::MAX_LEN;
26 UDPsocket client_bind(Uint16 port) {
27 UDPsocket sock = SDLNet_UDP_Open(port);
29 throw NetError("SDLNet_UDP_Open");
34 IPaddress client_resolve(const char *host, Uint16 port) {
36 if (SDLNet_ResolveHost(&addr, host, port) != 0) {
37 throw NetError("SDLNet_ResolveHost");
44 Client::Client(const Config &conf)
45 : conn(client_resolve(conf.host.c_str(), conf.port))
46 , client_sock(client_bind(0))
47 , client_pack{ -1, nullptr, 0 } {
48 client_pack.data = new Uint8[sizeof(Packet)];
49 client_pack.maxlen = sizeof(Packet);
50 // establish connection
55 delete[] client_pack.data;
56 SDLNet_UDP_Close(client_sock);
60 void Client::Handle() {
61 int result = SDLNet_UDP_Recv(client_sock, &client_pack);
63 HandlePacket(client_pack);
64 result = SDLNet_UDP_Recv(client_sock, &client_pack);
68 throw NetError("SDLNet_UDP_Recv");
72 void Client::HandlePacket(const UDPpacket &udp_pack) {
73 if (!conn.Matches(udp_pack.address)) {
74 // packet came from somewhere else, drop
77 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
78 if (pack.header.tag != Packet::TAG) {
79 // mistagged packet, drop
83 conn.Received(udp_pack);
86 void Client::Update(int dt) {
88 if (conn.ShouldPing()) {
93 uint16_t Client::SendPing() {
94 return conn.SendPing(client_pack, client_sock);
97 uint16_t Client::SendLogin(const string &name) {
98 auto pack = Packet::Make<Packet::Login>(client_pack);
99 pack.WritePlayerName(name);
100 return conn.Send(client_pack, client_sock);
104 Connection::Connection(const IPaddress &addr)
109 , ctrl_out{ 0, 0xFFFF, 0xFFFFFFFF }
110 , ctrl_in{ 0, 0xFFFF, 0xFFFFFFFF }
116 bool Connection::Matches(const IPaddress &remote) const noexcept {
117 return memcmp(&addr, &remote, sizeof(IPaddress)) == 0;
120 void Connection::FlagSend() noexcept {
124 void Connection::FlagRecv() noexcept {
128 bool Connection::ShouldPing() const noexcept {
129 return !closed && send_timer.HitOnce();
132 bool Connection::TimedOut() const noexcept {
133 return recv_timer.HitOnce();
136 void Connection::Update(int dt) {
137 send_timer.Update(dt);
138 recv_timer.Update(dt);
142 Handler().OnTimeout();
148 uint16_t Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
149 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
150 pack.header.ctrl = ctrl_out;
151 uint16_t seq = ctrl_out.seq++;
153 udp_pack.address = addr;
154 if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
155 throw NetError("SDLNet_UDP_Send");
162 void Connection::Received(const UDPpacket &udp_pack) {
163 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
166 int16_t diff = int16_t(pack.header.ctrl.seq) - int16_t(ctrl_out.ack);
171 ctrl_out.hist <<= diff;
172 ctrl_out.hist |= 1 << (diff - 1);
174 } else if (diff < 0 && diff >= -32) {
175 ctrl_out.hist |= 1 << (-diff - 1);
177 ctrl_out.ack = pack.header.ctrl.seq;
184 Packet::TControl ctrl_new = pack.header.ctrl;
185 Handler().Handle(udp_pack);
188 // if the packet holds more recent information
189 // check if remote failed to ack one of our packets
190 diff = int16_t(ctrl_new.ack) - int16_t(ctrl_in.ack);
191 // should always be true, but you never know…
193 for (int i = 0; i < diff; ++i) {
194 if (i > 32 || (i < 32 && (ctrl_in.hist & (1 << (31 - i))) == 0)) {
195 Handler().OnPacketLost(ctrl_in.ack - 32 + i);
203 uint16_t Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
204 Packet::Make<Packet::Ping>(udp_pack);
205 return Send(udp_pack, sock);
209 ostream &operator <<(ostream &out, const IPaddress &addr) {
210 const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
212 << '.' << int(host[1])
213 << '.' << int(host[2])
214 << '.' << int(host[3]);
216 out << ':' << SDLNet_Read16(&addr.port);
222 const char *Packet::Type2String(uint8_t t) noexcept {
238 void Packet::Payload::Write(const T &src, size_t off) noexcept {
239 if ((length - off) < sizeof(T)) {
240 // dismiss out of bounds write
243 *reinterpret_cast<T *>(&data[off]) = src;
247 void Packet::Payload::Read(T &dst, size_t off) const noexcept {
248 if ((length - off) < sizeof(T)) {
249 // dismiss out of bounds read
252 dst = *reinterpret_cast<T *>(&data[off]);
255 void Packet::Payload::WriteString(const string &src, size_t off, size_t maxlen) noexcept {
256 uint8_t *dst = &data[off];
257 size_t len = min(maxlen, length - off);
258 if (src.size() < len) {
259 memset(dst, '\0', len);
260 memcpy(dst, src.c_str(), src.size());
262 memcpy(dst, src.c_str(), len);
266 void Packet::Payload::ReadString(string &dst, size_t off, size_t maxlen) const noexcept {
267 size_t len = min(maxlen, length - off);
270 for (size_t i = 0; i < len && data[off + i] != '\0'; ++i) {
271 dst.push_back(data[off + i]);
276 void Packet::Login::WritePlayerName(const string &name) noexcept {
277 WriteString(name, 0, 32);
280 void Packet::Login::ReadPlayerName(string &name) const noexcept {
281 ReadString(name, 0, 32);
284 void Packet::Join::WritePlayer(const Entity &player) noexcept {
285 // TODO: generate entity IDs
286 Write(uint32_t(1), 0);
287 Write(player.ChunkCoords(), 4);
288 Write(player.Position(), 16);
289 Write(player.Velocity(), 28);
290 Write(player.Orientation(), 40);
291 Write(player.AngularVelocity(), 56);
294 void Packet::Join::ReadPlayer(Entity &player) const noexcept {
296 glm::ivec3 chunk_coords(0);
303 Read(chunk_coords, 4);
309 player.Position(chunk_coords, pos);
310 player.Velocity(vel);
311 player.Orientation(rot);
312 player.AngularVelocity(ang);
315 void Packet::Join::WriteWorldName(const string &name) noexcept {
316 WriteString(name, 68, 32);
319 void Packet::Join::ReadWorldName(string &name) const noexcept {
320 ReadString(name, 68, 32);
324 void ConnectionHandler::Handle(const UDPpacket &udp_pack) {
325 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
326 switch (pack.Type()) {
327 case Packet::Ping::TYPE:
328 On(Packet::As<Packet::Ping>(udp_pack));
330 case Packet::Login::TYPE:
331 On(Packet::As<Packet::Login>(udp_pack));
333 case Packet::Join::TYPE:
334 On(Packet::As<Packet::Join>(udp_pack));
336 case Packet::Part::TYPE:
337 On(Packet::As<Packet::Part>(udp_pack));
340 // drop unknown or unhandled packets
346 Server::Server(const Config &conf, World &world)
348 , serv_pack{ -1, nullptr, 0 }
351 serv_sock = SDLNet_UDP_Open(conf.port);
353 throw NetError("SDLNet_UDP_Open");
356 serv_pack.data = new Uint8[sizeof(Packet)];
357 serv_pack.maxlen = sizeof(Packet);
361 delete[] serv_pack.data;
362 SDLNet_UDP_Close(serv_sock);
366 void Server::Handle() {
367 int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
369 HandlePacket(serv_pack);
370 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
373 // a boo boo happened
374 throw NetError("SDLNet_UDP_Recv");
378 void Server::HandlePacket(const UDPpacket &udp_pack) {
379 if (udp_pack.len < int(sizeof(Packet::Header))) {
380 // packet too small, drop
383 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
384 if (pack.header.tag != Packet::TAG) {
385 // mistagged packet, drop
389 Connection &client = GetClient(udp_pack.address);
390 client.Received(udp_pack);
392 switch (pack.header.type) {
393 case Packet::Login::TYPE:
394 HandleLogin(client, udp_pack);
396 case Packet::Part::TYPE:
397 HandlePart(client, udp_pack);
400 // just drop packets of unknown or unhandled type
405 Connection &Server::GetClient(const IPaddress &addr) {
406 for (Connection &client : clients) {
407 if (client.Matches(addr)) {
411 clients.emplace_back(addr);
412 OnConnect(clients.back());
413 return clients.back();
416 void Server::OnConnect(Connection &client) {
417 cout << "new connection from " << client.Address() << endl;
418 // tell it we're alive
419 client.SendPing(serv_pack, serv_sock);
422 void Server::Update(int dt) {
423 for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
425 if (client->Closed()) {
426 OnDisconnect(*client);
427 client = clients.erase(client);
429 if (client->ShouldPing()) {
430 client->SendPing(serv_pack, serv_sock);
437 void Server::OnDisconnect(Connection &client) {
438 cout << "connection timeout from " << client.Address() << endl;
442 void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
443 auto pack = Packet::As<Packet::Login>(udp_pack);
446 pack.ReadPlayerName(name);
448 Entity *player = world.AddPlayer(name);
452 cout << "accepted login from player \"" << name << '"' << endl;
453 auto response = Packet::Make<Packet::Join>(serv_pack);
454 response.WritePlayer(*player);
455 response.WriteWorldName(world.Name());
456 client.Send(serv_pack, serv_sock);
459 cout << "rejected login from player \"" << name << '"' << endl;
460 Packet::Make<Packet::Part>(serv_pack);
461 client.Send(serv_pack, serv_sock);
466 void Server::HandlePart(Connection &client, const UDPpacket &udp_pack) {