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);
79 cout << "I got something!" << endl;
82 void Client::Update(int dt) {
84 if (conn.TimedOut()) {
85 cout << "connection timed out :(" << endl;
86 } else if (conn.ShouldPing()) {
91 void Client::SendPing() {
92 conn.SendPing(client_pack, client_sock);
95 void Client::SendLogin(const string &name) {
96 Packet &pack = *reinterpret_cast<Packet *>(client_pack.data);
97 client_pack.len = pack.Login(name);
98 conn.Send(client_pack, client_sock);
102 Connection::Connection(const IPaddress &addr)
106 , 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 udp_pack.address = addr;
142 if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
143 throw NetError("SDLNet_UDP_Send");
149 void Connection::Received(const UDPpacket &udp_pack) {
150 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
152 int diff = std::int16_t(pack.header.ctrl.seq) - std::int16_t(ctrl.ack);
155 // incoming more recent than last acked
157 // TODO: packets considered lost are detected here
158 // this should have ones for all of them:
159 // ~hist & ((1 << dist) - 1) if dist is < 32
162 // missed more than the last 32 oO
166 ctrl.hist |= 1 << (32 - diff);
168 } else if (diff < 0) {
169 // incoming older than acked
173 ctrl.hist |= 1 << (32 + diff);
176 // incoming the same as last acked oO
179 ctrl.ack = pack.header.ctrl.seq;
184 void Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
185 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
186 udp_pack.len = pack.Ping();
187 Send(udp_pack, sock);
191 ostream &operator <<(ostream &out, const IPaddress &addr) {
192 const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
194 << '.' << int(host[1])
195 << '.' << int(host[2])
196 << '.' << int(host[3]);
198 out << ':' << SDLNet_Read16(&addr.port);
204 void Packet::Tag() noexcept {
208 size_t Packet::Ping() noexcept {
211 return sizeof(Header);
214 size_t Packet::Login(const string &name) noexcept {
215 constexpr size_t maxname = 32;
219 if (name.size() < maxname) {
220 memset(payload, '\0', maxname);
221 memcpy(payload, name.c_str(), name.size());
223 memcpy(payload, name.c_str(), maxname);
225 return sizeof(Header) + maxname;
229 Server::Server(const Config &conf, World &world)
231 , serv_pack{ -1, nullptr, 0 }
234 serv_sock = SDLNet_UDP_Open(conf.port);
236 throw NetError("SDLNet_UDP_Open");
239 serv_pack.data = new Uint8[sizeof(Packet)];
240 serv_pack.maxlen = sizeof(Packet);
244 delete[] serv_pack.data;
245 SDLNet_UDP_Close(serv_sock);
249 void Server::Handle() {
250 int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
252 HandlePacket(serv_pack);
253 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
256 // a boo boo happened
257 throw NetError("SDLNet_UDP_Recv");
261 void Server::HandlePacket(const UDPpacket &udp_pack) {
262 if (udp_pack.len < int(sizeof(Packet::Header))) {
263 // packet too small, drop
266 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
267 if (pack.header.tag != Packet::TAG) {
268 // mistagged packet, drop
272 Connection &client = GetClient(udp_pack.address);
273 client.Received(udp_pack);
275 switch (pack.header.type) {
277 // already done all that's supposed to do
280 HandleLogin(client, udp_pack);
283 // just drop packets of unknown type
288 Connection &Server::GetClient(const IPaddress &addr) {
289 for (Connection &client : clients) {
290 if (client.Matches(addr)) {
294 clients.emplace_back(addr);
295 OnConnect(clients.back());
296 return clients.back();
299 void Server::OnConnect(Connection &client) {
300 cout << "new connection from " << client.Address() << endl;
301 // tell it we're alive
302 client.SendPing(serv_pack, serv_sock);
305 void Server::Update(int dt) {
306 for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
308 if (client->TimedOut()) {
309 OnDisconnect(*client);
310 client = clients.erase(client);
312 if (client->ShouldPing()) {
313 client->SendPing(serv_pack, serv_sock);
320 void Server::OnDisconnect(Connection &client) {
321 cout << "connection timeout from " << client.Address() << endl;
325 void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
326 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
327 size_t maxlen = min(udp_pack.len - int(sizeof(Packet::Header)), 32);
329 name.reserve(maxlen);
330 for (size_t i = 0; i < maxlen && pack.payload[i] != '\0'; ++i) {
331 name.push_back(pack.payload[i]);
333 cout << "got login request from player \"" << name << '"' << endl;
335 Entity *player = world.AddPlayer(name);
338 cout << "\taccepted" << endl;
341 cout << "\trejected" << endl;