Skip to content

Commit 14ea4cd

Browse files
committed
udp: Add optional broadcast capabilities
Signed-off-by: Konrad Gräfe <[email protected]>
1 parent c623ac3 commit 14ea4cd

File tree

3 files changed

+97
-9
lines changed

3 files changed

+97
-9
lines changed

src/adapters/udp.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ pub const MAX_LOCAL_PAYLOAD_LEN: usize = 65535 - 20 - 8;
2626
#[cfg(target_os = "macos")]
2727
pub const MAX_LOCAL_PAYLOAD_LEN: usize = 9216 - 20 - 8;
2828

29+
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
30+
pub struct UdpConnectConfig {
31+
/// Enables the socket capabilities to send broadcast messages. (Default: off)
32+
pub broadcast: Option<bool>,
33+
}
34+
35+
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
36+
pub struct UdpListenConfig {
37+
/// Enables the socket capabilities to send broadcast messages when the listening socket is
38+
/// also used for sending with
39+
/// [`Endpoint::from_listener`](crate::network::Endpoint::from_listener). (Default: off)
40+
pub broadcast: Option<bool>,
41+
}
42+
2943
pub(crate) struct UdpAdapter;
3044
impl Adapter for UdpAdapter {
3145
type Remote = RemoteResource;
@@ -44,11 +58,21 @@ impl Resource for RemoteResource {
4458

4559
impl Remote for RemoteResource {
4660
fn connect_with(
47-
_: TransportConnect,
61+
config: TransportConnect,
4862
remote_addr: RemoteAddr,
4963
) -> io::Result<ConnectionInfo<Self>> {
64+
let config = match config {
65+
TransportConnect::Udp(config) => config,
66+
_ => unreachable!(),
67+
};
68+
5069
let socket = UdpSocket::bind("0.0.0.0:0".parse().unwrap())?;
5170
let peer_addr = *remote_addr.socket_addr();
71+
72+
if let Some(broadcast) = config.broadcast {
73+
socket.set_broadcast(broadcast)?;
74+
}
75+
5276
socket.connect(peer_addr)?;
5377
let local_addr = socket.local_addr()?;
5478
Ok(ConnectionInfo { remote: RemoteResource { socket }, local_addr, peer_addr })
@@ -98,7 +122,12 @@ impl Resource for LocalResource {
98122
impl Local for LocalResource {
99123
type Remote = RemoteResource;
100124

101-
fn listen_with(_: TransportListen, addr: SocketAddr) -> io::Result<ListeningInfo<Self>> {
125+
fn listen_with(config: TransportListen, addr: SocketAddr) -> io::Result<ListeningInfo<Self>> {
126+
let config = match config {
127+
TransportListen::Udp(config) => config,
128+
_ => unreachable!(),
129+
};
130+
102131
let socket = match addr {
103132
SocketAddr::V4(addr) if addr.ip().is_multicast() => {
104133
let listening_addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, addr.port());
@@ -115,6 +144,10 @@ impl Local for LocalResource {
115144
_ => UdpSocket::bind(addr)?,
116145
};
117146

147+
if let Some(broadcast) = config.broadcast {
148+
socket.set_broadcast(broadcast)?;
149+
}
150+
118151
let local_addr = socket.local_addr().unwrap();
119152
Ok(ListeningInfo { local: { LocalResource { socket } }, local_addr })
120153
}

src/network.rs

+55
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,38 @@ impl NetworkController {
116116
/// the connection itself.
117117
/// If you want to check if the connection has been established or not you have to read the
118118
/// boolean indicator in the [`NetEvent::Connected`] event.
119+
///
120+
/// Example
121+
/// ```
122+
/// use message_io::node::{self, NodeEvent};
123+
/// use message_io::network::{TransportConnect, NetEvent};
124+
/// use message_io::adapters::udp::{UdpConnectConfig};
125+
///
126+
/// let (handler, listener) = node::split();
127+
/// handler.signals().send_with_timer((), std::time::Duration::from_secs(1));
128+
///
129+
/// let config = UdpConnectConfig { broadcast: Some(true)};
130+
/// let addr = "255.255.255.255:7777";
131+
/// let (conn_endpoint, _) = handler.network().connect_with(TransportConnect::Udp(config), addr).unwrap();
132+
/// // The socket could not be able to send yet.
133+
///
134+
/// listener.for_each(move |event| match event {
135+
/// NodeEvent::Network(net_event) => match net_event {
136+
/// NetEvent::Connected(endpoint, established) => {
137+
/// assert_eq!(conn_endpoint, endpoint);
138+
/// if established {
139+
/// println!("Connected!");
140+
/// handler.network().send(endpoint, &[42]);
141+
/// }
142+
/// else {
143+
/// println!("Could not connect");
144+
/// }
145+
/// },
146+
/// _ => (),
147+
/// }
148+
/// NodeEvent::Signal(_) => handler.stop(),
149+
/// });
150+
/// ```
119151
pub fn connect_with(
120152
&self,
121153
transport_connect: TransportConnect,
@@ -184,6 +216,29 @@ impl NetworkController {
184216
///
185217
/// In order to get the best scalability and performance, use the non-blocking
186218
/// [`NetworkController::connect_with()`] version.
219+
///
220+
/// Example
221+
/// ```
222+
/// use message_io::node::{self, NodeEvent};
223+
/// use message_io::network::{TransportConnect, NetEvent};
224+
/// use message_io::adapters::udp::{UdpConnectConfig};
225+
///
226+
/// let (handler, listener) = node::split();
227+
/// handler.signals().send_with_timer((), std::time::Duration::from_secs(1));
228+
///
229+
/// let config = UdpConnectConfig { broadcast: Some(true)};
230+
/// let addr = "255.255.255.255:7777";
231+
/// match handler.network().connect_sync_with(TransportConnect::Udp(config), addr) {
232+
/// Ok((endpoint, _)) => {
233+
/// println!("Connected!");
234+
/// handler.network().send(endpoint, &[42]);
235+
/// }
236+
/// Err(err) if err.kind() == std::io::ErrorKind::ConnectionRefused => {
237+
/// println!("Could not connect");
238+
/// }
239+
/// Err(err) => println!("An OS error creating the socket"),
240+
/// }
241+
/// ```
187242
pub fn connect_sync_with(
188243
&self,
189244
transport_connect: TransportConnect,

src/network/transport.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::adapters::tcp::{TcpAdapter};
55
#[cfg(feature = "tcp")]
66
use crate::adapters::framed_tcp::{FramedTcpAdapter};
77
#[cfg(feature = "udp")]
8-
use crate::adapters::udp::{self, UdpAdapter};
8+
use crate::adapters::udp::{self, UdpAdapter, UdpConnectConfig, UdpListenConfig};
99
#[cfg(feature = "websocket")]
1010
use crate::adapters::ws::{self, WsAdapter};
1111

@@ -163,7 +163,7 @@ pub enum TransportConnect {
163163
#[cfg(feature = "tcp")]
164164
FramedTcp,
165165
#[cfg(feature = "udp")]
166-
Udp,
166+
Udp(UdpConnectConfig),
167167
#[cfg(feature = "websocket")]
168168
Ws,
169169
}
@@ -176,7 +176,7 @@ impl TransportConnect {
176176
#[cfg(feature = "tcp")]
177177
Self::FramedTcp => Transport::FramedTcp,
178178
#[cfg(feature = "udp")]
179-
Self::Udp => Transport::Udp,
179+
Self::Udp(_) => Transport::Udp,
180180
#[cfg(feature = "websocket")]
181181
Self::Ws => Transport::Ws,
182182
};
@@ -193,7 +193,7 @@ impl From<Transport> for TransportConnect {
193193
#[cfg(feature = "tcp")]
194194
Transport::FramedTcp => Self::FramedTcp,
195195
#[cfg(feature = "udp")]
196-
Transport::Udp => Self::Udp,
196+
Transport::Udp => Self::Udp(UdpConnectConfig::default()),
197197
#[cfg(feature = "websocket")]
198198
Transport::Ws => Self::Ws,
199199
}
@@ -206,7 +206,7 @@ pub enum TransportListen {
206206
#[cfg(feature = "tcp")]
207207
FramedTcp,
208208
#[cfg(feature = "udp")]
209-
Udp,
209+
Udp(UdpListenConfig),
210210
#[cfg(feature = "websocket")]
211211
Ws,
212212
}
@@ -219,7 +219,7 @@ impl TransportListen {
219219
#[cfg(feature = "tcp")]
220220
Self::FramedTcp => Transport::FramedTcp,
221221
#[cfg(feature = "udp")]
222-
Self::Udp => Transport::Udp,
222+
Self::Udp(_) => Transport::Udp,
223223
#[cfg(feature = "websocket")]
224224
Self::Ws => Transport::Ws,
225225
};
@@ -236,7 +236,7 @@ impl From<Transport> for TransportListen {
236236
#[cfg(feature = "tcp")]
237237
Transport::FramedTcp => Self::FramedTcp,
238238
#[cfg(feature = "udp")]
239-
Transport::Udp => Self::Udp,
239+
Transport::Udp => Self::Udp(UdpListenConfig::default()),
240240
#[cfg(feature = "websocket")]
241241
Transport::Ws => Self::Ws,
242242
}

0 commit comments

Comments
 (0)