1 #include "dvlnet/tcp_server.h"
2
3 #include <functional>
4 #include <chrono>
5
6 #include "dvlnet/base.h"
7
8 namespace dvl {
9 namespace net {
10
tcp_server(asio::io_context & ioc,std::string bindaddr,unsigned short port,std::string pw)11 tcp_server::tcp_server(asio::io_context &ioc, std::string bindaddr,
12 unsigned short port, std::string pw)
13 : ioc(ioc)
14 , pktfty(pw)
15 {
16 auto addr = asio::ip::address::from_string(bindaddr);
17 auto ep = asio::ip::tcp::endpoint(addr, port);
18 acceptor.reset(new asio::ip::tcp::acceptor(ioc, ep, true));
19 start_accept();
20 }
21
localhost_self()22 std::string tcp_server::localhost_self()
23 {
24 auto addr = acceptor->local_endpoint().address();
25 if (addr.is_unspecified()) {
26 if (addr.is_v4()) {
27 return asio::ip::address_v4::loopback().to_string();
28 } else if (addr.is_v6()) {
29 return asio::ip::address_v6::loopback().to_string();
30 }
31 ABORT();
32 }
33 return addr.to_string();
34 }
35
make_connection()36 tcp_server::scc tcp_server::make_connection()
37 {
38 return std::make_shared<client_connection>(ioc);
39 }
40
next_free()41 plr_t tcp_server::next_free()
42 {
43 for (plr_t i = 0; i < MAX_PLRS; ++i)
44 if (!connections[i])
45 return i;
46 return PLR_BROADCAST;
47 }
48
empty()49 bool tcp_server::empty()
50 {
51 for (plr_t i = 0; i < MAX_PLRS; ++i)
52 if (connections[i])
53 return false;
54 return true;
55 }
56
start_recv(scc con)57 void tcp_server::start_recv(scc con)
58 {
59 con->socket.async_receive(asio::buffer(con->recv_buffer),
60 std::bind(&tcp_server::handle_recv, this, con,
61 std::placeholders::_1,
62 std::placeholders::_2));
63 }
64
handle_recv(scc con,const asio::error_code & ec,size_t bytes_read)65 void tcp_server::handle_recv(scc con, const asio::error_code &ec,
66 size_t bytes_read)
67 {
68 if (ec || bytes_read == 0) {
69 drop_connection(con);
70 return;
71 }
72 con->recv_buffer.resize(bytes_read);
73 con->recv_queue.write(std::move(con->recv_buffer));
74 con->recv_buffer.resize(frame_queue::max_frame_size);
75 while (con->recv_queue.packet_ready()) {
76 try {
77 auto pkt = pktfty.make_packet(con->recv_queue.read_packet());
78 if (con->plr == PLR_BROADCAST) {
79 handle_recv_newplr(con, *pkt);
80 } else {
81 con->timeout = timeout_active;
82 handle_recv_packet(*pkt);
83 }
84 } catch (dvlnet_exception &e) {
85 SDL_Log("Network error: %s", e.what());
86 drop_connection(con);
87 return;
88 }
89 }
90 start_recv(con);
91 }
92
send_connect(scc con)93 void tcp_server::send_connect(scc con)
94 {
95 auto pkt = pktfty.make_packet<PT_CONNECT>(PLR_MASTER, PLR_BROADCAST,
96 con->plr);
97 send_packet(*pkt);
98 }
99
handle_recv_newplr(scc con,packet & pkt)100 void tcp_server::handle_recv_newplr(scc con, packet &pkt)
101 {
102 auto newplr = next_free();
103 if (newplr == PLR_BROADCAST)
104 throw server_exception();
105 if (empty())
106 game_init_info = pkt.info();
107 auto reply = pktfty.make_packet<PT_JOIN_ACCEPT>(PLR_MASTER, PLR_BROADCAST,
108 pkt.cookie(), newplr,
109 game_init_info);
110 start_send(con, *reply);
111 con->plr = newplr;
112 connections[newplr] = con;
113 con->timeout = timeout_active;
114 send_connect(con);
115 }
116
handle_recv_packet(packet & pkt)117 void tcp_server::handle_recv_packet(packet &pkt)
118 {
119 send_packet(pkt);
120 }
121
send_packet(packet & pkt)122 void tcp_server::send_packet(packet &pkt)
123 {
124 if (pkt.dest() == PLR_BROADCAST) {
125 for (auto i = 0; i < MAX_PLRS; ++i)
126 if (i != pkt.src() && connections[i])
127 start_send(connections[i], pkt);
128 } else {
129 if (pkt.dest() >= MAX_PLRS)
130 throw server_exception();
131 if ((pkt.dest() != pkt.src()) && connections[pkt.dest()])
132 start_send(connections[pkt.dest()], pkt);
133 }
134 }
135
start_send(scc con,packet & pkt)136 void tcp_server::start_send(scc con, packet &pkt)
137 {
138 const auto *frame = new buffer_t(frame_queue::make_frame(pkt.data()));
139 auto buf = asio::buffer(*frame);
140 asio::async_write(con->socket, buf,
141 [this, con, frame](const asio::error_code &ec, size_t bytes_sent) {
142 handle_send(con, ec, bytes_sent);
143 delete frame;
144 });
145 }
146
handle_send(scc con,const asio::error_code & ec,size_t bytes_sent)147 void tcp_server::handle_send(scc con, const asio::error_code &ec,
148 size_t bytes_sent)
149 {
150 // empty for now
151 }
152
start_accept()153 void tcp_server::start_accept()
154 {
155 auto nextcon = make_connection();
156 acceptor->async_accept(nextcon->socket,
157 std::bind(&tcp_server::handle_accept,
158 this, nextcon,
159 std::placeholders::_1));
160 }
161
handle_accept(scc con,const asio::error_code & ec)162 void tcp_server::handle_accept(scc con, const asio::error_code &ec)
163 {
164 if (ec)
165 return;
166 if (next_free() == PLR_BROADCAST) {
167 drop_connection(con);
168 } else {
169 asio::ip::tcp::no_delay option(true);
170 con->socket.set_option(option);
171 con->timeout = timeout_connect;
172 start_recv(con);
173 start_timeout(con);
174 }
175 start_accept();
176 }
177
start_timeout(scc con)178 void tcp_server::start_timeout(scc con)
179 {
180 con->timer.expires_after(std::chrono::seconds(1));
181 con->timer.async_wait(std::bind(&tcp_server::handle_timeout, this, con,
182 std::placeholders::_1));
183 }
184
handle_timeout(scc con,const asio::error_code & ec)185 void tcp_server::handle_timeout(scc con, const asio::error_code &ec)
186 {
187 if (ec) {
188 drop_connection(con);
189 return;
190 }
191 if (con->timeout > 0)
192 con->timeout -= 1;
193 if (con->timeout < 0)
194 con->timeout = 0;
195 if (!con->timeout) {
196 drop_connection(con);
197 return;
198 }
199 start_timeout(con);
200 }
201
drop_connection(scc con)202 void tcp_server::drop_connection(scc con)
203 {
204 if (con->plr != PLR_BROADCAST) {
205 auto pkt = pktfty.make_packet<PT_DISCONNECT>(PLR_MASTER, PLR_BROADCAST,
206 con->plr, LEAVE_DROP);
207 connections[con->plr] = NULL;
208 send_packet(*pkt);
209 // TODO: investigate if it is really ok for the server to
210 // drop a client directly.
211 }
212 con->timer.cancel();
213 con->socket.close();
214 }
215
close()216 void tcp_server::close()
217 {
218 acceptor->close();
219 }
220
~tcp_server()221 tcp_server::~tcp_server()
222 {
223 }
224
225 } // namespace net
226 } // namespace dvl
227