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 m_socket.shutdown(boost::asio::ip::udp::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](auto ec, std::size_t sz) {
62 if(ec == boost::asio::error::operation_aborted)
63 return;
64
65 if(!ec && sz > 0)
66 {
67 try
68 {
69 f(m_data, sz);
70 }
71 catch(const std::exception& e)
72 {
73 ossia::logger().error("[udp_socket::receive]: {}", e.what());
74 }
75 catch(...)
76 {
77 ossia::logger().error("[udp_socket::receive]: unknown error");
78 }
79 }
80
81 this->receive(f);
82 });
83 }
84
85 Nano::Signal<void()> on_close;
86
87 boost::asio::io_context& m_context;
88 proto::endpoint m_endpoint;
89 proto::socket m_socket;
90 alignas(16) char m_data[65535];
91};
92
93class udp_send_socket
94{
95 using proto = boost::asio::ip::udp;
96
97public:
98 udp_send_socket(const outbound_socket_configuration& conf, boost::asio::io_context& ctx)
99 : m_context{ctx}
100 , m_endpoint{boost::asio::ip::make_address(conf.host), conf.port}
101 , m_socket{boost::asio::make_strand(ctx)}
102 , m_broadcast{conf.broadcast}
103 {
104 }
105
106 udp_send_socket(
107 const boost::asio::ip::address& host, const uint16_t port,
108 boost::asio::io_context& ctx)
109 : m_context{ctx}
110 , m_endpoint{host, port}
111 , m_socket{boost::asio::make_strand(ctx)}
112 {
113 }
114
115 void connect()
116 {
117 m_socket.open(boost::asio::ip::udp::v4());
118
119 m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
120
121 if(m_broadcast)
122 m_socket.set_option(boost::asio::socket_base::broadcast(true));
123 }
124
125 void close()
126 {
127 if(m_socket.is_open())
128 {
129 boost::asio::post(m_context, [this] {
130 m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
131 m_socket.close();
132 on_close();
133 });
134 }
135 }
136
137 void write(const proto::endpoint& ep, const char* data, std::size_t sz)
138 {
139 boost::system::error_code ec;
140 m_socket.send_to(boost::asio::const_buffer(data, sz), ep, 0, ec);
141 }
142
143 void write(const char* data, std::size_t sz) { write(m_endpoint, data, sz); }
144
145 Nano::Signal<void()> on_close;
146
147 boost::asio::io_context& m_context;
148 proto::endpoint m_endpoint;
149 proto::socket m_socket;
150 bool m_broadcast{};
151};
152
153}
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition context.cpp:118