Line data Source code
1 : #include "unix_socket.hpp"
2 : #include "../../util/logger.hpp"
3 : #include <boost/asio/read.hpp>
4 : #include <boost/asio/write.hpp>
5 : #include <boost/asio/read_until.hpp>
6 :
7 : namespace thinger::asio {
8 :
9 66 : unix_socket::unix_socket(const std::string &context, boost::asio::io_context &io_context)
10 66 : : socket(context, io_context), socket_(io_context) {
11 66 : }
12 :
13 66 : unix_socket::unix_socket(const std::string &context, boost::asio::local::stream_protocol::socket&& sock)
14 66 : : socket(context, static_cast<boost::asio::io_context&>(sock.get_executor().context()))
15 132 : , socket_(std::move(sock)) {
16 66 : }
17 :
18 132 : unix_socket::~unix_socket() {
19 132 : unix_socket::close();
20 132 : }
21 :
22 198 : void unix_socket::close() {
23 198 : if (socket_.is_open()) {
24 132 : boost::system::error_code ec;
25 132 : socket_.close(ec);
26 : }
27 198 : }
28 :
29 3 : void unix_socket::cancel() {
30 3 : socket_.cancel();
31 3 : }
32 :
33 66 : awaitable<boost::system::error_code> unix_socket::connect(const std::string &path, std::chrono::seconds timeout) {
34 : close();
35 :
36 : // Setup timeout timer
37 : boost::asio::steady_timer timer(io_context_);
38 : timer.expires_after(timeout);
39 :
40 : bool timed_out = false;
41 : boost::system::error_code connect_ec;
42 :
43 : // Start timeout
44 66 : auto timeout_coro = [&]() -> awaitable<void> {
45 : auto [ec] = co_await timer.async_wait(use_nothrow_awaitable);
46 : if (!ec) {
47 : timed_out = true;
48 : socket_.cancel();
49 : }
50 132 : };
51 :
52 : // Start connect
53 66 : auto connect_coro = [&]() -> awaitable<void> {
54 : auto [ec] = co_await socket_.async_connect(
55 : boost::asio::local::stream_protocol::endpoint(path),
56 : use_nothrow_awaitable);
57 : timer.cancel();
58 : if (ec) {
59 : connect_ec = timed_out ? boost::asio::error::timed_out : ec;
60 : }
61 132 : };
62 :
63 : co_spawn(io_context_, timeout_coro(), detached);
64 : co_await connect_coro();
65 :
66 : co_return connect_ec;
67 132 : }
68 :
69 0 : awaitable<boost::system::error_code> unix_socket::connect(
70 : const std::string &host,
71 : const std::string &port,
72 : std::chrono::seconds timeout)
73 : {
74 : LOG_WARNING("calling connect to a unix socket over host/port");
75 : co_return co_await connect(host, timeout);
76 0 : }
77 :
78 3 : std::string unix_socket::get_remote_ip() const {
79 3 : boost::system::error_code ec;
80 3 : auto remote_ep = socket_.remote_endpoint(ec);
81 3 : if (!ec) {
82 3 : return remote_ep.path();
83 : }
84 0 : return "";
85 : }
86 :
87 3 : std::string unix_socket::get_local_port() const {
88 6 : return "0";
89 : }
90 :
91 3 : std::string unix_socket::get_remote_port() const {
92 6 : return "0";
93 : }
94 :
95 263 : awaitable<size_t> unix_socket::read_some(uint8_t buffer[], size_t max_size) {
96 : auto [ec, bytes] = co_await socket_.async_read_some(
97 : boost::asio::buffer(buffer, max_size),
98 : use_nothrow_awaitable);
99 : if (ec) co_return 0;
100 : co_return bytes;
101 526 : }
102 :
103 3 : awaitable<size_t> unix_socket::read(uint8_t buffer[], size_t size) {
104 : auto [ec, bytes] = co_await boost::asio::async_read(
105 : socket_,
106 : boost::asio::buffer(buffer, size),
107 : boost::asio::transfer_exactly(size),
108 : use_nothrow_awaitable);
109 : if (ec) co_return 0;
110 : co_return bytes;
111 6 : }
112 :
113 0 : awaitable<size_t> unix_socket::read(boost::asio::streambuf& buffer, size_t size) {
114 : auto [ec, bytes] = co_await boost::asio::async_read(
115 : socket_,
116 : buffer,
117 : boost::asio::transfer_exactly(size),
118 : use_nothrow_awaitable);
119 : if (ec) co_return 0;
120 : co_return bytes;
121 0 : }
122 :
123 3 : awaitable<size_t> unix_socket::read_until(boost::asio::streambuf& buffer, std::string_view delim) {
124 : auto [ec, bytes] = co_await boost::asio::async_read_until(
125 : socket_,
126 : buffer,
127 : std::string(delim),
128 : use_nothrow_awaitable);
129 : if (ec) co_return 0;
130 : co_return bytes;
131 6 : }
132 :
133 15 : awaitable<size_t> unix_socket::write(const uint8_t buffer[], size_t size) {
134 : auto [ec, bytes] = co_await boost::asio::async_write(
135 : socket_,
136 : boost::asio::buffer(buffer, size),
137 : use_nothrow_awaitable);
138 : if (ec) co_return 0;
139 : co_return bytes;
140 30 : }
141 :
142 9 : awaitable<size_t> unix_socket::write(std::string_view str) {
143 : auto [ec, bytes] = co_await boost::asio::async_write(
144 : socket_,
145 : boost::asio::buffer(str.data(), str.size()),
146 : use_nothrow_awaitable);
147 : if (ec) co_return 0;
148 : co_return bytes;
149 18 : }
150 :
151 96 : awaitable<size_t> unix_socket::write(const std::vector<boost::asio::const_buffer>& buffers) {
152 : auto [ec, bytes] = co_await boost::asio::async_write(
153 : socket_,
154 : buffers,
155 : use_nothrow_awaitable);
156 : if (ec) co_return 0;
157 : co_return bytes;
158 192 : }
159 :
160 3 : awaitable<boost::system::error_code> unix_socket::wait(boost::asio::socket_base::wait_type type) {
161 : auto [ec] = co_await socket_.async_wait(type, use_nothrow_awaitable);
162 : co_return ec;
163 6 : }
164 :
165 302 : bool unix_socket::is_open() const {
166 302 : return socket_.is_open();
167 : }
168 :
169 51 : bool unix_socket::is_secure() const {
170 51 : return false;
171 : }
172 :
173 3 : size_t unix_socket::available() const {
174 3 : boost::system::error_code ec;
175 3 : auto size = socket_.available(ec);
176 3 : if (ec) {
177 0 : LOG_ERROR("error while getting socket available bytes ({}): {}", size, ec.message());
178 : }
179 3 : return size;
180 : }
181 :
182 : }
|