-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathecho_server.cpp
101 lines (85 loc) · 2.35 KB
/
echo_server.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "echo_server.h"
namespace
{
constexpr const timer::clock_t::duration timeout = std::chrono::seconds(15);
}
echo_server::connection::connection(echo_server *parent)
: parent(parent)
, socket(parent->ss.accept([this] {
this->parent->connections.erase(this);
}, [this] {
process(true);
}, client_socket::on_ready_t{}))
, timer(parent->ep.get_timer(), timeout, [this] {
this->parent->connections.erase(this);
})
, start_offset()
, end_offset()
{}
void echo_server::connection::try_read()
{
assert(start_offset == 0);
assert(end_offset == 0);
end_offset = socket.read_some(buf, sizeof buf);
}
void echo_server::connection::try_write()
{
assert(start_offset < end_offset);
assert(end_offset != 0);
size_t written = socket.write_some(buf + start_offset, end_offset - start_offset);
if (written == 0)
return;
timer.restart(parent->ep.get_timer(), timeout);
start_offset += written;
if (start_offset == end_offset)
{
start_offset = 0;
end_offset = 0;
}
}
void echo_server::connection::process(bool read)
{
bool incomplete_read = false;
if (!read)
goto process_write;
for (;;)
{
try_read();
if (end_offset == 0)
{
socket.set_on_read_write([this] { process(true); }, client_socket::on_ready_t{});
return;
}
incomplete_read = (end_offset != sizeof buf);
process_write:
try_write();
if (end_offset != 0)
{
socket.set_on_read_write(client_socket::on_ready_t{}, [this] { process(false); });
return;
}
if (incomplete_read)
{
socket.set_on_read_write([this] { process(true); }, client_socket::on_ready_t{});
return;
}
}
}
echo_server::echo_server(epoll& ep)
: ep(ep)
, ss{ep, std::bind(&echo_server::on_new_connection, this)}
{}
echo_server::echo_server(epoll &ep, ipv4_endpoint const& local_endpoint)
: ep(ep)
, ss{ep, local_endpoint, std::bind(&echo_server::on_new_connection, this)}
{}
ipv4_endpoint echo_server::local_endpoint() const
{
return ss.local_endpoint();
}
void echo_server::on_new_connection()
{
std::unique_ptr<connection> cc(new connection(this));
connection* pcc = cc.get();
connections.emplace(pcc, std::move(cc));
}