1use crate::poll::{PollEvents, POLLERR, POLLHUP, POLLIN, POLLOUT};
2use crate::vfs::normalize_path;
3use std::collections::{BTreeMap, BTreeSet, VecDeque};
4use std::error::Error;
5use std::fmt;
6use std::net::{Ipv4Addr, Ipv6Addr};
7use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
8use std::sync::{Arc, Mutex, MutexGuard};
9use std::time::Instant;
10
11pub type SocketId = u64;
12pub type SocketResult<T> = Result<T, SocketTableError>;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum SocketReadinessKind {
16 Data,
17 Accept,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct SocketReadiness {
22 pub socket_id: SocketId,
23 pub kind: SocketReadinessKind,
24}
25
26type SocketReadinessSink = Arc<dyn Fn(SocketReadiness) + Send + Sync + 'static>;
27
28#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
29pub struct SocketReadTraceSnapshot {
30 pub socket_record_clone_calls: u64,
31 pub socket_record_clone_us: u64,
32 pub read_recv_calls: u64,
33 pub read_recv_bytes: u64,
34 pub read_recv_chunks: u64,
35 pub read_recv_copy_us: u64,
36}
37
38struct SocketReadTraceCounters {
39 socket_record_clone_calls: AtomicU64,
40 socket_record_clone_us: AtomicU64,
41 read_recv_calls: AtomicU64,
42 read_recv_bytes: AtomicU64,
43 read_recv_chunks: AtomicU64,
44 read_recv_copy_us: AtomicU64,
45}
46
47impl SocketReadTraceCounters {
48 const fn new() -> Self {
49 Self {
50 socket_record_clone_calls: AtomicU64::new(0),
51 socket_record_clone_us: AtomicU64::new(0),
52 read_recv_calls: AtomicU64::new(0),
53 read_recv_bytes: AtomicU64::new(0),
54 read_recv_chunks: AtomicU64::new(0),
55 read_recv_copy_us: AtomicU64::new(0),
56 }
57 }
58}
59
60static SOCKET_READ_TRACE_ENABLED: AtomicBool = AtomicBool::new(false);
61static SOCKET_READ_TRACE_COUNTERS: SocketReadTraceCounters = SocketReadTraceCounters::new();
62
63pub fn set_socket_read_trace_enabled(enabled: bool) {
64 SOCKET_READ_TRACE_ENABLED.store(enabled, Ordering::Relaxed);
65}
66
67pub fn reset_socket_read_trace() {
68 for counter in [
69 &SOCKET_READ_TRACE_COUNTERS.socket_record_clone_calls,
70 &SOCKET_READ_TRACE_COUNTERS.socket_record_clone_us,
71 &SOCKET_READ_TRACE_COUNTERS.read_recv_calls,
72 &SOCKET_READ_TRACE_COUNTERS.read_recv_bytes,
73 &SOCKET_READ_TRACE_COUNTERS.read_recv_chunks,
74 &SOCKET_READ_TRACE_COUNTERS.read_recv_copy_us,
75 ] {
76 counter.store(0, Ordering::Relaxed);
77 }
78}
79
80pub fn socket_read_trace_snapshot() -> SocketReadTraceSnapshot {
81 SocketReadTraceSnapshot {
82 socket_record_clone_calls: SOCKET_READ_TRACE_COUNTERS
83 .socket_record_clone_calls
84 .load(Ordering::Relaxed),
85 socket_record_clone_us: SOCKET_READ_TRACE_COUNTERS
86 .socket_record_clone_us
87 .load(Ordering::Relaxed),
88 read_recv_calls: SOCKET_READ_TRACE_COUNTERS
89 .read_recv_calls
90 .load(Ordering::Relaxed),
91 read_recv_bytes: SOCKET_READ_TRACE_COUNTERS
92 .read_recv_bytes
93 .load(Ordering::Relaxed),
94 read_recv_chunks: SOCKET_READ_TRACE_COUNTERS
95 .read_recv_chunks
96 .load(Ordering::Relaxed),
97 read_recv_copy_us: SOCKET_READ_TRACE_COUNTERS
98 .read_recv_copy_us
99 .load(Ordering::Relaxed),
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
104pub struct InetSocketAddress {
105 host: String,
106 port: u16,
107}
108
109impl InetSocketAddress {
110 pub fn new(host: impl Into<String>, port: u16) -> Self {
111 Self {
112 host: host.into(),
113 port,
114 }
115 }
116
117 pub fn host(&self) -> &str {
118 &self.host
119 }
120
121 pub const fn port(&self) -> u16 {
122 self.port
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
127pub enum SocketDomain {
128 Inet,
129 Inet6,
130 Unix,
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
134pub enum SocketType {
135 Stream,
136 Datagram,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
140pub enum SocketState {
141 Created,
142 Bound,
143 Listening,
144 Connected,
145}
146
147impl SocketState {
148 pub const fn counts_as_listener(self) -> bool {
149 matches!(self, Self::Listening)
150 }
151
152 pub const fn counts_as_connection(self) -> bool {
153 matches!(self, Self::Connected)
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq)]
158pub enum SocketShutdown {
159 Read,
160 Write,
161 Both,
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub enum DatagramSocketOption {
166 ReuseAddr,
167 ReusePort,
168 Broadcast,
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub struct SocketSpec {
173 pub domain: SocketDomain,
174 pub socket_type: SocketType,
175}
176
177impl SocketSpec {
178 pub const fn new(domain: SocketDomain, socket_type: SocketType) -> Self {
179 Self {
180 domain,
181 socket_type,
182 }
183 }
184
185 pub const fn tcp() -> Self {
186 Self::new(SocketDomain::Inet, SocketType::Stream)
187 }
188
189 pub const fn udp() -> Self {
190 Self::new(SocketDomain::Inet, SocketType::Datagram)
191 }
192
193 pub const fn unix_stream() -> Self {
194 Self::new(SocketDomain::Unix, SocketType::Stream)
195 }
196
197 pub const fn unix_datagram() -> Self {
198 Self::new(SocketDomain::Unix, SocketType::Datagram)
199 }
200}
201
202#[derive(Debug, Clone, PartialEq, Eq)]
203pub struct SocketRecord {
204 id: SocketId,
205 owner_pid: u32,
206 spec: SocketSpec,
207 state: SocketState,
208 local_address: Option<InetSocketAddress>,
209 peer_address: Option<InetSocketAddress>,
210 local_unix_path: Option<String>,
211 peer_unix_path: Option<String>,
212 listener_state: Option<ListenerState>,
213 connection_state: Option<ConnectionState>,
214 datagram_state: Option<DatagramState>,
215}
216
217impl SocketRecord {
218 pub const fn id(&self) -> SocketId {
219 self.id
220 }
221
222 pub const fn owner_pid(&self) -> u32 {
223 self.owner_pid
224 }
225
226 pub const fn spec(&self) -> SocketSpec {
227 self.spec
228 }
229
230 pub const fn state(&self) -> SocketState {
231 self.state
232 }
233
234 pub fn local_address(&self) -> Option<&InetSocketAddress> {
235 self.local_address.as_ref()
236 }
237
238 pub fn peer_address(&self) -> Option<&InetSocketAddress> {
239 self.peer_address.as_ref()
240 }
241
242 pub fn local_unix_path(&self) -> Option<&str> {
243 self.local_unix_path.as_deref()
244 }
245
246 pub fn peer_unix_path(&self) -> Option<&str> {
247 self.peer_unix_path.as_deref()
248 }
249
250 pub fn listen_backlog(&self) -> Option<usize> {
251 self.listener_state.as_ref().map(|state| state.backlog)
252 }
253
254 pub fn pending_accept_count(&self) -> usize {
255 self.listener_state
256 .as_ref()
257 .map(|state| state.pending_accepts.len())
258 .unwrap_or(0)
259 }
260
261 pub fn peer_socket_id(&self) -> Option<SocketId> {
262 self.connection_state
263 .as_ref()
264 .and_then(|state| state.peer_socket_id)
265 }
266
267 pub fn buffered_read_bytes(&self) -> usize {
268 self.connection_state
269 .as_ref()
270 .map(ConnectionState::buffered_len)
271 .unwrap_or(0)
272 }
273
274 pub fn read_shutdown(&self) -> bool {
275 self.connection_state
276 .as_ref()
277 .map(|state| state.read_shutdown)
278 .unwrap_or(false)
279 }
280
281 pub fn write_shutdown(&self) -> bool {
282 self.connection_state
283 .as_ref()
284 .map(|state| state.write_shutdown)
285 .unwrap_or(false)
286 }
287
288 pub fn peer_write_shutdown(&self) -> bool {
289 self.connection_state
290 .as_ref()
291 .map(|state| state.peer_write_shutdown)
292 .unwrap_or(false)
293 }
294
295 pub fn queued_datagrams(&self) -> usize {
296 self.datagram_state
297 .as_ref()
298 .map(|state| state.recv_queue.len())
299 .unwrap_or(0)
300 }
301
302 pub fn queued_datagram_bytes(&self) -> usize {
303 self.datagram_state
304 .as_ref()
305 .map(|state| datagram_queue_bytes(&state.recv_queue))
306 .unwrap_or(0)
307 }
308
309 pub fn reuse_address(&self) -> bool {
310 self.datagram_state
311 .as_ref()
312 .map(|state| state.reuse_addr)
313 .unwrap_or(false)
314 }
315
316 pub fn reuse_port(&self) -> bool {
317 self.datagram_state
318 .as_ref()
319 .map(|state| state.reuse_port)
320 .unwrap_or(false)
321 }
322
323 pub fn broadcast_enabled(&self) -> bool {
324 self.datagram_state
325 .as_ref()
326 .map(|state| state.broadcast)
327 .unwrap_or(false)
328 }
329
330 pub fn multicast_membership_count(&self) -> usize {
331 self.datagram_state
332 .as_ref()
333 .map(|state| state.multicast_memberships.len())
334 .unwrap_or(0)
335 }
336
337 pub fn has_multicast_membership(&self, membership: &SocketMulticastMembership) -> bool {
338 self.datagram_state
339 .as_ref()
340 .map(|state| state.multicast_memberships.contains(membership))
341 .unwrap_or(false)
342 }
343}
344
345#[derive(Debug, Clone, PartialEq, Eq)]
346pub struct ReceivedDatagram {
347 source_address: Option<InetSocketAddress>,
348 payload: Vec<u8>,
349}
350
351impl ReceivedDatagram {
352 pub fn source_address(&self) -> Option<&InetSocketAddress> {
353 self.source_address.as_ref()
354 }
355
356 pub fn payload(&self) -> &[u8] {
357 &self.payload
358 }
359
360 pub fn into_parts(self) -> (Option<InetSocketAddress>, Vec<u8>) {
361 (self.source_address, self.payload)
362 }
363}
364
365#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
366pub struct SocketTableSnapshot {
367 pub sockets: usize,
368 pub listeners: usize,
369 pub connections: usize,
370 pub buffered_bytes: usize,
371 pub datagram_queue_len: usize,
372}
373
374#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
375pub struct SocketMulticastMembership {
376 group_address: String,
377 interface_address: Option<String>,
378}
379
380impl SocketMulticastMembership {
381 pub fn new(group_address: impl Into<String>, interface_address: Option<String>) -> Self {
382 Self {
383 group_address: group_address.into(),
384 interface_address,
385 }
386 }
387
388 pub fn group_address(&self) -> &str {
389 &self.group_address
390 }
391
392 pub fn interface_address(&self) -> Option<&str> {
393 self.interface_address.as_deref()
394 }
395}
396
397#[derive(Debug, Clone, PartialEq, Eq)]
398pub struct SocketTableError {
399 code: &'static str,
400 message: String,
401}
402
403impl SocketTableError {
404 pub fn code(&self) -> &'static str {
405 self.code
406 }
407
408 fn not_found(socket_id: SocketId) -> Self {
409 Self {
410 code: "ENOENT",
411 message: format!("no such socket {socket_id}"),
412 }
413 }
414
415 fn invalid_argument(message: impl Into<String>) -> Self {
416 Self {
417 code: "EINVAL",
418 message: message.into(),
419 }
420 }
421
422 fn address_in_use(message: impl Into<String>) -> Self {
423 Self {
424 code: "EADDRINUSE",
425 message: message.into(),
426 }
427 }
428
429 fn address_not_available(message: impl Into<String>) -> Self {
430 Self {
431 code: "EADDRNOTAVAIL",
432 message: message.into(),
433 }
434 }
435
436 fn not_found_address(message: impl Into<String>) -> Self {
437 Self {
438 code: "ECONNREFUSED",
439 message: message.into(),
440 }
441 }
442
443 fn would_block(message: impl Into<String>) -> Self {
444 Self {
445 code: "EAGAIN",
446 message: message.into(),
447 }
448 }
449
450 fn not_connected(message: impl Into<String>) -> Self {
451 Self {
452 code: "ENOTCONN",
453 message: message.into(),
454 }
455 }
456
457 fn broken_pipe(message: impl Into<String>) -> Self {
458 Self {
459 code: "EPIPE",
460 message: message.into(),
461 }
462 }
463}
464
465impl fmt::Display for SocketTableError {
466 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467 write!(f, "{}: {}", self.code, self.message)
468 }
469}
470
471impl Error for SocketTableError {}
472
473#[derive(Debug, Default)]
474struct SocketTableState {
475 sockets: BTreeMap<SocketId, SocketRecord>,
476 by_owner: BTreeMap<u32, BTreeSet<SocketId>>,
477 bound_inet_streams: BTreeMap<InetSocketAddress, SocketId>,
478 bound_inet_datagrams: BTreeMap<InetSocketAddress, BTreeSet<SocketId>>,
479 bound_unix_streams: BTreeMap<String, SocketId>,
480 multicast_groups: BTreeMap<SocketMulticastMembership, BTreeSet<SocketId>>,
481 next_socket_id: SocketId,
482}
483
484#[derive(Debug, Clone, PartialEq, Eq)]
485struct ListenerState {
486 backlog: usize,
487 pending_accepts: VecDeque<PendingConnection>,
488}
489
490#[derive(Debug, Clone, PartialEq, Eq, Default)]
491struct ConnectionState {
492 peer_socket_id: Option<SocketId>,
493 recv_buffer: VecDeque<Vec<u8>>,
494 recv_buffer_len: usize,
495 read_shutdown: bool,
496 write_shutdown: bool,
497 peer_write_shutdown: bool,
498}
499
500impl ConnectionState {
501 fn buffered_len(&self) -> usize {
502 self.recv_buffer_len
503 }
504
505 fn has_buffered_data(&self) -> bool {
506 self.recv_buffer_len > 0
507 }
508
509 fn push_recv(&mut self, data: &[u8]) {
510 if data.is_empty() {
511 return;
512 }
513 self.recv_buffer.push_back(data.to_vec());
514 self.recv_buffer_len = self.recv_buffer_len.saturating_add(data.len());
515 }
516
517 fn read_recv(&mut self, max_bytes: usize) -> Option<Vec<u8>> {
518 if max_bytes == 0 {
519 return Some(Vec::new());
520 }
521 if self.recv_buffer_len == 0 {
522 return None;
523 }
524
525 let read_len = self.recv_buffer_len.min(max_bytes);
526 self.recv_buffer_len -= read_len;
527
528 let mut remaining = read_len;
529 let mut chunks = 0usize;
530 let trace_started = SOCKET_READ_TRACE_ENABLED
531 .load(Ordering::Relaxed)
532 .then(Instant::now);
533 let mut out = Vec::with_capacity(read_len);
534 while remaining > 0 {
535 let mut chunk = self.recv_buffer.pop_front()?;
536 chunks += 1;
537 if chunk.len() <= remaining {
538 remaining -= chunk.len();
539 out.extend_from_slice(&chunk);
540 continue;
541 }
542
543 let tail = chunk.split_off(remaining);
544 out.extend_from_slice(&chunk);
545 self.recv_buffer.push_front(tail);
546 remaining = 0;
547 }
548 if let Some(started) = trace_started {
549 SOCKET_READ_TRACE_COUNTERS
550 .read_recv_calls
551 .fetch_add(1, Ordering::Relaxed);
552 SOCKET_READ_TRACE_COUNTERS.read_recv_bytes.fetch_add(
553 u64::try_from(read_len).unwrap_or(u64::MAX),
554 Ordering::Relaxed,
555 );
556 SOCKET_READ_TRACE_COUNTERS
557 .read_recv_chunks
558 .fetch_add(u64::try_from(chunks).unwrap_or(u64::MAX), Ordering::Relaxed);
559 SOCKET_READ_TRACE_COUNTERS.read_recv_copy_us.fetch_add(
560 u64::try_from(started.elapsed().as_micros()).unwrap_or(u64::MAX),
561 Ordering::Relaxed,
562 );
563 }
564 Some(out)
565 }
566
567 fn clear_recv(&mut self) {
568 self.recv_buffer.clear();
569 self.recv_buffer_len = 0;
570 }
571}
572
573#[derive(Debug, Clone, PartialEq, Eq)]
574struct PendingConnection {
575 peer_address: Option<InetSocketAddress>,
576 peer_unix_path: Option<String>,
577 accepted_socket_id: Option<SocketId>,
578}
579
580#[derive(Debug, Clone, PartialEq, Eq, Default)]
581struct DatagramState {
582 recv_queue: VecDeque<QueuedDatagram>,
583 reuse_addr: bool,
584 reuse_port: bool,
585 broadcast: bool,
586 multicast_memberships: BTreeSet<SocketMulticastMembership>,
587}
588
589#[derive(Debug, Clone, PartialEq, Eq)]
590struct QueuedDatagram {
591 source_address: Option<InetSocketAddress>,
592 payload: Vec<u8>,
593}
594
595struct SocketTableInner {
596 state: Mutex<SocketTableState>,
597 readiness_sink: Mutex<Option<SocketReadinessSink>>,
598}
599
600impl Default for SocketTableInner {
601 fn default() -> Self {
602 Self {
603 state: Mutex::new(SocketTableState::default()),
604 readiness_sink: Mutex::new(None),
605 }
606 }
607}
608
609impl fmt::Debug for SocketTableInner {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 f.debug_struct("SocketTableInner")
612 .field("state", &self.state)
613 .finish_non_exhaustive()
614 }
615}
616
617#[derive(Debug, Clone, Default)]
618pub struct SocketTable {
619 inner: Arc<SocketTableInner>,
620}
621
622impl SocketTable {
623 pub fn new() -> Self {
624 Self::default()
625 }
626
627 pub fn set_readiness_sink<F>(&self, sink: Option<F>)
628 where
629 F: Fn(SocketReadiness) + Send + Sync + 'static,
630 {
631 let mut target = lock_or_recover(&self.inner.readiness_sink);
632 *target = sink.map(|sink| Arc::new(sink) as SocketReadinessSink);
633 }
634
635 fn emit_readiness(&self, readiness: Option<SocketReadiness>) {
636 let Some(readiness) = readiness else {
637 return;
638 };
639 let sink = lock_or_recover(&self.inner.readiness_sink).clone();
640 if let Some(sink) = sink {
641 sink(readiness);
642 }
643 }
644
645 pub fn allocate(&self, owner_pid: u32, spec: SocketSpec) -> SocketRecord {
646 self.allocate_with_state(owner_pid, spec, SocketState::Created)
647 }
648
649 pub fn allocate_with_state(
650 &self,
651 owner_pid: u32,
652 spec: SocketSpec,
653 state: SocketState,
654 ) -> SocketRecord {
655 let mut table = lock_or_recover(&self.inner.state);
656 let socket_id = next_socket_id(&mut table);
657 let record = SocketRecord {
658 id: socket_id,
659 owner_pid,
660 spec,
661 state,
662 local_address: None,
663 peer_address: None,
664 local_unix_path: None,
665 peer_unix_path: None,
666 listener_state: None,
667 connection_state: default_connection_state(spec, state),
668 datagram_state: default_datagram_state(spec),
669 };
670 table.sockets.insert(socket_id, record.clone());
671 table
672 .by_owner
673 .entry(owner_pid)
674 .or_default()
675 .insert(socket_id);
676 record
677 }
678
679 pub fn get(&self, socket_id: SocketId) -> Option<SocketRecord> {
680 lock_or_recover(&self.inner.state)
681 .sockets
682 .get(&socket_id)
683 .cloned()
684 }
685
686 pub fn records_for_owner(&self, owner_pid: u32) -> Vec<SocketRecord> {
687 let table = lock_or_recover(&self.inner.state);
688 let Some(socket_ids) = table.by_owner.get(&owner_pid) else {
689 return Vec::new();
690 };
691 socket_ids
692 .iter()
693 .filter_map(|socket_id| table.sockets.get(socket_id).cloned())
694 .collect()
695 }
696
697 pub fn update_state(
698 &self,
699 socket_id: SocketId,
700 new_state: SocketState,
701 ) -> SocketResult<SocketRecord> {
702 let mut table = lock_or_recover(&self.inner.state);
703 let record = table
704 .sockets
705 .get_mut(&socket_id)
706 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
707 validate_state_transition(record.state, new_state)?;
708 record.state = new_state;
709 if new_state != SocketState::Listening {
710 record.listener_state = None;
711 }
712 if new_state == SocketState::Connected && supports_connection_lifecycle(record.spec) {
713 record
714 .connection_state
715 .get_or_insert_with(ConnectionState::default);
716 } else if new_state != SocketState::Connected {
717 record.connection_state = None;
718 }
719 Ok(record.clone())
720 }
721
722 pub fn bind_inet(
723 &self,
724 socket_id: SocketId,
725 address: InetSocketAddress,
726 ) -> SocketResult<SocketRecord> {
727 let mut address = normalize_inet_address(address);
728 let mut table = lock_or_recover(&self.inner.state);
729 let existing = table
730 .sockets
731 .get(&socket_id)
732 .cloned()
733 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
734 if !supports_inet_bind(existing.spec) {
735 return Err(SocketTableError::invalid_argument(format!(
736 "socket {socket_id} is not an INET socket"
737 )));
738 }
739 if address.port() == 0 {
742 let port = assign_ephemeral_inet_port(&table, existing.spec, address.host())?;
743 address = normalize_inet_address(InetSocketAddress::new(address.host(), port));
744 }
745 let conflicting_ids =
746 lookup_conflicting_bound_inet_socket_ids(&table, existing.spec, &address);
747 if has_incompatible_inet_bind_conflict(&table, &existing, &conflicting_ids) {
748 return Err(SocketTableError::address_in_use(format!(
749 "address {}:{} is already bound",
750 address.host(),
751 address.port()
752 )));
753 }
754 let cloned = {
755 let record = table
756 .sockets
757 .get_mut(&socket_id)
758 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
759
760 match record.state {
761 SocketState::Created => {}
762 SocketState::Bound if record.local_address.as_ref() == Some(&address) => {
763 return Ok(record.clone());
764 }
765 SocketState::Bound | SocketState::Listening | SocketState::Connected => {
766 return Err(SocketTableError::invalid_argument(format!(
767 "socket {socket_id} cannot bind in state {:?}",
768 record.state
769 )));
770 }
771 }
772
773 record.local_address = Some(address.clone());
774 record.peer_address = None;
775 record.local_unix_path = None;
776 record.peer_unix_path = None;
777 record.listener_state = None;
778 record.connection_state = None;
779 record.state = SocketState::Bound;
780 record.clone()
781 };
782 register_bound_inet_socket(&mut table, cloned.spec, address, socket_id);
783 Ok(cloned)
784 }
785
786 pub fn set_datagram_socket_option(
787 &self,
788 socket_id: SocketId,
789 option: DatagramSocketOption,
790 enabled: bool,
791 ) -> SocketResult<SocketRecord> {
792 let mut table = lock_or_recover(&self.inner.state);
793 let record = table
794 .sockets
795 .get_mut(&socket_id)
796 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
797 let datagram_state = datagram_state_mut(record)?;
798
799 match option {
800 DatagramSocketOption::ReuseAddr => datagram_state.reuse_addr = enabled,
801 DatagramSocketOption::ReusePort => datagram_state.reuse_port = enabled,
802 DatagramSocketOption::Broadcast => datagram_state.broadcast = enabled,
803 }
804
805 Ok(record.clone())
806 }
807
808 pub fn add_multicast_membership(
809 &self,
810 socket_id: SocketId,
811 membership: SocketMulticastMembership,
812 ) -> SocketResult<SocketRecord> {
813 let mut table = lock_or_recover(&self.inner.state);
814 let normalized_membership = {
815 let record = table
816 .sockets
817 .get(&socket_id)
818 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
819 validate_multicast_socket(record)?;
820 normalize_multicast_membership(record.spec, membership)?
821 };
822
823 let cloned = {
824 let record = table
825 .sockets
826 .get_mut(&socket_id)
827 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
828 let datagram_state = datagram_state_mut(record)?;
829 datagram_state
830 .multicast_memberships
831 .insert(normalized_membership.clone());
832 record.clone()
833 };
834
835 table
836 .multicast_groups
837 .entry(normalized_membership)
838 .or_default()
839 .insert(socket_id);
840 Ok(cloned)
841 }
842
843 pub fn drop_multicast_membership(
844 &self,
845 socket_id: SocketId,
846 membership: SocketMulticastMembership,
847 ) -> SocketResult<SocketRecord> {
848 let mut table = lock_or_recover(&self.inner.state);
849 let normalized_membership = {
850 let record = table
851 .sockets
852 .get(&socket_id)
853 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
854 validate_multicast_socket(record)?;
855 normalize_multicast_membership(record.spec, membership)?
856 };
857
858 let cloned = {
859 let record = table
860 .sockets
861 .get_mut(&socket_id)
862 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
863 let datagram_state = datagram_state_mut(record)?;
864 if !datagram_state
865 .multicast_memberships
866 .remove(&normalized_membership)
867 {
868 return Err(SocketTableError::address_not_available(format!(
869 "socket {socket_id} has not joined multicast group {}",
870 normalized_membership.group_address()
871 )));
872 }
873 record.clone()
874 };
875
876 if let Some(members) = table.multicast_groups.get_mut(&normalized_membership) {
877 members.remove(&socket_id);
878 if members.is_empty() {
879 table.multicast_groups.remove(&normalized_membership);
880 }
881 }
882
883 Ok(cloned)
884 }
885
886 pub fn bind_unix(
887 &self,
888 socket_id: SocketId,
889 path: impl Into<String>,
890 ) -> SocketResult<SocketRecord> {
891 let path = normalize_unix_socket_path(path.into())?;
892 let mut table = lock_or_recover(&self.inner.state);
893 let existing = table
894 .sockets
895 .get(&socket_id)
896 .cloned()
897 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
898 if !supports_unix_stream_lifecycle(existing.spec) {
899 return Err(SocketTableError::invalid_argument(format!(
900 "socket {socket_id} is not a Unix stream socket"
901 )));
902 }
903 let existing_id = table.bound_unix_streams.get(&path).copied();
904 let cloned = {
905 let record = table
906 .sockets
907 .get_mut(&socket_id)
908 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
909
910 if let Some(bound_socket_id) = existing_id {
911 if bound_socket_id != socket_id {
912 return Err(SocketTableError::address_in_use(format!(
913 "path {path} is already bound"
914 )));
915 }
916 }
917
918 match record.state {
919 SocketState::Created => {}
920 SocketState::Bound if record.local_unix_path.as_deref() == Some(path.as_str()) => {
921 return Ok(record.clone());
922 }
923 SocketState::Bound | SocketState::Listening | SocketState::Connected => {
924 return Err(SocketTableError::invalid_argument(format!(
925 "socket {socket_id} cannot bind in state {:?}",
926 record.state
927 )));
928 }
929 }
930
931 record.local_address = None;
932 record.peer_address = None;
933 record.local_unix_path = Some(path.clone());
934 record.peer_unix_path = None;
935 record.listener_state = None;
936 record.connection_state = None;
937 record.state = SocketState::Bound;
938 record.clone()
939 };
940 table.bound_unix_streams.insert(path, socket_id);
941 Ok(cloned)
942 }
943
944 pub fn listen(&self, socket_id: SocketId, backlog: usize) -> SocketResult<SocketRecord> {
945 if backlog == 0 {
946 return Err(SocketTableError::invalid_argument(
947 "listener backlog must be greater than zero",
948 ));
949 }
950
951 let mut table = lock_or_recover(&self.inner.state);
952 let record = table
953 .sockets
954 .get_mut(&socket_id)
955 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
956
957 if !supports_listener_lifecycle(record.spec) {
958 return Err(SocketTableError::invalid_argument(format!(
959 "socket {socket_id} is not a stream socket"
960 )));
961 }
962 if record.state != SocketState::Bound || !has_bound_endpoint(record) {
963 return Err(SocketTableError::invalid_argument(format!(
964 "socket {socket_id} must be bound before listen"
965 )));
966 }
967
968 record.state = SocketState::Listening;
969 record.listener_state = Some(ListenerState {
970 backlog,
971 pending_accepts: VecDeque::new(),
972 });
973 Ok(record.clone())
974 }
975
976 pub fn enqueue_incoming_tcp_connection(
977 &self,
978 listener_socket_id: SocketId,
979 peer_address: InetSocketAddress,
980 ) -> SocketResult<()> {
981 let readiness = {
982 let mut table = lock_or_recover(&self.inner.state);
983 let record = table
984 .sockets
985 .get_mut(&listener_socket_id)
986 .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?;
987
988 if record.state != SocketState::Listening {
989 return Err(SocketTableError::invalid_argument(format!(
990 "socket {listener_socket_id} is not listening"
991 )));
992 }
993
994 let listener_state = record.listener_state.as_mut().ok_or_else(|| {
995 SocketTableError::invalid_argument(format!(
996 "socket {listener_socket_id} has no listener state"
997 ))
998 })?;
999
1000 if listener_state.pending_accepts.len() >= listener_state.backlog {
1001 return Err(SocketTableError::would_block(format!(
1002 "listener {listener_socket_id} backlog is full"
1003 )));
1004 }
1005
1006 let was_empty = listener_state.pending_accepts.is_empty();
1007 listener_state.pending_accepts.push_back(PendingConnection {
1008 peer_address: Some(peer_address),
1009 peer_unix_path: None,
1010 accepted_socket_id: None,
1011 });
1012 was_empty.then_some(SocketReadiness {
1013 socket_id: listener_socket_id,
1014 kind: SocketReadinessKind::Accept,
1015 })
1016 };
1017 self.emit_readiness(readiness);
1018 Ok(())
1019 }
1020
1021 pub fn accept(&self, listener_socket_id: SocketId) -> SocketResult<SocketRecord> {
1022 let mut table = lock_or_recover(&self.inner.state);
1023 let (owner_pid, spec, local_address, local_unix_path, pending) = {
1024 let record = table
1025 .sockets
1026 .get_mut(&listener_socket_id)
1027 .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?;
1028
1029 if record.state != SocketState::Listening {
1030 return Err(SocketTableError::invalid_argument(format!(
1031 "socket {listener_socket_id} is not listening"
1032 )));
1033 }
1034
1035 let listener_state = record.listener_state.as_mut().ok_or_else(|| {
1036 SocketTableError::invalid_argument(format!(
1037 "socket {listener_socket_id} has no listener state"
1038 ))
1039 })?;
1040 let pending = listener_state.pending_accepts.pop_front().ok_or_else(|| {
1041 SocketTableError::would_block(format!(
1042 "listener {listener_socket_id} has no pending connections"
1043 ))
1044 })?;
1045
1046 (
1047 record.owner_pid,
1048 record.spec,
1049 record.local_address.clone(),
1050 record.local_unix_path.clone(),
1051 pending,
1052 )
1053 };
1054
1055 if let Some(accepted_socket_id) = pending.accepted_socket_id {
1056 return table
1057 .sockets
1058 .get(&accepted_socket_id)
1059 .cloned()
1060 .ok_or_else(|| SocketTableError::not_found(accepted_socket_id));
1061 }
1062
1063 let socket_id = next_socket_id(&mut table);
1064 let record = SocketRecord {
1065 id: socket_id,
1066 owner_pid,
1067 spec,
1068 state: SocketState::Connected,
1069 local_address,
1070 peer_address: pending.peer_address,
1071 local_unix_path,
1072 peer_unix_path: pending.peer_unix_path,
1073 listener_state: None,
1074 connection_state: default_connection_state(spec, SocketState::Connected),
1075 datagram_state: default_datagram_state(spec),
1076 };
1077 table.sockets.insert(socket_id, record.clone());
1078 table
1079 .by_owner
1080 .entry(owner_pid)
1081 .or_default()
1082 .insert(socket_id);
1083 Ok(record)
1084 }
1085
1086 pub fn connect_pair(
1087 &self,
1088 socket_id: SocketId,
1089 peer_socket_id: SocketId,
1090 ) -> SocketResult<(SocketRecord, SocketRecord)> {
1091 if socket_id == peer_socket_id {
1092 return Err(SocketTableError::invalid_argument(
1093 "socket cannot connect to itself",
1094 ));
1095 }
1096
1097 let mut table = lock_or_recover(&self.inner.state);
1098 let mut socket = table
1099 .sockets
1100 .remove(&socket_id)
1101 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1102 let Some(mut peer) = table.sockets.remove(&peer_socket_id) else {
1103 table.sockets.insert(socket_id, socket);
1104 return Err(SocketTableError::not_found(peer_socket_id));
1105 };
1106
1107 if let Err(error) = validate_connect_pair(&socket, &peer) {
1108 table.sockets.insert(socket_id, socket);
1109 table.sockets.insert(peer_socket_id, peer);
1110 return Err(error);
1111 }
1112
1113 socket.state = SocketState::Connected;
1114 socket.peer_address = peer.local_address.clone();
1115 socket.peer_unix_path = peer.local_unix_path.clone();
1116 socket.listener_state = None;
1117 socket.connection_state = Some(ConnectionState {
1118 peer_socket_id: Some(peer_socket_id),
1119 ..ConnectionState::default()
1120 });
1121
1122 peer.state = SocketState::Connected;
1123 peer.peer_address = socket.local_address.clone();
1124 peer.peer_unix_path = socket.local_unix_path.clone();
1125 peer.listener_state = None;
1126 peer.connection_state = Some(ConnectionState {
1127 peer_socket_id: Some(socket_id),
1128 ..ConnectionState::default()
1129 });
1130
1131 let socket_clone = socket.clone();
1132 let peer_clone = peer.clone();
1133 table.sockets.insert(socket_id, socket);
1134 table.sockets.insert(peer_socket_id, peer);
1135 Ok((socket_clone, peer_clone))
1136 }
1137
1138 pub fn find_bound_inet_socket(
1139 &self,
1140 spec: SocketSpec,
1141 address: &InetSocketAddress,
1142 ) -> Option<SocketRecord> {
1143 let address = normalize_inet_address(address.clone());
1144 let table = lock_or_recover(&self.inner.state);
1145 let socket_id = lookup_bound_inet_socket(&table, spec, &address)?;
1146 table.sockets.get(&socket_id).cloned()
1147 }
1148
1149 pub fn connect_to_bound_inet_stream(
1150 &self,
1151 socket_id: SocketId,
1152 target_address: InetSocketAddress,
1153 ) -> SocketResult<()> {
1154 let target_address = normalize_inet_address(target_address);
1155 let (result, readiness) = {
1156 let mut table = lock_or_recover(&self.inner.state);
1157 let listener_socket_id =
1158 lookup_bound_inet_socket_in_table(&table.bound_inet_streams, &target_address)
1159 .ok_or_else(|| {
1160 SocketTableError::not_found_address(format!(
1161 "no listening socket bound at {}:{}",
1162 target_address.host(),
1163 target_address.port()
1164 ))
1165 })?;
1166
1167 if socket_id == listener_socket_id {
1168 return Err(SocketTableError::invalid_argument(
1169 "socket cannot connect to its own listening endpoint",
1170 ));
1171 }
1172
1173 let mut client = table
1174 .sockets
1175 .remove(&socket_id)
1176 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1177 let mut accept_was_empty = false;
1178 let result = (|| {
1179 {
1184 let listener = table
1185 .sockets
1186 .get(&listener_socket_id)
1187 .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?;
1188 validate_connect_to_listener(&client, listener)?;
1189
1190 let listener_state = listener.listener_state.as_ref().ok_or_else(|| {
1191 SocketTableError::invalid_argument(format!(
1192 "socket {listener_socket_id} has no listener state"
1193 ))
1194 })?;
1195 if listener_state.pending_accepts.len() >= listener_state.backlog {
1196 return Err(SocketTableError::would_block(format!(
1197 "listener {listener_socket_id} backlog is full"
1198 )));
1199 }
1200 }
1201
1202 let accepted_socket_id = next_socket_id(&mut table);
1204 let listener = table
1205 .sockets
1206 .get_mut(&listener_socket_id)
1207 .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?;
1208 let listener_state = listener.listener_state.as_mut().ok_or_else(|| {
1209 SocketTableError::invalid_argument(format!(
1210 "socket {listener_socket_id} has no listener state"
1211 ))
1212 })?;
1213
1214 let accepted = SocketRecord {
1215 id: accepted_socket_id,
1216 owner_pid: listener.owner_pid,
1217 spec: listener.spec,
1218 state: SocketState::Connected,
1219 local_address: listener.local_address.clone(),
1220 peer_address: client.local_address.clone(),
1221 local_unix_path: None,
1222 peer_unix_path: None,
1223 listener_state: None,
1224 connection_state: Some(ConnectionState {
1225 peer_socket_id: Some(socket_id),
1226 ..ConnectionState::default()
1227 }),
1228 datagram_state: default_datagram_state(listener.spec),
1229 };
1230
1231 accept_was_empty = listener_state.pending_accepts.is_empty();
1232 listener_state.pending_accepts.push_back(PendingConnection {
1233 peer_address: client.local_address.clone(),
1234 peer_unix_path: None,
1235 accepted_socket_id: Some(accepted_socket_id),
1236 });
1237
1238 client.state = SocketState::Connected;
1239 client.peer_address = listener.local_address.clone();
1240 client.peer_unix_path = None;
1241 client.listener_state = None;
1242 client.connection_state = Some(ConnectionState {
1243 peer_socket_id: Some(accepted_socket_id),
1244 ..ConnectionState::default()
1245 });
1246
1247 Ok(accepted)
1248 })();
1249
1250 let result = match result {
1251 Ok(accepted) => {
1252 let accepted_socket_id = accepted.id;
1253 table.sockets.insert(socket_id, client);
1254 table.sockets.insert(accepted_socket_id, accepted.clone());
1255 table
1256 .by_owner
1257 .entry(accepted.owner_pid)
1258 .or_default()
1259 .insert(accepted_socket_id);
1260 Ok(())
1261 }
1262 Err(error) => {
1263 table.sockets.insert(socket_id, client);
1264 Err(error)
1265 }
1266 };
1267 let readiness = result.is_ok().then_some(()).and_then(|()| {
1268 accept_was_empty.then_some(SocketReadiness {
1269 socket_id: listener_socket_id,
1270 kind: SocketReadinessKind::Accept,
1271 })
1272 });
1273 (result, readiness)
1274 };
1275 self.emit_readiness(readiness);
1276 result
1277 }
1278
1279 pub fn find_bound_unix_socket(&self, path: &str) -> Option<SocketRecord> {
1280 let path = normalize_unix_socket_path(path).ok()?;
1281 let table = lock_or_recover(&self.inner.state);
1282 let socket_id = table.bound_unix_streams.get(&path).copied()?;
1283 table.sockets.get(&socket_id).cloned()
1284 }
1285
1286 pub fn connect_to_bound_unix_stream(
1287 &self,
1288 socket_id: SocketId,
1289 target_path: impl Into<String>,
1290 ) -> SocketResult<()> {
1291 let target_path = normalize_unix_socket_path(target_path.into())?;
1292 let (result, readiness) = {
1293 let mut table = lock_or_recover(&self.inner.state);
1294 let listener_socket_id = table
1295 .bound_unix_streams
1296 .get(&target_path)
1297 .copied()
1298 .ok_or_else(|| {
1299 SocketTableError::not_found_address(format!(
1300 "no listening socket bound at path {target_path}"
1301 ))
1302 })?;
1303
1304 if socket_id == listener_socket_id {
1305 return Err(SocketTableError::invalid_argument(
1306 "socket cannot connect to its own listening endpoint",
1307 ));
1308 }
1309
1310 let mut client = table
1311 .sockets
1312 .remove(&socket_id)
1313 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1314 let mut accept_was_empty = false;
1315 let result = (|| {
1316 {
1321 let listener = table
1322 .sockets
1323 .get(&listener_socket_id)
1324 .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?;
1325 validate_connect_to_listener(&client, listener)?;
1326
1327 let listener_state = listener.listener_state.as_ref().ok_or_else(|| {
1328 SocketTableError::invalid_argument(format!(
1329 "socket {listener_socket_id} has no listener state"
1330 ))
1331 })?;
1332 if listener_state.pending_accepts.len() >= listener_state.backlog {
1333 return Err(SocketTableError::would_block(format!(
1334 "listener {listener_socket_id} backlog is full"
1335 )));
1336 }
1337 }
1338
1339 let accepted_socket_id = next_socket_id(&mut table);
1341 let listener = table
1342 .sockets
1343 .get_mut(&listener_socket_id)
1344 .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?;
1345 let listener_state = listener.listener_state.as_mut().ok_or_else(|| {
1346 SocketTableError::invalid_argument(format!(
1347 "socket {listener_socket_id} has no listener state"
1348 ))
1349 })?;
1350
1351 let accepted = SocketRecord {
1352 id: accepted_socket_id,
1353 owner_pid: listener.owner_pid,
1354 spec: listener.spec,
1355 state: SocketState::Connected,
1356 local_address: None,
1357 peer_address: None,
1358 local_unix_path: listener.local_unix_path.clone(),
1359 peer_unix_path: client.local_unix_path.clone(),
1360 listener_state: None,
1361 connection_state: Some(ConnectionState {
1362 peer_socket_id: Some(socket_id),
1363 ..ConnectionState::default()
1364 }),
1365 datagram_state: default_datagram_state(listener.spec),
1366 };
1367
1368 accept_was_empty = listener_state.pending_accepts.is_empty();
1369 listener_state.pending_accepts.push_back(PendingConnection {
1370 peer_address: None,
1371 peer_unix_path: client.local_unix_path.clone(),
1372 accepted_socket_id: Some(accepted_socket_id),
1373 });
1374
1375 client.state = SocketState::Connected;
1376 client.peer_address = None;
1377 client.peer_unix_path = listener.local_unix_path.clone();
1378 client.listener_state = None;
1379 client.connection_state = Some(ConnectionState {
1380 peer_socket_id: Some(accepted_socket_id),
1381 ..ConnectionState::default()
1382 });
1383
1384 Ok(accepted)
1385 })();
1386
1387 let result = match result {
1388 Ok(accepted) => {
1389 let accepted_socket_id = accepted.id;
1390 table.sockets.insert(socket_id, client);
1391 table.sockets.insert(accepted_socket_id, accepted.clone());
1392 table
1393 .by_owner
1394 .entry(accepted.owner_pid)
1395 .or_default()
1396 .insert(accepted_socket_id);
1397 Ok(())
1398 }
1399 Err(error) => {
1400 table.sockets.insert(socket_id, client);
1401 Err(error)
1402 }
1403 };
1404 let readiness = result.is_ok().then_some(()).and_then(|()| {
1405 accept_was_empty.then_some(SocketReadiness {
1406 socket_id: listener_socket_id,
1407 kind: SocketReadinessKind::Accept,
1408 })
1409 });
1410 (result, readiness)
1411 };
1412 self.emit_readiness(readiness);
1413 result
1414 }
1415
1416 pub fn send_to_bound_udp_socket(
1417 &self,
1418 socket_id: SocketId,
1419 target_address: InetSocketAddress,
1420 data: &[u8],
1421 ) -> SocketResult<usize> {
1422 let target_address = normalize_inet_address(target_address);
1423 let readiness = {
1424 let mut table = lock_or_recover(&self.inner.state);
1425 let sender = table
1426 .sockets
1427 .get(&socket_id)
1428 .cloned()
1429 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1430 validate_bound_udp_sender(&sender)?;
1431
1432 let receiver_socket_id = lookup_bound_inet_datagram_socket_in_table(
1433 &table.bound_inet_datagrams,
1434 &target_address,
1435 )
1436 .ok_or_else(|| {
1437 SocketTableError::not_found_address(format!(
1438 "no UDP socket bound at {}:{}",
1439 target_address.host(),
1440 target_address.port()
1441 ))
1442 })?;
1443 let receiver = table
1444 .sockets
1445 .get_mut(&receiver_socket_id)
1446 .ok_or_else(|| SocketTableError::not_found(receiver_socket_id))?;
1447 validate_bound_udp_receiver(receiver)?;
1448
1449 let datagram_state = receiver.datagram_state.as_mut().ok_or_else(|| {
1450 SocketTableError::invalid_argument(format!(
1451 "socket {receiver_socket_id} does not support datagrams"
1452 ))
1453 })?;
1454 let was_empty = datagram_state.recv_queue.is_empty();
1455 datagram_state.recv_queue.push_back(QueuedDatagram {
1456 source_address: sender.local_address.clone(),
1457 payload: data.to_vec(),
1458 });
1459 was_empty.then_some(SocketReadiness {
1460 socket_id: receiver_socket_id,
1461 kind: SocketReadinessKind::Data,
1462 })
1463 };
1464 self.emit_readiness(readiness);
1465 Ok(data.len())
1466 }
1467
1468 pub fn check_send_to_bound_udp_socket(
1469 &self,
1470 socket_id: SocketId,
1471 target_address: InetSocketAddress,
1472 ) -> SocketResult<()> {
1473 let target_address = normalize_inet_address(target_address);
1474 let table = lock_or_recover(&self.inner.state);
1475 let sender = table
1476 .sockets
1477 .get(&socket_id)
1478 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1479 validate_bound_udp_sender(sender)?;
1480
1481 let receiver_socket_id = lookup_bound_inet_datagram_socket_in_table(
1482 &table.bound_inet_datagrams,
1483 &target_address,
1484 )
1485 .ok_or_else(|| {
1486 SocketTableError::not_found_address(format!(
1487 "no UDP socket bound at {}:{}",
1488 target_address.host(),
1489 target_address.port()
1490 ))
1491 })?;
1492 let receiver = table
1493 .sockets
1494 .get(&receiver_socket_id)
1495 .ok_or_else(|| SocketTableError::not_found(receiver_socket_id))?;
1496 validate_bound_udp_receiver(receiver)?;
1497 Ok(())
1498 }
1499
1500 pub fn recv_datagram(
1501 &self,
1502 socket_id: SocketId,
1503 max_bytes: usize,
1504 ) -> SocketResult<Option<ReceivedDatagram>> {
1505 let mut table = lock_or_recover(&self.inner.state);
1506 let record = table
1507 .sockets
1508 .get_mut(&socket_id)
1509 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1510 validate_bound_udp_receiver(record)?;
1511
1512 let datagram_state = record.datagram_state.as_mut().ok_or_else(|| {
1513 SocketTableError::invalid_argument(format!(
1514 "socket {socket_id} does not support datagrams"
1515 ))
1516 })?;
1517 let Some(datagram) = datagram_state.recv_queue.pop_front() else {
1518 return Err(SocketTableError::would_block(format!(
1519 "socket {socket_id} has no queued datagrams"
1520 )));
1521 };
1522
1523 let payload = if datagram.payload.len() > max_bytes {
1524 datagram.payload[..max_bytes].to_vec()
1525 } else {
1526 datagram.payload
1527 };
1528 Ok(Some(ReceivedDatagram {
1529 source_address: datagram.source_address,
1530 payload,
1531 }))
1532 }
1533
1534 pub fn poll(&self, socket_id: SocketId, requested: PollEvents) -> SocketResult<PollEvents> {
1535 let table = lock_or_recover(&self.inner.state);
1536 let record = table
1537 .sockets
1538 .get(&socket_id)
1539 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1540
1541 let mut events = PollEvents::empty();
1542 match record.state {
1543 SocketState::Listening => {
1544 if requested.intersects(POLLIN) && record.pending_accept_count() > 0 {
1545 events |= POLLIN;
1546 }
1547 }
1548 SocketState::Connected => {
1549 let connection = record.connection_state.as_ref().ok_or_else(|| {
1550 SocketTableError::not_connected(format!("socket {socket_id} is not connected"))
1551 })?;
1552 let peer = connection
1553 .peer_socket_id
1554 .and_then(|peer_socket_id| table.sockets.get(&peer_socket_id));
1555
1556 if requested.intersects(POLLIN) && connection.has_buffered_data() {
1557 events |= POLLIN;
1558 }
1559 if connection.peer_write_shutdown || peer.is_none() {
1560 events |= POLLHUP;
1561 }
1562
1563 if requested.intersects(POLLOUT) && !connection.write_shutdown {
1564 if peer
1565 .and_then(|peer| peer.connection_state.as_ref())
1566 .map(|peer_connection| peer_connection.read_shutdown)
1567 .unwrap_or(true)
1568 {
1569 events |= POLLERR;
1570 } else {
1571 events |= POLLOUT;
1572 }
1573 }
1574 }
1575 SocketState::Bound if supports_inet_datagram_lifecycle(record.spec) => {
1576 let datagram_state = record.datagram_state.as_ref().ok_or_else(|| {
1577 SocketTableError::invalid_argument(format!(
1578 "socket {socket_id} does not support datagrams"
1579 ))
1580 })?;
1581 if requested.intersects(POLLIN) && !datagram_state.recv_queue.is_empty() {
1582 events |= POLLIN;
1583 }
1584 if requested.intersects(POLLOUT) {
1585 events |= POLLOUT;
1586 }
1587 }
1588 SocketState::Created | SocketState::Bound => {}
1589 }
1590
1591 Ok(events)
1592 }
1593
1594 pub fn write(&self, socket_id: SocketId, data: &[u8]) -> SocketResult<usize> {
1595 let readiness = {
1596 let mut table = lock_or_recover(&self.inner.state);
1597 let record = table
1598 .sockets
1599 .get(&socket_id)
1600 .cloned()
1601 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1602 let connection = record.connection_state.as_ref().ok_or_else(|| {
1603 SocketTableError::not_connected(format!("socket {socket_id} is not connected"))
1604 })?;
1605 if record.state != SocketState::Connected {
1606 return Err(SocketTableError::not_connected(format!(
1607 "socket {socket_id} is not connected"
1608 )));
1609 }
1610 if connection.write_shutdown {
1611 return Err(SocketTableError::broken_pipe(format!(
1612 "socket {socket_id} write side is shut down"
1613 )));
1614 }
1615
1616 let peer_socket_id = connection.peer_socket_id.ok_or_else(|| {
1617 SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed"))
1618 })?;
1619 let peer = table.sockets.get_mut(&peer_socket_id).ok_or_else(|| {
1620 SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed"))
1621 })?;
1622 let peer_connection = peer.connection_state.as_mut().ok_or_else(|| {
1623 SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed"))
1624 })?;
1625 if peer_connection.read_shutdown {
1626 return Err(SocketTableError::broken_pipe(format!(
1627 "socket {peer_socket_id} read side is shut down"
1628 )));
1629 }
1630
1631 let was_empty = !peer_connection.has_buffered_data();
1632 peer_connection.push_recv(data);
1633 (was_empty && !data.is_empty()).then_some(SocketReadiness {
1634 socket_id: peer_socket_id,
1635 kind: SocketReadinessKind::Data,
1636 })
1637 };
1638 self.emit_readiness(readiness);
1639 Ok(data.len())
1640 }
1641
1642 pub fn check_write(&self, socket_id: SocketId) -> SocketResult<()> {
1643 let table = lock_or_recover(&self.inner.state);
1644 let record = table
1645 .sockets
1646 .get(&socket_id)
1647 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1648 let connection = record.connection_state.as_ref().ok_or_else(|| {
1649 SocketTableError::not_connected(format!("socket {socket_id} is not connected"))
1650 })?;
1651 if record.state != SocketState::Connected {
1652 return Err(SocketTableError::not_connected(format!(
1653 "socket {socket_id} is not connected"
1654 )));
1655 }
1656 if connection.write_shutdown {
1657 return Err(SocketTableError::broken_pipe(format!(
1658 "socket {socket_id} write side is shut down"
1659 )));
1660 }
1661
1662 let peer_socket_id = connection.peer_socket_id.ok_or_else(|| {
1663 SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed"))
1664 })?;
1665 let peer = table.sockets.get(&peer_socket_id).ok_or_else(|| {
1666 SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed"))
1667 })?;
1668 let peer_connection = peer.connection_state.as_ref().ok_or_else(|| {
1669 SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed"))
1670 })?;
1671 if peer_connection.read_shutdown {
1672 return Err(SocketTableError::broken_pipe(format!(
1673 "socket {peer_socket_id} read side is shut down"
1674 )));
1675 }
1676
1677 Ok(())
1678 }
1679
1680 pub fn read(&self, socket_id: SocketId, max_bytes: usize) -> SocketResult<Option<Vec<u8>>> {
1681 if max_bytes == 0 {
1682 return Ok(Some(Vec::new()));
1683 }
1684
1685 let mut table = lock_or_recover(&self.inner.state);
1686 let record_ref = table
1687 .sockets
1688 .get(&socket_id)
1689 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1690 let clone_started = SOCKET_READ_TRACE_ENABLED
1691 .load(Ordering::Relaxed)
1692 .then(Instant::now);
1693 let record = record_ref.clone();
1694 if let Some(started) = clone_started {
1695 SOCKET_READ_TRACE_COUNTERS
1696 .socket_record_clone_calls
1697 .fetch_add(1, Ordering::Relaxed);
1698 SOCKET_READ_TRACE_COUNTERS.socket_record_clone_us.fetch_add(
1699 u64::try_from(started.elapsed().as_micros()).unwrap_or(u64::MAX),
1700 Ordering::Relaxed,
1701 );
1702 }
1703 if record.state != SocketState::Connected {
1704 return Err(SocketTableError::not_connected(format!(
1705 "socket {socket_id} is not connected"
1706 )));
1707 }
1708
1709 let connection = record.connection_state.as_ref().ok_or_else(|| {
1710 SocketTableError::not_connected(format!("socket {socket_id} is not connected"))
1711 })?;
1712 if connection.read_shutdown {
1713 return Ok(None);
1714 }
1715 if connection.has_buffered_data() {
1716 let record = table
1717 .sockets
1718 .get_mut(&socket_id)
1719 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1720 let connection = record.connection_state.as_mut().ok_or_else(|| {
1721 SocketTableError::not_connected(format!("socket {socket_id} is not connected"))
1722 })?;
1723 return Ok(connection.read_recv(max_bytes));
1724 }
1725
1726 let peer_open = connection
1727 .peer_socket_id
1728 .map(|peer_socket_id| table.sockets.contains_key(&peer_socket_id))
1729 .unwrap_or(false);
1730 if connection.peer_write_shutdown || !peer_open {
1731 return Ok(None);
1732 }
1733
1734 Err(SocketTableError::would_block(format!(
1735 "socket {socket_id} has no readable data"
1736 )))
1737 }
1738
1739 pub fn shutdown(&self, socket_id: SocketId, how: SocketShutdown) -> SocketResult<SocketRecord> {
1740 let mut table = lock_or_recover(&self.inner.state);
1741 let record = table
1742 .sockets
1743 .remove(&socket_id)
1744 .ok_or_else(|| SocketTableError::not_found(socket_id))?;
1745
1746 if record.state != SocketState::Connected {
1747 table.sockets.insert(socket_id, record);
1748 return Err(SocketTableError::not_connected(format!(
1749 "socket {socket_id} is not connected"
1750 )));
1751 }
1752
1753 let Some(mut connection) = record.connection_state.clone() else {
1754 table.sockets.insert(socket_id, record);
1755 return Err(SocketTableError::not_connected(format!(
1756 "socket {socket_id} is not connected"
1757 )));
1758 };
1759
1760 if matches!(how, SocketShutdown::Read | SocketShutdown::Both) {
1761 connection.clear_recv();
1762 connection.read_shutdown = true;
1763 }
1764 if matches!(how, SocketShutdown::Write | SocketShutdown::Both) {
1765 connection.write_shutdown = true;
1766 if let Some(peer_socket_id) = connection.peer_socket_id {
1767 if let Some(peer) = table.sockets.get_mut(&peer_socket_id) {
1768 if let Some(peer_connection) = peer.connection_state.as_mut() {
1769 peer_connection.peer_write_shutdown = true;
1770 }
1771 }
1772 }
1773 }
1774
1775 let mut record = record;
1776 record.connection_state = Some(connection);
1777 let cloned = record.clone();
1778 table.sockets.insert(socket_id, record);
1779 Ok(cloned)
1780 }
1781
1782 pub fn remove(&self, socket_id: SocketId) -> SocketResult<SocketRecord> {
1783 let mut table = lock_or_recover(&self.inner.state);
1784 remove_socket(&mut table, socket_id).ok_or_else(|| SocketTableError::not_found(socket_id))
1785 }
1786
1787 pub fn remove_all_for_pid(&self, owner_pid: u32) -> Vec<SocketRecord> {
1788 let mut table = lock_or_recover(&self.inner.state);
1789 let Some(socket_ids) = table.by_owner.remove(&owner_pid) else {
1790 return Vec::new();
1791 };
1792
1793 socket_ids
1794 .into_iter()
1795 .filter_map(|socket_id| remove_socket(&mut table, socket_id))
1796 .collect()
1797 }
1798
1799 pub fn snapshot(&self) -> SocketTableSnapshot {
1800 let table = lock_or_recover(&self.inner.state);
1801 let mut snapshot = SocketTableSnapshot {
1802 sockets: table.sockets.len(),
1803 ..SocketTableSnapshot::default()
1804 };
1805 for record in table.sockets.values() {
1806 if record.state.counts_as_listener() {
1807 snapshot.listeners += 1;
1808 }
1809 if record.state.counts_as_connection() {
1810 snapshot.connections += 1;
1811 }
1812 if let Some(connection) = &record.connection_state {
1813 snapshot.buffered_bytes = snapshot
1814 .buffered_bytes
1815 .saturating_add(connection.buffered_len());
1816 }
1817 if let Some(datagram_state) = &record.datagram_state {
1818 snapshot.datagram_queue_len = snapshot
1819 .datagram_queue_len
1820 .saturating_add(datagram_state.recv_queue.len());
1821 snapshot.buffered_bytes = snapshot
1822 .buffered_bytes
1823 .saturating_add(datagram_queue_bytes(&datagram_state.recv_queue));
1824 }
1825 }
1826 snapshot
1827 }
1828}
1829
1830fn datagram_queue_bytes(queue: &VecDeque<QueuedDatagram>) -> usize {
1831 queue
1832 .iter()
1833 .map(|datagram| datagram.payload.len())
1834 .sum::<usize>()
1835}
1836
1837fn next_socket_id(table: &mut SocketTableState) -> SocketId {
1838 if table.next_socket_id == 0 {
1839 table.next_socket_id = 1;
1840 }
1841 let socket_id = table.next_socket_id;
1842 table.next_socket_id = table.next_socket_id.saturating_add(1);
1843 socket_id
1844}
1845
1846fn validate_state_transition(current: SocketState, next: SocketState) -> SocketResult<()> {
1847 if current == SocketState::Connected && next != SocketState::Connected {
1848 return Err(SocketTableError::invalid_argument(format!(
1849 "invalid socket state transition from {current:?} to {next:?}"
1850 )));
1851 }
1852 Ok(())
1853}
1854
1855fn validate_connect_pair(socket: &SocketRecord, peer: &SocketRecord) -> SocketResult<()> {
1856 if !supports_connection_lifecycle(socket.spec) {
1857 return Err(SocketTableError::invalid_argument(format!(
1858 "socket {} does not support stream connections",
1859 socket.id
1860 )));
1861 }
1862 if !supports_connection_lifecycle(peer.spec) {
1863 return Err(SocketTableError::invalid_argument(format!(
1864 "socket {} does not support stream connections",
1865 peer.id
1866 )));
1867 }
1868 if !matches!(socket.state, SocketState::Created | SocketState::Bound) {
1869 return Err(SocketTableError::invalid_argument(format!(
1870 "socket {} cannot connect in state {:?}",
1871 socket.id, socket.state
1872 )));
1873 }
1874 if !matches!(peer.state, SocketState::Created | SocketState::Bound) {
1875 return Err(SocketTableError::invalid_argument(format!(
1876 "socket {} cannot connect in state {:?}",
1877 peer.id, peer.state
1878 )));
1879 }
1880 Ok(())
1881}
1882
1883fn default_connection_state(spec: SocketSpec, state: SocketState) -> Option<ConnectionState> {
1884 if state == SocketState::Connected && supports_connection_lifecycle(spec) {
1885 Some(ConnectionState::default())
1886 } else {
1887 None
1888 }
1889}
1890
1891fn default_datagram_state(spec: SocketSpec) -> Option<DatagramState> {
1892 if supports_inet_datagram_lifecycle(spec) {
1893 Some(DatagramState::default())
1894 } else {
1895 None
1896 }
1897}
1898
1899fn supports_connection_lifecycle(spec: SocketSpec) -> bool {
1900 matches!(spec.socket_type, SocketType::Stream)
1901}
1902
1903fn supports_listener_lifecycle(spec: SocketSpec) -> bool {
1904 matches!(spec.socket_type, SocketType::Stream)
1905 && matches!(
1906 spec.domain,
1907 SocketDomain::Inet | SocketDomain::Inet6 | SocketDomain::Unix
1908 )
1909}
1910
1911fn supports_inet_bind(spec: SocketSpec) -> bool {
1912 matches!(spec.domain, SocketDomain::Inet | SocketDomain::Inet6)
1913 && matches!(spec.socket_type, SocketType::Stream | SocketType::Datagram)
1914}
1915
1916fn supports_unix_stream_lifecycle(spec: SocketSpec) -> bool {
1917 matches!(spec.socket_type, SocketType::Stream) && matches!(spec.domain, SocketDomain::Unix)
1918}
1919
1920fn supports_inet_stream_lifecycle(spec: SocketSpec) -> bool {
1921 matches!(spec.socket_type, SocketType::Stream)
1922 && matches!(spec.domain, SocketDomain::Inet | SocketDomain::Inet6)
1923}
1924
1925fn supports_inet_datagram_lifecycle(spec: SocketSpec) -> bool {
1926 matches!(spec.socket_type, SocketType::Datagram)
1927 && matches!(spec.domain, SocketDomain::Inet | SocketDomain::Inet6)
1928}
1929
1930fn assign_ephemeral_inet_port(
1933 table: &SocketTableState,
1934 spec: SocketSpec,
1935 host: &str,
1936) -> SocketResult<u16> {
1937 const EPHEMERAL_START: u16 = 49152;
1938 const EPHEMERAL_END: u16 = 65535;
1939 for port in EPHEMERAL_START..=EPHEMERAL_END {
1940 let candidate = normalize_inet_address(InetSocketAddress::new(host, port));
1941 if lookup_conflicting_bound_inet_socket_ids(table, spec, &candidate).is_empty() {
1942 return Ok(port);
1943 }
1944 }
1945 Err(SocketTableError::address_in_use(
1946 "no free ephemeral port available",
1947 ))
1948}
1949
1950fn lookup_conflicting_bound_inet_socket_ids(
1951 table: &SocketTableState,
1952 spec: SocketSpec,
1953 address: &InetSocketAddress,
1954) -> Vec<SocketId> {
1955 if supports_inet_stream_lifecycle(spec) {
1956 table
1957 .bound_inet_streams
1958 .iter()
1959 .find_map(|(bound_address, socket_id)| {
1960 inet_stream_bind_addresses_overlap(bound_address, address).then_some(*socket_id)
1961 })
1962 .into_iter()
1963 .collect()
1964 } else if supports_inet_datagram_lifecycle(spec) {
1965 table
1966 .bound_inet_datagrams
1967 .iter()
1968 .filter(|(bound_address, _)| inet_stream_bind_addresses_overlap(bound_address, address))
1969 .flat_map(|(_, socket_ids)| socket_ids.iter().copied())
1970 .collect()
1971 } else {
1972 Vec::new()
1973 }
1974}
1975
1976fn lookup_bound_inet_socket(
1977 table: &SocketTableState,
1978 spec: SocketSpec,
1979 address: &InetSocketAddress,
1980) -> Option<SocketId> {
1981 if supports_inet_stream_lifecycle(spec) {
1982 lookup_bound_inet_socket_in_table(&table.bound_inet_streams, address)
1983 } else if supports_inet_datagram_lifecycle(spec) {
1984 lookup_bound_inet_datagram_socket_in_table(&table.bound_inet_datagrams, address)
1985 } else {
1986 None
1987 }
1988}
1989
1990fn inet_stream_bind_addresses_overlap(
1991 existing: &InetSocketAddress,
1992 requested: &InetSocketAddress,
1993) -> bool {
1994 if existing == requested {
1995 return true;
1996 }
1997
1998 wildcard_inet_address(existing).as_ref() == Some(requested)
1999 || wildcard_inet_address(requested).as_ref() == Some(existing)
2000}
2001
2002fn lookup_bound_inet_socket_in_table(
2003 sockets: &BTreeMap<InetSocketAddress, SocketId>,
2004 address: &InetSocketAddress,
2005) -> Option<SocketId> {
2006 sockets.get(address).copied().or_else(|| {
2007 wildcard_inet_address(address).and_then(|wildcard| sockets.get(&wildcard).copied())
2008 })
2009}
2010
2011fn lookup_bound_inet_datagram_socket_in_table(
2012 sockets: &BTreeMap<InetSocketAddress, BTreeSet<SocketId>>,
2013 address: &InetSocketAddress,
2014) -> Option<SocketId> {
2015 sockets
2016 .get(address)
2017 .and_then(|socket_ids| socket_ids.first().copied())
2018 .or_else(|| {
2019 wildcard_inet_address(address).and_then(|wildcard| {
2020 sockets
2021 .get(&wildcard)
2022 .and_then(|socket_ids| socket_ids.first().copied())
2023 })
2024 })
2025}
2026
2027fn register_bound_inet_socket(
2028 table: &mut SocketTableState,
2029 spec: SocketSpec,
2030 address: InetSocketAddress,
2031 socket_id: SocketId,
2032) {
2033 if supports_inet_stream_lifecycle(spec) {
2034 table.bound_inet_streams.insert(address, socket_id);
2035 } else if supports_inet_datagram_lifecycle(spec) {
2036 table
2037 .bound_inet_datagrams
2038 .entry(address)
2039 .or_default()
2040 .insert(socket_id);
2041 }
2042}
2043
2044fn validate_connect_to_listener(
2045 client: &SocketRecord,
2046 listener: &SocketRecord,
2047) -> SocketResult<()> {
2048 if !supports_connection_lifecycle(client.spec) {
2049 return Err(SocketTableError::invalid_argument(format!(
2050 "socket {} does not support stream connections",
2051 client.id
2052 )));
2053 }
2054 if !supports_listener_lifecycle(listener.spec) {
2055 return Err(SocketTableError::invalid_argument(format!(
2056 "socket {} is not a stream listener",
2057 listener.id
2058 )));
2059 }
2060 if !matches!(client.state, SocketState::Created | SocketState::Bound) {
2061 return Err(SocketTableError::invalid_argument(format!(
2062 "socket {} cannot connect in state {:?}",
2063 client.id, client.state
2064 )));
2065 }
2066 if listener.state != SocketState::Listening {
2067 return Err(SocketTableError::invalid_argument(format!(
2068 "socket {} is not listening",
2069 listener.id
2070 )));
2071 }
2072 Ok(())
2073}
2074
2075fn has_bound_endpoint(record: &SocketRecord) -> bool {
2076 record.local_address.is_some() || record.local_unix_path.is_some()
2077}
2078
2079fn validate_bound_udp_sender(sender: &SocketRecord) -> SocketResult<()> {
2080 if !supports_inet_datagram_lifecycle(sender.spec) {
2081 return Err(SocketTableError::invalid_argument(format!(
2082 "socket {} is not an INET datagram socket",
2083 sender.id
2084 )));
2085 }
2086 if sender.state != SocketState::Bound || sender.local_address.is_none() {
2087 return Err(SocketTableError::invalid_argument(format!(
2088 "socket {} must be bound before sending datagrams",
2089 sender.id
2090 )));
2091 }
2092 Ok(())
2093}
2094
2095fn validate_bound_udp_receiver(receiver: &SocketRecord) -> SocketResult<()> {
2096 if !supports_inet_datagram_lifecycle(receiver.spec) {
2097 return Err(SocketTableError::invalid_argument(format!(
2098 "socket {} is not an INET datagram socket",
2099 receiver.id
2100 )));
2101 }
2102 if receiver.state != SocketState::Bound || receiver.local_address.is_none() {
2103 return Err(SocketTableError::invalid_argument(format!(
2104 "socket {} must be bound to receive datagrams",
2105 receiver.id
2106 )));
2107 }
2108 Ok(())
2109}
2110
2111fn datagram_state_mut(record: &mut SocketRecord) -> SocketResult<&mut DatagramState> {
2112 if !supports_inet_datagram_lifecycle(record.spec) {
2113 return Err(SocketTableError::invalid_argument(format!(
2114 "socket {} is not an INET datagram socket",
2115 record.id
2116 )));
2117 }
2118 record.datagram_state.as_mut().ok_or_else(|| {
2119 SocketTableError::invalid_argument(format!(
2120 "socket {} does not support datagrams",
2121 record.id
2122 ))
2123 })
2124}
2125
2126fn validate_multicast_socket(record: &SocketRecord) -> SocketResult<()> {
2127 validate_bound_udp_receiver(record)?;
2128 if record.spec.domain != SocketDomain::Inet {
2129 return Err(SocketTableError::invalid_argument(format!(
2130 "socket {} multicast membership is only implemented for IPv4 datagrams",
2131 record.id
2132 )));
2133 }
2134 Ok(())
2135}
2136
2137fn normalize_multicast_membership(
2138 spec: SocketSpec,
2139 membership: SocketMulticastMembership,
2140) -> SocketResult<SocketMulticastMembership> {
2141 let group_address = membership.group_address.trim().to_ascii_lowercase();
2142 let interface_address = membership
2143 .interface_address
2144 .map(|value| value.trim().to_ascii_lowercase())
2145 .filter(|value| !value.is_empty());
2146
2147 match spec.domain {
2148 SocketDomain::Inet => {
2149 let parsed = group_address.parse::<Ipv4Addr>().map_err(|_| {
2150 SocketTableError::invalid_argument(format!(
2151 "invalid IPv4 multicast address {group_address}"
2152 ))
2153 })?;
2154 if !parsed.is_multicast() {
2155 return Err(SocketTableError::invalid_argument(format!(
2156 "address {group_address} is not an IPv4 multicast group"
2157 )));
2158 }
2159 }
2160 SocketDomain::Inet6 => {
2161 let parsed = group_address.parse::<Ipv6Addr>().map_err(|_| {
2162 SocketTableError::invalid_argument(format!(
2163 "invalid IPv6 multicast address {group_address}"
2164 ))
2165 })?;
2166 if !parsed.is_multicast() {
2167 return Err(SocketTableError::invalid_argument(format!(
2168 "address {group_address} is not an IPv6 multicast group"
2169 )));
2170 }
2171 }
2172 SocketDomain::Unix => {
2173 return Err(SocketTableError::invalid_argument(
2174 "unix sockets do not support multicast membership",
2175 ));
2176 }
2177 }
2178
2179 Ok(SocketMulticastMembership::new(
2180 group_address,
2181 interface_address,
2182 ))
2183}
2184
2185fn has_incompatible_inet_bind_conflict(
2186 table: &SocketTableState,
2187 record: &SocketRecord,
2188 conflicting_ids: &[SocketId],
2189) -> bool {
2190 conflicting_ids.iter().any(|conflicting_id| {
2191 if *conflicting_id == record.id {
2192 return false;
2193 }
2194
2195 let Some(existing) = table.sockets.get(conflicting_id) else {
2196 return false;
2197 };
2198
2199 if supports_inet_datagram_lifecycle(record.spec) {
2200 !inet_datagram_bind_shares_port(record, existing)
2201 } else {
2202 true
2203 }
2204 })
2205}
2206
2207fn inet_datagram_bind_shares_port(requested: &SocketRecord, existing: &SocketRecord) -> bool {
2208 (requested.reuse_port() && existing.reuse_port())
2209 || (requested.reuse_address() && existing.reuse_address())
2210}
2211
2212fn remove_socket(table: &mut SocketTableState, socket_id: SocketId) -> Option<SocketRecord> {
2213 let record = table.sockets.remove(&socket_id)?;
2214 unregister_bound_socket(table, &record);
2215 unregister_multicast_memberships(table, &record);
2216 if let Some(listener_state) = record.listener_state.as_ref() {
2217 let pending_socket_ids = listener_state
2218 .pending_accepts
2219 .iter()
2220 .filter_map(|pending| pending.accepted_socket_id)
2221 .collect::<Vec<_>>();
2222 for pending_socket_id in pending_socket_ids {
2223 let _ = remove_socket(table, pending_socket_id);
2224 }
2225 }
2226 if let Some(connection) = record.connection_state.as_ref() {
2227 if let Some(peer_socket_id) = connection.peer_socket_id {
2228 if let Some(peer) = table.sockets.get_mut(&peer_socket_id) {
2229 if let Some(peer_connection) = peer.connection_state.as_mut() {
2230 if peer_connection.peer_socket_id == Some(socket_id) {
2231 peer_connection.peer_socket_id = None;
2232 }
2233 peer_connection.peer_write_shutdown = true;
2234 }
2235 }
2236 }
2237 }
2238 if let Some(owner_sockets) = table.by_owner.get_mut(&record.owner_pid) {
2239 owner_sockets.remove(&socket_id);
2240 if owner_sockets.is_empty() {
2241 table.by_owner.remove(&record.owner_pid);
2242 }
2243 }
2244 Some(record)
2245}
2246
2247fn unregister_bound_socket(table: &mut SocketTableState, record: &SocketRecord) {
2248 let Some(address) = record.local_address.as_ref() else {
2249 if supports_unix_stream_lifecycle(record.spec) {
2250 if let Some(path) = record.local_unix_path.as_ref() {
2251 if table.bound_unix_streams.get(path).copied() == Some(record.id) {
2252 table.bound_unix_streams.remove(path);
2253 }
2254 }
2255 }
2256 return;
2257 };
2258 if supports_inet_stream_lifecycle(record.spec)
2259 && table.bound_inet_streams.get(address).copied() == Some(record.id)
2260 {
2261 table.bound_inet_streams.remove(address);
2262 }
2263 if supports_inet_datagram_lifecycle(record.spec) {
2264 if let Some(socket_ids) = table.bound_inet_datagrams.get_mut(address) {
2265 socket_ids.remove(&record.id);
2266 if socket_ids.is_empty() {
2267 table.bound_inet_datagrams.remove(address);
2268 }
2269 }
2270 }
2271}
2272
2273fn unregister_multicast_memberships(table: &mut SocketTableState, record: &SocketRecord) {
2274 let Some(datagram_state) = record.datagram_state.as_ref() else {
2275 return;
2276 };
2277
2278 for membership in &datagram_state.multicast_memberships {
2279 if let Some(socket_ids) = table.multicast_groups.get_mut(membership) {
2280 socket_ids.remove(&record.id);
2281 if socket_ids.is_empty() {
2282 table.multicast_groups.remove(membership);
2283 }
2284 }
2285 }
2286}
2287
2288fn normalize_inet_address(address: InetSocketAddress) -> InetSocketAddress {
2289 match address.host().to_ascii_lowercase().as_str() {
2290 "localhost" => InetSocketAddress::new("127.0.0.1", address.port()),
2291 _ => address,
2292 }
2293}
2294
2295fn wildcard_inet_address(address: &InetSocketAddress) -> Option<InetSocketAddress> {
2296 match address.host() {
2297 "127.0.0.1" => Some(InetSocketAddress::new("0.0.0.0", address.port())),
2298 "::1" => Some(InetSocketAddress::new("::", address.port())),
2299 _ => None,
2300 }
2301}
2302
2303fn normalize_unix_socket_path(path: impl AsRef<str>) -> SocketResult<String> {
2304 let normalized = normalize_path(path.as_ref());
2305 if normalized == "/" {
2306 return Err(SocketTableError::invalid_argument(
2307 "unix socket path must not be empty or root",
2308 ));
2309 }
2310 Ok(normalized)
2311}
2312
2313fn lock_or_recover<'a, T>(mutex: &'a Mutex<T>) -> MutexGuard<'a, T> {
2314 match mutex.lock() {
2315 Ok(guard) => guard,
2316 Err(poisoned) => poisoned.into_inner(),
2317 }
2318}
2319
2320#[cfg(test)]
2321mod tests {
2322 use super::*;
2323
2324 fn peek_next_socket_id(table: &SocketTable) -> SocketId {
2327 lock_or_recover(&table.inner.state).next_socket_id
2328 }
2329
2330 #[test]
2331 fn full_backlog_unix_connect_does_not_consume_socket_id() {
2332 let table = SocketTable::new();
2333 let path = "/tmp/leak-test/server.sock";
2334
2335 let listener = table.allocate(1, SocketSpec::unix_stream());
2336 table
2337 .bind_unix(listener.id, path)
2338 .expect("bind unix listener");
2339 table.listen(listener.id, 1).expect("listen with backlog 1");
2340
2341 let first = table.allocate(2, SocketSpec::unix_stream());
2343 table
2344 .connect_to_bound_unix_stream(first.id, path)
2345 .expect("first connect fills the backlog");
2346
2347 let second = table.allocate(2, SocketSpec::unix_stream());
2350 let before = peek_next_socket_id(&table);
2351 let error = table
2352 .connect_to_bound_unix_stream(second.id, path)
2353 .expect_err("full-backlog connect must fail");
2354 assert_eq!(error.code(), "EAGAIN");
2355 let after = peek_next_socket_id(&table);
2356
2357 assert_eq!(
2358 before, after,
2359 "full-backlog unix connect leaked a socket id (counter advanced from {before} to {after})"
2360 );
2361 }
2362
2363 #[test]
2364 fn full_backlog_inet_connect_does_not_consume_socket_id() {
2365 let table = SocketTable::new();
2366 let target = InetSocketAddress::new("127.0.0.1", 49222);
2367
2368 let listener = table.allocate(1, SocketSpec::tcp());
2369 table
2370 .bind_inet(listener.id, target.clone())
2371 .expect("bind inet listener");
2372 table.listen(listener.id, 1).expect("listen with backlog 1");
2373
2374 let first = table.allocate(2, SocketSpec::tcp());
2376 table
2377 .connect_to_bound_inet_stream(first.id, target.clone())
2378 .expect("first connect fills the backlog");
2379
2380 let second = table.allocate(2, SocketSpec::tcp());
2383 let before = peek_next_socket_id(&table);
2384 let error = table
2385 .connect_to_bound_inet_stream(second.id, target)
2386 .expect_err("full-backlog connect must fail");
2387 assert_eq!(error.code(), "EAGAIN");
2388 let after = peek_next_socket_id(&table);
2389
2390 assert_eq!(
2391 before, after,
2392 "full-backlog inet connect leaked a socket id (counter advanced from {before} to {after})"
2393 );
2394 }
2395}