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 78 : unix_socket::unix_socket(const std::string &context, boost::asio::io_context &io_context)
10 78 : : socket(context, io_context), socket_(io_context) {
11 78 : }
12 :
13 78 : unix_socket::unix_socket(const std::string &context, boost::asio::local::stream_protocol::socket&& sock)
14 78 : : socket(context, static_cast<boost::asio::io_context&>(sock.get_executor().context()))
15 156 : , socket_(std::move(sock)) {
16 78 : }
17 :
18 156 : unix_socket::~unix_socket() {
19 156 : unix_socket::close();
20 156 : }
21 :
22 237 : void unix_socket::close() {
23 237 : if (socket_.is_open()) {
24 156 : boost::system::error_code ec;
25 156 : socket_.close(ec);
26 : }
27 237 : }
28 :
29 3 : void unix_socket::cancel() {
30 3 : socket_.cancel();
31 3 : }
32 :
33 78 : 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 78 : 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 156 : };
51 :
52 : // Start connect
53 78 : 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 156 : };
62 :
63 : co_spawn(io_context_, timeout_coro(), detached);
64 : co_await connect_coro();
65 :
66 : co_return connect_ec;
67 156 : }
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 253 : awaitable<io_result> unix_socket::read_some(uint8_t buffer[], size_t max_size) {
96 : co_return co_await socket_.async_read_some(
97 : boost::asio::buffer(buffer, max_size),
98 : use_nothrow_awaitable);
99 506 : }
100 :
101 3 : awaitable<io_result> unix_socket::read(uint8_t buffer[], size_t size) {
102 : co_return co_await boost::asio::async_read(
103 : socket_,
104 : boost::asio::buffer(buffer, size),
105 : boost::asio::transfer_exactly(size),
106 : use_nothrow_awaitable);
107 6 : }
108 :
109 0 : awaitable<io_result> unix_socket::read(boost::asio::streambuf& buffer, size_t size) {
110 : co_return co_await boost::asio::async_read(
111 : socket_,
112 : buffer,
113 : boost::asio::transfer_exactly(size),
114 : use_nothrow_awaitable);
115 0 : }
116 :
117 3 : awaitable<io_result> unix_socket::read_until(boost::asio::streambuf& buffer, std::string_view delim) {
118 : co_return co_await boost::asio::async_read_until(
119 : socket_,
120 : buffer,
121 : std::string(delim),
122 : use_nothrow_awaitable);
123 6 : }
124 :
125 15 : awaitable<io_result> unix_socket::write(const uint8_t buffer[], size_t size) {
126 : co_return co_await boost::asio::async_write(
127 : socket_,
128 : boost::asio::buffer(buffer, size),
129 : use_nothrow_awaitable);
130 30 : }
131 :
132 12 : awaitable<io_result> unix_socket::write(std::string_view str) {
133 : co_return co_await boost::asio::async_write(
134 : socket_,
135 : boost::asio::buffer(str.data(), str.size()),
136 : use_nothrow_awaitable);
137 24 : }
138 :
139 114 : awaitable<io_result> unix_socket::write(const std::vector<boost::asio::const_buffer>& buffers) {
140 : co_return co_await boost::asio::async_write(
141 : socket_,
142 : buffers,
143 : use_nothrow_awaitable);
144 228 : }
145 :
146 3 : awaitable<boost::system::error_code> unix_socket::wait(boost::asio::socket_base::wait_type type) {
147 : auto [ec] = co_await socket_.async_wait(type, use_nothrow_awaitable);
148 : co_return ec;
149 6 : }
150 :
151 295 : bool unix_socket::is_open() const {
152 295 : return socket_.is_open();
153 : }
154 :
155 60 : bool unix_socket::is_secure() const {
156 60 : return false;
157 : }
158 :
159 3 : size_t unix_socket::available() const {
160 3 : boost::system::error_code ec;
161 3 : auto size = socket_.available(ec);
162 3 : if (ec) {
163 0 : LOG_ERROR("error while getting socket available bytes ({}): {}", size, ec.message());
164 : }
165 3 : return size;
166 : }
167 :
168 : }
|