2 #include "Connection.hpp"
5 #include "PacketHandler.hpp"
8 #include "../app/init.hpp"
9 #include "../world/World.hpp"
21 UDPsocket client_bind(Uint16 port) {
22 UDPsocket sock = SDLNet_UDP_Open(port);
24 throw NetError("SDLNet_UDP_Open");
29 IPaddress client_resolve(const char *host, Uint16 port) {
31 if (SDLNet_ResolveHost(&addr, host, port) != 0) {
32 throw NetError("SDLNet_ResolveHost");
39 Client::Client(const Config &conf)
40 : conn(client_resolve(conf.host.c_str(), conf.port))
41 , client_sock(client_bind(0))
42 , client_pack{ -1, nullptr, 0 } {
43 client_pack.data = new Uint8[sizeof(Packet)];
44 client_pack.maxlen = sizeof(Packet);
45 // establish connection
50 delete[] client_pack.data;
51 SDLNet_UDP_Close(client_sock);
55 void Client::Handle() {
56 int result = SDLNet_UDP_Recv(client_sock, &client_pack);
58 HandlePacket(client_pack);
59 result = SDLNet_UDP_Recv(client_sock, &client_pack);
63 throw NetError("SDLNet_UDP_Recv");
67 void Client::HandlePacket(const UDPpacket &udp_pack) {
68 if (!conn.Matches(udp_pack.address)) {
69 // packet came from somewhere else, drop
72 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
73 if (pack.header.tag != Packet::TAG) {
74 // mistagged packet, drop
78 conn.Received(udp_pack);
81 void Client::Update(int dt) {
83 if (conn.TimedOut()) {
84 cout << "connection timed out :(" << endl;
85 } else if (conn.ShouldPing()) {
90 void Client::SendPing() {
91 conn.SendPing(client_pack, client_sock);
94 void Client::SendLogin(const string &name) {
95 auto pack = Packet::Make<Packet::Login>(client_pack);
96 pack.WritePlayerName(name);
97 conn.Send(client_pack, client_sock);
101 Connection::Connection(const IPaddress &addr)
106 , ctrl{ 0, 0xFFFF, 0xFFFF }
112 bool Connection::Matches(const IPaddress &remote) const noexcept {
113 return memcmp(&addr, &remote, sizeof(IPaddress)) == 0;
116 void Connection::FlagSend() noexcept {
120 void Connection::FlagRecv() noexcept {
124 bool Connection::ShouldPing() const noexcept {
125 return send_timer.HitOnce();
128 bool Connection::TimedOut() const noexcept {
129 return recv_timer.HitOnce();
132 void Connection::Update(int dt) {
133 send_timer.Update(dt);
134 recv_timer.Update(dt);
138 void Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
139 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
140 pack.header.ctrl = ctrl;
143 cout << "sending " << pack.TypeString() << " to " << Address() << endl;
145 udp_pack.address = addr;
146 if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
147 throw NetError("SDLNet_UDP_Send");
153 void Connection::Received(const UDPpacket &udp_pack) {
154 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
156 cout << "received " << pack.TypeString() << " from " << Address() << endl;
158 int diff = std::int16_t(pack.header.ctrl.seq) - std::int16_t(ctrl.ack);
161 // incoming more recent than last acked
163 // TODO: packets considered lost are detected here
164 // this should have ones for all of them:
165 // ~hist & ((1 << dist) - 1) if dist is < 32
168 // missed more than the last 32 oO
172 ctrl.hist |= 1 << (32 - diff);
174 } else if (diff < 0) {
175 // incoming older than acked
179 ctrl.hist |= 1 << (32 + diff);
182 // incoming the same as last acked oO
185 ctrl.ack = pack.header.ctrl.seq;
188 Handler().Handle(udp_pack);
194 void Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
195 Packet::Make<Packet::Ping>(udp_pack);
196 Send(udp_pack, sock);
200 ostream &operator <<(ostream &out, const IPaddress &addr) {
201 const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
203 << '.' << int(host[1])
204 << '.' << int(host[2])
205 << '.' << int(host[3]);
207 out << ':' << SDLNet_Read16(&addr.port);
213 const char *Packet::Type2String(uint8_t t) noexcept {
229 void Packet::Payload::Write(const T &src, size_t off) noexcept {
230 if ((length - off) < sizeof(T)) {
231 // dismiss out of bounds write
234 *reinterpret_cast<T *>(&data[off]) = src;
238 void Packet::Payload::Read(T &dst, size_t off) const noexcept {
239 if ((length - off) < sizeof(T)) {
240 // dismiss out of bounds read
243 dst = *reinterpret_cast<T *>(&data[off]);
246 void Packet::Payload::WriteString(const string &src, size_t off, size_t maxlen) noexcept {
247 uint8_t *dst = &data[off];
248 size_t len = min(maxlen, length - off);
249 if (src.size() < len) {
250 memset(dst, '\0', len);
251 memcpy(dst, src.c_str(), src.size());
253 memcpy(dst, src.c_str(), len);
257 void Packet::Payload::ReadString(string &dst, size_t off, size_t maxlen) const noexcept {
258 size_t len = min(maxlen, length - off);
261 for (size_t i = 0; i < len && data[off + i] != '\0'; ++i) {
262 dst.push_back(data[off + i]);
267 void Packet::Login::WritePlayerName(const string &name) noexcept {
268 WriteString(name, 0, 32);
271 void Packet::Login::ReadPlayerName(string &name) const noexcept {
272 ReadString(name, 0, 32);
275 void Packet::Join::WritePlayer(const Entity &player) noexcept {
276 // TODO: generate entity IDs
277 Write(uint32_t(1), 0);
278 Write(player.ChunkCoords(), 4);
279 Write(player.Position(), 16);
280 Write(player.Velocity(), 28);
281 Write(player.Orientation(), 40);
282 Write(player.AngularVelocity(), 56);
285 void Packet::Join::ReadPlayer(Entity &player) const noexcept {
287 glm::ivec3 chunk_coords(0);
294 Read(chunk_coords, 4);
300 player.Position(chunk_coords, pos);
301 player.Velocity(vel);
302 player.Orientation(rot);
303 player.AngularVelocity(ang);
306 void Packet::Join::WriteWorldName(const string &name) noexcept {
307 WriteString(name, 68, 32);
310 void Packet::Join::ReadWorldName(string &name) const noexcept {
311 ReadString(name, 68, 32);
315 void PacketHandler::Handle(const UDPpacket &udp_pack) {
316 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
317 switch (pack.Type()) {
318 case Packet::Ping::TYPE:
319 On(Packet::As<Packet::Ping>(udp_pack));
321 case Packet::Login::TYPE:
322 On(Packet::As<Packet::Login>(udp_pack));
324 case Packet::Join::TYPE:
325 On(Packet::As<Packet::Join>(udp_pack));
327 case Packet::Part::TYPE:
328 On(Packet::As<Packet::Part>(udp_pack));
331 // drop unknown or unhandled packets
337 Server::Server(const Config &conf, World &world)
339 , serv_pack{ -1, nullptr, 0 }
342 serv_sock = SDLNet_UDP_Open(conf.port);
344 throw NetError("SDLNet_UDP_Open");
347 serv_pack.data = new Uint8[sizeof(Packet)];
348 serv_pack.maxlen = sizeof(Packet);
352 delete[] serv_pack.data;
353 SDLNet_UDP_Close(serv_sock);
357 void Server::Handle() {
358 int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
360 HandlePacket(serv_pack);
361 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
364 // a boo boo happened
365 throw NetError("SDLNet_UDP_Recv");
369 void Server::HandlePacket(const UDPpacket &udp_pack) {
370 if (udp_pack.len < int(sizeof(Packet::Header))) {
371 // packet too small, drop
374 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
375 if (pack.header.tag != Packet::TAG) {
376 // mistagged packet, drop
380 Connection &client = GetClient(udp_pack.address);
381 client.Received(udp_pack);
383 switch (pack.header.type) {
384 case Packet::Login::TYPE:
385 HandleLogin(client, udp_pack);
387 case Packet::Part::TYPE:
388 HandlePart(client, udp_pack);
391 // just drop packets of unknown or unhandled type
396 Connection &Server::GetClient(const IPaddress &addr) {
397 for (Connection &client : clients) {
398 if (client.Matches(addr)) {
402 clients.emplace_back(addr);
403 OnConnect(clients.back());
404 return clients.back();
407 void Server::OnConnect(Connection &client) {
408 cout << "new connection from " << client.Address() << endl;
409 // tell it we're alive
410 client.SendPing(serv_pack, serv_sock);
413 void Server::Update(int dt) {
414 for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
416 if (client->Closed()) {
417 OnDisconnect(*client);
418 client = clients.erase(client);
420 if (client->ShouldPing()) {
421 client->SendPing(serv_pack, serv_sock);
428 void Server::OnDisconnect(Connection &client) {
429 cout << "connection timeout from " << client.Address() << endl;
433 void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
434 auto pack = Packet::As<Packet::Login>(udp_pack);
437 pack.ReadPlayerName(name);
439 Entity *player = world.AddPlayer(name);
443 cout << "accepted login from player \"" << name << '"' << endl;
444 auto response = Packet::Make<Packet::Join>(serv_pack);
445 response.WritePlayer(*player);
446 response.WriteWorldName(world.Name());
447 client.Send(serv_pack, serv_sock);
450 cout << "rejected login from player \"" << name << '"' << endl;
451 Packet::Make<Packet::Part>(serv_pack);
452 client.Send(serv_pack, serv_sock);
457 void Server::HandlePart(Connection &client, const UDPpacket &udp_pack) {