mavlink_core/connection/udp/
sync.rs1use super::config::{UdpConfig, UdpMode};
4
5use crate::Dialect;
6use crate::MavlinkReader;
7use crate::connection::get_socket_addr;
8use crate::connection::sync::{Connectable, DialectConnection, SyncTransport, Transport};
9use std::io::{self, Read, Write};
10use std::net::{SocketAddr, UdpSocket};
11use std::sync::{Arc, Mutex};
12
13pub(crate) struct UdpRead {
14 socket: UdpSocket,
15 reply_destination: Option<Arc<Mutex<Option<SocketAddr>>>>,
16}
17
18impl Read for UdpRead {
19 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
20 let (len, address) = self.socket.recv_from(buf)?;
21 if let Some(reply_destination) = &self.reply_destination {
22 *reply_destination.lock().unwrap() = Some(address);
23 }
24 Ok(len)
25 }
26}
27
28pub(crate) struct UdpWrite {
29 socket: UdpSocket,
30 destination: Arc<Mutex<Option<SocketAddr>>>,
31 connected: bool,
32}
33
34impl Write for UdpWrite {
35 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
36 if self.connected {
37 return self.socket.send(buf);
38 }
39 self.socket.send_to(
40 buf,
41 self.destination
42 .lock()
43 .unwrap()
44 .expect("destination checked before write"),
45 )
46 }
47
48 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
49 if self.write(buf)? == buf.len() {
50 Ok(())
51 } else {
52 Err(io::ErrorKind::WriteZero.into())
53 }
54 }
55
56 fn flush(&mut self) -> io::Result<()> {
57 Ok(())
58 }
59}
60
61pub struct UdpConnection {
62 reader: Mutex<MavlinkReader<UdpRead>>,
63 writer: Mutex<UdpWrite>,
64}
65
66impl UdpConnection {
67 fn new(
68 socket: UdpSocket,
69 server: bool,
70 dest: Option<SocketAddr>,
71 connected: bool,
72 ) -> io::Result<Self> {
73 let destination = Arc::new(Mutex::new(dest));
74 Ok(Self {
75 reader: Mutex::new(MavlinkReader::new(UdpRead {
76 socket: socket.try_clone()?,
77 reply_destination: server.then(|| destination.clone()),
78 })),
79 writer: Mutex::new(UdpWrite {
80 socket,
81 destination,
82 connected,
83 }),
84 })
85 }
86}
87
88impl SyncTransport for UdpConnection {
89 type Reader = UdpRead;
90 type Writer = UdpWrite;
91
92 fn reader(&self) -> std::sync::MutexGuard<'_, MavlinkReader<Self::Reader>> {
93 self.reader.lock().unwrap()
94 }
95
96 fn lock_writer(&self) -> Option<std::sync::MutexGuard<'_, Self::Writer>> {
97 let writer = self.writer.lock().unwrap();
98 let has_destination = writer.destination.lock().unwrap().is_some();
99 has_destination.then_some(writer)
100 }
101
102 fn set_nonblocking(
103 &self,
104 reader: &mut MavlinkReader<Self::Reader>,
105 enabled: bool,
106 ) -> io::Result<()> {
107 reader.get_mut().socket.set_nonblocking(enabled)
108 }
109}
110
111impl UdpConfig {
112 pub(crate) fn open(&self) -> io::Result<UdpConnection> {
113 let (address, server, dest): (&str, _, _) = match self.mode {
114 UdpMode::Udpin => (&self.address, true, None),
115 _ => ("0.0.0.0:0", false, Some(get_socket_addr(&self.address)?)),
116 };
117 let (socket, connected) = match self.take_socket()? {
118 Some(socket) => (socket, !server),
119 None => (UdpSocket::bind(address)?, false),
120 };
121 if let Some(timeout) = self.read_timeout {
122 socket.set_read_timeout(Some(timeout))?;
123 }
124 if matches!(self.mode, UdpMode::UdpBroadcast) {
125 socket.set_broadcast(true)?;
126 }
127 UdpConnection::new(socket, server, dest, connected)
128 }
129}
130
131impl Connectable for UdpConfig {
132 fn connect_with_dialect<D: Dialect + Send + Sync>(
133 &self,
134 dialect: D,
135 ) -> io::Result<DialectConnection<D>> {
136 Ok(DialectConnection::new(
137 Transport::Udp(self.open()?),
138 dialect,
139 ))
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_datagram_reading() {
149 let receiver_socket = UdpSocket::bind("127.0.0.1:5000").unwrap();
150 let mut udp_reader = UdpRead {
151 socket: receiver_socket.try_clone().unwrap(),
152 reply_destination: None,
153 };
154 let sender_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
155 sender_socket.connect("127.0.0.1:5000").unwrap();
156
157 let datagram: Vec<u8> = (0..50).collect::<Vec<_>>();
158
159 let mut n_sent = sender_socket.send(&datagram).unwrap();
160 assert_eq!(n_sent, datagram.len());
161 n_sent = sender_socket.send(&datagram).unwrap();
162 assert_eq!(n_sent, datagram.len());
163
164 let mut buf = [0u8; 50];
165
166 let mut n_read = udp_reader.read(&mut buf).unwrap();
167 assert_eq!(n_read, 50);
168 assert_eq!(&buf[0..n_read], datagram.as_slice());
169
170 n_read = udp_reader.read(&mut buf).unwrap();
171 assert_eq!(n_read, 50);
172 assert_eq!(&buf[0..n_read], datagram.as_slice());
173 }
174}