ts_netstack_smoltcp_socket/
udp.rs1use core::{
2 fmt::{Debug, Formatter},
3 net::SocketAddr,
4 num::NonZeroUsize,
5};
6
7use bytes::Bytes;
8use netcore::{HasChannel, Response, smoltcp::iface::SocketHandle};
9
10use crate::netcore::{DisplayExt, udp};
11
12pub struct UdpSocket {
14 pub(crate) sender: netcore::Channel,
15 pub(crate) handle: SocketHandle,
16
17 pub(crate) local: SocketAddr,
18}
19
20impl Debug for UdpSocket {
21 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
22 f.debug_struct("UdpSocket")
23 .field("handle", &self.handle.as_display_debug())
24 .field("local_endpoint", &self.local)
25 .finish()
26 }
27}
28
29impl UdpSocket {
30 pub fn send_to_blocking(
32 &self,
33 endpoint: SocketAddr,
34 data: &[u8],
35 ) -> Result<(), netcore::Error> {
36 self.request_blocking(udp::Command::Send {
37 endpoint,
38 local: None,
39 buf: Bytes::copy_from_slice(data),
40 })?
41 .to_ok()
42 }
43
44 pub async fn send_to(&self, endpoint: SocketAddr, data: &[u8]) -> Result<(), netcore::Error> {
46 self.request(udp::Command::Send {
47 endpoint,
48 local: None,
49 buf: Bytes::copy_from_slice(data),
50 })
51 .await?
52 .to_ok()
53 }
54
55 pub fn send_to_from_blocking(
60 &self,
61 endpoint: SocketAddr,
62 local: core::net::IpAddr,
63 data: &[u8],
64 ) -> Result<(), netcore::Error> {
65 self.request_blocking(udp::Command::Send {
66 endpoint,
67 local: Some(local),
68 buf: Bytes::copy_from_slice(data),
69 })?
70 .to_ok()
71 }
72
73 pub async fn send_to_from(
78 &self,
79 endpoint: SocketAddr,
80 local: core::net::IpAddr,
81 data: &[u8],
82 ) -> Result<(), netcore::Error> {
83 self.request(udp::Command::Send {
84 endpoint,
85 local: Some(local),
86 buf: Bytes::copy_from_slice(data),
87 })
88 .await?
89 .to_ok()
90 }
91
92 pub fn recv_from_blocking(
94 &self,
95 buf: &mut [u8],
96 ) -> Result<(SocketAddr, usize), netcore::Error> {
97 let len = NonZeroUsize::new(buf.len()).ok_or(netcore::Error::zero_buffer())?;
98
99 let resp = self.request_blocking(udp::Command::Recv { max_len: Some(len) })?;
100
101 self._udp_recv(resp, buf)
102 }
103
104 pub fn recv_from_bytes_blocking(&self) -> Result<(SocketAddr, Bytes), netcore::Error> {
106 let resp = self.request_blocking(udp::Command::Recv { max_len: None })?;
107 self._udp_recv_bytes(resp)
108 }
109
110 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(SocketAddr, usize), netcore::Error> {
112 let len = NonZeroUsize::new(buf.len()).ok_or(netcore::Error::zero_buffer())?;
113
114 let resp = self
115 .request(udp::Command::Recv { max_len: Some(len) })
116 .await?;
117
118 self._udp_recv(resp, buf)
119 }
120
121 pub async fn recv_from_bytes(&self) -> Result<(SocketAddr, Bytes), netcore::Error> {
123 let resp = self.request(udp::Command::Recv { max_len: None }).await?;
124
125 self._udp_recv_bytes(resp)
126 }
127
128 pub fn recv_from_with_dst_bytes_blocking(
134 &self,
135 ) -> Result<(SocketAddr, SocketAddr, Bytes), netcore::Error> {
136 let resp = self.request_blocking(udp::Command::Recv { max_len: None })?;
137 self._udp_recv_with_dst_bytes(resp)
138 }
139
140 pub async fn recv_from_with_dst_bytes(
146 &self,
147 ) -> Result<(SocketAddr, SocketAddr, Bytes), netcore::Error> {
148 let resp = self.request(udp::Command::Recv { max_len: None }).await?;
149 self._udp_recv_with_dst_bytes(resp)
150 }
151
152 fn _udp_recv(
153 &self,
154 resp: Response,
155 buf: &mut [u8],
156 ) -> Result<(SocketAddr, usize), netcore::Error> {
157 let (remote, ret) = self._udp_recv_bytes(resp)?;
158
159 debug_assert!(ret.len() <= buf.len());
160 let n_copied = ret.len().min(buf.len());
161
162 buf[..n_copied].copy_from_slice(&ret[..n_copied]);
163
164 Ok((remote, n_copied))
165 }
166
167 fn _udp_recv_bytes(&self, resp: Response) -> Result<(SocketAddr, Bytes), netcore::Error> {
168 let (remote, _local, ret) = self._udp_recv_with_dst_bytes(resp)?;
169 Ok((remote, ret))
170 }
171
172 fn _udp_recv_with_dst_bytes(
173 &self,
174 resp: Response,
175 ) -> Result<(SocketAddr, SocketAddr, Bytes), netcore::Error> {
176 netcore::try_response_as!(
177 resp,
178 udp::Response::RecvFrom {
179 remote,
180 local,
181 buf: ret,
182 truncated,
183 }
184 );
185
186 if let Some(truncated) = truncated {
187 tracing::warn!(truncated, "udp recv truncated");
188 }
189
190 Ok((remote, local, ret))
191 }
192
193 pub const fn local_addr(&self) -> SocketAddr {
195 self.local
196 }
197
198 socket_requestor_impl!();
199}
200
201impl Drop for UdpSocket {
202 fn drop(&mut self) {
203 if let Err(e) = self
204 .sender
205 .request_nonblocking(Some(self.handle), udp::Command::Close)
206 {
207 tracing::warn!(err = %e, "possible socket leak");
208 }
209 }
210}