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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#include "control_interface.hpp"
#include <boost/system/error_code.hpp>
#include <unistd.h>
#include <algorithm>
#include <iterator>
#include <string>
#include <utility>
namespace wanda
{
// 'socket_deleter' implementation
socket_deleter::~socket_deleter()
{
if (std::filesystem::exists(path))
{
std::filesystem::remove(path);
}
}
// 'control_interface' implementation
control_interface::control_interface(control_interface::key key, boost::asio::io_service &service, control_interface::protocol::endpoint endpoint)
: keyed{key},
m_service{service},
m_endpoint{std::move(endpoint)},
m_socket{m_service},
m_acceptor{m_service}
{
}
boost::system::error_code control_interface::start()
{
if (auto error = boost::system::error_code{}; m_acceptor.open(m_endpoint.protocol(), error))
{
return error;
}
if (auto error = boost::system::error_code{}; m_acceptor.bind(m_endpoint, error))
{
return error;
}
if (auto error = boost::system::error_code{}; m_acceptor.listen(128, error))
{
return error;
}
else
{
perform_accept();
return error;
}
}
boost::system::error_code control_interface::shutdown()
{
for (auto &connection : m_connections)
{
connection->close();
}
auto error = boost::system::error_code{};
return m_acceptor.close(error);
}
void control_interface::perform_accept()
{
m_acceptor.async_accept(m_socket, [that = shared_from_this(), this](auto const &error) {
if (error && error != boost::asio::error::operation_aborted)
{
// TODO: Handle error
}
else
{
auto [connection, inserted] = m_connections.insert(make_control_connection(std::move(m_socket)));
if (inserted)
{
(*connection)->add(this);
(*connection)->start();
}
perform_accept();
}
});
}
void control_interface::on_close(control_connection::pointer connection)
{
m_connections.erase(connection);
}
void control_interface::on_received(control_connection::pointer connection, message message)
{
if (m_connections.find(connection) == m_connections.cend())
{
// TODO: Handle unknown connection
return;
}
switch (connection->current_state())
{
case control_connection::state::fresh:
if (message.command == "HELLO")
{
connection->send({"D", "HELLO", "1.0.0"});
connection->update(control_connection::state::established);
}
}
}
control_interface::pointer make_interface(boost::asio::io_service &service, std::filesystem::path file)
{
if (std::filesystem::exists(file))
{
std::filesystem::remove(file);
}
control_interface::protocol::endpoint endpoint{file.string()};
return std::make_shared<control_interface>(control_interface::key{}, service, std::move(endpoint));
}
} // namespace wanda
|