2 #include "Connection.hpp"
7 #include "../app/init.hpp"
19 UDPsocket client_bind(Uint16 port) {
20 UDPsocket sock = SDLNet_UDP_Open(port);
22 throw NetError("SDLNet_UDP_Open");
27 IPaddress client_resolve(const char *host, Uint16 port) {
29 if (SDLNet_ResolveHost(&addr, host, port) != 0) {
30 throw NetError("SDLNet_ResolveHost");
37 Client::Client(const Config &conf, World &world)
39 , conn(client_resolve(conf.host.c_str(), conf.port))
40 , client_sock(client_bind(0))
41 , client_pack{ -1, nullptr, 0 } {
42 client_pack.data = new Uint8[sizeof(Packet)];
43 client_pack.maxlen = sizeof(Packet);
44 // establish connection
45 conn.SendPing(client_pack, client_sock);
49 delete[] client_pack.data;
50 SDLNet_UDP_Close(client_sock);
54 void Client::Handle() {
55 int result = SDLNet_UDP_Recv(client_sock, &client_pack);
57 HandlePacket(client_pack);
58 result = SDLNet_UDP_Recv(client_sock, &client_pack);
62 throw NetError("SDLNet_UDP_Recv");
66 void Client::HandlePacket(const UDPpacket &udp_pack) {
67 if (!conn.Matches(udp_pack.address)) {
68 // packet came from somewhere else, drop
71 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
72 if (pack.header.tag != Packet::TAG) {
73 // mistagged packet, drop
78 cout << "I got something!" << endl;
81 void Client::Update(int dt) {
83 if (conn.TimedOut()) {
84 cout << "connection timed out :(" << endl;
85 } else if (conn.ShouldPing()) {
86 conn.SendPing(client_pack, client_sock);
91 Connection::Connection(const IPaddress &addr)
99 bool Connection::Matches(const IPaddress &remote) const noexcept {
100 return memcmp(&addr, &remote, sizeof(IPaddress)) == 0;
103 void Connection::FlagSend() noexcept {
107 void Connection::FlagRecv() noexcept {
111 bool Connection::ShouldPing() const noexcept {
112 return send_timer.HitOnce();
115 bool Connection::TimedOut() const noexcept {
116 return recv_timer.HitOnce();
119 void Connection::Update(int dt) {
120 send_timer.Update(dt);
121 recv_timer.Update(dt);
125 void Connection::Send(UDPpacket &pack, UDPsocket sock) {
127 if (SDLNet_UDP_Send(sock, -1, &pack) == 0) {
128 throw NetError("SDLNet_UDP_Send");
133 void Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
134 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
135 udp_pack.len = pack.Ping();
136 Send(udp_pack, sock);
140 ostream &operator <<(ostream &out, const IPaddress &addr) {
141 const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
143 << '.' << int(host[1])
144 << '.' << int(host[2])
145 << '.' << int(host[3]);
147 out << ':' << SDLNet_Read16(&addr.port);
153 void Packet::Tag() noexcept {
157 size_t Packet::Ping() noexcept {
160 return sizeof(Header);
164 Server::Server(const Config &conf, World &world)
166 , serv_pack{ -1, nullptr, 0 }
169 serv_sock = SDLNet_UDP_Open(conf.port);
171 throw NetError("SDLNet_UDP_Open");
174 serv_pack.data = new Uint8[sizeof(Packet)];
175 serv_pack.maxlen = sizeof(Packet);
179 delete[] serv_pack.data;
180 SDLNet_UDP_Close(serv_sock);
184 void Server::Handle() {
185 int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
187 HandlePacket(serv_pack);
188 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
191 // a boo boo happened
192 throw NetError("SDLNet_UDP_Recv");
196 void Server::HandlePacket(const UDPpacket &udp_pack) {
197 if (udp_pack.len < int(sizeof(Packet::Header))) {
198 // packet too small, drop
201 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
202 if (pack.header.tag != Packet::TAG) {
203 // mistagged packet, drop
207 Connection &client = GetClient(udp_pack.address);
211 Connection &Server::GetClient(const IPaddress &addr) {
212 for (Connection &client : clients) {
213 if (client.Matches(addr)) {
217 clients.emplace_back(addr);
218 OnConnect(clients.back());
219 return clients.back();
222 void Server::OnConnect(Connection &client) {
223 cout << "new connection from " << client.Address() << endl;
224 // tell it we're alive
225 client.SendPing(serv_pack, serv_sock);
228 void Server::Update(int dt) {
229 for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
231 if (client->TimedOut()) {
232 OnDisconnect(*client);
233 client = clients.erase(client);
235 if (client->ShouldPing()) {
236 client->SendPing(serv_pack, serv_sock);
243 void Server::OnDisconnect(Connection &client) {
244 cout << "connection timeout from " << client.Address() << endl;