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