1use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
28use core::{
29 net::{IpAddr, Ipv4Addr, SocketAddr},
30 task::Waker,
31};
32
33use ax_io::prelude::*;
34use ax_sync::{Mutex, SpinLock};
35use axpoll::{ExclusiveRegistrationSink, IoEvents, Pollable, SharedRegistrationSink};
36use axpoll_set::PollSet;
37use smoltcp::{
38 iface::SocketHandle,
39 phy::PacketMeta,
40 socket::udp::{self as smol, UdpMetadata},
41 storage::PacketMetadata,
42 wire::{IpAddress, IpEndpoint, IpListenEndpoint, IpProtocol},
43};
44
45use crate::{
46 ConnectStatus, IpCmsg, NetError, NetResult, ReadinessVersion, RecvFlags, RecvOptions,
47 SOCKET_SET, SendFlags, SendOptions, Shutdown, SocketAddrEx, SocketDeferPollWake, SocketOps,
48 addr::allocate_ephemeral_port,
49 config::{DeviceBinding, InterfaceId},
50 consts::{UDP_RX_BUF_LEN, UDP_TX_BUF_LEN},
51 flush_egress,
52 general::GeneralOptions,
53 get_control, interface_by_id,
54 ip_tos::{EgressIpTosKey, clear_egress_ip_tos, set_egress_ip_tos},
55 options::{Configurable, GetSocketOption, SetSocketOption},
56 request_poll,
57 rx_meta::{ReceivedTrafficClass, received_traffic_class},
58};
59
60struct CorkState {
65 buf: Vec<u8>,
66 remote: IpEndpoint,
67 source: IpAddress,
68}
69
70pub struct UdpSocket {
72 handle: SocketHandle,
74 bind_lock: Mutex<()>,
76 local_addr: Mutex<Option<IpEndpoint>>,
78 peer_addr: Mutex<Option<(IpEndpoint, IpAddress)>>,
80
81 general: GeneralOptions,
83 poll_state: Arc<PollSet>,
85 readiness_version: ReadinessVersion,
87 tos_keys: SpinLock<Vec<EgressIpTosKey>>,
89 cork: Mutex<Option<CorkState>>,
95}
96
97impl UdpSocket {
98 pub fn new() -> Self {
100 Self {
101 handle: SOCKET_SET.add(smol::Socket::new(
102 smol::PacketBuffer::new(vec![PacketMetadata::EMPTY; 256], vec![0; UDP_RX_BUF_LEN]),
103 smol::PacketBuffer::new(vec![PacketMetadata::EMPTY; 256], vec![0; UDP_TX_BUF_LEN]),
104 )),
105 bind_lock: Mutex::new(()),
106 local_addr: Mutex::new(None),
107 peer_addr: Mutex::new(None),
108
109 general: GeneralOptions::new(2, 2, 17), poll_state: Arc::new(PollSet::new()),
111 readiness_version: ReadinessVersion::new(),
112 tos_keys: SpinLock::new(Vec::new()),
113 cork: Mutex::new(None),
114 }
115 }
116
117 pub fn readiness_version(&self) -> u64 {
119 self.readiness_version.current()
120 }
121
122 pub fn bind_device(&self, interface_id: InterfaceId) -> NetResult {
124 if interface_by_id(interface_id).is_none() {
125 return Err(NetError::NoSuchDevice);
126 }
127 self.general.set_device_binding(DeviceBinding {
128 bound_if: Some(interface_id),
129 });
130 Ok(())
131 }
132
133 fn with_smol_socket<R>(&self, f: impl FnOnce(&mut smol::Socket) -> R) -> R {
135 SOCKET_SET.with_socket_mut::<smol::Socket, _, _>(self.handle, f)
136 }
137
138 fn remote_endpoint(&self) -> NetResult<(IpEndpoint, IpAddress)> {
140 match self.peer_addr.try_lock() {
141 Some(addr) => addr.ok_or(NetError::NotConnected),
142 None => Err(NetError::NotConnected),
143 }
144 }
145
146 fn source_for_remote(&self, remote: &IpAddress) -> NetResult<IpAddress> {
148 Ok(get_control()
149 .select_route_with_binding(remote, self.general.device_binding())?
150 .source)
151 }
152
153 fn send_source_for_remote(&self, remote: &IpAddress) -> NetResult<IpAddress> {
154 if let Some(local_ep) = *self.local_addr.lock()
155 && !local_ep.addr.is_unspecified()
156 {
157 Ok(local_ep.addr)
158 } else {
159 self.source_for_remote(remote)
160 }
161 }
162
163 fn source_and_binding_update_for_remote(
164 &self,
165 remote: &IpAddress,
166 ) -> NetResult<(IpAddress, bool)> {
167 if let Some(local_ep) = *self.local_addr.lock()
168 && !local_ep.addr.is_unspecified()
169 {
170 Ok((local_ep.addr, false))
171 } else {
172 Ok((self.source_for_remote(remote)?, true))
173 }
174 }
175
176 fn track_egress_ip_tos(&self, local_addr: Option<IpAddress>, remote: IpEndpoint) {
177 let tos = self.general.ip_tos();
178 if tos == 0 {
179 return;
180 }
181 let Some(local_addr) = local_addr else {
182 return;
183 };
184 let Some(local) = self.local_addr.lock().map(|endpoint| IpEndpoint {
185 addr: local_addr,
186 port: endpoint.port,
187 }) else {
188 return;
189 };
190 let Some(key) = EgressIpTosKey::exact(IpProtocol::Udp, local, remote) else {
191 return;
192 };
193
194 let mut keys = self.tos_keys.lock();
195 if !keys.contains(&key) {
196 keys.push(key);
197 }
198 set_egress_ip_tos(key, tos);
199 }
200
201 fn sync_tracked_egress_ip_tos(&self) {
202 let tos = self.general.ip_tos();
203 for key in self.tos_keys.lock().iter().copied() {
204 set_egress_ip_tos(key, tos);
205 }
206 }
207
208 fn clear_tracked_egress_ip_tos(&self) {
209 for key in self.tos_keys.lock().drain(..) {
210 clear_egress_ip_tos(key);
211 }
212 }
213}
214
215impl Configurable for UdpSocket {
216 fn get_option_inner(&self, option: &mut GetSocketOption) -> NetResult<bool> {
217 use GetSocketOption as O;
218
219 if self.general.get_option_inner(option)? {
220 return Ok(true);
221 }
222 match option {
223 O::Ttl(ttl) => {
224 self.with_smol_socket(|socket| {
225 **ttl = socket.hop_limit().unwrap_or(64);
226 });
227 }
228 O::SendBuffer(size) => {
229 **size = UDP_TX_BUF_LEN;
230 }
231 O::ReceiveBuffer(size) => {
232 **size = UDP_RX_BUF_LEN;
233 }
234 _ => return Ok(false),
235 }
236 Ok(true)
237 }
238
239 fn set_option_inner(&self, option: SetSocketOption) -> NetResult<bool> {
240 use SetSocketOption as O;
241
242 if let O::IpTos(tos) = option {
243 self.general.set_ip_tos(*tos);
244 self.sync_tracked_egress_ip_tos();
245 return Ok(true);
246 }
247
248 if self.general.set_option_inner(option)? {
249 return Ok(true);
250 }
251 match option {
252 O::Ttl(ttl) => {
253 self.with_smol_socket(|socket| {
254 socket.set_hop_limit(Some(*ttl));
255 });
256 }
257 _ => return Ok(false),
258 }
259 Ok(true)
260 }
261}
262impl SocketOps for UdpSocket {
263 fn bind(&self, local_addr: SocketAddrEx) -> NetResult {
265 let mut local_addr = local_addr.into_ip()?;
266 let _bind_guard = self.bind_lock.lock();
267
268 if self.local_addr.lock().is_some() {
269 return Err(NetError::InvalidInput);
270 }
271 if local_addr.port() == 0 {
272 local_addr.set_port(get_ephemeral_port()?);
273 }
274
275 let local_endpoint = IpEndpoint::from(local_addr);
276 let endpoint = IpListenEndpoint {
277 addr: (!local_endpoint.addr.is_unspecified()).then_some(local_endpoint.addr),
278 port: local_endpoint.port,
279 };
280 let binding = get_control().local_binding_for(&endpoint)?;
281
282 self.with_smol_socket(|socket| {
283 socket.bind(endpoint).map_err(|e| match e {
284 smol::BindError::InvalidState => NetError::InvalidInput,
285 smol::BindError::Unaddressable => NetError::ConnectionRefused,
286 })
287 })?;
288 if let Err(err) = SOCKET_SET.udp_bind(
289 self.handle,
290 local_endpoint.addr,
291 local_endpoint.port,
292 self.general.reuse_port(),
293 ) {
294 self.with_smol_socket(|socket| socket.close());
295 return Err(err);
296 }
297 if binding.bound_if.is_some() {
298 self.general.set_device_binding(binding);
299 }
300
301 *self.local_addr.lock() = Some(local_endpoint);
302 info!("UDP socket {}: bound on {}", self.handle, endpoint);
303 Ok(())
304 }
305
306 fn start_connect(&self, remote_addr: SocketAddrEx) -> NetResult<ConnectStatus> {
308 let remote_addr = remote_addr.into_ip()?;
309 let mut guard = self.peer_addr.lock();
310
311 if self.local_addr.lock().is_none() {
312 self.bind(SocketAddrEx::Ip(SocketAddr::new(
313 IpAddr::V4(Ipv4Addr::UNSPECIFIED),
314 0,
315 )))?;
316 }
317
318 let remote_addr = IpEndpoint::from(remote_addr);
319 let local_port = self.local_addr.lock().map_or(0, |endpoint| endpoint.port);
320 let (src, should_update_binding) =
321 self.source_and_binding_update_for_remote(&remote_addr.addr)?;
322
323 *guard = Some((remote_addr, src));
324
325 if should_update_binding {
326 self.general
327 .set_device_binding(get_control().local_binding_for(&IpListenEndpoint {
328 addr: Some(src),
329 port: local_port,
330 })?);
331 }
332
333 debug!("UDP socket {}: connected to {}", self.handle, remote_addr);
334 Ok(ConnectStatus::Connected)
335 }
336
337 fn try_send(&self, mut src: impl Read + IoBuf, options: &mut SendOptions) -> NetResult<usize> {
339 if options.flags.contains(SendFlags::OOB) {
341 return Err(NetError::OperationNotSupported);
342 }
343
344 if self.local_addr.lock().is_none() {
345 self.bind(SocketAddrEx::Ip(SocketAddr::new(
346 IpAddr::V4(Ipv4Addr::UNSPECIFIED),
347 0,
348 )))?;
349 }
350 const CORK_MAX: usize = UDP_TX_BUF_LEN;
354 let more = options.flags.contains(SendFlags::MORE);
355
356 if more {
357 let (remote_addr, source_addr) = match options.to.clone() {
358 Some(addr) => {
359 let addr = IpEndpoint::from(addr.into_ip()?);
360 let src = self.send_source_for_remote(&addr.addr)?;
361 (addr, src)
362 }
363 None => match self.remote_endpoint() {
364 Ok((endpoint, src)) => (endpoint, src),
365 Err(_) => return Err(NetError::DestAddrRequired),
366 },
367 };
368 if remote_addr.port == 0 || remote_addr.addr.is_unspecified() {
369 return Err(NetError::InvalidInput);
370 }
371 let len = src.remaining();
372 if len > CORK_MAX {
373 return Err(NetError::MessageTooLong);
374 }
375 let mut tmp = alloc::vec![0u8; len];
376 let read = src.read(&mut tmp)?;
377 let mut cork = self.cork.lock();
378 if cork.is_none() {
379 *cork = Some(CorkState {
380 buf: tmp[..read].to_vec(),
381 remote: remote_addr,
382 source: source_addr,
383 });
384 } else {
385 let prev = cork.as_ref().unwrap().buf.len();
386 let new_len = prev.checked_add(read).ok_or(NetError::MessageTooLong)?;
387 if new_len > CORK_MAX {
388 return Err(NetError::MessageTooLong);
389 }
390 cork.as_mut().unwrap().buf.extend_from_slice(&tmp[..read]);
391 }
392 return Ok(read);
393 }
394
395 let resolved = match options.to.clone() {
399 Some(addr) => {
400 let addr = IpEndpoint::from(addr.into_ip()?);
401 let src = self.send_source_for_remote(&addr.addr)?;
402 Some((addr, src))
403 }
404 None => self.remote_endpoint().ok(),
405 };
406
407 request_poll();
408 let mut cork_guard = self.cork.lock();
409 let (endpoint, local_addr, payload_len) = if let Some(ref c) = *cork_guard {
412 let total = c
413 .buf
414 .len()
415 .checked_add(src.remaining())
416 .ok_or(NetError::MessageTooLong)?;
417 if total > CORK_MAX {
418 return Err(NetError::MessageTooLong);
419 }
420 (c.remote, Some(c.source), total)
421 } else {
422 match resolved {
423 Some((remote, source)) => {
424 if remote.port == 0 || remote.addr.is_unspecified() {
425 return Err(NetError::InvalidInput);
426 }
427 (remote, Some(source), src.remaining())
428 }
429 None => return Err(NetError::DestAddrRequired),
430 }
431 };
432 let result = self.with_smol_socket(|socket| {
433 if !socket.is_open() {
434 Err(NetError::NotConnected)
436 } else if !socket.can_send() {
437 Err(NetError::WouldBlock)
438 } else {
439 self.track_egress_ip_tos(local_addr, endpoint);
440 if payload_len == 0 {
442 socket
443 .send(
444 0,
445 UdpMetadata {
446 endpoint,
447 local_address: local_addr,
448 meta: PacketMeta::default(),
449 },
450 )
451 .map_err(|e| match e {
452 smol::SendError::BufferFull => NetError::WouldBlock,
453 smol::SendError::Unaddressable => NetError::ConnectionRefused,
454 })?;
455 *cork_guard = None;
456 return Ok(0);
457 }
458 let buf = socket
459 .send(
460 payload_len,
461 UdpMetadata {
462 endpoint,
463 local_address: local_addr,
464 meta: PacketMeta::default(),
465 },
466 )
467 .map_err(|e| match e {
468 smol::SendError::BufferFull => NetError::WouldBlock,
469 smol::SendError::Unaddressable => NetError::ConnectionRefused,
470 })?;
471 let mut total_written = 0;
472 let mut cur_read = 0;
473 if let Some(ref c) = *cork_guard {
474 let n = c.buf.len().min(buf.len());
475 buf[..n].copy_from_slice(&c.buf[..n]);
476 total_written += n;
477 }
478 if total_written < buf.len() {
479 cur_read = src.read(&mut buf[total_written..])?;
480 total_written += cur_read;
481 }
482 assert_eq!(total_written, buf.len());
483 *cork_guard = None;
485 Ok(cur_read)
487 }
488 })?;
489 request_poll();
490 Ok(result)
491 }
492
493 fn try_recv(&self, mut dst: impl Write, options: &mut RecvOptions) -> NetResult<usize> {
495 enum ExpectedRemote<'a> {
496 Any(&'a mut SocketAddrEx),
497 AnyDiscard,
498 Expecting(IpEndpoint),
499 }
500 let mut expected_remote = match options.from.as_deref_mut() {
501 Some(addr) => ExpectedRemote::Any(addr),
502 None => match self.remote_endpoint() {
503 Ok((endpoint, _)) => ExpectedRemote::Expecting(endpoint),
504 Err(_) => ExpectedRemote::AnyDiscard,
505 },
506 };
507
508 request_poll();
509 self.with_smol_socket(|socket| {
510 if !socket.can_recv() {
511 Err(NetError::WouldBlock)
512 } else {
513 let result = if options.flags.contains(RecvFlags::PEEK) {
514 socket.peek().map(|(data, meta)| (data, *meta))
515 } else {
516 socket.recv()
517 };
518 match result {
519 Ok((src, meta)) => {
520 match &mut expected_remote {
521 ExpectedRemote::Any(remote_addr) => {
522 **remote_addr = SocketAddrEx::Ip(meta.endpoint.into());
523 }
524 ExpectedRemote::AnyDiscard => {
525 }
527 ExpectedRemote::Expecting(expected) => {
528 if (!expected.addr.is_unspecified()
529 && expected.addr != meta.endpoint.addr)
530 || (expected.port != 0 && expected.port != meta.endpoint.port)
531 {
532 return Err(NetError::WouldBlock);
533 }
534 }
535 }
536
537 let read = dst.write(src)?;
538 if read < src.len() {
539 warn!("UDP message truncated: {} -> {} bytes", src.len(), read);
540 if let Some(ref mut truncated) = options.truncated {
541 **truncated = true;
542 }
543 }
544
545 if let Some(cmsg) = options.cmsg.as_deref_mut()
546 && let Some(traffic_class) = received_traffic_class(meta.meta)
547 {
548 match traffic_class {
549 ReceivedTrafficClass::Ipv4(tos)
550 if self.general.recv_traffic_class() =>
551 {
552 cmsg.push(Box::new(IpCmsg::Ipv6TrafficClass(tos)));
553 }
554 ReceivedTrafficClass::Ipv4(tos) if self.general.recv_tos() => {
555 cmsg.push(Box::new(IpCmsg::Ipv4Tos(tos)));
556 }
557 ReceivedTrafficClass::Ipv6(tclass)
558 if self.general.recv_traffic_class() =>
559 {
560 cmsg.push(Box::new(IpCmsg::Ipv6TrafficClass(tclass)));
561 }
562 _ => {}
563 }
564 }
565
566 Ok(if options.flags.contains(RecvFlags::TRUNCATE) {
567 src.len()
568 } else {
569 read
570 })
571 }
572 Err(smol::RecvError::Exhausted) => Err(NetError::WouldBlock),
573 Err(smol::RecvError::Truncated) => {
574 unreachable!("UDP socket recv never returns Err(Truncated)")
575 }
576 }
577 }
578 })
579 }
580
581 fn local_addr(&self) -> NetResult<SocketAddrEx> {
582 match self.local_addr.try_lock() {
583 Some(addr) => addr
584 .map(Into::into)
585 .map(SocketAddrEx::Ip)
586 .ok_or(NetError::NotConnected),
587 None => Err(NetError::NotConnected),
588 }
589 }
590
591 fn peer_addr(&self) -> NetResult<SocketAddrEx> {
592 self.remote_endpoint()
593 .map(|it| it.0.into())
594 .map(SocketAddrEx::Ip)
595 }
596
597 fn shutdown(&self, _how: Shutdown) -> NetResult {
598 request_poll();
600
601 self.with_smol_socket(|socket| {
602 debug!("UDP socket {}: shutting down", self.handle);
603 socket.close();
604 });
605 Ok(())
606 }
607}
608
609impl Pollable for UdpSocket {
610 fn poll(&self) -> IoEvents {
611 request_poll();
612 let Some(local_addr) = self.local_addr.try_lock() else {
613 return IoEvents::empty();
614 };
615 if local_addr.is_none() {
616 return IoEvents::empty();
617 }
618 drop(local_addr);
619
620 let mut events = IoEvents::empty();
621 self.with_smol_socket(|socket| {
622 events.set(IoEvents::IN, socket.can_recv());
623 events.set(IoEvents::OUT, socket.can_send());
624 });
625 events
626 }
627
628 unsafe fn register_shared(&self, sink: &mut dyn SharedRegistrationSink, events: IoEvents) {
629 unsafe { sink.register_shared(&self.poll_state, events) };
630 self.arm_poll_sources(events);
631 }
632
633 unsafe fn register_exclusive(
634 &self,
635 sink: &mut dyn ExclusiveRegistrationSink,
636 events: IoEvents,
637 ) {
638 unsafe { sink.register_exclusive(&self.poll_state, events) };
639 self.arm_poll_sources(events);
640 }
641}
642
643impl UdpSocket {
644 fn arm_poll_sources(&self, events: IoEvents) {
645 self.with_smol_socket(|socket| {
646 if events.contains(IoEvents::IN) {
647 socket.register_recv_waker(&Waker::from(Arc::new(SocketDeferPollWake::new(
648 self.poll_state.clone(),
649 IoEvents::IN,
650 self.readiness_version.clone(),
651 ))));
652 }
653 if events.contains(IoEvents::OUT) {
654 socket.register_send_waker(&Waker::from(Arc::new(SocketDeferPollWake::new(
655 self.poll_state.clone(),
656 IoEvents::OUT,
657 self.readiness_version.clone(),
658 ))));
659 }
660 });
661 if events.intersects(IoEvents::IN | IoEvents::OUT) {
662 self.general
663 .register_waker(&Waker::from(Arc::new(SocketDeferPollWake::new(
664 self.poll_state.clone(),
665 events,
666 self.readiness_version.clone(),
667 ))));
668 }
669 }
670}
671
672impl Default for UdpSocket {
673 fn default() -> Self {
674 Self::new()
675 }
676}
677
678impl Drop for UdpSocket {
679 fn drop(&mut self) {
680 flush_egress();
685 self.shutdown(Shutdown::Both).ok();
686 self.clear_tracked_egress_ip_tos();
687 SOCKET_SET.remove(self.handle);
688 }
689}
690
691fn get_ephemeral_port() -> NetResult<u16> {
692 allocate_ephemeral_port(|port| {
693 SOCKET_SET.udp_port_available(IpAddress::Ipv4(Ipv4Addr::UNSPECIFIED), port)
694 })
695}