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