OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
unix_socket.hpp
1#pragma once
3#include <ossia/network/context.hpp>
4#include <ossia/network/sockets/configuration.hpp>
5
6#include <boost/asio/io_context.hpp>
7#include <boost/asio/ip/udp.hpp>
8#include <boost/asio/local/datagram_protocol.hpp>
9#include <boost/asio/local/stream_protocol.hpp>
10#include <boost/asio/placeholders.hpp>
11#include <boost/asio/strand.hpp>
12#include <boost/asio/write.hpp>
13
14#include <nano_signal_slot.hpp>
15
16namespace ossia::net
17{
18#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
19class unix_datagram_socket
20{
21 using proto = boost::asio::local::datagram_protocol;
22
23public:
24 unix_datagram_socket(const fd_configuration& conf, boost::asio::io_context& ctx)
25 : m_context{ctx}
26 , m_endpoint{conf.fd}
27 , m_socket{boost::asio::make_strand(ctx)}
28 {
29 }
30
31 void open()
32 {
33 ::unlink(m_endpoint.path().data());
34 m_socket.open();
35 m_socket.bind(m_endpoint);
36 }
37
38 void connect()
39 {
40 m_socket.open();
41 // m_socket.connect(m_endpoint);
42 }
43
44 void close()
45 {
46 if(m_socket.is_open())
47 {
48 boost::asio::post(m_context, [this] {
49 m_socket.shutdown(boost::asio::local::datagram_protocol::socket::shutdown_both);
50 m_socket.close();
51 on_close();
52 });
53 }
54 }
55
56 template <typename F>
57 void receive(F f)
58 {
59 m_socket.async_receive_from(
60 boost::asio::mutable_buffer(&m_data[0], std::size(m_data)), m_endpoint,
61 [this, f](boost::system::error_code ec, std::size_t sz) {
62 if(ec == boost::asio::error::operation_aborted)
63 return;
64
65 if(!ec && sz > 0)
66 try
67 {
68 f(m_data, sz);
69 }
70 catch(...)
71 {
72 }
73
74 this->receive(f);
75 });
76 }
77
78 void write(const char* data, std::size_t sz)
79 {
80 m_socket.send_to(boost::asio::buffer(data, sz), m_endpoint);
81 }
82
83 Nano::Signal<void()> on_close;
84
85 boost::asio::io_context& m_context;
86 proto::endpoint m_endpoint;
87 proto::socket m_socket;
88 alignas(16) char m_data[65535];
89};
90
91class unix_stream_listener
92{
93public:
94 using proto = boost::asio::local::stream_protocol;
95 unix_stream_listener() = delete;
96 unix_stream_listener(const unix_stream_listener&) = delete;
97 unix_stream_listener& operator=(const unix_stream_listener&) = delete;
98 unix_stream_listener(unix_stream_listener&&) = default;
99 unix_stream_listener& operator=(unix_stream_listener&&) = default;
100 explicit unix_stream_listener(proto::socket sock)
101 : m_socket{std::move(sock)}
102 {
103 }
104
105 void close()
106 {
107 m_socket.shutdown(boost::asio::local::stream_protocol::socket::shutdown_both);
108 m_socket.close();
109 }
110
111 void write(const boost::asio::const_buffer& buf) { boost::asio::write(m_socket, buf); }
112
113 void on_close() { }
114
115 void on_fail() { }
116
117 proto::socket m_socket;
118};
119
120class unix_stream_server
121{
122public:
123 using proto = boost::asio::local::stream_protocol;
124 using listener = unix_stream_listener;
125 [[no_unique_address]] struct ensure_reuse
126 {
127 explicit ensure_reuse(const proto::endpoint& endpoint)
128 {
129 ::unlink(endpoint.path().data());
130 }
131 } m_ensure_reuse;
132
133 unix_stream_server(const fd_configuration& conf, boost::asio::io_context& ctx)
134 : m_ensure_reuse{conf.fd}
135 , m_context{ctx}
136 , m_acceptor{boost::asio::make_strand(ctx), conf.fd}
137 {
138 }
139
140 unix_stream_server(const fd_configuration& conf, ossia::net::network_context_ptr ctx)
141 : unix_stream_server{conf, ctx->context}
142 {
143 }
144
145 boost::asio::io_context& m_context;
146 proto::acceptor m_acceptor;
147};
148
149class unix_stream_client
150{
151public:
152 using proto = boost::asio::local::stream_protocol;
153 using socket = typename proto::socket;
154
155 unix_stream_client(const fd_configuration& conf, boost::asio::io_context& ctx)
156 : m_context{ctx}
157 , m_endpoint{conf.fd}
158 , m_socket{boost::asio::make_strand(ctx)}
159 {
160 }
161
162 void connect()
163 {
164 m_socket.connect(m_endpoint);
165 on_open();
166 }
167
168 bool connected() const { return m_connected; }
169
170 void close()
171 {
172 boost::asio::post(m_context, [this] {
173 m_socket.shutdown(boost::asio::local::stream_protocol::socket::shutdown_both);
174 m_socket.close();
175 on_close();
176 });
177 }
178
179 void write(const char* data, std::size_t sz)
180 {
181 boost::asio::write(m_socket, boost::asio::buffer(data, sz));
182 }
183
184 Nano::Signal<void()> on_open;
185 Nano::Signal<void()> on_close;
186 Nano::Signal<void()> on_fail;
187
188 boost::asio::io_context& m_context;
189 proto::endpoint m_endpoint;
190 proto::socket m_socket;
191 bool m_connected{false};
192};
193#endif
194}