aboutsummaryrefslogtreecommitdiff
path: root/src/control_interface.cpp
blob: caeb6da4ad74f75d31c4f307d787809d0d9c2aa9 (plain)
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
125
126
127
128
129
130
131
#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;
    }

    if (message.source != message_source_controller)
    {
        // TODO: Handle illegal message source
        return;
    }

    if (auto state = connection->current_state(); message.command == message_command_hello && state == control_connection::state::fresh)
    {
        connection->send({message_source_daemon, message_command_hello, message_argument_hello});
        connection->update(control_connection::state::established);
    }
    else
    {
        // TODO: Handle unexpected message
    }
}

control_interface::pointer make_interface(boost::asio::io_service &service, std::filesystem::path file)
{
    if (std::filesystem::exists(file))
    {
        return {};
    }

    control_interface::protocol::endpoint endpoint{file.string()};
    return std::make_shared<control_interface>(control_interface::key{}, service, std::move(endpoint));
}

} // namespace wanda