1use core::convert::Infallible as Never;
9use core::fmt::Debug;
10use core::hash::Hash;
11use core::marker::PhantomData;
12use core::num::NonZeroU16;
13
14use derivative::Derivative;
15use net_types::ip::{GenericOverIp, Ip, IpAddress, IpVersion, IpVersionMarker, Ipv4, Ipv6};
16use net_types::{
17 AddrAndZone, MulticastAddress, ScopeableAddress, SpecifiedAddr, Witness, ZonedAddr,
18};
19use thiserror::Error;
20
21use crate::LocalAddressError;
22use crate::data_structures::socketmap::{
23 Entry, IterShadows, OccupiedEntry as SocketMapOccupiedEntry, SocketMap, Tagged,
24};
25use crate::device::{
26 DeviceIdentifier, EitherDeviceId, StrongDeviceIdentifier, WeakDeviceIdentifier,
27};
28use crate::error::{ExistsError, NotFoundError, ZonedAddressError};
29use crate::ip::BroadcastIpExt;
30use crate::socket::SocketCookie;
31use crate::socket::address::{
32 AddrVecIter, ConnAddr, ConnIpAddr, ListenerAddr, ListenerIpAddr, SocketIpAddr,
33};
34use packet_formats::ip::{IpProto, Ipv4Proto, Ipv6Proto};
35
36pub trait DualStackIpExt: Ip {
39 type OtherVersion: DualStackIpExt<OtherVersion = Self>;
41}
42
43impl DualStackIpExt for Ipv4 {
44 type OtherVersion = Ipv6;
45}
46
47impl DualStackIpExt for Ipv6 {
48 type OtherVersion = Ipv4;
49}
50
51pub struct DualStackTuple<I: DualStackIpExt, T: GenericOverIp<I> + GenericOverIp<I::OtherVersion>> {
53 this_stack: <T as GenericOverIp<I>>::Type,
54 other_stack: <T as GenericOverIp<I::OtherVersion>>::Type,
55 _marker: IpVersionMarker<I>,
56}
57
58impl<I: DualStackIpExt, T: GenericOverIp<I> + GenericOverIp<I::OtherVersion>> DualStackTuple<I, T> {
59 pub fn new(this_stack: T, other_stack: <T as GenericOverIp<I::OtherVersion>>::Type) -> Self
61 where
62 T: GenericOverIp<I, Type = T>,
63 {
64 Self { this_stack, other_stack, _marker: IpVersionMarker::new() }
65 }
66
67 pub fn into_inner(
69 self,
70 ) -> (<T as GenericOverIp<I>>::Type, <T as GenericOverIp<I::OtherVersion>>::Type) {
71 let Self { this_stack, other_stack, _marker } = self;
72 (this_stack, other_stack)
73 }
74
75 pub fn into_this_stack(self) -> <T as GenericOverIp<I>>::Type {
77 self.this_stack
78 }
79
80 pub fn this_stack(&self) -> &<T as GenericOverIp<I>>::Type {
82 &self.this_stack
83 }
84
85 pub fn into_other_stack(self) -> <T as GenericOverIp<I::OtherVersion>>::Type {
87 self.other_stack
88 }
89
90 pub fn other_stack(&self) -> &<T as GenericOverIp<I::OtherVersion>>::Type {
92 &self.other_stack
93 }
94
95 pub fn flip(self) -> DualStackTuple<I::OtherVersion, T> {
97 let Self { this_stack, other_stack, _marker } = self;
98 DualStackTuple {
99 this_stack: other_stack,
100 other_stack: this_stack,
101 _marker: IpVersionMarker::new(),
102 }
103 }
104
105 pub fn cast<X>(self) -> DualStackTuple<X, T>
114 where
115 X: DualStackIpExt,
116 T: GenericOverIp<X>
117 + GenericOverIp<X::OtherVersion>
118 + GenericOverIp<Ipv4>
119 + GenericOverIp<Ipv6>,
120 {
121 I::map_ip_in(
122 self,
123 |v4| X::map_ip_out(v4, |t| t, |t| t.flip()),
124 |v6| X::map_ip_out(v6, |t| t.flip(), |t| t),
125 )
126 }
127}
128
129impl<
130 I: DualStackIpExt,
131 NewIp: DualStackIpExt,
132 T: GenericOverIp<NewIp>
133 + GenericOverIp<NewIp::OtherVersion>
134 + GenericOverIp<I>
135 + GenericOverIp<I::OtherVersion>,
136> GenericOverIp<NewIp> for DualStackTuple<I, T>
137{
138 type Type = DualStackTuple<NewIp, T>;
139}
140
141pub trait SocketIpExt: Ip {
143 const LOOPBACK_ADDRESS_AS_SOCKET_IP_ADDR: SocketIpAddr<Self::Addr> = unsafe {
145 SocketIpAddr::new_from_specified_unchecked(Self::LOOPBACK_ADDRESS)
148 };
149}
150
151impl<I: Ip> SocketIpExt for I {}
152
153#[cfg(test)]
154mod socket_ip_ext_test {
155 use super::*;
156 use ip_test_macro::ip_test;
157
158 #[ip_test(I)]
159 fn loopback_addr_is_valid_socket_addr<I: SocketIpExt>() {
160 let _addr = SocketIpAddr::new(I::LOOPBACK_ADDRESS_AS_SOCKET_IP_ADDR.addr())
165 .expect("loopback address should be a valid SocketIpAddr");
166 }
167}
168
169#[derive(Copy, Clone, Debug, PartialEq, Eq, GenericOverIp)]
171#[generic_over_ip()]
172pub enum EitherIpProto {
173 V4(Ipv4Proto),
175 V6(Ipv6Proto),
177}
178
179impl EitherIpProto {
180 pub fn ip_version(&self) -> IpVersion {
182 match self {
183 Self::V4(_) => IpVersion::V4,
184 Self::V6(_) => IpVersion::V6,
185 }
186 }
187
188 pub fn ip_proto(&self) -> Option<IpProto> {
190 match self {
191 Self::V4(p) => match p {
192 Ipv4Proto::Proto(proto) => Some(*proto),
193 _ => None,
194 },
195 Self::V6(p) => match p {
196 Ipv6Proto::Proto(proto) => Some(*proto),
197 _ => None,
198 },
199 }
200 }
201
202 pub fn u8_value(&self) -> u8 {
204 match self {
205 Self::V4(p) => (*p).into(),
206 Self::V6(p) => (*p).into(),
207 }
208 }
209}
210
211#[derive(Clone, Debug)]
213#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq, Eq))]
214pub struct SocketInfo {
215 pub proto: EitherIpProto,
217 pub cookie: SocketCookie,
219}
220
221#[derive(Debug, PartialEq, Eq)]
229pub enum EitherStack<T, O> {
230 ThisStack(T),
232 OtherStack(O),
234}
235
236impl<T, O> Clone for EitherStack<T, O>
237where
238 T: Clone,
239 O: Clone,
240{
241 #[cfg_attr(feature = "instrumented", track_caller)]
242 fn clone(&self) -> Self {
243 match self {
244 Self::ThisStack(t) => Self::ThisStack(t.clone()),
245 Self::OtherStack(t) => Self::OtherStack(t.clone()),
246 }
247 }
248}
249
250#[derive(Debug)]
268#[allow(missing_docs)]
269pub enum MaybeDualStack<DS, NDS> {
270 DualStack(DS),
271 NotDualStack(NDS),
272}
273
274impl<I: DualStackIpExt, DS: GenericOverIp<I>, NDS: GenericOverIp<I>> GenericOverIp<I>
277 for MaybeDualStack<DS, NDS>
278{
279 type Type = MaybeDualStack<<DS as GenericOverIp<I>>::Type, <NDS as GenericOverIp<I>>::Type>;
280}
281
282#[derive(Copy, Clone, Debug, Eq, GenericOverIp, PartialEq, Error)]
284#[generic_over_ip()]
285pub enum SetDualStackEnabledError {
286 #[error("a socket can only have dual stack enabled or disabled while unbound")]
288 SocketIsBound,
289 #[error(transparent)]
291 NotCapable(#[from] NotDualStackCapableError),
292}
293
294#[derive(Copy, Clone, Debug, Eq, GenericOverIp, PartialEq, Error)]
297#[generic_over_ip()]
298#[error("socket's protocol is not dual-stack capable")]
299pub struct NotDualStackCapableError;
300
301#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
303pub struct Shutdown {
304 pub send: bool,
308 pub receive: bool,
312}
313
314#[derive(Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
316#[generic_over_ip()]
317pub enum ShutdownType {
318 Send,
320 Receive,
322 SendAndReceive,
324}
325
326impl ShutdownType {
327 pub fn to_send_receive(&self) -> (bool, bool) {
329 match self {
330 Self::Send => (true, false),
331 Self::Receive => (false, true),
332 Self::SendAndReceive => (true, true),
333 }
334 }
335
336 pub fn from_send_receive(send: bool, receive: bool) -> Option<Self> {
338 match (send, receive) {
339 (true, false) => Some(Self::Send),
340 (false, true) => Some(Self::Receive),
341 (true, true) => Some(Self::SendAndReceive),
342 (false, false) => None,
343 }
344 }
345}
346
347pub trait SocketIpAddrExt<A: IpAddress>: Witness<A> + ScopeableAddress {
349 fn must_have_zone(&self) -> bool
355 where
356 Self: Copy,
357 {
358 self.try_into_null_zoned().is_some()
359 }
360
361 fn try_into_null_zoned(self) -> Option<AddrAndZone<Self, ()>> {
365 if self.get().is_loopback() {
366 return None;
367 }
368 AddrAndZone::new(self, ())
369 }
370}
371
372impl<A: IpAddress, W: Witness<A> + ScopeableAddress> SocketIpAddrExt<A> for W {}
373
374pub trait SocketZonedAddrExt<W, A, D> {
376 fn resolve_addr_with_device(
384 self,
385 device: Option<D::Weak>,
386 ) -> Result<(W, Option<EitherDeviceId<D, D::Weak>>), ZonedAddressError>
387 where
388 D: StrongDeviceIdentifier;
389}
390
391impl<W, A, D> SocketZonedAddrExt<W, A, D> for ZonedAddr<W, D>
392where
393 W: ScopeableAddress + AsRef<SpecifiedAddr<A>>,
394 A: IpAddress,
395{
396 fn resolve_addr_with_device(
397 self,
398 device: Option<D::Weak>,
399 ) -> Result<(W, Option<EitherDeviceId<D, D::Weak>>), ZonedAddressError>
400 where
401 D: StrongDeviceIdentifier,
402 {
403 let (addr, zone) = self.into_addr_zone();
404 let device = match (zone, device) {
405 (Some(zone), Some(device)) => {
406 if device != zone {
407 return Err(ZonedAddressError::DeviceZoneMismatch);
408 }
409 Some(EitherDeviceId::Strong(zone))
410 }
411 (Some(zone), None) => Some(EitherDeviceId::Strong(zone)),
412 (None, Some(device)) => Some(EitherDeviceId::Weak(device)),
413 (None, None) => {
414 if addr.as_ref().must_have_zone() {
415 return Err(ZonedAddressError::RequiredZoneNotProvided);
416 } else {
417 None
418 }
419 }
420 };
421 Ok((addr, device))
422 }
423}
424
425pub struct SocketDeviceUpdate<'a, A: IpAddress, D: WeakDeviceIdentifier> {
431 pub local_ip: Option<&'a SpecifiedAddr<A>>,
433 pub remote_ip: Option<&'a SpecifiedAddr<A>>,
435 pub old_device: Option<&'a D>,
437}
438
439impl<'a, A: IpAddress, D: WeakDeviceIdentifier> SocketDeviceUpdate<'a, A, D> {
440 pub fn check_update<N>(
443 self,
444 new_device: Option<&N>,
445 ) -> Result<(), SocketDeviceUpdateNotAllowedError>
446 where
447 D: PartialEq<N>,
448 {
449 let Self { local_ip, remote_ip, old_device } = self;
450 let must_have_zone = local_ip.is_some_and(|a| a.must_have_zone())
451 || remote_ip.is_some_and(|a| a.must_have_zone());
452
453 if !must_have_zone {
454 return Ok(());
455 }
456
457 let old_device = old_device.unwrap_or_else(|| {
458 panic!("local_ip={:?} or remote_ip={:?} must have zone", local_ip, remote_ip)
459 });
460
461 if new_device.is_some_and(|new_device| old_device == new_device) {
462 Ok(())
463 } else {
464 Err(SocketDeviceUpdateNotAllowedError)
465 }
466 }
467}
468
469pub struct SocketDeviceUpdateNotAllowedError;
471
472pub trait SocketMapAddrSpec {
477 type LocalIdentifier: Copy + Clone + Debug + Send + Sync + Hash + Eq + Into<NonZeroU16>;
479 type RemoteIdentifier: Copy + Clone + Debug + Send + Sync + Hash + Eq;
481}
482
483pub struct ListenerAddrInfo {
485 pub has_device: bool,
487 pub specified_addr: bool,
490}
491
492impl<A: IpAddress, D: DeviceIdentifier, LI> ListenerAddr<ListenerIpAddr<A, LI>, D> {
493 pub(crate) fn info(&self) -> ListenerAddrInfo {
494 let Self { device, ip: ListenerIpAddr { addr, identifier: _ } } = self;
495 ListenerAddrInfo { has_device: device.is_some(), specified_addr: addr.is_some() }
496 }
497}
498
499pub trait SocketMapStateSpec {
501 type AddrVecTag: Eq + Copy + Debug + 'static;
506
507 fn listener_tag(info: ListenerAddrInfo, state: &Self::ListenerAddrState) -> Self::AddrVecTag;
509
510 fn connected_tag(has_device: bool, state: &Self::ConnAddrState) -> Self::AddrVecTag;
512
513 type ListenerId: Clone + Debug;
515 type ConnId: Clone + Debug;
517
518 type ListenerSharingState: Clone + Debug;
521
522 type ConnSharingState: Clone + Debug;
525
526 type ListenerAddrState: SocketMapAddrStateSpec<Id = Self::ListenerId, SharingState = Self::ListenerSharingState>
528 + Debug;
529
530 type ConnAddrState: SocketMapAddrStateSpec<Id = Self::ConnId, SharingState = Self::ConnSharingState>
532 + Debug;
533}
534
535#[derive(Copy, Clone, Debug, Eq, PartialEq)]
538pub struct IncompatibleError;
539
540pub trait Inserter<T> {
542 fn insert(self, item: T);
547}
548
549impl<'a, T, E: Extend<T>> Inserter<T> for &'a mut E {
550 fn insert(self, item: T) {
551 self.extend([item])
552 }
553}
554
555impl<T> Inserter<T> for Never {
556 fn insert(self, _: T) {
557 match self {}
558 }
559}
560
561pub trait SocketMapAddrStateSpec {
563 type Id;
565
566 type SharingState;
573
574 type Inserter<'a>: Inserter<Self::Id> + 'a
576 where
577 Self: 'a,
578 Self::Id: 'a;
579
580 fn new(new_sharing_state: &Self::SharingState, id: Self::Id) -> Self;
583
584 fn contains_id(&self, id: &Self::Id) -> bool;
586
587 fn try_get_inserter<'a, 'b>(
595 &'b mut self,
596 new_sharing_state: &'a Self::SharingState,
597 ) -> Result<Self::Inserter<'b>, IncompatibleError>;
598
599 fn could_insert(&self, new_sharing_state: &Self::SharingState)
604 -> Result<(), IncompatibleError>;
605
606 fn remove_by_id(&mut self, id: Self::Id) -> RemoveResult;
610
611 fn sharing_state(&self) -> Self::SharingState;
613}
614
615pub trait SocketMapAddrStateUpdateSharingSpec: SocketMapAddrStateSpec {
617 fn try_update_sharing(
620 &mut self,
621 id: Self::Id,
622 new_sharing_state: &Self::SharingState,
623 ) -> Result<(), IncompatibleError>;
624}
625
626pub trait SocketMapConflictPolicy<
628 Addr,
629 SharingState,
630 I: Ip,
631 D: DeviceIdentifier,
632 A: SocketMapAddrSpec,
633>: SocketMapStateSpec
634{
635 fn check_insert_conflicts(
644 new_sharing_state: &SharingState,
645 addr: &Addr,
646 socketmap: &SocketMap<AddrVec<I, D, A>, Bound<Self>>,
647 ) -> Result<(), InsertError>;
648}
649
650pub trait SocketMapUpdateSharingPolicy<Addr, SharingState, I: Ip, D: DeviceIdentifier, A>:
653 SocketMapConflictPolicy<Addr, SharingState, I, D, A>
654where
655 A: SocketMapAddrSpec,
656{
657 fn allows_sharing_update(
660 socketmap: &SocketMap<AddrVec<I, D, A>, Bound<Self>>,
661 addr: &Addr,
662 old_sharing: &SharingState,
663 new_sharing: &SharingState,
664 ) -> Result<(), UpdateSharingError>;
665}
666
667#[derive(Derivative)]
669#[derivative(Debug(bound = "S::ListenerAddrState: Debug, S::ConnAddrState: Debug"))]
670#[allow(missing_docs)]
671pub enum Bound<S: SocketMapStateSpec + ?Sized> {
672 Listen(S::ListenerAddrState),
673 Conn(S::ConnAddrState),
674}
675
676#[derive(Derivative)]
691#[derivative(
692 Debug(bound = "D: Debug"),
693 Clone(bound = "D: Clone"),
694 Eq(bound = "D: Eq"),
695 PartialEq(bound = "D: PartialEq"),
696 Hash(bound = "D: Hash")
697)]
698#[allow(missing_docs)]
699pub enum AddrVec<I: Ip, D, A: SocketMapAddrSpec + ?Sized> {
700 Listen(ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>),
701 Conn(ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>),
702}
703
704impl<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec, S: SocketMapStateSpec + ?Sized>
705 Tagged<AddrVec<I, D, A>> for Bound<S>
706{
707 type Tag = S::AddrVecTag;
708 fn tag(&self, address: &AddrVec<I, D, A>) -> Self::Tag {
709 match (self, address) {
710 (Bound::Listen(l), AddrVec::Listen(addr)) => S::listener_tag(addr.info(), l),
711 (Bound::Conn(c), AddrVec::Conn(ConnAddr { device, ip: _ })) => {
712 S::connected_tag(device.is_some(), c)
713 }
714 (Bound::Listen(_), AddrVec::Conn(_)) => {
715 unreachable!("found listen state for conn addr")
716 }
717 (Bound::Conn(_), AddrVec::Listen(_)) => {
718 unreachable!("found conn state for listen addr")
719 }
720 }
721 }
722}
723
724impl<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec> IterShadows for AddrVec<I, D, A> {
725 type IterShadows = AddrVecIter<I, D, A>;
726
727 fn iter_shadows(&self) -> Self::IterShadows {
728 let (socket_ip_addr, device) = match self.clone() {
729 AddrVec::Conn(ConnAddr { ip, device }) => (ip.into(), device),
730 AddrVec::Listen(ListenerAddr { ip, device }) => (ip.into(), device),
731 };
732 let mut iter = match device {
733 Some(device) => AddrVecIter::with_device(socket_ip_addr, device),
734 None => AddrVecIter::without_device(socket_ip_addr),
735 };
736 assert_eq!(iter.next().as_ref(), Some(self));
738 iter
739 }
740}
741
742#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
744#[allow(missing_docs)]
745pub enum SocketAddrType {
746 AnyListener,
747 SpecificListener,
748 Connected,
749}
750
751impl<'a, A: IpAddress, LI> From<&'a ListenerIpAddr<A, LI>> for SocketAddrType {
752 fn from(ListenerIpAddr { addr, identifier: _ }: &'a ListenerIpAddr<A, LI>) -> Self {
753 match addr {
754 Some(_) => SocketAddrType::SpecificListener,
755 None => SocketAddrType::AnyListener,
756 }
757 }
758}
759
760impl<'a, A: IpAddress, LI, RI> From<&'a ConnIpAddr<A, LI, RI>> for SocketAddrType {
761 fn from(_: &'a ConnIpAddr<A, LI, RI>) -> Self {
762 SocketAddrType::Connected
763 }
764}
765
766pub enum RemoveResult {
768 Success,
770 IsLast,
773}
774
775#[derive(Derivative)]
776#[derivative(Clone(bound = "S::ListenerId: Clone, S::ConnId: Clone"), Debug(bound = ""))]
777pub enum SocketId<S: SocketMapStateSpec> {
778 Listener(S::ListenerId),
779 Connection(S::ConnId),
780}
781
782#[derive(Derivative)]
796#[derivative(Default(bound = ""))]
797pub struct BoundSocketMap<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec, S: SocketMapStateSpec> {
798 addr_to_state: SocketMap<AddrVec<I, D, A>, Bound<S>>,
799}
800
801impl<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec, S: SocketMapStateSpec>
802 BoundSocketMap<I, D, A, S>
803{
804 pub fn len(&self) -> usize {
806 self.addr_to_state.len()
807 }
808}
809
810pub enum Listener {}
812pub enum Connection {}
814
815pub struct Sockets<AddrToStateMap, SocketType>(AddrToStateMap, PhantomData<SocketType>);
817
818impl<
819 'a,
820 I: Ip,
821 D: DeviceIdentifier,
822 SocketType: ConvertSocketMapState<I, D, A, S>,
823 A: SocketMapAddrSpec,
824 S: SocketMapConflictPolicy<SocketType::Addr, SocketType::SharingState, I, D, A>,
825> Sockets<&'a SocketMap<AddrVec<I, D, A>, Bound<S>>, SocketType>
826{
827 pub fn get_by_addr(self, addr: &SocketType::Addr) -> Option<&'a SocketType::AddrState> {
829 let Self(addr_to_state, _marker) = self;
830 addr_to_state.get(&SocketType::to_addr_vec(addr)).map(|state| {
831 SocketType::from_bound_ref(state)
832 .unwrap_or_else(|| unreachable!("found {:?} for address {:?}", state, addr))
833 })
834 }
835
836 pub fn could_insert(
842 self,
843 addr: &SocketType::Addr,
844 sharing: &SocketType::SharingState,
845 ) -> Result<(), InsertError> {
846 let Self(addr_to_state, _) = self;
847 match self.get_by_addr(addr) {
848 Some(state) => {
849 state.could_insert(sharing).map_err(|IncompatibleError| InsertError::Exists)
850 }
851 None => S::check_insert_conflicts(&sharing, &addr, &addr_to_state),
852 }
853 }
854}
855
856#[derive(Derivative)]
858#[derivative(Debug(bound = ""))]
859pub struct SocketStateEntry<
860 'a,
861 I: Ip,
862 D: DeviceIdentifier,
863 A: SocketMapAddrSpec,
864 S: SocketMapStateSpec,
865 SocketType,
866> {
867 id: SocketId<S>,
868 addr_entry: SocketMapOccupiedEntry<'a, AddrVec<I, D, A>, Bound<S>>,
869 _marker: PhantomData<SocketType>,
870}
871
872impl<
873 'a,
874 I: Ip,
875 D: DeviceIdentifier,
876 SocketType: ConvertSocketMapState<I, D, A, S>,
877 A: SocketMapAddrSpec,
878 S: SocketMapConflictPolicy<SocketType::Addr, SocketType::SharingState, I, D, A>,
879> Sockets<&'a mut SocketMap<AddrVec<I, D, A>, Bound<S>>, SocketType>
880where
881 SocketType::SharingState: Clone,
882 SocketType::Id: Clone,
883{
884 pub fn try_insert(
887 self,
888 socket_addr: SocketType::Addr,
889 tag_state: SocketType::SharingState,
890 id: SocketType::Id,
891 ) -> Result<SocketStateEntry<'a, I, D, A, S, SocketType>, InsertError> {
892 self.try_insert_with(socket_addr, tag_state, |_addr, _sharing| (id, ()))
893 .map(|(entry, ())| entry)
894 }
895
896 pub fn try_insert_with<R>(
901 self,
902 socket_addr: SocketType::Addr,
903 tag_state: SocketType::SharingState,
904 make_id: impl FnOnce(SocketType::Addr, SocketType::SharingState) -> (SocketType::Id, R),
905 ) -> Result<(SocketStateEntry<'a, I, D, A, S, SocketType>, R), InsertError> {
906 let Self(addr_to_state, _) = self;
907 S::check_insert_conflicts(&tag_state, &socket_addr, &addr_to_state)?;
908
909 let addr = SocketType::to_addr_vec(&socket_addr);
910
911 match addr_to_state.entry(addr) {
912 Entry::Occupied(mut o) => {
913 let (id, ret) = o.map_mut(|bound| {
914 let bound = match SocketType::from_bound_mut(bound) {
915 Some(bound) => bound,
916 None => unreachable!("found {:?} for address {:?}", bound, socket_addr),
917 };
918 match <SocketType::AddrState as SocketMapAddrStateSpec>::try_get_inserter(
919 bound, &tag_state,
920 ) {
921 Ok(v) => {
922 let (id, ret) = make_id(socket_addr, tag_state);
923 v.insert(id.clone());
924 Ok((SocketType::to_socket_id(id), ret))
925 }
926 Err(IncompatibleError) => Err(InsertError::Exists),
927 }
928 })?;
929 Ok((SocketStateEntry { id, addr_entry: o, _marker: Default::default() }, ret))
930 }
931 Entry::Vacant(v) => {
932 let (id, ret) = make_id(socket_addr, tag_state.clone());
933 let addr_entry = v.insert(SocketType::to_bound(SocketType::AddrState::new(
934 &tag_state,
935 id.clone(),
936 )));
937 let id = SocketType::to_socket_id(id);
938 Ok((SocketStateEntry { id, addr_entry, _marker: Default::default() }, ret))
939 }
940 }
941 }
942
943 pub fn entry(
945 self,
946 id: &SocketType::Id,
947 addr: &SocketType::Addr,
948 ) -> Option<SocketStateEntry<'a, I, D, A, S, SocketType>> {
949 let Self(addr_to_state, _) = self;
950 let addr_entry = match addr_to_state.entry(SocketType::to_addr_vec(addr)) {
951 Entry::Vacant(_) => return None,
952 Entry::Occupied(o) => o,
953 };
954 let state = SocketType::from_bound_ref(addr_entry.get())?;
955
956 state.contains_id(id).then_some(SocketStateEntry {
957 id: SocketType::to_socket_id(id.clone()),
958 addr_entry,
959 _marker: PhantomData::default(),
960 })
961 }
962
963 pub fn remove(self, id: &SocketType::Id, addr: &SocketType::Addr) -> Result<(), NotFoundError> {
965 self.entry(id, addr)
966 .map(|entry| {
967 entry.remove();
968 })
969 .ok_or(NotFoundError)
970 }
971}
972
973#[derive(Debug)]
976pub struct UpdateSharingError;
977
978impl<
979 'a,
980 I: Ip,
981 D: DeviceIdentifier,
982 SocketType: ConvertSocketMapState<I, D, A, S>,
983 A: SocketMapAddrSpec,
984 S: SocketMapConflictPolicy<SocketType::Addr, SocketType::SharingState, I, D, A>,
985> SocketStateEntry<'a, I, D, A, S, SocketType>
986where
987 SocketType::Id: Clone,
988{
989 pub fn get_addr(&self) -> &SocketType::Addr {
991 let Self { id: _, addr_entry, _marker } = self;
992 SocketType::from_addr_vec_ref(addr_entry.key())
993 }
994
995 pub fn id(&self) -> &SocketType::Id {
997 let Self { id, addr_entry: _, _marker } = self;
998 SocketType::from_socket_id_ref(id)
999 }
1000
1001 pub fn try_update_addr(self, new_addr: SocketType::Addr) -> Result<Self, (ExistsError, Self)> {
1003 let Self { id, addr_entry, _marker } = self;
1004
1005 let new_addrvec = SocketType::to_addr_vec(&new_addr);
1006 let old_addr = addr_entry.key().clone();
1007 let (addr_state, addr_to_state) = addr_entry.remove_from_map();
1008 let addr_to_state = match addr_to_state.entry(new_addrvec) {
1009 Entry::Occupied(o) => o.into_map(),
1010 Entry::Vacant(v) => {
1011 let sharing_state = SocketType::from_bound_ref(&addr_state)
1012 .unwrap_or_else(|| {
1013 unreachable!("found {:?} for address {:?}", addr_state, old_addr)
1014 })
1015 .sharing_state();
1016 match S::check_insert_conflicts(&sharing_state, &new_addr, v.get_map()) {
1017 Ok(_) => {
1018 let new_addr_entry = v.insert(addr_state);
1019 return Ok(SocketStateEntry { id, addr_entry: new_addr_entry, _marker });
1020 }
1021 Err(_) => v.into_map(),
1022 }
1023 }
1024 };
1025 let to_restore = addr_state;
1026 let addr_entry = match addr_to_state.entry(old_addr) {
1028 Entry::Occupied(_) => unreachable!("just-removed-from entry is occupied"),
1029 Entry::Vacant(v) => v.insert(to_restore),
1030 };
1031 return Err((ExistsError, SocketStateEntry { id, addr_entry, _marker }));
1032 }
1033
1034 pub fn remove(self) {
1036 let Self { id, mut addr_entry, _marker } = self;
1037 let addr = addr_entry.key().clone();
1038 match addr_entry.map_mut(|value| {
1039 let value = match SocketType::from_bound_mut(value) {
1040 Some(value) => value,
1041 None => unreachable!("found {:?} for address {:?}", value, addr),
1042 };
1043 value.remove_by_id(SocketType::from_socket_id_ref(&id).clone())
1044 }) {
1045 RemoveResult::Success => (),
1046 RemoveResult::IsLast => {
1047 let _: Bound<S> = addr_entry.remove();
1048 }
1049 }
1050 }
1051
1052 pub fn try_update_sharing(
1054 &mut self,
1055 old_sharing_state: &SocketType::SharingState,
1056 new_sharing_state: SocketType::SharingState,
1057 ) -> Result<(), UpdateSharingError>
1058 where
1059 SocketType::AddrState: SocketMapAddrStateUpdateSharingSpec,
1060 S: SocketMapUpdateSharingPolicy<SocketType::Addr, SocketType::SharingState, I, D, A>,
1061 {
1062 let Self { id, addr_entry, _marker } = self;
1063 let addr = SocketType::from_addr_vec_ref(addr_entry.key());
1064
1065 S::allows_sharing_update(
1066 addr_entry.get_map(),
1067 addr,
1068 old_sharing_state,
1069 &new_sharing_state,
1070 )?;
1071
1072 addr_entry
1073 .map_mut(|value| {
1074 let value = match SocketType::from_bound_mut(value) {
1075 Some(value) => value,
1076 None => unreachable!("found invalid state {:?}", value),
1080 };
1081
1082 value.try_update_sharing(
1083 SocketType::from_socket_id_ref(id).clone(),
1084 &new_sharing_state,
1085 )
1086 })
1087 .map_err(|IncompatibleError| UpdateSharingError)
1088 }
1089}
1090
1091impl<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec, S> BoundSocketMap<I, D, A, S>
1092where
1093 AddrVec<I, D, A>: IterShadows,
1094 S: SocketMapStateSpec,
1095{
1096 pub fn listeners(&self) -> Sockets<&SocketMap<AddrVec<I, D, A>, Bound<S>>, Listener>
1098 where
1099 S: SocketMapConflictPolicy<
1100 ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>,
1101 <S as SocketMapStateSpec>::ListenerSharingState,
1102 I,
1103 D,
1104 A,
1105 >,
1106 S::ListenerAddrState:
1107 SocketMapAddrStateSpec<Id = S::ListenerId, SharingState = S::ListenerSharingState>,
1108 {
1109 let Self { addr_to_state } = self;
1110 Sockets(addr_to_state, Default::default())
1111 }
1112
1113 pub fn listeners_mut(&mut self) -> Sockets<&mut SocketMap<AddrVec<I, D, A>, Bound<S>>, Listener>
1115 where
1116 S: SocketMapConflictPolicy<
1117 ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>,
1118 <S as SocketMapStateSpec>::ListenerSharingState,
1119 I,
1120 D,
1121 A,
1122 >,
1123 S::ListenerAddrState:
1124 SocketMapAddrStateSpec<Id = S::ListenerId, SharingState = S::ListenerSharingState>,
1125 {
1126 let Self { addr_to_state } = self;
1127 Sockets(addr_to_state, Default::default())
1128 }
1129
1130 pub fn conns(&self) -> Sockets<&SocketMap<AddrVec<I, D, A>, Bound<S>>, Connection>
1132 where
1133 S: SocketMapConflictPolicy<
1134 ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>,
1135 <S as SocketMapStateSpec>::ConnSharingState,
1136 I,
1137 D,
1138 A,
1139 >,
1140 S::ConnAddrState:
1141 SocketMapAddrStateSpec<Id = S::ConnId, SharingState = S::ConnSharingState>,
1142 {
1143 let Self { addr_to_state } = self;
1144 Sockets(addr_to_state, Default::default())
1145 }
1146
1147 pub fn conns_mut(&mut self) -> Sockets<&mut SocketMap<AddrVec<I, D, A>, Bound<S>>, Connection>
1149 where
1150 S: SocketMapConflictPolicy<
1151 ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>,
1152 <S as SocketMapStateSpec>::ConnSharingState,
1153 I,
1154 D,
1155 A,
1156 >,
1157 S::ConnAddrState:
1158 SocketMapAddrStateSpec<Id = S::ConnId, SharingState = S::ConnSharingState>,
1159 {
1160 let Self { addr_to_state } = self;
1161 Sockets(addr_to_state, Default::default())
1162 }
1163
1164 #[cfg(test)]
1165 pub(crate) fn iter_addrs(&self) -> impl Iterator<Item = &AddrVec<I, D, A>> {
1166 let Self { addr_to_state } = self;
1167 addr_to_state.iter().map(|(a, _v): (_, &Bound<S>)| a)
1168 }
1169
1170 pub fn get_shadower_counts(&self, addr: &AddrVec<I, D, A>) -> usize {
1172 let Self { addr_to_state } = self;
1173 addr_to_state.descendant_counts(&addr).map(|(_sharing, size)| size.get()).sum()
1174 }
1175}
1176
1177pub enum FoundSockets<A, It> {
1179 Single(A),
1181 Multicast(It),
1184}
1185
1186#[allow(missing_docs)]
1188#[derive(Debug)]
1189pub enum AddrEntry<'a, I: Ip, D, A: SocketMapAddrSpec, S: SocketMapStateSpec> {
1190 Listen(&'a S::ListenerAddrState, ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>),
1191 Conn(
1192 &'a S::ConnAddrState,
1193 ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>,
1194 ),
1195}
1196
1197impl<I, D, A, S> BoundSocketMap<I, D, A, S>
1198where
1199 I: BroadcastIpExt<Addr: MulticastAddress>,
1200 D: DeviceIdentifier,
1201 A: SocketMapAddrSpec,
1202 S: SocketMapStateSpec
1203 + SocketMapConflictPolicy<
1204 ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>,
1205 <S as SocketMapStateSpec>::ListenerSharingState,
1206 I,
1207 D,
1208 A,
1209 > + SocketMapConflictPolicy<
1210 ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>,
1211 <S as SocketMapStateSpec>::ConnSharingState,
1212 I,
1213 D,
1214 A,
1215 >,
1216{
1217 pub fn lookup_connected(
1223 &self,
1224 (src_ip, src_port): (SocketIpAddr<I::Addr>, A::RemoteIdentifier),
1225 (dst_ip, dst_port): (SocketIpAddr<I::Addr>, A::LocalIdentifier),
1226 device: D,
1227 ) -> Option<&'_ S::ConnAddrState> {
1228 let mut addr = ConnAddr {
1229 ip: ConnIpAddr { local: (dst_ip, dst_port), remote: (src_ip, src_port) },
1230 device: Some(device),
1231 };
1232 let entry = self.conns().get_by_addr(&addr);
1233 if entry.is_some() {
1234 return entry;
1235 }
1236 addr.device = None;
1237 self.conns().get_by_addr(&addr)
1238 }
1239
1240 pub fn iter_receivers(
1246 &self,
1247 (src_ip, src_port): (Option<SocketIpAddr<I::Addr>>, Option<A::RemoteIdentifier>),
1248 (dst_ip, dst_port): (SocketIpAddr<I::Addr>, A::LocalIdentifier),
1249 device: D,
1250 broadcast: Option<I::BroadcastMarker>,
1251 ) -> Option<
1252 FoundSockets<
1253 AddrEntry<'_, I, D, A, S>,
1254 impl Iterator<Item = AddrEntry<'_, I, D, A, S>> + '_,
1255 >,
1256 > {
1257 let mut matching_entries = AddrVecIter::with_device(
1258 match (src_ip, src_port) {
1259 (Some(specified_src_ip), Some(src_port)) => {
1260 ConnIpAddr { local: (dst_ip, dst_port), remote: (specified_src_ip, src_port) }
1261 .into()
1262 }
1263 _ => ListenerIpAddr { addr: Some(dst_ip), identifier: dst_port }.into(),
1264 },
1265 device,
1266 )
1267 .filter_map(move |addr: AddrVec<I, D, A>| match addr {
1268 AddrVec::Listen(l) => {
1269 self.listeners().get_by_addr(&l).map(|state| AddrEntry::Listen(state, l))
1270 }
1271 AddrVec::Conn(c) => self.conns().get_by_addr(&c).map(|state| AddrEntry::Conn(state, c)),
1272 });
1273
1274 if broadcast.is_some() || dst_ip.addr().is_multicast() {
1275 Some(FoundSockets::Multicast(matching_entries))
1276 } else {
1277 let single_entry: Option<_> = matching_entries.next();
1278 single_entry.map(FoundSockets::Single)
1279 }
1280 }
1281}
1282
1283#[derive(Debug, Eq, PartialEq)]
1285pub enum InsertError {
1286 ShadowAddrExists,
1288 Exists,
1290 WouldShadowExisting,
1292 IndirectConflict,
1294}
1295
1296impl From<InsertError> for LocalAddressError {
1297 fn from(value: InsertError) -> Self {
1298 match value {
1299 InsertError::ShadowAddrExists
1300 | InsertError::Exists
1301 | InsertError::IndirectConflict
1302 | InsertError::WouldShadowExisting => LocalAddressError::AddressInUse,
1303 }
1304 }
1305}
1306
1307pub trait ConvertSocketMapState<I: Ip, D, A: SocketMapAddrSpec, S: SocketMapStateSpec> {
1310 type Id;
1311 type SharingState;
1312 type Addr: Debug;
1313 type AddrState: SocketMapAddrStateSpec<Id = Self::Id, SharingState = Self::SharingState>;
1314
1315 fn to_addr_vec(addr: &Self::Addr) -> AddrVec<I, D, A>;
1316 fn from_addr_vec_ref(addr: &AddrVec<I, D, A>) -> &Self::Addr;
1317 fn from_bound_ref(bound: &Bound<S>) -> Option<&Self::AddrState>;
1318 fn from_bound_mut(bound: &mut Bound<S>) -> Option<&mut Self::AddrState>;
1319 fn to_bound(state: Self::AddrState) -> Bound<S>;
1320 fn to_socket_id(id: Self::Id) -> SocketId<S>;
1321 fn from_socket_id_ref(id: &SocketId<S>) -> &Self::Id;
1322}
1323
1324impl<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec, S: SocketMapStateSpec>
1325 ConvertSocketMapState<I, D, A, S> for Listener
1326{
1327 type Id = S::ListenerId;
1328 type SharingState = S::ListenerSharingState;
1329 type Addr = ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>;
1330 type AddrState = S::ListenerAddrState;
1331 fn to_addr_vec(addr: &Self::Addr) -> AddrVec<I, D, A> {
1332 AddrVec::Listen(addr.clone())
1333 }
1334
1335 fn from_addr_vec_ref(addr: &AddrVec<I, D, A>) -> &Self::Addr {
1336 match addr {
1337 AddrVec::Listen(l) => l,
1338 AddrVec::Conn(c) => unreachable!("conn addr for listener: {c:?}"),
1339 }
1340 }
1341
1342 fn from_bound_ref(bound: &Bound<S>) -> Option<&S::ListenerAddrState> {
1343 match bound {
1344 Bound::Listen(l) => Some(l),
1345 Bound::Conn(_c) => None,
1346 }
1347 }
1348
1349 fn from_bound_mut(bound: &mut Bound<S>) -> Option<&mut S::ListenerAddrState> {
1350 match bound {
1351 Bound::Listen(l) => Some(l),
1352 Bound::Conn(_c) => None,
1353 }
1354 }
1355
1356 fn to_bound(state: S::ListenerAddrState) -> Bound<S> {
1357 Bound::Listen(state)
1358 }
1359 fn from_socket_id_ref(id: &SocketId<S>) -> &Self::Id {
1360 match id {
1361 SocketId::Listener(id) => id,
1362 SocketId::Connection(_) => unreachable!("connection ID for listener"),
1363 }
1364 }
1365 fn to_socket_id(id: Self::Id) -> SocketId<S> {
1366 SocketId::Listener(id)
1367 }
1368}
1369
1370impl<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec, S: SocketMapStateSpec>
1371 ConvertSocketMapState<I, D, A, S> for Connection
1372{
1373 type Id = S::ConnId;
1374 type SharingState = S::ConnSharingState;
1375 type Addr = ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>;
1376 type AddrState = S::ConnAddrState;
1377 fn to_addr_vec(addr: &Self::Addr) -> AddrVec<I, D, A> {
1378 AddrVec::Conn(addr.clone())
1379 }
1380
1381 fn from_addr_vec_ref(addr: &AddrVec<I, D, A>) -> &Self::Addr {
1382 match addr {
1383 AddrVec::Conn(c) => c,
1384 AddrVec::Listen(l) => unreachable!("listener addr for conn: {l:?}"),
1385 }
1386 }
1387
1388 fn from_bound_ref(bound: &Bound<S>) -> Option<&S::ConnAddrState> {
1389 match bound {
1390 Bound::Listen(_l) => None,
1391 Bound::Conn(c) => Some(c),
1392 }
1393 }
1394
1395 fn from_bound_mut(bound: &mut Bound<S>) -> Option<&mut S::ConnAddrState> {
1396 match bound {
1397 Bound::Listen(_l) => None,
1398 Bound::Conn(c) => Some(c),
1399 }
1400 }
1401
1402 fn to_bound(state: S::ConnAddrState) -> Bound<S> {
1403 Bound::Conn(state)
1404 }
1405
1406 fn from_socket_id_ref(id: &SocketId<S>) -> &Self::Id {
1407 match id {
1408 SocketId::Connection(id) => id,
1409 SocketId::Listener(_) => unreachable!("listener ID for connection"),
1410 }
1411 }
1412 fn to_socket_id(id: Self::Id) -> SocketId<S> {
1413 SocketId::Connection(id)
1414 }
1415}
1416
1417#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
1419pub struct SharingDomain(u64);
1420
1421impl SharingDomain {
1422 pub const fn new(id: u64) -> Self {
1426 SharingDomain(id)
1427 }
1428}
1429
1430#[derive(Default, Debug, Eq, PartialEq, Clone, Copy, Hash)]
1433pub enum ReusePortOption {
1434 #[default]
1436 Disabled,
1437
1438 Enabled(SharingDomain),
1441}
1442
1443impl ReusePortOption {
1444 pub fn is_enabled(&self) -> bool {
1446 matches!(self, ReusePortOption::Enabled(_))
1447 }
1448
1449 pub fn is_shareable_with(&self, other: &Self) -> bool {
1452 match (self, other) {
1453 (ReusePortOption::Enabled(domain1), ReusePortOption::Enabled(domain2)) => {
1454 domain1 == domain2
1455 }
1456 _ => false,
1457 }
1458 }
1459}
1460
1461pub trait SocketDiagnosticsSeed {
1464 type Output;
1466
1467 fn resolve(self) -> Option<Self::Output>;
1469}
1470
1471#[cfg(test)]
1472mod tests {
1473 use alloc::vec;
1474 use alloc::vec::Vec;
1475
1476 use assert_matches::assert_matches;
1477 use net_declare::{net_ip_v4, net_ip_v6};
1478 use net_types::ip::{Ipv4Addr, Ipv6, Ipv6Addr};
1479 use netstack3_hashmap::HashSet;
1480 use test_case::test_case;
1481
1482 use crate::device::testutil::{FakeDeviceId, FakeWeakDeviceId, MultipleDevicesId};
1483 use crate::testutil::set_logger_for_test;
1484
1485 use super::*;
1486
1487 #[test_case(net_ip_v4!("8.8.8.8"))]
1488 #[test_case(net_ip_v4!("127.0.0.1"))]
1489 #[test_case(net_ip_v4!("127.0.8.9"))]
1490 #[test_case(net_ip_v4!("224.1.2.3"))]
1491 fn must_never_have_zone_ipv4(addr: Ipv4Addr) {
1492 let addr = SpecifiedAddr::new(addr).unwrap();
1494 assert_eq!(addr.must_have_zone(), false);
1495 }
1496
1497 #[test_case(net_ip_v6!("1::2:3"), false)]
1498 #[test_case(net_ip_v6!("::1"), false; "localhost")]
1499 #[test_case(net_ip_v6!("1::"), false)]
1500 #[test_case(net_ip_v6!("ff03:1:2:3::1"), false)]
1501 #[test_case(net_ip_v6!("ff02:1:2:3::1"), true)]
1502 #[test_case(Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.get(), true)]
1503 #[test_case(net_ip_v6!("fe80::1"), true)]
1504 fn must_have_zone_ipv6(addr: Ipv6Addr, must_have: bool) {
1505 let addr = SpecifiedAddr::new(addr).unwrap();
1508 assert_eq!(addr.must_have_zone(), must_have);
1509 }
1510
1511 #[test]
1512 fn try_into_null_zoned_ipv6() {
1513 assert_eq!(Ipv6::LOOPBACK_ADDRESS.try_into_null_zoned(), None);
1514 let zoned = Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified();
1515 const ZONE: u32 = 5;
1516 assert_eq!(
1517 zoned.try_into_null_zoned().map(|a| a.map_zone(|()| ZONE)),
1518 Some(AddrAndZone::new(zoned, ZONE).unwrap())
1519 );
1520 }
1521
1522 enum FakeSpec {}
1523
1524 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
1525 struct Listener(usize);
1526
1527 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
1528 struct SharingState {
1529 tag: char,
1530 shared: bool,
1531 }
1532
1533 impl SharingState {
1534 fn exclusive(tag: char) -> Self {
1535 Self { tag, shared: false }
1536 }
1537
1538 fn shared(tag: char) -> Self {
1539 Self { tag, shared: true }
1540 }
1541 }
1542
1543 impl SharingState {
1544 fn can_share_with(&self, other: &Self) -> bool {
1545 self.tag == other.tag && self.shared && other.shared
1546 }
1547 }
1548
1549 #[derive(PartialEq, Eq, Debug)]
1550 struct Multiple<T> {
1551 sharing_state: SharingState,
1552 entries: Vec<T>,
1553 }
1554
1555 impl<T> Multiple<T> {
1556 fn new_exclusive(tag: char, entries: Vec<T>) -> Self {
1557 Self { sharing_state: SharingState { tag, shared: false }, entries }
1558 }
1559 }
1560
1561 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
1562 struct Conn(usize);
1563
1564 enum FakeAddrSpec {}
1565
1566 impl SocketMapAddrSpec for FakeAddrSpec {
1567 type LocalIdentifier = NonZeroU16;
1568 type RemoteIdentifier = ();
1569 }
1570
1571 impl SocketMapStateSpec for FakeSpec {
1572 type AddrVecTag = SharingState;
1573
1574 type ListenerId = Listener;
1575 type ConnId = Conn;
1576
1577 type ListenerSharingState = SharingState;
1578 type ConnSharingState = SharingState;
1579
1580 type ListenerAddrState = Multiple<Listener>;
1581 type ConnAddrState = Multiple<Conn>;
1582
1583 fn listener_tag(_: ListenerAddrInfo, state: &Self::ListenerAddrState) -> Self::AddrVecTag {
1584 state.sharing_state
1585 }
1586
1587 fn connected_tag(_has_device: bool, state: &Self::ConnAddrState) -> Self::AddrVecTag {
1588 state.sharing_state
1589 }
1590 }
1591
1592 type FakeBoundSocketMap =
1593 BoundSocketMap<Ipv4, FakeWeakDeviceId<FakeDeviceId>, FakeAddrSpec, FakeSpec>;
1594
1595 #[derive(Default)]
1599 struct FakeSocketIdGen {
1600 next_id: usize,
1601 }
1602
1603 impl FakeSocketIdGen {
1604 fn next(&mut self) -> usize {
1605 let next_next_id = self.next_id + 1;
1606 core::mem::replace(&mut self.next_id, next_next_id)
1607 }
1608 }
1609
1610 impl<I: Eq> SocketMapAddrStateSpec for Multiple<I> {
1611 type Id = I;
1612 type SharingState = SharingState;
1613 type Inserter<'a>
1614 = &'a mut Vec<I>
1615 where
1616 I: 'a;
1617
1618 fn new(sharing_state: &SharingState, id: I) -> Self {
1619 Self { sharing_state: *sharing_state, entries: vec![id] }
1620 }
1621
1622 fn contains_id(&self, id: &Self::Id) -> bool {
1623 self.entries.contains(id)
1624 }
1625
1626 fn try_get_inserter<'a, 'b>(
1627 &'b mut self,
1628 new_sharing_state: &'a SharingState,
1629 ) -> Result<Self::Inserter<'b>, IncompatibleError> {
1630 (self.sharing_state == *new_sharing_state)
1631 .then_some(&mut self.entries)
1632 .ok_or(IncompatibleError)
1633 }
1634
1635 fn could_insert(&self, new_sharing_state: &SharingState) -> Result<(), IncompatibleError> {
1636 (self.sharing_state == *new_sharing_state).then_some(()).ok_or(IncompatibleError)
1637 }
1638
1639 fn remove_by_id(&mut self, id: I) -> RemoveResult {
1640 let index = self.entries.iter().position(|i| i == &id).expect("did not find id");
1641 let _: I = self.entries.swap_remove(index);
1642 if self.entries.is_empty() { RemoveResult::IsLast } else { RemoveResult::Success }
1643 }
1644
1645 fn sharing_state(&self) -> Self::SharingState {
1646 self.sharing_state
1647 }
1648 }
1649
1650 impl<D: DeviceIdentifier, A: Into<AddrVec<Ipv4, D, FakeAddrSpec>> + Clone>
1651 SocketMapConflictPolicy<A, SharingState, Ipv4, D, FakeAddrSpec> for FakeSpec
1652 {
1653 fn check_insert_conflicts(
1654 new_sharing_state: &SharingState,
1655 addr: &A,
1656 socketmap: &SocketMap<AddrVec<Ipv4, D, FakeAddrSpec>, Bound<FakeSpec>>,
1657 ) -> Result<(), InsertError> {
1658 let dest: AddrVec<_, _, _> = addr.clone().into();
1659 if dest.iter_shadows().any(|a| {
1660 let entry = socketmap.get(&a);
1661 match entry {
1662 Some(Bound::Listen(Multiple { sharing_state, .. }))
1663 | Some(Bound::Conn(Multiple { sharing_state, .. })) => {
1664 !sharing_state.can_share_with(new_sharing_state)
1665 }
1666 None => false,
1667 }
1668 }) {
1669 return Err(InsertError::ShadowAddrExists);
1670 }
1671
1672 match socketmap.get(&dest) {
1673 Some(Bound::Listen(Multiple { sharing_state, .. }))
1674 | Some(Bound::Conn(Multiple { sharing_state, .. })) => {
1675 if sharing_state != new_sharing_state {
1678 return Err(InsertError::Exists);
1679 }
1680 }
1681 None => (),
1682 }
1683
1684 if socketmap
1685 .descendant_counts(&dest)
1686 .any(|(sharing_state, _count)| !sharing_state.can_share_with(new_sharing_state))
1687 {
1688 Err(InsertError::WouldShadowExisting)
1689 } else {
1690 Ok(())
1691 }
1692 }
1693 }
1694
1695 impl<I: Eq> SocketMapAddrStateUpdateSharingSpec for Multiple<I> {
1696 fn try_update_sharing(
1697 &mut self,
1698 id: Self::Id,
1699 new_sharing_state: &Self::SharingState,
1700 ) -> Result<(), IncompatibleError> {
1701 if self.sharing_state == *new_sharing_state {
1702 return Ok(());
1703 }
1704
1705 if self.entries.len() != 1 {
1710 return Err(IncompatibleError);
1711 }
1712 assert!(self.entries.contains(&id));
1713 self.sharing_state = *new_sharing_state;
1714 Ok(())
1715 }
1716 }
1717
1718 impl<D: DeviceIdentifier, A: Into<AddrVec<Ipv4, D, FakeAddrSpec>> + Clone>
1719 SocketMapUpdateSharingPolicy<A, SharingState, Ipv4, D, FakeAddrSpec> for FakeSpec
1720 {
1721 fn allows_sharing_update(
1722 _socketmap: &SocketMap<AddrVec<Ipv4, D, FakeAddrSpec>, Bound<Self>>,
1723 _addr: &A,
1724 _old_sharing: &SharingState,
1725 _new_sharing_state: &SharingState,
1726 ) -> Result<(), UpdateSharingError> {
1727 Ok(())
1728 }
1729 }
1730
1731 const LISTENER_ADDR: ListenerAddr<
1732 ListenerIpAddr<Ipv4Addr, NonZeroU16>,
1733 FakeWeakDeviceId<FakeDeviceId>,
1734 > = ListenerAddr {
1735 ip: ListenerIpAddr {
1736 addr: Some(unsafe { SocketIpAddr::new_unchecked(net_ip_v4!("1.2.3.4")) }),
1737 identifier: NonZeroU16::new(1).unwrap(),
1738 },
1739 device: None,
1740 };
1741
1742 const CONN_ADDR: ConnAddr<
1743 ConnIpAddr<Ipv4Addr, NonZeroU16, ()>,
1744 FakeWeakDeviceId<FakeDeviceId>,
1745 > = ConnAddr {
1746 ip: ConnIpAddr {
1747 local: (
1748 unsafe { SocketIpAddr::new_unchecked(net_ip_v4!("5.6.7.8")) },
1749 NonZeroU16::new(1).unwrap(),
1750 ),
1751 remote: unsafe { (SocketIpAddr::new_unchecked(net_ip_v4!("8.7.6.5")), ()) },
1752 },
1753 device: None,
1754 };
1755
1756 #[test]
1757 fn bound_insert_get_remove_listener() {
1758 set_logger_for_test();
1759 let mut bound = FakeBoundSocketMap::default();
1760 let mut fake_id_gen = FakeSocketIdGen::default();
1761
1762 let addr = LISTENER_ADDR;
1763
1764 let id = {
1765 let entry = bound
1766 .listeners_mut()
1767 .try_insert(addr, SharingState::exclusive('v'), Listener(fake_id_gen.next()))
1768 .unwrap();
1769 assert_eq!(entry.get_addr(), &addr);
1770 entry.id().clone()
1771 };
1772
1773 assert_eq!(
1774 bound.listeners().get_by_addr(&addr),
1775 Some(&Multiple::new_exclusive('v', vec![id]))
1776 );
1777
1778 assert_eq!(bound.listeners_mut().remove(&id, &addr), Ok(()));
1779 assert_eq!(bound.listeners().get_by_addr(&addr), None);
1780 }
1781
1782 #[test]
1783 fn bound_insert_get_remove_conn() {
1784 set_logger_for_test();
1785 let mut bound = FakeBoundSocketMap::default();
1786 let mut fake_id_gen = FakeSocketIdGen::default();
1787
1788 let addr = CONN_ADDR;
1789
1790 let id = {
1791 let entry = bound
1792 .conns_mut()
1793 .try_insert(addr, SharingState::exclusive('v'), Conn(fake_id_gen.next()))
1794 .unwrap();
1795 assert_eq!(entry.get_addr(), &addr);
1796 entry.id().clone()
1797 };
1798
1799 assert_eq!(bound.conns().get_by_addr(&addr), Some(&Multiple::new_exclusive('v', vec![id])));
1800
1801 assert_eq!(bound.conns_mut().remove(&id, &addr), Ok(()));
1802 assert_eq!(bound.conns().get_by_addr(&addr), None);
1803 }
1804
1805 #[test]
1806 fn bound_iter_addrs() {
1807 set_logger_for_test();
1808 let mut bound = FakeBoundSocketMap::default();
1809 let mut fake_id_gen = FakeSocketIdGen::default();
1810
1811 let listener_addrs = [
1812 (Some(net_ip_v4!("1.1.1.1")), 1),
1813 (Some(net_ip_v4!("2.2.2.2")), 2),
1814 (Some(net_ip_v4!("1.1.1.1")), 3),
1815 (None, 4),
1816 ]
1817 .map(|(ip, identifier)| ListenerAddr {
1818 device: None,
1819 ip: ListenerIpAddr {
1820 addr: ip.map(|x| SocketIpAddr::new(x).unwrap()),
1821 identifier: NonZeroU16::new(identifier).unwrap(),
1822 },
1823 });
1824 let conn_addrs = [
1825 (net_ip_v4!("3.3.3.3"), 3, net_ip_v4!("4.4.4.4")),
1826 (net_ip_v4!("4.4.4.4"), 3, net_ip_v4!("3.3.3.3")),
1827 ]
1828 .map(|(local_ip, local_identifier, remote_ip)| ConnAddr {
1829 ip: ConnIpAddr {
1830 local: (
1831 SocketIpAddr::new(local_ip).unwrap(),
1832 NonZeroU16::new(local_identifier).unwrap(),
1833 ),
1834 remote: (SocketIpAddr::new(remote_ip).unwrap(), ()),
1835 },
1836 device: None,
1837 });
1838
1839 for addr in listener_addrs.iter().cloned() {
1840 let _entry = bound
1841 .listeners_mut()
1842 .try_insert(addr, SharingState::exclusive('a'), Listener(fake_id_gen.next()))
1843 .unwrap();
1844 }
1845 for addr in conn_addrs.iter().cloned() {
1846 let _entry = bound
1847 .conns_mut()
1848 .try_insert(addr, SharingState::exclusive('a'), Conn(fake_id_gen.next()))
1849 .unwrap();
1850 }
1851 let expected_addrs = listener_addrs
1852 .into_iter()
1853 .map(Into::into)
1854 .chain(conn_addrs.into_iter().map(Into::into))
1855 .collect::<HashSet<_>>();
1856
1857 assert_eq!(expected_addrs, bound.iter_addrs().cloned().collect());
1858 }
1859
1860 #[test]
1861 fn try_insert_with_callback_not_called_on_error() {
1862 set_logger_for_test();
1865 let mut bound = FakeBoundSocketMap::default();
1866 let addr = LISTENER_ADDR;
1867
1868 let _: &Listener = bound
1870 .listeners_mut()
1871 .try_insert(addr, SharingState::exclusive('a'), Listener(0))
1872 .unwrap()
1873 .id();
1874
1875 fn is_never_called<A, B, T>(_: A, _: B) -> (T, ()) {
1879 panic!("should never be called");
1880 }
1881
1882 assert_matches!(
1883 bound.listeners_mut().try_insert_with(
1884 addr,
1885 SharingState::exclusive('b'),
1886 is_never_called
1887 ),
1888 Err(InsertError::Exists)
1889 );
1890 assert_matches!(
1891 bound.listeners_mut().try_insert_with(
1892 ListenerAddr { device: Some(FakeWeakDeviceId(FakeDeviceId)), ..addr },
1893 SharingState::exclusive('b'),
1894 is_never_called
1895 ),
1896 Err(InsertError::ShadowAddrExists)
1897 );
1898 assert_matches!(
1899 bound.conns_mut().try_insert_with(
1900 ConnAddr {
1901 device: None,
1902 ip: ConnIpAddr {
1903 local: (addr.ip.addr.unwrap(), addr.ip.identifier),
1904 remote: (SocketIpAddr::new(net_ip_v4!("1.1.1.1")).unwrap(), ()),
1905 },
1906 },
1907 SharingState::exclusive('b'),
1908 is_never_called,
1909 ),
1910 Err(InsertError::ShadowAddrExists)
1911 );
1912 }
1913
1914 #[test]
1915 fn insert_listener_conflict_with_listener() {
1916 set_logger_for_test();
1917 let mut bound = FakeBoundSocketMap::default();
1918 let mut fake_id_gen = FakeSocketIdGen::default();
1919 let addr = LISTENER_ADDR;
1920
1921 let _: &Listener = bound
1922 .listeners_mut()
1923 .try_insert(addr, SharingState::exclusive('a'), Listener(fake_id_gen.next()))
1924 .unwrap()
1925 .id();
1926 assert_matches!(
1927 bound.listeners_mut().try_insert(
1928 addr,
1929 SharingState::exclusive('b'),
1930 Listener(fake_id_gen.next())
1931 ),
1932 Err(InsertError::Exists)
1933 );
1934 }
1935
1936 #[test]
1937 fn insert_listener_conflict_with_shadower() {
1938 set_logger_for_test();
1939 let mut bound = FakeBoundSocketMap::default();
1940 let mut fake_id_gen = FakeSocketIdGen::default();
1941 let addr = LISTENER_ADDR;
1942 let shadows_addr = {
1943 assert_eq!(addr.device, None);
1944 ListenerAddr { device: Some(FakeWeakDeviceId(FakeDeviceId)), ..addr }
1945 };
1946
1947 let _: &Listener = bound
1948 .listeners_mut()
1949 .try_insert(addr, SharingState::exclusive('a'), Listener(fake_id_gen.next()))
1950 .unwrap()
1951 .id();
1952 assert_matches!(
1953 bound.listeners_mut().try_insert(
1954 shadows_addr,
1955 SharingState::exclusive('b'),
1956 Listener(fake_id_gen.next())
1957 ),
1958 Err(InsertError::ShadowAddrExists)
1959 );
1960 }
1961
1962 #[test]
1963 fn insert_conn_conflict_with_listener() {
1964 set_logger_for_test();
1965 let mut bound = FakeBoundSocketMap::default();
1966 let mut fake_id_gen = FakeSocketIdGen::default();
1967 let addr = LISTENER_ADDR;
1968 let shadows_addr = ConnAddr {
1969 device: None,
1970 ip: ConnIpAddr {
1971 local: (addr.ip.addr.unwrap(), addr.ip.identifier),
1972 remote: (SocketIpAddr::new(net_ip_v4!("1.1.1.1")).unwrap(), ()),
1973 },
1974 };
1975
1976 let _: &Listener = bound
1977 .listeners_mut()
1978 .try_insert(addr, SharingState::exclusive('a'), Listener(fake_id_gen.next()))
1979 .unwrap()
1980 .id();
1981 assert_matches!(
1982 bound.conns_mut().try_insert(
1983 shadows_addr,
1984 SharingState::exclusive('b'),
1985 Conn(fake_id_gen.next())
1986 ),
1987 Err(InsertError::ShadowAddrExists)
1988 );
1989 }
1990
1991 #[test]
1992 fn insert_and_remove_listener() {
1993 set_logger_for_test();
1994 let mut bound = FakeBoundSocketMap::default();
1995 let mut fake_id_gen = FakeSocketIdGen::default();
1996 let addr = LISTENER_ADDR;
1997
1998 let a = bound
1999 .listeners_mut()
2000 .try_insert(addr, SharingState::exclusive('x'), Listener(fake_id_gen.next()))
2001 .unwrap()
2002 .id()
2003 .clone();
2004 let b = bound
2005 .listeners_mut()
2006 .try_insert(addr, SharingState::exclusive('x'), Listener(fake_id_gen.next()))
2007 .unwrap()
2008 .id()
2009 .clone();
2010 assert_ne!(a, b);
2011
2012 assert_eq!(bound.listeners_mut().remove(&a, &addr), Ok(()));
2013 assert_eq!(
2014 bound.listeners().get_by_addr(&addr),
2015 Some(&Multiple::new_exclusive('x', vec![b]))
2016 );
2017 }
2018
2019 #[test]
2020 fn insert_and_remove_conn() {
2021 set_logger_for_test();
2022 let mut bound = FakeBoundSocketMap::default();
2023 let mut fake_id_gen = FakeSocketIdGen::default();
2024 let addr = CONN_ADDR;
2025
2026 let a = bound
2027 .conns_mut()
2028 .try_insert(addr, SharingState::exclusive('x'), Conn(fake_id_gen.next()))
2029 .unwrap()
2030 .id()
2031 .clone();
2032 let b = bound
2033 .conns_mut()
2034 .try_insert(addr, SharingState::exclusive('x'), Conn(fake_id_gen.next()))
2035 .unwrap()
2036 .id()
2037 .clone();
2038 assert_ne!(a, b);
2039
2040 assert_eq!(bound.conns_mut().remove(&a, &addr), Ok(()));
2041 assert_eq!(bound.conns().get_by_addr(&addr), Some(&Multiple::new_exclusive('x', vec![b])));
2042 }
2043
2044 #[test]
2045 fn update_listener_to_shadowed_addr_fails() {
2046 let mut bound = FakeBoundSocketMap::default();
2047 let mut fake_id_gen = FakeSocketIdGen::default();
2048
2049 let first_addr = LISTENER_ADDR;
2050 let second_addr = ListenerAddr {
2051 ip: ListenerIpAddr {
2052 addr: Some(SocketIpAddr::new(net_ip_v4!("1.1.1.1")).unwrap()),
2053 ..LISTENER_ADDR.ip
2054 },
2055 ..LISTENER_ADDR
2056 };
2057 let both_shadow = ListenerAddr {
2058 ip: ListenerIpAddr { addr: None, identifier: first_addr.ip.identifier },
2059 device: None,
2060 };
2061
2062 let first = bound
2063 .listeners_mut()
2064 .try_insert(first_addr, SharingState::exclusive('a'), Listener(fake_id_gen.next()))
2065 .unwrap()
2066 .id()
2067 .clone();
2068 let second = bound
2069 .listeners_mut()
2070 .try_insert(second_addr, SharingState::exclusive('b'), Listener(fake_id_gen.next()))
2071 .unwrap()
2072 .id()
2073 .clone();
2074
2075 let (ExistsError, entry) = bound
2078 .listeners_mut()
2079 .entry(&second, &second_addr)
2080 .unwrap()
2081 .try_update_addr(both_shadow)
2082 .expect_err("update should fail");
2083
2084 assert_eq!(entry.id(), &second);
2086 drop(entry);
2087
2088 let (ExistsError, entry) = bound
2089 .listeners_mut()
2090 .entry(&first, &first_addr)
2091 .unwrap()
2092 .try_update_addr(both_shadow)
2093 .expect_err("update should fail");
2094 assert_eq!(entry.get_addr(), &first_addr);
2095 }
2096
2097 #[test]
2098 fn update_listener_to_conflicting_addr_fails() {
2099 let mut bound = BoundSocketMap::<
2100 Ipv4,
2101 FakeWeakDeviceId<MultipleDevicesId>,
2102 FakeAddrSpec,
2103 FakeSpec,
2104 >::default();
2105 let mut fake_id_gen = FakeSocketIdGen::default();
2106 let device_a_wildcard_addr = ListenerAddr {
2107 ip: ListenerIpAddr { addr: None, identifier: NonZeroU16::new(80).unwrap() },
2108 device: Some(FakeWeakDeviceId(MultipleDevicesId::A)),
2109 };
2110 let device_b_specific_addr = ListenerAddr {
2111 ip: ListenerIpAddr {
2112 addr: Some(SocketIpAddr::new(net_ip_v4!("192.168.1.1")).unwrap()),
2113 identifier: NonZeroU16::new(80).unwrap(),
2114 },
2115 device: Some(FakeWeakDeviceId(MultipleDevicesId::B)),
2116 };
2117 let device_a_specific_addr = ListenerAddr {
2118 ip: ListenerIpAddr {
2119 addr: Some(SocketIpAddr::new(net_ip_v4!("192.168.1.1")).unwrap()),
2120 identifier: NonZeroU16::new(80).unwrap(),
2121 },
2122 device: Some(FakeWeakDeviceId(MultipleDevicesId::A)),
2123 };
2124
2125 let _ = bound
2126 .listeners_mut()
2127 .try_insert(
2128 device_a_wildcard_addr,
2129 SharingState::exclusive('a'),
2130 Listener(fake_id_gen.next()),
2131 )
2132 .expect("binding wildcard listener should succeed");
2133
2134 assert_matches!(
2136 bound.listeners_mut().try_insert(
2137 device_a_specific_addr,
2138 SharingState::exclusive('b'),
2139 Listener(fake_id_gen.next()),
2140 ),
2141 Err(_)
2142 );
2143
2144 let specific_entry = bound
2147 .listeners_mut()
2148 .try_insert(
2149 device_b_specific_addr,
2150 SharingState::exclusive('b'),
2151 Listener(fake_id_gen.next()),
2152 )
2153 .expect("binding dev A specific listener should succeed");
2154
2155 assert_matches!(specific_entry.try_update_addr(device_a_specific_addr), Err(_));
2156 }
2157
2158 #[test]
2159 fn nonexistent_conn_entry() {
2160 let mut map = FakeBoundSocketMap::default();
2161 let mut fake_id_gen = FakeSocketIdGen::default();
2162 let addr = CONN_ADDR;
2163 let conn_id = map
2164 .conns_mut()
2165 .try_insert(addr.clone(), SharingState::exclusive('a'), Conn(fake_id_gen.next()))
2166 .expect("failed to insert")
2167 .id()
2168 .clone();
2169 assert_matches!(map.conns_mut().remove(&conn_id, &addr), Ok(()));
2170
2171 assert!(map.conns_mut().entry(&conn_id, &addr).is_none());
2172 }
2173
2174 #[test]
2175 fn update_conn_sharing() {
2176 let mut map = FakeBoundSocketMap::default();
2177 let mut fake_id_gen = FakeSocketIdGen::default();
2178 let addr = CONN_ADDR;
2179 let mut entry = map
2180 .conns_mut()
2181 .try_insert(addr.clone(), SharingState::exclusive('a'), Conn(fake_id_gen.next()))
2182 .expect("failed to insert");
2183
2184 entry
2185 .try_update_sharing(&SharingState::exclusive('a'), SharingState::exclusive('d'))
2186 .expect("worked");
2187 let mut second_conn = map
2190 .conns_mut()
2191 .try_insert(addr.clone(), SharingState::exclusive('d'), Conn(fake_id_gen.next()))
2192 .expect("can insert");
2193 assert_matches!(
2194 second_conn
2195 .try_update_sharing(&SharingState::exclusive('d'), SharingState::exclusive('e')),
2196 Err(UpdateSharingError)
2197 );
2198 }
2199
2200 #[test]
2201 fn lookup_connected() {
2202 let mut map = FakeBoundSocketMap::default();
2203 let mut fake_id_gen = FakeSocketIdGen::default();
2204
2205 let sharing_state = SharingState::shared('a');
2206
2207 let device_id = FakeWeakDeviceId(FakeDeviceId);
2208 let entry1 = map
2209 .conns_mut()
2210 .try_insert(CONN_ADDR, sharing_state, Conn(fake_id_gen.next()))
2211 .expect("failed to insert")
2212 .id()
2213 .clone();
2214 let conn = map
2215 .lookup_connected(CONN_ADDR.ip.remote, CONN_ADDR.ip.local, device_id)
2216 .expect("lookup should succeed");
2217 assert!(conn.contains_id(&entry1));
2218
2219 let addr_with_device = ConnAddr { device: Some(device_id), ..CONN_ADDR };
2222 let entry2 = map
2223 .conns_mut()
2224 .try_insert(addr_with_device, sharing_state, Conn(fake_id_gen.next()))
2225 .expect("failed to insert")
2226 .id()
2227 .clone();
2228 let conn = map
2229 .lookup_connected(CONN_ADDR.ip.remote, CONN_ADDR.ip.local, device_id)
2230 .expect("lookup should succeed");
2231 assert!(conn.contains_id(&entry2));
2232 }
2233}