2 #include "Connection.hpp"
7 #include "../app/init.hpp"
8 #include "../world/World.hpp"
20 UDPsocket client_bind(Uint16 port) {
21 UDPsocket sock = SDLNet_UDP_Open(port);
23 throw NetError("SDLNet_UDP_Open");
28 IPaddress client_resolve(const char *host, Uint16 port) {
30 if (SDLNet_ResolveHost(&addr, host, port) != 0) {
31 throw NetError("SDLNet_ResolveHost");
38 Client::Client(const Config &conf, World &world)
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 Packet &pack = *reinterpret_cast<Packet *>(client_pack.data);
96 client_pack.len = pack.MakeLogin(name);
97 conn.Send(client_pack, client_sock);
101 Connection::Connection(const IPaddress &addr)
105 , ctrl{ 0, 0xFFFF, 0xFFFF }
111 bool Connection::Matches(const IPaddress &remote) const noexcept {
112 return memcmp(&addr, &remote, sizeof(IPaddress)) == 0;
115 void Connection::FlagSend() noexcept {
119 void Connection::FlagRecv() noexcept {
123 bool Connection::ShouldPing() const noexcept {
124 return send_timer.HitOnce();
127 bool Connection::TimedOut() const noexcept {
128 return recv_timer.HitOnce();
131 void Connection::Update(int dt) {
132 send_timer.Update(dt);
133 recv_timer.Update(dt);
137 void Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
138 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
139 pack.header.ctrl = ctrl;
141 cout << "sending " << pack.GetType() << " to " << Address() << endl;
143 udp_pack.address = addr;
144 if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
145 throw NetError("SDLNet_UDP_Send");
151 void Connection::Received(const UDPpacket &udp_pack) {
152 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
154 cout << "received " << pack.GetType() << " from " << Address() << endl;
156 int diff = std::int16_t(pack.header.ctrl.seq) - std::int16_t(ctrl.ack);
159 // incoming more recent than last acked
161 // TODO: packets considered lost are detected here
162 // this should have ones for all of them:
163 // ~hist & ((1 << dist) - 1) if dist is < 32
166 // missed more than the last 32 oO
170 ctrl.hist |= 1 << (32 - diff);
172 } else if (diff < 0) {
173 // incoming older than acked
177 ctrl.hist |= 1 << (32 + diff);
180 // incoming the same as last acked oO
183 ctrl.ack = pack.header.ctrl.seq;
188 void Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
189 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
190 udp_pack.len = pack.MakePing();
191 Send(udp_pack, sock);
195 ostream &operator <<(ostream &out, const IPaddress &addr) {
196 const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
198 << '.' << int(host[1])
199 << '.' << int(host[2])
200 << '.' << int(host[3]);
202 out << ':' << SDLNet_Read16(&addr.port);
208 const char *Packet::Type2String(Type t) noexcept {
223 void Packet::Tag() noexcept {
227 size_t Packet::MakePing() noexcept {
230 return sizeof(Header);
233 size_t Packet::MakeLogin(const string &name) noexcept {
234 constexpr size_t maxname = 32;
238 if (name.size() < maxname) {
239 memset(payload, '\0', maxname);
240 memcpy(payload, name.c_str(), name.size());
242 memcpy(payload, name.c_str(), maxname);
244 return sizeof(Header) + maxname;
247 size_t Packet::MakeJoin(const Entity &player, const string &world_name) noexcept {
248 constexpr size_t maxname = 32;
253 uint8_t *cursor = &payload[0];
255 // TODO: generate entity IDs
256 *reinterpret_cast<uint32_t *>(cursor) = 1;
259 *reinterpret_cast<glm::ivec3 *>(cursor) = player.ChunkCoords();
262 *reinterpret_cast<glm::vec3 *>(cursor) = player.Position();
264 *reinterpret_cast<glm::vec3 *>(cursor) = player.Velocity();
267 *reinterpret_cast<glm::quat *>(cursor) = player.Orientation();
269 *reinterpret_cast<glm::vec3 *>(cursor) = player.AngularVelocity();
272 if (world_name.size() < maxname) {
273 memset(cursor, '\0', maxname);
274 memcpy(cursor, world_name.c_str(), world_name.size());
276 memcpy(cursor, world_name.c_str(), maxname);
280 return sizeof(Header) + (cursor - &payload[0]);
283 size_t Packet::MakePart() noexcept {
286 return sizeof(Header);
290 Server::Server(const Config &conf, World &world)
292 , serv_pack{ -1, nullptr, 0 }
295 serv_sock = SDLNet_UDP_Open(conf.port);
297 throw NetError("SDLNet_UDP_Open");
300 serv_pack.data = new Uint8[sizeof(Packet)];
301 serv_pack.maxlen = sizeof(Packet);
305 delete[] serv_pack.data;
306 SDLNet_UDP_Close(serv_sock);
310 void Server::Handle() {
311 int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
313 HandlePacket(serv_pack);
314 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
317 // a boo boo happened
318 throw NetError("SDLNet_UDP_Recv");
322 void Server::HandlePacket(const UDPpacket &udp_pack) {
323 if (udp_pack.len < int(sizeof(Packet::Header))) {
324 // packet too small, drop
327 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
328 if (pack.header.tag != Packet::TAG) {
329 // mistagged packet, drop
333 Connection &client = GetClient(udp_pack.address);
334 client.Received(udp_pack);
336 switch (pack.header.type) {
338 HandleLogin(client, udp_pack);
341 HandlePart(client, udp_pack);
344 // just drop packets of unknown or unhandled type
349 Connection &Server::GetClient(const IPaddress &addr) {
350 for (Connection &client : clients) {
351 if (client.Matches(addr)) {
355 clients.emplace_back(addr);
356 OnConnect(clients.back());
357 return clients.back();
360 void Server::OnConnect(Connection &client) {
361 cout << "new connection from " << client.Address() << endl;
362 // tell it we're alive
363 client.SendPing(serv_pack, serv_sock);
366 void Server::Update(int dt) {
367 for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
369 if (client->Closed()) {
370 OnDisconnect(*client);
371 client = clients.erase(client);
373 if (client->ShouldPing()) {
374 client->SendPing(serv_pack, serv_sock);
381 void Server::OnDisconnect(Connection &client) {
382 cout << "connection timeout from " << client.Address() << endl;
386 void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
387 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
388 size_t maxlen = min(udp_pack.len - int(sizeof(Packet::Header)), 32);
390 name.reserve(maxlen);
391 for (size_t i = 0; i < maxlen && pack.payload[i] != '\0'; ++i) {
392 name.push_back(pack.payload[i]);
395 Entity *player = world.AddPlayer(name);
396 Packet &response = *reinterpret_cast<Packet *>(serv_pack.data);
400 cout << "accepted login from player \"" << name << '"' << endl;
401 response.MakeJoin(*player, world.Name());
402 client.Send(serv_pack, serv_sock);
405 cout << "rejected login from player \"" << name << '"' << endl;
407 client.Send(serv_pack, serv_sock);
412 void Server::HandlePart(Connection &client, const UDPpacket &udp_pack) {