]> git.localhorst.tv Git - blank.git/blob - src/net/net.cpp
fixed transmission control
[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         // 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);
292 }
293
294 void Packet::Join::ReadPlayer(Entity &player) const noexcept {
295         uint32_t id = 0;
296         glm::ivec3 chunk_coords(0);
297         glm::vec3 pos;
298         glm::vec3 vel;
299         glm::quat rot;
300         glm::vec3 ang;
301
302         Read(id, 0);
303         Read(chunk_coords, 4);
304         Read(pos, 16);
305         Read(vel, 28);
306         Read(rot, 40);
307         Read(ang, 56);
308
309         player.Position(chunk_coords, pos);
310         player.Velocity(vel);
311         player.Orientation(rot);
312         player.AngularVelocity(ang);
313 }
314
315 void Packet::Join::WriteWorldName(const string &name) noexcept {
316         WriteString(name, 68, 32);
317 }
318
319 void Packet::Join::ReadWorldName(string &name) const noexcept {
320         ReadString(name, 68, 32);
321 }
322
323
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));
329                         break;
330                 case Packet::Login::TYPE:
331                         On(Packet::As<Packet::Login>(udp_pack));
332                         break;
333                 case Packet::Join::TYPE:
334                         On(Packet::As<Packet::Join>(udp_pack));
335                         break;
336                 case Packet::Part::TYPE:
337                         On(Packet::As<Packet::Part>(udp_pack));
338                         break;
339                 default:
340                         // drop unknown or unhandled packets
341                         break;
342         }
343 }
344
345
346 Server::Server(const Config &conf, World &world)
347 : serv_sock(nullptr)
348 , serv_pack{ -1, nullptr, 0 }
349 , clients()
350 , world(world) {
351         serv_sock = SDLNet_UDP_Open(conf.port);
352         if (!serv_sock) {
353                 throw NetError("SDLNet_UDP_Open");
354         }
355
356         serv_pack.data = new Uint8[sizeof(Packet)];
357         serv_pack.maxlen = sizeof(Packet);
358 }
359
360 Server::~Server() {
361         delete[] serv_pack.data;
362         SDLNet_UDP_Close(serv_sock);
363 }
364
365
366 void Server::Handle() {
367         int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
368         while (result > 0) {
369                 HandlePacket(serv_pack);
370                 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
371         }
372         if (result == -1) {
373                 // a boo boo happened
374                 throw NetError("SDLNet_UDP_Recv");
375         }
376 }
377
378 void Server::HandlePacket(const UDPpacket &udp_pack) {
379         if (udp_pack.len < int(sizeof(Packet::Header))) {
380                 // packet too small, drop
381                 return;
382         }
383         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
384         if (pack.header.tag != Packet::TAG) {
385                 // mistagged packet, drop
386                 return;
387         }
388
389         Connection &client = GetClient(udp_pack.address);
390         client.Received(udp_pack);
391
392         switch (pack.header.type) {
393                 case Packet::Login::TYPE:
394                         HandleLogin(client, udp_pack);
395                         break;
396                 case Packet::Part::TYPE:
397                         HandlePart(client, udp_pack);
398                         break;
399                 default:
400                         // just drop packets of unknown or unhandled type
401                         break;
402         }
403 }
404
405 Connection &Server::GetClient(const IPaddress &addr) {
406         for (Connection &client : clients) {
407                 if (client.Matches(addr)) {
408                         return client;
409                 }
410         }
411         clients.emplace_back(addr);
412         OnConnect(clients.back());
413         return clients.back();
414 }
415
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);
420 }
421
422 void Server::Update(int dt) {
423         for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
424                 client->Update(dt);
425                 if (client->Closed()) {
426                         OnDisconnect(*client);
427                         client = clients.erase(client);
428                 } else {
429                         if (client->ShouldPing()) {
430                                 client->SendPing(serv_pack, serv_sock);
431                         }
432                         ++client;
433                 }
434         }
435 }
436
437 void Server::OnDisconnect(Connection &client) {
438         cout << "connection timeout from " << client.Address() << endl;
439 }
440
441
442 void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
443         auto pack = Packet::As<Packet::Login>(udp_pack);
444
445         string name;
446         pack.ReadPlayerName(name);
447
448         Entity *player = world.AddPlayer(name);
449
450         if (player) {
451                 // success!
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);
457         } else {
458                 // aw no :(
459                 cout << "rejected login from player \"" << name << '"' << endl;
460                 Packet::Make<Packet::Part>(serv_pack);
461                 client.Send(serv_pack, serv_sock);
462                 client.Close();
463         }
464 }
465
466 void Server::HandlePart(Connection &client, const UDPpacket &udp_pack) {
467         client.Close();
468 }
469
470 }