OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
udp_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/placeholders.hpp>
9#include <boost/asio/strand.hpp>
10#include <boost/asio/write.hpp>
11
12#include <nano_signal_slot.hpp>
13
14namespace ossia::net
15{
16
17class udp_receive_socket
18{
19 using proto = boost::asio::ip::udp;
20
21public:
22 udp_receive_socket(boost::asio::io_context& ctx)
23 : m_context{ctx}
24 , m_socket{boost::asio::make_strand(ctx)}
25 {
26 }
27
28 udp_receive_socket(const inbound_socket_configuration& conf, boost::asio::io_context& ctx)
29 : m_context{ctx}
30 , m_endpoint{boost::asio::ip::make_address(conf.bind), conf.port}
31 , m_socket{boost::asio::make_strand(ctx)}
32 {
33 }
34
35 ~udp_receive_socket() = default;
36
37 void assign(int sock) { m_socket.assign(boost::asio::ip::udp::v4(), sock); }
38 void open()
39 {
40 m_socket.open(boost::asio::ip::udp::v4());
41 m_socket.bind(m_endpoint);
42 }
43
44 void close()
45 {
46 if(m_socket.is_open())
47 {
48 boost::asio::post(m_context, [this] {
49 try
50 {
51 m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
52 }
53 catch(...)
54 {
55 }
56
57 m_socket.close();
58 on_close();
59 });
60 }
61 }
62
63 template <typename F>
64 void receive(F f)
65 {
66 m_socket.async_receive_from(
67 boost::asio::mutable_buffer(&m_data[0], std::size(m_data)), m_endpoint,
68 [this, f](auto ec, std::size_t sz) {
69 if(ec == boost::asio::error::operation_aborted)
70 return;
71
72 if(!ec && sz > 0)
73 {
74 try
75 {
76 f(m_data, sz);
77 }
78 catch(const std::exception& e)
79 {
80 ossia::logger().error("[udp_socket::receive]: {}", e.what());
81 }
82 catch(...)
83 {
84 ossia::logger().error("[udp_socket::receive]: unknown error");
85 }
86 }
87
88 this->receive(f);
89 });
90 }
91
92 Nano::Signal<void()> on_close;
93
94 boost::asio::io_context& m_context;
95 proto::endpoint m_endpoint;
96 proto::socket m_socket;
97 alignas(16) char m_data[65535];
98};
99
100class udp_send_socket
101{
102 using proto = boost::asio::ip::udp;
103
104public:
105 udp_send_socket(const outbound_socket_configuration& conf, boost::asio::io_context& ctx)
106 : m_context{ctx}
107 , m_endpoint{boost::asio::ip::make_address(conf.host), conf.port}
108 , m_socket{boost::asio::make_strand(ctx)}
109 , m_broadcast{conf.broadcast}
110 {
111 }
112
113 udp_send_socket(
114 const boost::asio::ip::address& host, const uint16_t port,
115 boost::asio::io_context& ctx)
116 : m_context{ctx}
117 , m_endpoint{host, port}
118 , m_socket{boost::asio::make_strand(ctx)}
119 {
120 }
121
122 void connect()
123 {
124 m_socket.open(boost::asio::ip::udp::v4());
125
126 m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
127
128 if(m_broadcast)
129 m_socket.set_option(boost::asio::socket_base::broadcast(true));
130 }
131
132 void close()
133 {
134 if(m_socket.is_open())
135 {
136 boost::asio::post(m_context, [this] {
137 try
138 {
139 m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
140 }
141 catch(...)
142 {
143 }
144 m_socket.close();
145 on_close();
146 });
147 }
148 }
149
150 void write(const proto::endpoint& ep, const char* data, std::size_t sz)
151 {
152 boost::system::error_code ec;
153 m_socket.send_to(boost::asio::const_buffer(data, sz), ep, 0, ec);
154 }
155
156 void write(const char* data, std::size_t sz) { write(m_endpoint, data, sz); }
157
158 Nano::Signal<void()> on_close;
159
160 boost::asio::io_context& m_context;
161 proto::endpoint m_endpoint;
162 proto::socket m_socket;
163 bool m_broadcast{};
164};
165
166}
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition context.cpp:118