]> git.localhorst.tv Git - blank.git/blob - src/net/net.cpp
give unique IDs to entities
[blank.git] / src / net / net.cpp
1 #include "Client.hpp"
2 #include "Connection.hpp"
3 #include "ConnectionHandler.hpp"
4 #include "io.hpp"
5 #include "Packet.hpp"
6 #include "Server.hpp"
7
8 #include "../app/init.hpp"
9 #include "../world/World.hpp"
10
11 #include <cstring>
12 #include <iostream>
13
14 using namespace std;
15
16
17 namespace blank {
18
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;
23
24 namespace {
25
26 UDPsocket client_bind(Uint16 port) {
27         UDPsocket sock = SDLNet_UDP_Open(port);
28         if (!sock) {
29                 throw NetError("SDLNet_UDP_Open");
30         }
31         return sock;
32 }
33
34 IPaddress client_resolve(const char *host, Uint16 port) {
35         IPaddress addr;
36         if (SDLNet_ResolveHost(&addr, host, port) != 0) {
37                 throw NetError("SDLNet_ResolveHost");
38         }
39         return addr;
40 }
41
42 }
43
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
51         SendPing();
52 }
53
54 Client::~Client() {
55         delete[] client_pack.data;
56         SDLNet_UDP_Close(client_sock);
57 }
58
59
60 void Client::Handle() {
61         int result = SDLNet_UDP_Recv(client_sock, &client_pack);
62         while (result > 0) {
63                 HandlePacket(client_pack);
64                 result = SDLNet_UDP_Recv(client_sock, &client_pack);
65         }
66         if (result == -1) {
67                 // a boo boo happened
68                 throw NetError("SDLNet_UDP_Recv");
69         }
70 }
71
72 void Client::HandlePacket(const UDPpacket &udp_pack) {
73         if (!conn.Matches(udp_pack.address)) {
74                 // packet came from somewhere else, drop
75                 return;
76         }
77         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
78         if (pack.header.tag != Packet::TAG) {
79                 // mistagged packet, drop
80                 return;
81         }
82
83         conn.Received(udp_pack);
84 }
85
86 void Client::Update(int dt) {
87         conn.Update(dt);
88         if (conn.ShouldPing()) {
89                 SendPing();
90         }
91 }
92
93 uint16_t Client::SendPing() {
94         return conn.SendPing(client_pack, client_sock);
95 }
96
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);
101 }
102
103
104 Connection::Connection(const IPaddress &addr)
105 : handler(nullptr)
106 , addr(addr)
107 , send_timer(500)
108 , recv_timer(10000)
109 , ctrl_out{ 0, 0xFFFF, 0xFFFFFFFF }
110 , ctrl_in{ 0, 0xFFFF, 0xFFFFFFFF }
111 , closed(false) {
112         send_timer.Start();
113         recv_timer.Start();
114 }
115
116 bool Connection::Matches(const IPaddress &remote) const noexcept {
117         return memcmp(&addr, &remote, sizeof(IPaddress)) == 0;
118 }
119
120 void Connection::FlagSend() noexcept {
121         send_timer.Reset();
122 }
123
124 void Connection::FlagRecv() noexcept {
125         recv_timer.Reset();
126 }
127
128 bool Connection::ShouldPing() const noexcept {
129         return !closed && send_timer.HitOnce();
130 }
131
132 bool Connection::TimedOut() const noexcept {
133         return recv_timer.HitOnce();
134 }
135
136 void Connection::Update(int dt) {
137         send_timer.Update(dt);
138         recv_timer.Update(dt);
139         if (TimedOut()) {
140                 Close();
141                 if (HasHandler()) {
142                         Handler().OnTimeout();
143                 }
144         }
145 }
146
147
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++;
152
153         udp_pack.address = addr;
154         if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
155                 throw NetError("SDLNet_UDP_Send");
156         }
157
158         FlagSend();
159         return seq;
160 }
161
162 void Connection::Received(const UDPpacket &udp_pack) {
163         Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
164
165         // ack to the remote
166         int16_t diff = int16_t(pack.header.ctrl.seq) - int16_t(ctrl_out.ack);
167         if (diff > 0) {
168                 if (diff >= 32) {
169                         ctrl_out.hist = 0;
170                 } else {
171                         ctrl_out.hist <<= diff;
172                         ctrl_out.hist |= 1 << (diff - 1);
173                 }
174         } else if (diff < 0 && diff >= -32) {
175                 ctrl_out.hist |= 1 << (-diff - 1);
176         }
177         ctrl_out.ack = pack.header.ctrl.seq;
178         FlagRecv();
179
180         if (!HasHandler()) {
181                 return;
182         }
183
184         Packet::TControl ctrl_new = pack.header.ctrl;
185         Handler().Handle(udp_pack);
186
187         if (diff > 0) {
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…
192                 if (diff > 0) {
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);
196                                 }
197                         }
198                 }
199                 ctrl_in = ctrl_new;
200         }
201 }
202
203 uint16_t Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
204         Packet::Make<Packet::Ping>(udp_pack);
205         return Send(udp_pack, sock);
206 }
207
208
209 ostream &operator <<(ostream &out, const IPaddress &addr) {
210         const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
211         out << int(host[0])
212                 << '.' << int(host[1])
213                 << '.' << int(host[2])
214                 << '.' << int(host[3]);
215         if (addr.port) {
216                 out << ':' << SDLNet_Read16(&addr.port);
217         }
218         return out;
219 }
220
221
222 const char *Packet::Type2String(uint8_t t) noexcept {
223         switch (t) {
224                 case Ping::TYPE:
225                         return "Ping";
226                 case Login::TYPE:
227                         return "Login";
228                 case Join::TYPE:
229                         return "Join";
230                 case Part::TYPE:
231                         return "Part";
232                 default:
233                         return "Unknown";
234         }
235 }
236
237 template<class T>
238 void Packet::Payload::Write(const T &src, size_t off) noexcept {
239         if ((length - off) < sizeof(T)) {
240                 // dismiss out of bounds write
241                 return;
242         }
243         *reinterpret_cast<T *>(&data[off]) = src;
244 }
245
246 template<class T>
247 void Packet::Payload::Read(T &dst, size_t off) const noexcept {
248         if ((length - off) < sizeof(T)) {
249                 // dismiss out of bounds read
250                 return;
251         }
252         dst = *reinterpret_cast<T *>(&data[off]);
253 }
254
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());
261         } else {
262                 memcpy(dst, src.c_str(), len);
263         }
264 }
265
266 void Packet::Payload::ReadString(string &dst, size_t off, size_t maxlen) const noexcept {
267         size_t len = min(maxlen, length - off);
268         dst.clear();
269         dst.reserve(len);
270         for (size_t i = 0; i < len && data[off + i] != '\0'; ++i) {
271                 dst.push_back(data[off + i]);
272         }
273 }
274
275
276 void Packet::Login::WritePlayerName(const string &name) noexcept {
277         WriteString(name, 0, 32);
278 }
279
280 void Packet::Login::ReadPlayerName(string &name) const noexcept {
281         ReadString(name, 0, 32);
282 }
283
284 void Packet::Join::WritePlayer(const Entity &player) noexcept {
285         Write(player.ID(), 0);
286         Write(player.ChunkCoords(), 4);
287         Write(player.Position(), 16);
288         Write(player.Velocity(), 28);
289         Write(player.Orientation(), 40);
290         Write(player.AngularVelocity(), 56);
291 }
292
293 void Packet::Join::ReadPlayerID(uint32_t &id) const noexcept {
294         Read(id, 0);
295 }
296
297 void Packet::Join::ReadPlayer(Entity &player) const noexcept {
298         glm::ivec3 chunk_coords(0);
299         glm::vec3 pos;
300         glm::vec3 vel;
301         glm::quat rot;
302         glm::vec3 ang;
303
304         Read(chunk_coords, 4);
305         Read(pos, 16);
306         Read(vel, 28);
307         Read(rot, 40);
308         Read(ang, 56);
309
310         player.Position(chunk_coords, pos);
311         player.Velocity(vel);
312         player.Orientation(rot);
313         player.AngularVelocity(ang);
314 }
315
316 void Packet::Join::WriteWorldName(const string &name) noexcept {
317         WriteString(name, 68, 32);
318 }
319
320 void Packet::Join::ReadWorldName(string &name) const noexcept {
321         ReadString(name, 68, 32);
322 }
323
324
325 void ConnectionHandler::Handle(const UDPpacket &udp_pack) {
326         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
327         switch (pack.Type()) {
328                 case Packet::Ping::TYPE:
329                         On(Packet::As<Packet::Ping>(udp_pack));
330                         break;
331                 case Packet::Login::TYPE:
332                         On(Packet::As<Packet::Login>(udp_pack));
333                         break;
334                 case Packet::Join::TYPE:
335                         On(Packet::As<Packet::Join>(udp_pack));
336                         break;
337                 case Packet::Part::TYPE:
338                         On(Packet::As<Packet::Part>(udp_pack));
339                         break;
340                 default:
341                         // drop unknown or unhandled packets
342                         break;
343         }
344 }
345
346
347 Server::Server(const Config &conf, World &world)
348 : serv_sock(nullptr)
349 , serv_pack{ -1, nullptr, 0 }
350 , clients()
351 , world(world) {
352         serv_sock = SDLNet_UDP_Open(conf.port);
353         if (!serv_sock) {
354                 throw NetError("SDLNet_UDP_Open");
355         }
356
357         serv_pack.data = new Uint8[sizeof(Packet)];
358         serv_pack.maxlen = sizeof(Packet);
359 }
360
361 Server::~Server() {
362         delete[] serv_pack.data;
363         SDLNet_UDP_Close(serv_sock);
364 }
365
366
367 void Server::Handle() {
368         int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
369         while (result > 0) {
370                 HandlePacket(serv_pack);
371                 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
372         }
373         if (result == -1) {
374                 // a boo boo happened
375                 throw NetError("SDLNet_UDP_Recv");
376         }
377 }
378
379 void Server::HandlePacket(const UDPpacket &udp_pack) {
380         if (udp_pack.len < int(sizeof(Packet::Header))) {
381                 // packet too small, drop
382                 return;
383         }
384         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
385         if (pack.header.tag != Packet::TAG) {
386                 // mistagged packet, drop
387                 return;
388         }
389
390         Connection &client = GetClient(udp_pack.address);
391         client.Received(udp_pack);
392
393         switch (pack.header.type) {
394                 case Packet::Login::TYPE:
395                         HandleLogin(client, udp_pack);
396                         break;
397                 case Packet::Part::TYPE:
398                         HandlePart(client, udp_pack);
399                         break;
400                 default:
401                         // just drop packets of unknown or unhandled type
402                         break;
403         }
404 }
405
406 Connection &Server::GetClient(const IPaddress &addr) {
407         for (Connection &client : clients) {
408                 if (client.Matches(addr)) {
409                         return client;
410                 }
411         }
412         clients.emplace_back(addr);
413         OnConnect(clients.back());
414         return clients.back();
415 }
416
417 void Server::OnConnect(Connection &client) {
418         cout << "new connection from " << client.Address() << endl;
419         // tell it we're alive
420         client.SendPing(serv_pack, serv_sock);
421 }
422
423 void Server::Update(int dt) {
424         for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
425                 client->Update(dt);
426                 if (client->Closed()) {
427                         OnDisconnect(*client);
428                         client = clients.erase(client);
429                 } else {
430                         if (client->ShouldPing()) {
431                                 client->SendPing(serv_pack, serv_sock);
432                         }
433                         ++client;
434                 }
435         }
436 }
437
438 void Server::OnDisconnect(Connection &client) {
439         cout << "connection timeout from " << client.Address() << endl;
440 }
441
442
443 void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
444         auto pack = Packet::As<Packet::Login>(udp_pack);
445
446         string name;
447         pack.ReadPlayerName(name);
448
449         Entity *player = world.AddPlayer(name);
450
451         if (player) {
452                 // success!
453                 cout << "accepted login from player \"" << name << '"' << endl;
454                 auto response = Packet::Make<Packet::Join>(serv_pack);
455                 response.WritePlayer(*player);
456                 response.WriteWorldName(world.Name());
457                 client.Send(serv_pack, serv_sock);
458         } else {
459                 // aw no :(
460                 cout << "rejected login from player \"" << name << '"' << endl;
461                 Packet::Make<Packet::Part>(serv_pack);
462                 client.Send(serv_pack, serv_sock);
463                 client.Close();
464         }
465 }
466
467 void Server::HandlePart(Connection &client, const UDPpacket &udp_pack) {
468         client.Close();
469 }
470
471 }