]> git.localhorst.tv Git - blank.git/commitdiff
fixed transmission control
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 4 Sep 2015 14:38:56 +0000 (16:38 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 4 Sep 2015 14:38:56 +0000 (16:38 +0200)
src/client/MasterState.hpp
src/client/client.cpp
src/net/Client.hpp
src/net/Connection.hpp
src/net/ConnectionHandler.hpp [new file with mode: 0644]
src/net/PacketHandler.hpp [deleted file]
src/net/net.cpp

index af2e6aac8710a7b92e4af91566766e8387a43a0c..6bdb671836a9193a54068b67132a1284dad0e4c4 100644 (file)
@@ -5,7 +5,7 @@
 #include "InteractiveState.hpp"
 #include "../app/State.hpp"
 #include "../net/Client.hpp"
-#include "../net/PacketHandler.hpp"
+#include "../net/ConnectionHandler.hpp"
 
 #include <memory>
 
@@ -20,7 +20,7 @@ class InteractiveState;
 
 class MasterState
 : public State
-, public PacketHandler {
+, public ConnectionHandler {
 
 public:
        MasterState(
@@ -46,6 +46,9 @@ public:
        void Update(int dt) override;
        void Render(Viewport &) override;
 
+       void OnPacketLost(std::uint16_t) override;
+       void OnTimeout() override;
+
        void On(const Packet::Join &) override;
        void On(const Packet::Part &) override;
 
@@ -59,6 +62,8 @@ private:
 
        InitialState init_state;
 
+       int login_packet;
+
 };
 
 }
index ac682bb8d8909eb37bfd876541d20f7ad3c58eb0..49ea4007d6a63524c392ad9953fc67812ef0dfb0 100644 (file)
@@ -120,7 +120,8 @@ MasterState::MasterState(
 , client_conf(cc)
 , state()
 , client(cc)
-, init_state(*this) {
+, init_state(*this)
+, login_packet(-1) {
        client.GetConnection().SetHandler(this);
 }
 
@@ -130,7 +131,7 @@ void MasterState::Quit() {
 
 
 void MasterState::OnEnter() {
-       client.SendLogin(intf_conf.player_name);
+       login_packet = client.SendLogin(intf_conf.player_name);
        env.state.Push(&init_state);
 }
 
@@ -143,10 +144,6 @@ void MasterState::Handle(const SDL_Event &event) {
 void MasterState::Update(int dt) {
        client.Handle();
        client.Update(dt);
-       if (client.GetConnection().Closed()) {
-               Quit();
-               // TODO: push disconnected message
-       }
 }
 
 
@@ -155,6 +152,19 @@ void MasterState::Render(Viewport &) {
 }
 
 
+void MasterState::OnPacketLost(std::uint16_t id) {
+       if (id == login_packet) {
+               login_packet = client.SendLogin(intf_conf.player_name);
+       }
+}
+
+void MasterState::OnTimeout() {
+       if (client.GetConnection().Closed()) {
+               Quit();
+               // TODO: push disconnected message
+       }
+}
+
 void MasterState::On(const Packet::Join &pack) {
        pack.ReadWorldName(world_conf.name);
 
index 3960e845c9fed551ae15b2046013bab7504af3a2..bd29c85fa0add60cbb6dc3df4f85af51933491b3 100644 (file)
@@ -30,8 +30,8 @@ public:
        Connection &GetConnection() noexcept { return conn; }
        const Connection &GetConnection() const noexcept { return conn; }
 
-       void SendPing();
-       void SendLogin(const std::string &);
+       std::uint16_t SendPing();
+       std::uint16_t SendLogin(const std::string &);
 
 private:
        void HandlePacket(const UDPpacket &);
index 58f315d4d58e0358033cc74dee6e4e1162cd1a14..ed7a946aab01d2296123f9f68229d46a2b9b4b48 100644 (file)
 
 namespace blank {
 
-class PacketHandler;
+class ConnectionHandler;
 
 class Connection {
 
 public:
        explicit Connection(const IPaddress &);
 
-       void SetHandler(PacketHandler *h) noexcept { handler = h; }
+       void SetHandler(ConnectionHandler *h) noexcept { handler = h; }
        void RemoveHandler() noexcept { handler = nullptr; }
        bool HasHandler() const noexcept { return handler; }
-       PacketHandler &Handler() noexcept { return *handler; }
+       ConnectionHandler &Handler() noexcept { return *handler; }
 
        const IPaddress &Address() const noexcept { return addr; }
 
@@ -30,13 +30,13 @@ public:
        bool TimedOut() const noexcept;
 
        void Close() noexcept { closed = true; }
-       bool Closed() const noexcept { return closed || TimedOut(); }
+       bool Closed() const noexcept { return closed; }
 
        void Update(int dt);
 
-       void SendPing(UDPpacket &, UDPsocket);
+       std::uint16_t SendPing(UDPpacket &, UDPsocket);
 
-       void Send(UDPpacket &, UDPsocket);
+       std::uint16_t Send(UDPpacket &, UDPsocket);
        void Received(const UDPpacket &);
 
 private:
@@ -44,12 +44,13 @@ private:
        void FlagRecv() noexcept;
 
 private:
-       PacketHandler *handler;
+       ConnectionHandler *handler;
        IPaddress addr;
        IntervalTimer send_timer;
        IntervalTimer recv_timer;
 
-       Packet::TControl ctrl;
+       Packet::TControl ctrl_out;
+       Packet::TControl ctrl_in;
 
        bool closed;
 
diff --git a/src/net/ConnectionHandler.hpp b/src/net/ConnectionHandler.hpp
new file mode 100644 (file)
index 0000000..3eb8f55
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef BLANK_NET_CONNECTIONHANDLER_HPP_
+#define BLANK_NET_CONNECTIONHANDLER_HPP_
+
+#include "Packet.hpp"
+
+#include <SDL_net.h>
+
+
+namespace blank {
+
+class ConnectionHandler {
+
+public:
+       void Handle(const UDPpacket &);
+
+       virtual void OnPacketLost(std::uint16_t) { }
+
+       virtual void OnTimeout() { }
+
+private:
+       virtual void On(const Packet::Ping &) { }
+       virtual void On(const Packet::Login &) { }
+       virtual void On(const Packet::Join &) { }
+       virtual void On(const Packet::Part &) { }
+
+};
+
+}
+
+#endif
diff --git a/src/net/PacketHandler.hpp b/src/net/PacketHandler.hpp
deleted file mode 100644 (file)
index 0ea9b57..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef BLANK_NET_PACKETHANDLER_HPP_
-#define BLANK_NET_PACKETHANDLER_HPP_
-
-#include "Packet.hpp"
-
-#include <SDL_net.h>
-
-
-namespace blank {
-
-class PacketHandler {
-
-public:
-       void Handle(const UDPpacket &);
-
-private:
-       virtual void On(const Packet::Ping &) { }
-       virtual void On(const Packet::Login &) { }
-       virtual void On(const Packet::Join &) { }
-       virtual void On(const Packet::Part &) { }
-
-};
-
-}
-
-#endif
index 1be712b9fd51b0985da0b0924c29ae3c8cf0d248..852efd3a419f2075ebd4b2878ff17216ce61e36c 100644 (file)
@@ -1,8 +1,8 @@
 #include "Client.hpp"
 #include "Connection.hpp"
+#include "ConnectionHandler.hpp"
 #include "io.hpp"
 #include "Packet.hpp"
-#include "PacketHandler.hpp"
 #include "Server.hpp"
 
 #include "../app/init.hpp"
@@ -16,6 +16,11 @@ using namespace std;
 
 namespace blank {
 
+constexpr size_t Packet::Ping::MAX_LEN;
+constexpr size_t Packet::Login::MAX_LEN;
+constexpr size_t Packet::Join::MAX_LEN;
+constexpr size_t Packet::Part::MAX_LEN;
+
 namespace {
 
 UDPsocket client_bind(Uint16 port) {
@@ -80,30 +85,29 @@ void Client::HandlePacket(const UDPpacket &udp_pack) {
 
 void Client::Update(int dt) {
        conn.Update(dt);
-       if (conn.TimedOut()) {
-               cout << "connection timed out :(" << endl;
-       } else if (conn.ShouldPing()) {
+       if (conn.ShouldPing()) {
                SendPing();
        }
 }
 
-void Client::SendPing() {
-       conn.SendPing(client_pack, client_sock);
+uint16_t Client::SendPing() {
+       return conn.SendPing(client_pack, client_sock);
 }
 
-void Client::SendLogin(const string &name) {
+uint16_t Client::SendLogin(const string &name) {
        auto pack = Packet::Make<Packet::Login>(client_pack);
        pack.WritePlayerName(name);
-       conn.Send(client_pack, client_sock);
+       return conn.Send(client_pack, client_sock);
 }
 
 
 Connection::Connection(const IPaddress &addr)
 : handler(nullptr)
 , addr(addr)
-, send_timer(3000)
+, send_timer(500)
 , recv_timer(10000)
-, ctrl{ 0, 0xFFFF, 0xFFFF }
+, ctrl_out{ 0, 0xFFFF, 0xFFFFFFFF }
+, ctrl_in{ 0, 0xFFFF, 0xFFFFFFFF }
 , closed(false) {
        send_timer.Start();
        recv_timer.Start();
@@ -122,7 +126,7 @@ void Connection::FlagRecv() noexcept {
 }
 
 bool Connection::ShouldPing() const noexcept {
-       return send_timer.HitOnce();
+       return !closed && send_timer.HitOnce();
 }
 
 bool Connection::TimedOut() const noexcept {
@@ -132,15 +136,19 @@ bool Connection::TimedOut() const noexcept {
 void Connection::Update(int dt) {
        send_timer.Update(dt);
        recv_timer.Update(dt);
+       if (TimedOut()) {
+               Close();
+               if (HasHandler()) {
+                       Handler().OnTimeout();
+               }
+       }
 }
 
 
-void Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
+uint16_t Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
        Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
-       pack.header.ctrl = ctrl;
-       ++ctrl.seq;
-
-       cout << "sending " << pack.TypeString() << " to " << Address() << endl;
+       pack.header.ctrl = ctrl_out;
+       uint16_t seq = ctrl_out.seq++;
 
        udp_pack.address = addr;
        if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
@@ -148,52 +156,53 @@ void Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
        }
 
        FlagSend();
+       return seq;
 }
 
 void Connection::Received(const UDPpacket &udp_pack) {
        Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
 
-       cout << "received " << pack.TypeString() << " from " << Address() << endl;
-
-       int diff = std::int16_t(pack.header.ctrl.seq) - std::int16_t(ctrl.ack);
-
+       // ack to the remote
+       int16_t diff = int16_t(pack.header.ctrl.seq) - int16_t(ctrl_out.ack);
        if (diff > 0) {
-               // incoming more recent than last acked
-
-               // TODO: packets considered lost are detected here
-               //       this should have ones for all of them:
-               //       ~hist & ((1 << dist) - 1) if dist is < 32
-
                if (diff >= 32) {
-                       // missed more than the last 32 oO
-                       ctrl.hist = 0;
-               } else {
-                       ctrl.hist >>= diff;
-                       ctrl.hist |= 1 << (32 - diff);
-               }
-       } else if (diff < 0) {
-               // incoming older than acked
-               if (diff > -32) {
-                       // too late :/
+                       ctrl_out.hist = 0;
                } else {
-                       ctrl.hist |= 1 << (32 + diff);
+                       ctrl_out.hist <<= diff;
+                       ctrl_out.hist |= 1 << (diff - 1);
                }
-       } else {
-               // incoming the same as last acked oO
+       } else if (diff < 0 && diff >= -32) {
+               ctrl_out.hist |= 1 << (-diff - 1);
        }
+       ctrl_out.ack = pack.header.ctrl.seq;
+       FlagRecv();
 
-       ctrl.ack = pack.header.ctrl.seq;
-
-       if (HasHandler()) {
-               Handler().Handle(udp_pack);
+       if (!HasHandler()) {
+               return;
        }
 
-       FlagRecv();
+       Packet::TControl ctrl_new = pack.header.ctrl;
+       Handler().Handle(udp_pack);
+
+       if (diff > 0) {
+               // if the packet holds more recent information
+               // check if remote failed to ack one of our packets
+               diff = int16_t(ctrl_new.ack) - int16_t(ctrl_in.ack);
+               // should always be true, but you never know…
+               if (diff > 0) {
+                       for (int i = 0; i < diff; ++i) {
+                               if (i > 32 || (i < 32 && (ctrl_in.hist & (1 << (31 - i))) == 0)) {
+                                       Handler().OnPacketLost(ctrl_in.ack - 32 + i);
+                               }
+                       }
+               }
+               ctrl_in = ctrl_new;
+       }
 }
 
-void Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
+uint16_t Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
        Packet::Make<Packet::Ping>(udp_pack);
-       Send(udp_pack, sock);
+       return Send(udp_pack, sock);
 }
 
 
@@ -312,7 +321,7 @@ void Packet::Join::ReadWorldName(string &name) const noexcept {
 }
 
 
-void PacketHandler::Handle(const UDPpacket &udp_pack) {
+void ConnectionHandler::Handle(const UDPpacket &udp_pack) {
        const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
        switch (pack.Type()) {
                case Packet::Ping::TYPE: