1use core::convert::Infallible as Never;
6use core::num::NonZeroU16;
7
8use net_types::Witness as _;
9use net_types::ip::{Ip, IpAddress as _};
10use netstack3_base::{
11 InstantBindingsTypes, IpSocketProperties, Marks, Matcher, SocketDiagnosticsSeed,
12 WeakDeviceIdentifier,
13};
14
15use crate::TcpCountersWithSocket;
16use crate::internal::socket::{
17 BoundState, DualStackIpExt, Listener, SocketCookie, TcpBindingsTypes, TcpSocketId,
18 TcpSocketState, TcpSocketStateInner, Unbound,
19};
20use crate::internal::state::State;
21use crate::internal::state::info::TcpSocketInfo;
22
23pub(crate) struct TcpSocketStateForMatching<
26 'a,
27 I: DualStackIpExt,
28 D: netstack3_base::WeakDeviceIdentifier,
29 BT: TcpBindingsTypes,
30> {
31 pub(crate) state: &'a TcpSocketState<I, D, BT>,
32 pub(crate) id: &'a TcpSocketId<I, D, BT>,
33}
34
35impl<'a, I: DualStackIpExt, D: netstack3_base::WeakDeviceIdentifier, BT: TcpBindingsTypes>
36 netstack3_base::MaybeSocketTransportProperties for TcpSocketStateForMatching<'a, I, D, BT>
37{
38 type TcpProps<'b>
39 = Self
40 where
41 Self: 'b;
42
43 type UdpProps<'b>
44 = Never
45 where
46 Self: 'b;
47
48 fn tcp_socket_properties(&self) -> Option<&Self::TcpProps<'_>> {
49 Some(self)
50 }
51
52 fn udp_socket_properties(&self) -> Option<&Self::UdpProps<'_>> {
53 None
54 }
55}
56
57impl<'a, I: DualStackIpExt, D: netstack3_base::WeakDeviceIdentifier, BT: TcpBindingsTypes>
58 netstack3_base::TcpSocketProperties for TcpSocketStateForMatching<'a, I, D, BT>
59{
60 fn src_port_matches(&self, matcher: &netstack3_base::BoundPortMatcher) -> bool {
61 let src_port = match &self.state.socket_state {
62 TcpSocketStateInner::Unbound(_) => None,
63 TcpSocketStateInner::Bound(BoundState { addr, .. })
64 | TcpSocketStateInner::Listener(Listener { addr, .. }) => {
65 Some(I::get_bound_info(addr).port.get())
66 }
67 TcpSocketStateInner::Connected { conn, .. } => {
68 Some(I::get_conn_info(conn).local_addr.port.get())
69 }
70 };
71
72 matcher.matches(&src_port)
73 }
74
75 fn dst_port_matches(&self, matcher: &netstack3_base::BoundPortMatcher) -> bool {
76 let dst_port = match &self.state.socket_state {
77 TcpSocketStateInner::Unbound(_)
78 | TcpSocketStateInner::Bound(_)
79 | TcpSocketStateInner::Listener(_) => None,
80 TcpSocketStateInner::Connected { conn, .. } => {
81 Some(I::get_conn_info(conn).remote_addr.port.get())
82 }
83 };
84
85 matcher.matches(&dst_port)
86 }
87
88 fn state_matches(&self, matcher: &netstack3_base::TcpStateMatcher) -> bool {
89 matcher.matches(&self.state.base_state())
90 }
91}
92
93impl<'a, I: DualStackIpExt, D: netstack3_base::WeakDeviceIdentifier, BT: TcpBindingsTypes>
94 IpSocketProperties<BT::DeviceClass> for TcpSocketStateForMatching<'a, I, D, BT>
95where
96 D::Strong: netstack3_base::InterfaceProperties<BT::DeviceClass>,
97{
98 fn family_matches(&self, family: &net_types::ip::IpVersion) -> bool {
99 I::VERSION == *family
100 }
101
102 fn src_addr_matches(&self, addr: &netstack3_base::BoundAddressMatcherEither) -> bool {
103 let src_addr = match &self.state.socket_state {
104 TcpSocketStateInner::Unbound(_) => None,
105 TcpSocketStateInner::Bound(BoundState { addr, .. })
106 | TcpSocketStateInner::Listener(Listener { addr, .. }) => {
107 I::get_bound_info(addr).addr.map(|a| a.addr().get())
108 }
109 TcpSocketStateInner::Connected { conn, .. } => {
110 Some(I::get_conn_info(conn).local_addr.ip.addr().get())
111 }
112 };
113
114 addr.matches(&src_addr.map(|a| a.to_ip_addr()))
115 }
116
117 fn dst_addr_matches(&self, addr: &netstack3_base::BoundAddressMatcherEither) -> bool {
118 let dst_addr = match &self.state.socket_state {
119 TcpSocketStateInner::Unbound(_)
120 | TcpSocketStateInner::Bound(_)
121 | TcpSocketStateInner::Listener(_) => None,
122 TcpSocketStateInner::Connected { conn, .. } => {
123 Some(I::get_conn_info(conn).remote_addr.ip.addr().get())
124 }
125 };
126
127 addr.matches(&dst_addr.map(|a| a.to_ip_addr()))
128 }
129
130 fn transport_protocol_matches(
131 &self,
132 proto: &netstack3_base::SocketTransportProtocolMatcher,
133 ) -> bool {
134 proto.matches(self)
135 }
136
137 fn bound_interface_matches(
138 &self,
139 iface: &netstack3_base::BoundInterfaceMatcher<BT::DeviceClass>,
140 ) -> bool {
141 let device = match &self.state.socket_state {
142 TcpSocketStateInner::Unbound(_) => None,
143 TcpSocketStateInner::Bound(BoundState { addr, .. })
144 | TcpSocketStateInner::Listener(Listener { addr, .. }) => {
145 I::get_bound_info(addr).device
146 }
147 TcpSocketStateInner::Connected { conn, .. } => I::get_conn_info(conn).device,
148 };
149 iface.matches(&device.and_then(|d| d.upgrade()).as_ref())
150 }
151
152 fn cookie_matches(&self, cookie: &netstack3_base::SocketCookieMatcher) -> bool {
153 cookie.matches(&self.id.socket_cookie().export_value())
154 }
155
156 fn mark_matches(&self, matcher: &netstack3_base::MarkInDomainMatcher) -> bool {
157 matcher.matcher.matches(self.state.socket_options.ip_options.marks.get(matcher.domain))
158 }
159}
160
161#[cfg_attr(any(test, feature = "testutils"), derive(Debug, PartialEq, Eq))]
163pub struct TcpSocketDiagnostics<I: Ip, Instant> {
164 pub state_machine: netstack3_base::TcpSocketState,
166 pub tuple: TcpSocketDiagnosticTuple<I>,
168 pub cookie: SocketCookie,
170 pub marks: Marks,
172 pub tcp_info: Option<TcpSocketInfo<Instant>>,
174}
175
176pub struct TcpSocketDiagnosticsSeed<I, D, BT>
179where
180 I: DualStackIpExt,
181 D: WeakDeviceIdentifier,
182 BT: TcpBindingsTypes,
183{
184 pub(crate) state: TcpSocketState<I, D, BT>,
185 pub(crate) counters: TcpCountersWithSocket<I>,
186 pub(crate) cookie: SocketCookie,
187}
188
189impl<I, D, BT> SocketDiagnosticsSeed for TcpSocketDiagnosticsSeed<I, D, BT>
190where
191 I: DualStackIpExt,
192 D: WeakDeviceIdentifier,
193 BT: TcpBindingsTypes,
194{
195 type Output = TcpSocketDiagnostics<I, <BT as InstantBindingsTypes>::Instant>;
196
197 fn resolve(self) -> Option<Self::Output> {
198 let Self { state, counters, cookie } = self;
199
200 state.get_diagnostics(&counters, true).map(|(tuple, state_machine, marks, tcp_info)| {
201 TcpSocketDiagnostics { tuple, state_machine, cookie, marks, tcp_info }
202 })
203 }
204}
205
206#[derive(Debug, PartialEq, Eq)]
212#[allow(missing_docs)]
213pub enum TcpSocketDiagnosticTuple<I: Ip> {
214 Bound { src_addr: Option<I::Addr>, src_port: NonZeroU16 },
218 Connected { src_addr: I::Addr, src_port: NonZeroU16, dst_addr: I::Addr, dst_port: NonZeroU16 },
220}
221
222impl<I: Ip> TcpSocketDiagnosticTuple<I> {
223 pub fn src_addr(&self) -> Option<I::Addr> {
225 match self {
226 Self::Bound { src_addr, src_port: _ } => *src_addr,
227 Self::Connected { src_addr, src_port: _, dst_addr: _, dst_port: _ } => Some(*src_addr),
228 }
229 }
230
231 pub fn src_port(&self) -> Option<NonZeroU16> {
233 match self {
234 Self::Bound { src_addr: _, src_port }
235 | Self::Connected { src_addr: _, src_port, dst_addr: _, dst_port: _ } => {
236 Some(*src_port)
237 }
238 }
239 }
240
241 pub fn dst_addr(&self) -> Option<I::Addr> {
243 match self {
244 Self::Bound { src_addr: _, src_port: _ } => None,
245 Self::Connected { src_addr: _, src_port: _, dst_addr, dst_port: _ } => Some(*dst_addr),
246 }
247 }
248
249 pub fn dst_port(&self) -> Option<NonZeroU16> {
251 match self {
252 Self::Bound { src_addr: _, src_port: _ } => None,
253 Self::Connected { src_addr: _, src_port: _, dst_addr: _, dst_port } => Some(*dst_port),
254 }
255 }
256}
257
258impl<I, D, BT> TcpSocketState<I, D, BT>
259where
260 I: DualStackIpExt,
261 D: WeakDeviceIdentifier,
262 BT: TcpBindingsTypes,
263{
264 pub(crate) fn tcp_info(
265 &self,
266 counters: &crate::internal::counters::TcpCountersWithSocket<I>,
267 ) -> TcpSocketInfo<BT::Instant> {
268 match &self.socket_state {
269 TcpSocketStateInner::Unbound(unbound) => {
270 TcpSocketInfo::from_partial_state(unbound.base_state(), counters.as_ref())
271 }
272 TcpSocketStateInner::Bound(bound) => {
273 TcpSocketInfo::from_partial_state(bound.base_state(), counters.as_ref())
274 }
275 TcpSocketStateInner::Listener(listener) => {
276 TcpSocketInfo::from_partial_state(listener.base_state(), counters.as_ref())
277 }
278 TcpSocketStateInner::Connected { conn, timer: _ } => {
279 TcpSocketInfo::from_full_state(I::get_state(conn), counters.as_ref())
280 }
281 }
282 }
283
284 pub(crate) fn get_diagnostics(
285 &self,
286 counters: &crate::internal::counters::TcpCountersWithSocket<I>,
287 extended_info: bool,
288 ) -> Option<(
289 TcpSocketDiagnosticTuple<I>,
290 netstack3_base::TcpSocketState,
291 Marks,
292 Option<TcpSocketInfo<BT::Instant>>,
293 )> {
294 let tuple = match &self.socket_state {
295 TcpSocketStateInner::Unbound(_) => None,
296 TcpSocketStateInner::Bound(BoundState { addr, .. })
297 | TcpSocketStateInner::Listener(Listener { addr, .. }) => {
298 let addr_info = I::get_bound_info(addr);
299 Some(TcpSocketDiagnosticTuple::Bound {
300 src_addr: addr_info.addr.map(|ip| ip.addr().get()),
301 src_port: addr_info.port,
302 })
303 }
304 TcpSocketStateInner::Connected { conn, .. } => {
305 let info = I::get_conn_info(conn);
306 Some(TcpSocketDiagnosticTuple::Connected {
307 src_addr: info.local_addr.ip.addr().get(),
308 dst_addr: info.remote_addr.ip.addr().get(),
309 src_port: info.local_addr.port,
310 dst_port: info.remote_addr.port,
311 })
312 }
313 }?;
314
315 Some((
316 tuple,
317 self.base_state(),
318 self.socket_options.ip_options.marks,
319 extended_info.then(|| self.tcp_info(counters)),
320 ))
321 }
322
323 pub(crate) fn base_state(&self) -> netstack3_base::TcpSocketState {
324 match &self.socket_state {
325 TcpSocketStateInner::Unbound(unbound) => unbound.base_state(),
326 TcpSocketStateInner::Bound(bound) => bound.base_state(),
327 TcpSocketStateInner::Listener(listener) => listener.base_state(),
328 TcpSocketStateInner::Connected { conn, .. } => match I::get_state(conn) {
329 State::Closed(_) => netstack3_base::TcpSocketState::Close,
330 State::Listen(_) => netstack3_base::TcpSocketState::Listen,
331 State::SynRcvd(_) => netstack3_base::TcpSocketState::SynRecv,
332 State::SynSent(_) => netstack3_base::TcpSocketState::SynSent,
333 State::Established(_) => netstack3_base::TcpSocketState::Established,
334 State::CloseWait(_) => netstack3_base::TcpSocketState::CloseWait,
335 State::LastAck(_) => netstack3_base::TcpSocketState::LastAck,
336 State::FinWait1(_) => netstack3_base::TcpSocketState::FinWait1,
337 State::FinWait2(_) => netstack3_base::TcpSocketState::FinWait2,
338 State::Closing(_) => netstack3_base::TcpSocketState::Closing,
339 State::TimeWait(_) => netstack3_base::TcpSocketState::TimeWait,
340 },
341 }
342 }
343}
344
345impl<D, Extra> Unbound<D, Extra> {
346 fn base_state(&self) -> netstack3_base::TcpSocketState {
347 netstack3_base::TcpSocketState::Close
348 }
349}
350
351impl<I, D, BT> BoundState<I, D, BT>
352where
353 I: DualStackIpExt,
354 D: WeakDeviceIdentifier,
355 BT: TcpBindingsTypes,
356{
357 fn base_state(&self) -> netstack3_base::TcpSocketState {
358 netstack3_base::TcpSocketState::Close
359 }
360}
361
362impl<I, D, BT> Listener<I, D, BT>
363where
364 I: DualStackIpExt,
365 D: WeakDeviceIdentifier,
366 BT: TcpBindingsTypes,
367{
368 fn base_state(&self) -> netstack3_base::TcpSocketState {
369 netstack3_base::TcpSocketState::Listen
370 }
371}
372
373#[cfg(test)]
374mod tests {
375 use alloc::string::ToString;
376 use alloc::vec;
377 use alloc::vec::Vec;
378 use assert_matches::assert_matches;
379 use core::num::NonZeroUsize;
380 use core::time::Duration;
381
382 use ip_test_macro::ip_test;
383 use net_types::ZonedAddr;
384 use net_types::ip::{Ip, Subnet};
385 use netstack3_base::testutil::{
386 FakeDeviceId, FakeInstant, FakeNetworkSpec as _, set_logger_for_test,
387 };
388 use netstack3_base::{
389 AddressMatcher, AddressMatcherEither, AddressMatcherType, BoundAddressMatcherEither,
390 BoundInterfaceMatcher, BoundPortMatcher, InterfaceMatcher, IpSocketMatcher, Mark,
391 MarkDomain, MarkMatcher, PortMatcher, SocketCookieMatcher, SocketTransportProtocolMatcher,
392 StrongDeviceIdentifier, SubnetMatcher, TcpSocketMatcher, TcpStateMatcher, UdpSocketMatcher,
393 };
394 use test_case::test_case;
395 use test_util::assert_gt;
396
397 use super::*;
398 use crate::AcceptError;
399 use crate::internal::base::ConnectionError;
400 use crate::internal::socket::TcpContext;
401 use crate::internal::socket::tests::{
402 FakeTcpNetworkSpec, TcpApiExt, TcpBindingsCtx, TcpCoreCtx, TcpCtx, TcpTestIpExt,
403 };
404 use crate::internal::state::info::CongestionControlState;
405
406 const LOCAL_PORT_1: NonZeroU16 = NonZeroU16::new(1234).unwrap();
407 const LOCAL_PORT_2: NonZeroU16 = NonZeroU16::new(5678).unwrap();
408 const LOCAL_PORT_3: NonZeroU16 = NonZeroU16::new(4321).unwrap();
409
410 const REMOTE_PORT_1: NonZeroU16 = NonZeroU16::new(100).unwrap();
411 const REMOTE_PORT_2: NonZeroU16 = NonZeroU16::new(200).unwrap();
412
413 const MARK: u32 = 0x10;
414 const MARK_MASK: u32 = !0;
415
416 #[ip_test(I)]
417 fn diagnostics_match_ip_version<I: TcpTestIpExt>()
418 where
419 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
420 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
421 {
422 set_logger_for_test();
423
424 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
425 I::TEST_ADDRS.local_ip,
426 I::TEST_ADDRS.remote_ip,
427 ));
428 let mut api = ctx.tcp_api::<I>();
429 let s = api.create(Default::default());
430 api.bind(&s, None, Some(LOCAL_PORT_1)).expect("bind should succeed");
431 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
432
433 let mut results = Vec::new();
434 api.bound_sockets_diagnostics(&IpSocketMatcher::Family(I::VERSION), &mut results, false);
435 assert_eq!(
436 results,
437 vec![TcpSocketDiagnostics {
438 state_machine: netstack3_base::TcpSocketState::Listen,
439 tuple: TcpSocketDiagnosticTuple::Bound { src_addr: None, src_port: LOCAL_PORT_1 },
440 cookie: s.socket_cookie(),
441 marks: Marks::default(),
442 tcp_info: None,
443 }]
444 );
445
446 results.clear();
447 api.bound_sockets_diagnostics(
448 &IpSocketMatcher::Family(
449 <<I as netstack3_base::socket::DualStackIpExt>::OtherVersion as Ip>::VERSION,
450 ),
451 &mut results,
452 false,
453 );
454 assert_eq!(results, Vec::new());
455 }
456
457 #[ip_test(I)]
458 fn diagnostics_match_src_addr<I: TcpTestIpExt>()
459 where
460 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
461 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
462 {
463 set_logger_for_test();
464
465 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
466 I::TEST_ADDRS.local_ip,
467 I::TEST_ADDRS.remote_ip,
468 ));
469 let mut api = ctx.tcp_api::<I>();
470 let s = api.create(Default::default());
471 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
472 .expect("bind should succeed");
473 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
474
475 let mut results = Vec::new();
476 let matcher = I::map_ip_in(
477 I::TEST_ADDRS.local_ip.get(),
478 |addr| {
479 BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
480 matcher: AddressMatcherType::Subnet(SubnetMatcher(
481 Subnet::new(addr, 32).unwrap(),
482 )),
483 invert: false,
484 }))
485 },
486 |addr| {
487 BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
488 matcher: AddressMatcherType::Subnet(SubnetMatcher(
489 Subnet::new(addr, 128).unwrap(),
490 )),
491 invert: false,
492 }))
493 },
494 );
495 api.bound_sockets_diagnostics(&IpSocketMatcher::SrcAddr(matcher), &mut results, false);
496 assert_eq!(
497 results,
498 vec![TcpSocketDiagnostics {
499 state_machine: netstack3_base::TcpSocketState::Listen,
500 tuple: TcpSocketDiagnosticTuple::Bound {
501 src_addr: Some(I::TEST_ADDRS.local_ip.get()),
502 src_port: LOCAL_PORT_1,
503 },
504 cookie: s.socket_cookie(),
505 marks: Marks::default(),
506 tcp_info: None,
507 }]
508 );
509
510 results.clear();
511 let matcher = I::map_ip_in(
512 I::TEST_ADDRS.remote_ip.get(),
513 |addr| {
514 BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
515 matcher: AddressMatcherType::Subnet(SubnetMatcher(
516 Subnet::new(addr, 32).unwrap(),
517 )),
518 invert: false,
519 }))
520 },
521 |addr| {
522 BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
523 matcher: AddressMatcherType::Subnet(SubnetMatcher(
524 Subnet::new(addr, 128).unwrap(),
525 )),
526 invert: false,
527 }))
528 },
529 );
530 api.bound_sockets_diagnostics(&IpSocketMatcher::SrcAddr(matcher), &mut results, false);
531 assert_eq!(results, Vec::new());
532 }
533
534 #[ip_test(I)]
535 fn diagnostics_match_dst_addr<I: TcpTestIpExt>()
536 where
537 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
538 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
539 {
540 set_logger_for_test();
541
542 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
543 I::TEST_ADDRS.local_ip,
544 I::TEST_ADDRS.remote_ip,
545 ));
546 let mut api = ctx.tcp_api::<I>();
547 let s = api.create(Default::default());
548 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
549 .expect("bind should succeed");
550 api.connect(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), LOCAL_PORT_2)
551 .expect("connect should succeed");
552
553 let mut results = Vec::new();
554 let matcher = I::map_ip_in(
555 I::TEST_ADDRS.remote_ip.get(),
556 |addr| {
557 BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
558 matcher: AddressMatcherType::Subnet(SubnetMatcher(
559 Subnet::new(addr, 32).unwrap(),
560 )),
561 invert: false,
562 }))
563 },
564 |addr| {
565 BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
566 matcher: AddressMatcherType::Subnet(SubnetMatcher(
567 Subnet::new(addr, 128).unwrap(),
568 )),
569 invert: false,
570 }))
571 },
572 );
573 api.bound_sockets_diagnostics(&IpSocketMatcher::DstAddr(matcher), &mut results, false);
574 assert_eq!(
575 results,
576 vec![TcpSocketDiagnostics {
577 state_machine: netstack3_base::TcpSocketState::SynSent,
578 tuple: TcpSocketDiagnosticTuple::Connected {
579 src_addr: I::TEST_ADDRS.local_ip.get(),
580 src_port: LOCAL_PORT_1,
581 dst_addr: I::TEST_ADDRS.remote_ip.get(),
582 dst_port: LOCAL_PORT_2,
583 },
584 cookie: s.socket_cookie(),
585 marks: Marks::default(),
586 tcp_info: None,
587 }]
588 );
589
590 results.clear();
591 let matcher = I::map_ip_in(
592 I::TEST_ADDRS.local_ip.get(),
593 |addr| {
594 BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
595 matcher: AddressMatcherType::Subnet(SubnetMatcher(
596 Subnet::new(addr, 32).unwrap(),
597 )),
598 invert: false,
599 }))
600 },
601 |addr| {
602 BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
603 matcher: AddressMatcherType::Subnet(SubnetMatcher(
604 Subnet::new(addr, 128).unwrap(),
605 )),
606 invert: false,
607 }))
608 },
609 );
610 api.bound_sockets_diagnostics(&IpSocketMatcher::DstAddr(matcher), &mut results, false);
611 assert_eq!(results, Vec::new());
612 }
613
614 #[ip_test(I)]
615 fn diagnostics_match_proto<I: TcpTestIpExt>()
616 where
617 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
618 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
619 {
620 set_logger_for_test();
621
622 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
623 I::TEST_ADDRS.local_ip,
624 I::TEST_ADDRS.remote_ip,
625 ));
626 let mut api = ctx.tcp_api::<I>();
627 let s = api.create(Default::default());
628 api.bind(&s, None, Some(LOCAL_PORT_1)).expect("bind should succeed");
629 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
630
631 let mut results = Vec::new();
632 api.bound_sockets_diagnostics(
633 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::Empty)),
634 &mut results,
635 false,
636 );
637 assert_eq!(
638 results,
639 vec![TcpSocketDiagnostics {
640 state_machine: netstack3_base::TcpSocketState::Listen,
641 tuple: TcpSocketDiagnosticTuple::Bound { src_addr: None, src_port: LOCAL_PORT_1 },
642 cookie: s.socket_cookie(),
643 marks: Marks::default(),
644 tcp_info: None,
645 }]
646 );
647
648 results.clear();
649 api.bound_sockets_diagnostics(
650 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Udp(UdpSocketMatcher::Empty)),
651 &mut results,
652 false,
653 );
654 assert_eq!(results, Vec::new());
655 }
656
657 #[ip_test(I)]
658 fn diagnostics_match_device<I: TcpTestIpExt>()
659 where
660 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
661 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
662 {
663 set_logger_for_test();
664
665 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
666 I::TEST_ADDRS.local_ip,
667 I::TEST_ADDRS.remote_ip,
668 ));
669 let mut api = ctx.tcp_api::<I>();
670 let s = api.create(Default::default());
671 api.set_device(&s, Some(FakeDeviceId)).expect("set device should succeed");
672 api.bind(&s, None, Some(LOCAL_PORT_1)).expect("bind should succeed");
673 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
674
675 let mut results = Vec::new();
676 api.bound_sockets_diagnostics(
677 &IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Bound(InterfaceMatcher::Name(
678 FakeDeviceId::FAKE_NAME.to_string(),
679 ))),
680 &mut results,
681 false,
682 );
683 assert_eq!(
684 results,
685 vec![TcpSocketDiagnostics {
686 state_machine: netstack3_base::TcpSocketState::Listen,
687 tuple: TcpSocketDiagnosticTuple::Bound { src_addr: None, src_port: LOCAL_PORT_1 },
688 cookie: s.socket_cookie(),
689 marks: Marks::default(),
690 tcp_info: None,
691 }]
692 );
693
694 results.clear();
695 api.bound_sockets_diagnostics(
696 &IpSocketMatcher::BoundInterface(BoundInterfaceMatcher::Unbound),
697 &mut results,
698 false,
699 );
700 assert_eq!(results, Vec::new());
701 }
702
703 #[ip_test(I)]
704 fn diagnostics_match_cookie<I: TcpTestIpExt>()
705 where
706 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
707 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
708 {
709 set_logger_for_test();
710
711 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
712 I::TEST_ADDRS.local_ip,
713 I::TEST_ADDRS.remote_ip,
714 ));
715 let mut api = ctx.tcp_api::<I>();
716
717 let socket_1 = api.create(Default::default());
718 api.bind(&socket_1, None, Some(LOCAL_PORT_1)).expect("bind should succeed");
719 api.listen(&socket_1, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
720 let socket_2 = api.create(Default::default());
721 api.bind(&socket_2, None, Some(LOCAL_PORT_2)).expect("bind should succeed");
722 api.listen(&socket_2, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
723
724 let mut results = Vec::new();
725 api.bound_sockets_diagnostics(
726 &IpSocketMatcher::Cookie(SocketCookieMatcher {
727 cookie: socket_1.socket_cookie().export_value(),
728 invert: false,
729 }),
730 &mut results,
731 false,
732 );
733 assert_eq!(
734 results,
735 vec![TcpSocketDiagnostics {
736 state_machine: netstack3_base::TcpSocketState::Listen,
737 tuple: TcpSocketDiagnosticTuple::Bound { src_addr: None, src_port: LOCAL_PORT_1 },
738 cookie: socket_1.socket_cookie(),
739 marks: Marks::default(),
740 tcp_info: None,
741 }]
742 );
743
744 results.clear();
745 api.bound_sockets_diagnostics(
746 &IpSocketMatcher::Cookie(SocketCookieMatcher {
747 cookie: socket_2.socket_cookie().export_value(),
748 invert: false,
749 }),
750 &mut results,
751 false,
752 );
753 assert_eq!(
754 results,
755 vec![TcpSocketDiagnostics {
756 state_machine: netstack3_base::TcpSocketState::Listen,
757 tuple: TcpSocketDiagnosticTuple::Bound { src_addr: None, src_port: LOCAL_PORT_2 },
758 cookie: socket_2.socket_cookie(),
759 marks: Marks::default(),
760 tcp_info: None,
761 }]
762 );
763 }
764
765 #[ip_test(I, test = false)]
766 #[test_case::test_case(MarkDomain::Mark1; "mark_1")]
767 #[test_case::test_case(MarkDomain::Mark2; "mark_2")]
768 fn diagnostics_match_mark<I: TcpTestIpExt>(domain: MarkDomain)
769 where
770 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
771 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
772 {
773 set_logger_for_test();
774
775 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
776 I::TEST_ADDRS.local_ip,
777 I::TEST_ADDRS.remote_ip,
778 ));
779 let mut api = ctx.tcp_api::<I>();
780
781 let s = api.create(Default::default());
782 api.bind(&s, None, Some(LOCAL_PORT_1)).expect("bind should succeed");
783 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
784 api.set_mark(&s, domain, Mark(Some(MARK)));
785
786 let mut results = Vec::new();
787 let matcher = |query_mark| {
788 IpSocketMatcher::Mark(netstack3_base::MarkInDomainMatcher {
789 domain,
790 matcher: MarkMatcher::Marked {
791 mask: MARK_MASK,
792 start: query_mark,
793 end: query_mark,
794 invert: false,
795 },
796 })
797 };
798 api.bound_sockets_diagnostics(&matcher(MARK), &mut results, false);
799 assert_eq!(
800 results,
801 vec![TcpSocketDiagnostics {
802 state_machine: netstack3_base::TcpSocketState::Listen,
803 tuple: TcpSocketDiagnosticTuple::Bound { src_addr: None, src_port: LOCAL_PORT_1 },
804 cookie: s.socket_cookie(),
805 marks: netstack3_base::MarkStorage::new([(domain, MARK)]),
806 tcp_info: None,
807 }]
808 );
809
810 results.clear();
811 api.bound_sockets_diagnostics(&matcher(MARK + 1), &mut results, false);
812 assert_eq!(results, Vec::new());
813 }
814
815 #[ip_test(I)]
816 fn diagnostics_match_multiple<I: TcpTestIpExt>()
817 where
818 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
819 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
820 {
821 set_logger_for_test();
822
823 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
824 I::TEST_ADDRS.local_ip,
825 I::TEST_ADDRS.remote_ip,
826 ));
827 let mut api = ctx.tcp_api::<I>();
828
829 let socket_1 = api.create(Default::default());
830 api.bind(&socket_1, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
831 .expect("bind should succeed");
832 api.connect(&socket_1, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
833 .expect("connect socket 1");
834 let socket_2 = api.create(Default::default());
835 api.bind(&socket_2, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_2))
836 .expect("bind should succeed");
837 api.connect(&socket_2, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
838 .expect("connect socket 2");
839 let socket_3 = api.create(Default::default());
840 api.bind(&socket_3, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_3))
841 .expect("bind should succeed");
842 api.connect(&socket_3, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_2)
843 .expect("connect socket 3");
844
845 let mut results = Vec::new();
846
847 api.bound_sockets_diagnostics(
848 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
849 TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(PortMatcher {
850 range: REMOTE_PORT_1.get()..=REMOTE_PORT_1.get(),
851 invert: false,
852 })),
853 )),
854 &mut results,
855 false,
856 );
857
858 results.sort_by(|a, b| a.cookie.cmp(&b.cookie));
859 let mut expected = vec![
860 TcpSocketDiagnostics {
861 state_machine: netstack3_base::TcpSocketState::SynSent,
862 tuple: TcpSocketDiagnosticTuple::Connected {
863 src_addr: I::TEST_ADDRS.local_ip.get(),
864 src_port: LOCAL_PORT_1,
865 dst_addr: I::TEST_ADDRS.remote_ip.get(),
866 dst_port: REMOTE_PORT_1,
867 },
868 cookie: socket_1.socket_cookie(),
869 marks: Marks::default(),
870 tcp_info: None,
871 },
872 TcpSocketDiagnostics {
873 state_machine: netstack3_base::TcpSocketState::SynSent,
874 tuple: TcpSocketDiagnosticTuple::Connected {
875 src_addr: I::TEST_ADDRS.local_ip.get(),
876 src_port: LOCAL_PORT_2,
877 dst_addr: I::TEST_ADDRS.remote_ip.get(),
878 dst_port: REMOTE_PORT_1,
879 },
880 cookie: socket_2.socket_cookie(),
881 marks: Marks::default(),
882 tcp_info: None,
883 },
884 ];
885 expected.sort_by(|a, b| a.cookie.cmp(&b.cookie));
886 assert_eq!(results, expected);
887
888 results.clear();
889 api.bound_sockets_diagnostics(
890 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
891 TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(PortMatcher {
892 range: REMOTE_PORT_2.get()..=REMOTE_PORT_2.get(),
893 invert: false,
894 })),
895 )),
896 &mut results,
897 false,
898 );
899 assert_eq!(
900 results,
901 vec![TcpSocketDiagnostics {
902 state_machine: netstack3_base::TcpSocketState::SynSent,
903 tuple: TcpSocketDiagnosticTuple::Connected {
904 src_addr: I::TEST_ADDRS.local_ip.get(),
905 src_port: LOCAL_PORT_3,
906 dst_addr: I::TEST_ADDRS.remote_ip.get(),
907 dst_port: REMOTE_PORT_2,
908 },
909 cookie: socket_3.socket_cookie(),
910 marks: Marks::default(),
911 tcp_info: None,
912 }]
913 );
914 }
915
916 #[ip_test(I)]
917 fn diagnostics_match_src_port<I: TcpTestIpExt>()
918 where
919 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
920 I,
921 TcpBindingsCtx<FakeDeviceId>,
922 SingleStackConverter = I::SingleStackConverter,
923 DualStackConverter = I::DualStackConverter,
924 >,
925 {
926 set_logger_for_test();
927
928 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
929 I::TEST_ADDRS.local_ip,
930 I::TEST_ADDRS.remote_ip,
931 ));
932 let mut api = ctx.tcp_api::<I>();
933 let s = api.create(Default::default());
934 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
935 .expect("bind should succeed");
936 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
937
938 let mut results = Vec::new();
939 api.bound_sockets_diagnostics(
940 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
941 TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(PortMatcher {
942 range: LOCAL_PORT_1.get()..=LOCAL_PORT_1.get(),
943 invert: false,
944 })),
945 )),
946 &mut results,
947 false,
948 );
949 assert_eq!(
950 results,
951 vec![TcpSocketDiagnostics {
952 state_machine: netstack3_base::TcpSocketState::Listen,
953 tuple: TcpSocketDiagnosticTuple::Bound {
954 src_addr: Some(I::TEST_ADDRS.local_ip.get()),
955 src_port: LOCAL_PORT_1,
956 },
957 cookie: s.socket_cookie(),
958 marks: Marks::default(),
959 tcp_info: None,
960 }]
961 );
962
963 results.clear();
964 api.bound_sockets_diagnostics(
965 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
966 TcpSocketMatcher::SrcPort(BoundPortMatcher::Bound(PortMatcher {
967 range: (LOCAL_PORT_1.get() + 1)..=(LOCAL_PORT_1.get() + 1),
968 invert: false,
969 })),
970 )),
971 &mut results,
972 false,
973 );
974 assert_eq!(results, Vec::new());
975 }
976
977 #[ip_test(I)]
978 fn diagnostics_match_dst_port<I: TcpTestIpExt>()
979 where
980 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
981 I,
982 TcpBindingsCtx<FakeDeviceId>,
983 SingleStackConverter = I::SingleStackConverter,
984 DualStackConverter = I::DualStackConverter,
985 >,
986 {
987 set_logger_for_test();
988
989 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
990 I::TEST_ADDRS.local_ip,
991 I::TEST_ADDRS.remote_ip,
992 ));
993 let mut api = ctx.tcp_api::<I>();
994 let s = api.create(Default::default());
995 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
996 .expect("bind should succeed");
997 api.connect(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), LOCAL_PORT_2)
998 .expect("connect should succeed");
999
1000 let mut results = Vec::new();
1001 api.bound_sockets_diagnostics(
1002 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
1003 TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(PortMatcher {
1004 range: LOCAL_PORT_2.get()..=LOCAL_PORT_2.get(),
1005 invert: false,
1006 })),
1007 )),
1008 &mut results,
1009 false,
1010 );
1011 assert_eq!(
1012 results,
1013 vec![TcpSocketDiagnostics {
1014 state_machine: netstack3_base::TcpSocketState::SynSent,
1015 tuple: TcpSocketDiagnosticTuple::Connected {
1016 src_addr: I::TEST_ADDRS.local_ip.get(),
1017 src_port: LOCAL_PORT_1,
1018 dst_addr: I::TEST_ADDRS.remote_ip.get(),
1019 dst_port: LOCAL_PORT_2,
1020 },
1021 cookie: s.socket_cookie(),
1022 marks: Marks::default(),
1023 tcp_info: None,
1024 }]
1025 );
1026
1027 results.clear();
1028 api.bound_sockets_diagnostics(
1029 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
1030 TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(PortMatcher {
1031 range: (LOCAL_PORT_2.get() + 1)..=(LOCAL_PORT_2.get() + 1),
1032 invert: false,
1033 })),
1034 )),
1035 &mut results,
1036 false,
1037 );
1038 assert_eq!(results, Vec::new());
1039 }
1040
1041 #[ip_test(I)]
1042 fn diagnostics_match_state<I: TcpTestIpExt>()
1043 where
1044 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
1045 I,
1046 TcpBindingsCtx<FakeDeviceId>,
1047 SingleStackConverter = I::SingleStackConverter,
1048 DualStackConverter = I::DualStackConverter,
1049 >,
1050 {
1051 set_logger_for_test();
1052
1053 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1054 I::TEST_ADDRS.local_ip,
1055 I::TEST_ADDRS.remote_ip,
1056 ));
1057 let mut api = ctx.tcp_api::<I>();
1058
1059 let listen_socket = api.create(Default::default());
1061 api.bind(
1062 &listen_socket,
1063 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)),
1064 Some(LOCAL_PORT_1),
1065 )
1066 .expect("bind");
1067 api.listen(&listen_socket, NonZeroUsize::new(1).unwrap()).expect("listen");
1068
1069 let syn_sent_socket = api.create(Default::default());
1071 api.bind(
1072 &syn_sent_socket,
1073 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)),
1074 Some(LOCAL_PORT_2),
1075 )
1076 .expect("bind");
1077 api.connect(
1080 &syn_sent_socket,
1081 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
1082 LOCAL_PORT_3,
1083 )
1084 .expect("connect");
1085
1086 let mut results = Vec::new();
1087
1088 api.bound_sockets_diagnostics(
1089 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::State(
1090 TcpStateMatcher::LISTEN,
1091 ))),
1092 &mut results,
1093 false,
1094 );
1095 assert_eq!(
1096 results,
1097 vec![TcpSocketDiagnostics {
1098 state_machine: netstack3_base::TcpSocketState::Listen,
1099 tuple: TcpSocketDiagnosticTuple::Bound {
1100 src_addr: Some(I::TEST_ADDRS.local_ip.get()),
1101 src_port: LOCAL_PORT_1,
1102 },
1103 cookie: listen_socket.socket_cookie(),
1104 marks: Marks::default(),
1105 tcp_info: None,
1106 }]
1107 );
1108
1109 results.clear();
1110 api.bound_sockets_diagnostics(
1111 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::State(
1112 TcpStateMatcher::SYN_SENT,
1113 ))),
1114 &mut results,
1115 false,
1116 );
1117 assert_eq!(
1118 results,
1119 vec![TcpSocketDiagnostics {
1120 state_machine: netstack3_base::TcpSocketState::SynSent,
1121 tuple: TcpSocketDiagnosticTuple::Connected {
1122 src_addr: I::TEST_ADDRS.local_ip.get(),
1123 src_port: LOCAL_PORT_2,
1124 dst_addr: I::TEST_ADDRS.remote_ip.get(),
1125 dst_port: LOCAL_PORT_3,
1126 },
1127 cookie: syn_sent_socket.socket_cookie(),
1128 marks: Marks::default(),
1129 tcp_info: None,
1130 }]
1131 );
1132
1133 results.clear();
1134 api.bound_sockets_diagnostics(
1135 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(TcpSocketMatcher::State(
1136 TcpStateMatcher::ESTABLISHED,
1137 ))),
1138 &mut results,
1139 false,
1140 );
1141 assert_eq!(results, Vec::new());
1142 }
1143
1144 #[ip_test(I)]
1145 fn diagnostics_match_src_addr_unbound<I: TcpTestIpExt>()
1146 where
1147 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
1148 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
1149 {
1150 set_logger_for_test();
1151
1152 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1153 I::TEST_ADDRS.local_ip,
1154 I::TEST_ADDRS.remote_ip,
1155 ));
1156 let mut api = ctx.tcp_api::<I>();
1157
1158 let s1 = api.create(Default::default());
1160 api.bind(&s1, None, Some(LOCAL_PORT_1)).expect("bind should succeed");
1161 api.listen(&s1, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
1162
1163 let s2 = api.create(Default::default());
1165 api.bind(&s2, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_2))
1166 .expect("bind should succeed");
1167 api.listen(&s2, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
1168
1169 let mut results = Vec::new();
1170 let matcher = match I::VERSION {
1171 net_types::ip::IpVersion::V4 => BoundAddressMatcherEither::Unbound,
1172 net_types::ip::IpVersion::V6 => BoundAddressMatcherEither::Unbound,
1173 };
1174 api.bound_sockets_diagnostics(&IpSocketMatcher::SrcAddr(matcher), &mut results, false);
1175 assert_eq!(
1176 results,
1177 vec![TcpSocketDiagnostics {
1178 state_machine: netstack3_base::TcpSocketState::Listen,
1179 tuple: TcpSocketDiagnosticTuple::Bound { src_addr: None, src_port: LOCAL_PORT_1 },
1180 cookie: s1.socket_cookie(),
1181 marks: Marks::default(),
1182 tcp_info: None,
1183 }]
1184 );
1185
1186 results.clear();
1187 let matcher = I::map_ip_in(
1188 I::TEST_ADDRS.local_ip.get(),
1189 |addr| {
1190 BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
1191 matcher: AddressMatcherType::Subnet(SubnetMatcher(
1192 Subnet::new(addr, 32).unwrap(),
1193 )),
1194 invert: false,
1195 }))
1196 },
1197 |addr| {
1198 BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
1199 matcher: AddressMatcherType::Subnet(SubnetMatcher(
1200 Subnet::new(addr, 128).unwrap(),
1201 )),
1202 invert: false,
1203 }))
1204 },
1205 );
1206 api.bound_sockets_diagnostics(&IpSocketMatcher::SrcAddr(matcher), &mut results, false);
1207 assert_eq!(
1208 results,
1209 vec![TcpSocketDiagnostics {
1210 state_machine: netstack3_base::TcpSocketState::Listen,
1211 tuple: TcpSocketDiagnosticTuple::Bound {
1212 src_addr: Some(I::TEST_ADDRS.local_ip.get()),
1213 src_port: LOCAL_PORT_2,
1214 },
1215 cookie: s2.socket_cookie(),
1216 marks: Marks::default(),
1217 tcp_info: None,
1218 }]
1219 );
1220 }
1221
1222 #[ip_test(I)]
1223 fn diagnostics_match_dst_addr_unbound<I: TcpTestIpExt>()
1224 where
1225 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
1226 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
1227 {
1228 set_logger_for_test();
1229
1230 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1231 I::TEST_ADDRS.local_ip,
1232 I::TEST_ADDRS.remote_ip,
1233 ));
1234 let mut api = ctx.tcp_api::<I>();
1235
1236 let s1 = api.create(Default::default());
1238 api.bind(&s1, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
1239 .expect("bind should succeed");
1240 api.listen(&s1, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
1241
1242 let s2 = api.create(Default::default());
1244 api.bind(&s2, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_2))
1245 .expect("bind should succeed");
1246 api.connect(&s2, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
1247 .expect("connect should succeed");
1248
1249 let mut results = Vec::new();
1250 let matcher = match I::VERSION {
1251 net_types::ip::IpVersion::V4 => BoundAddressMatcherEither::Unbound,
1252 net_types::ip::IpVersion::V6 => BoundAddressMatcherEither::Unbound,
1253 };
1254 api.bound_sockets_diagnostics(&IpSocketMatcher::DstAddr(matcher), &mut results, false);
1255 assert_eq!(
1256 results,
1257 vec![TcpSocketDiagnostics {
1258 state_machine: netstack3_base::TcpSocketState::Listen,
1259 tuple: TcpSocketDiagnosticTuple::Bound {
1260 src_addr: Some(I::TEST_ADDRS.local_ip.get()),
1261 src_port: LOCAL_PORT_1
1262 },
1263 cookie: s1.socket_cookie(),
1264 marks: Marks::default(),
1265 tcp_info: None,
1266 }]
1267 );
1268
1269 results.clear();
1270 let matcher = I::map_ip_in(
1271 I::TEST_ADDRS.remote_ip.get(),
1272 |addr| {
1273 BoundAddressMatcherEither::Bound(AddressMatcherEither::V4(AddressMatcher {
1274 matcher: AddressMatcherType::Subnet(SubnetMatcher(
1275 Subnet::new(addr, 32).unwrap(),
1276 )),
1277 invert: false,
1278 }))
1279 },
1280 |addr| {
1281 BoundAddressMatcherEither::Bound(AddressMatcherEither::V6(AddressMatcher {
1282 matcher: AddressMatcherType::Subnet(SubnetMatcher(
1283 Subnet::new(addr, 128).unwrap(),
1284 )),
1285 invert: false,
1286 }))
1287 },
1288 );
1289 api.bound_sockets_diagnostics(&IpSocketMatcher::DstAddr(matcher), &mut results, false);
1290 assert_eq!(
1291 results,
1292 vec![TcpSocketDiagnostics {
1293 state_machine: netstack3_base::TcpSocketState::SynSent,
1294 tuple: TcpSocketDiagnosticTuple::Connected {
1295 src_addr: I::TEST_ADDRS.local_ip.get(),
1296 src_port: LOCAL_PORT_2,
1297 dst_addr: I::TEST_ADDRS.remote_ip.get(),
1298 dst_port: REMOTE_PORT_1,
1299 },
1300 cookie: s2.socket_cookie(),
1301 marks: Marks::default(),
1302 tcp_info: None,
1303 }]
1304 );
1305 }
1306
1307 #[ip_test(I)]
1308 fn diagnostics_match_src_port_unbound<I: TcpTestIpExt>()
1309 where
1310 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
1311 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
1312 {
1313 set_logger_for_test();
1314
1315 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1316 I::TEST_ADDRS.local_ip,
1317 I::TEST_ADDRS.remote_ip,
1318 ));
1319 let mut api = ctx.tcp_api::<I>();
1320
1321 let s1 = api.create(Default::default());
1322 api.bind(&s1, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
1323 .expect("bind should succeed");
1324 api.listen(&s1, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
1325
1326 let mut results = Vec::new();
1327 api.bound_sockets_diagnostics(
1328 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
1329 TcpSocketMatcher::SrcPort(BoundPortMatcher::Unbound),
1330 )),
1331 &mut results,
1332 false,
1333 );
1334 assert_eq!(results, Vec::new());
1336 }
1337
1338 #[ip_test(I)]
1339 fn diagnostics_match_dst_port_unbound<I: TcpTestIpExt>()
1340 where
1341 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>:
1342 TcpContext<I, TcpBindingsCtx<FakeDeviceId>>,
1343 {
1344 set_logger_for_test();
1345
1346 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1347 I::TEST_ADDRS.local_ip,
1348 I::TEST_ADDRS.remote_ip,
1349 ));
1350 let mut api = ctx.tcp_api::<I>();
1351
1352 let s1 = api.create(Default::default());
1354 api.bind(&s1, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
1355 .expect("bind should succeed");
1356 api.listen(&s1, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
1357
1358 let s2 = api.create(Default::default());
1360 api.bind(&s2, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_2))
1361 .expect("bind should succeed");
1362 api.connect(&s2, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
1363 .expect("connect should succeed");
1364
1365 let mut results = Vec::new();
1366 api.bound_sockets_diagnostics(
1367 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
1368 TcpSocketMatcher::DstPort(BoundPortMatcher::Unbound),
1369 )),
1370 &mut results,
1371 false,
1372 );
1373 assert_eq!(
1374 results,
1375 vec![TcpSocketDiagnostics {
1376 state_machine: netstack3_base::TcpSocketState::Listen,
1377 tuple: TcpSocketDiagnosticTuple::Bound {
1378 src_addr: Some(I::TEST_ADDRS.local_ip.get()),
1379 src_port: LOCAL_PORT_1
1380 },
1381 cookie: s1.socket_cookie(),
1382 marks: Marks::default(),
1383 tcp_info: None,
1384 }]
1385 );
1386
1387 results.clear();
1388 api.bound_sockets_diagnostics(
1389 &IpSocketMatcher::Proto(SocketTransportProtocolMatcher::Tcp(
1390 TcpSocketMatcher::DstPort(BoundPortMatcher::Bound(PortMatcher {
1391 range: REMOTE_PORT_1.get()..=REMOTE_PORT_1.get(),
1392 invert: false,
1393 })),
1394 )),
1395 &mut results,
1396 false,
1397 );
1398 assert_eq!(
1399 results,
1400 vec![TcpSocketDiagnostics {
1401 state_machine: netstack3_base::TcpSocketState::SynSent,
1402 tuple: TcpSocketDiagnosticTuple::Connected {
1403 src_addr: I::TEST_ADDRS.local_ip.get(),
1404 src_port: LOCAL_PORT_2,
1405 dst_addr: I::TEST_ADDRS.remote_ip.get(),
1406 dst_port: REMOTE_PORT_1,
1407 },
1408 cookie: s2.socket_cookie(),
1409 marks: Marks::default(),
1410 tcp_info: None,
1411 }]
1412 );
1413 }
1414
1415 const LOCAL: &'static str = "local";
1416 const REMOTE: &'static str = "remote";
1417
1418 #[ip_test(I)]
1419 fn disconnect_connected<I: TcpTestIpExt>()
1420 where
1421 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
1422 I,
1423 TcpBindingsCtx<FakeDeviceId>,
1424 SingleStackConverter = I::SingleStackConverter,
1425 DualStackConverter = I::DualStackConverter,
1426 >,
1427 {
1428 set_logger_for_test();
1429
1430 let mut net = FakeTcpNetworkSpec::new_network(
1431 [
1432 (
1433 LOCAL,
1434 TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1435 I::TEST_ADDRS.local_ip,
1436 I::TEST_ADDRS.remote_ip,
1437 )),
1438 ),
1439 (
1440 REMOTE,
1441 TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1442 I::TEST_ADDRS.remote_ip,
1443 I::TEST_ADDRS.local_ip,
1444 )),
1445 ),
1446 ],
1447 |net, meta| {
1448 if net == LOCAL {
1449 alloc::vec![(REMOTE, meta, None)]
1450 } else {
1451 alloc::vec![(LOCAL, meta, None)]
1452 }
1453 },
1454 );
1455
1456 let client_socket = net.with_context(LOCAL, |ctx| {
1457 let mut api = ctx.tcp_api();
1458 let s: TcpSocketId<I, _, _> = api.create(Default::default());
1459 api.set_device(&s, Some(FakeDeviceId)).expect("set device should succeed");
1461 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
1462 .expect("bind should succeed");
1463 api.connect(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
1464 .expect("can connect");
1465 s
1466 });
1467 let server_listener = net.with_context(REMOTE, |ctx| {
1468 let mut api = ctx.tcp_api::<I>();
1469 let s = api.create(Default::default());
1470 api.bind(&s, None, Some(REMOTE_PORT_1)).expect("failed to bind the server socket");
1471 api.listen(&s, NonZeroUsize::MIN).expect("can listen");
1472 s
1473 });
1474
1475 net.run_until_idle();
1476
1477 let server_socket = net.with_context(REMOTE, |ctx| {
1478 let mut api = ctx.tcp_api();
1479 let (server_connection, _addr, _buffers) =
1480 api.accept(&server_listener).expect("connection is waiting");
1481 server_connection
1482 });
1483
1484 net.with_context(LOCAL, |ctx| {
1485 let mut api = ctx.tcp_api();
1486 let count = api.disconnect_bound(&IpSocketMatcher::Cookie(SocketCookieMatcher {
1487 cookie: client_socket.socket_cookie().export_value(),
1488 invert: false,
1489 }));
1490 assert_eq!(count, 1);
1491
1492 ctx.core_ctx.with_socket(&client_socket, |s| {
1493 let conn = assert_matches!(
1494 &s.socket_state,
1495 TcpSocketStateInner::Connected {conn, ..} => conn
1496 );
1497
1498 let info = I::get_conn_info(conn);
1499 assert_eq!(info.local_addr.ip.addr().get(), I::TEST_ADDRS.local_ip.get());
1500 assert_eq!(info.remote_addr.ip.addr().get(), I::TEST_ADDRS.remote_ip.get());
1501 assert_eq!(info.local_addr.port, LOCAL_PORT_1);
1502 assert_eq!(info.remote_addr.port, REMOTE_PORT_1);
1503 assert_eq!(info.device, Some(FakeDeviceId.downgrade()));
1504 });
1505 });
1506
1507 net.run_until_idle();
1509
1510 net.with_context(REMOTE, |ctx| {
1511 let mut api = ctx.tcp_api();
1512 assert_matches!(
1513 api.get_socket_error(&server_socket),
1514 Some(ConnectionError::ConnectionReset)
1515 );
1516 });
1517
1518 net.with_context(LOCAL, |ctx| {
1524 let mut api = ctx.tcp_api::<I>();
1525 assert_matches!(
1526 api.connect(
1527 &client_socket,
1528 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
1529 REMOTE_PORT_1
1530 ),
1531 Ok(())
1532 );
1533 });
1534 net.run_until_idle();
1535 net.with_context(REMOTE, |ctx| {
1536 let mut api = ctx.tcp_api();
1537 assert_matches!(api.accept(&server_listener), Err(AcceptError::WouldBlock));
1538 });
1539
1540 net.with_context(LOCAL, |ctx| {
1543 let mut api = ctx.tcp_api();
1544 let s: TcpSocketId<I, _, _> = api.create(Default::default());
1545 api.set_device(&s, Some(FakeDeviceId)).expect("set device should succeed");
1546 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
1547 .expect("bind should succeed");
1548 api.connect(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
1549 .expect("can connect");
1550
1551 api.close(s);
1554 api.close(client_socket);
1555 });
1556 }
1557
1558 #[ip_test(I)]
1559 fn disconnect_listener<I: TcpTestIpExt>()
1560 where
1561 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
1562 I,
1563 TcpBindingsCtx<FakeDeviceId>,
1564 SingleStackConverter = I::SingleStackConverter,
1565 DualStackConverter = I::DualStackConverter,
1566 >,
1567 {
1568 set_logger_for_test();
1569
1570 let mut net = FakeTcpNetworkSpec::new_network(
1571 [
1572 (
1573 LOCAL,
1574 TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1575 I::TEST_ADDRS.local_ip,
1576 I::TEST_ADDRS.remote_ip,
1577 )),
1578 ),
1579 (
1580 REMOTE,
1581 TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1582 I::TEST_ADDRS.remote_ip,
1583 I::TEST_ADDRS.local_ip,
1584 )),
1585 ),
1586 ],
1587 |net, meta| {
1588 if net == LOCAL {
1589 alloc::vec![(REMOTE, meta, None)]
1590 } else {
1591 alloc::vec![(LOCAL, meta, None)]
1592 }
1593 },
1594 );
1595
1596 let client_accepted_socket = net.with_context(LOCAL, |ctx| {
1597 let mut api = ctx.tcp_api();
1598 let s: TcpSocketId<I, _, _> = api.create(Default::default());
1599 api.connect(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
1600 .expect("can connect");
1601 s
1602 });
1603 let client_unaccepted_socket = net.with_context(LOCAL, |ctx| {
1604 let mut api = ctx.tcp_api();
1605 let s: TcpSocketId<I, _, _> = api.create(Default::default());
1606 api.connect(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), REMOTE_PORT_1)
1607 .expect("can connect");
1608 s
1609 });
1610 let server_listener = net.with_context(REMOTE, |ctx| {
1611 let mut api = ctx.tcp_api::<I>();
1612 let s = api.create(Default::default());
1613 api.set_device(&s, Some(FakeDeviceId)).expect("set device should succeed");
1615 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), Some(REMOTE_PORT_1))
1616 .expect("bind should succeed");
1617 api.listen(&s, NonZeroUsize::new(2).unwrap()).expect("listen should succeed");
1618 s
1619 });
1620
1621 net.run_until_idle();
1623
1624 net.with_context(REMOTE, |ctx| {
1625 let mut api = ctx.tcp_api();
1626 let _: (TcpSocketId<_, _, _>, _, _) =
1627 api.accept(&server_listener).expect("connection is waiting");
1628
1629 let count = api.disconnect_bound(&IpSocketMatcher::Cookie(SocketCookieMatcher {
1630 cookie: server_listener.socket_cookie().export_value(),
1631 invert: false,
1632 }));
1633 assert_eq!(count, 1);
1634
1635 ctx.core_ctx.with_socket(&server_listener, |s| {
1636 let addr = assert_matches!(
1637 &s.socket_state,
1638 TcpSocketStateInner::Bound(BoundState { addr, .. }) => addr
1639 );
1640 let info = I::get_bound_info(addr);
1641 assert_eq!(
1642 info.addr.expect("address is set").addr().get(),
1643 I::TEST_ADDRS.remote_ip.get(),
1644 );
1645 assert_eq!(info.port, REMOTE_PORT_1);
1646 assert_eq!(info.device, Some(FakeDeviceId.downgrade()));
1647 });
1648
1649 let mut api = ctx.tcp_api::<I>();
1650 api.listen(&server_listener, NonZeroUsize::new(1).unwrap())
1651 .expect("listen should succeed");
1652 });
1653
1654 net.run_until_idle();
1656
1657 net.with_context(LOCAL, |ctx| {
1661 let mut api = ctx.tcp_api();
1662 assert_matches!(api.get_socket_error(&client_accepted_socket), None);
1663 assert_matches!(
1664 api.get_socket_error(&client_unaccepted_socket),
1665 Some(ConnectionError::ConnectionReset)
1666 );
1667 })
1668 }
1669
1670 #[ip_test(I)]
1671 fn disconnect_bound<I: TcpTestIpExt>()
1672 where
1673 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
1674 I,
1675 TcpBindingsCtx<FakeDeviceId>,
1676 SingleStackConverter = I::SingleStackConverter,
1677 DualStackConverter = I::DualStackConverter,
1678 >,
1679 {
1680 set_logger_for_test();
1681
1682 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1683 I::TEST_ADDRS.local_ip,
1684 I::TEST_ADDRS.remote_ip,
1685 ));
1686 let mut api = ctx.tcp_api::<I>();
1687 let s = api.create(Default::default());
1688 api.set_device(&s, Some(FakeDeviceId)).expect("set device should succeed");
1690 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
1691 .expect("bind should succeed");
1692
1693 let mut api = ctx.tcp_api::<I>();
1694 let count = api.disconnect_bound(&IpSocketMatcher::Cookie(SocketCookieMatcher {
1695 cookie: s.socket_cookie().export_value(),
1696 invert: false,
1697 }));
1698 assert_eq!(count, 1);
1699
1700 ctx.core_ctx.with_socket(&s, |s| {
1701 let addr = assert_matches!(
1702 &s.socket_state,
1703 TcpSocketStateInner::Bound(BoundState { addr, .. }) => addr
1704 );
1705 let info = I::get_bound_info(addr);
1706 assert_eq!(
1707 info.addr.expect("address is set").addr().get(),
1708 I::TEST_ADDRS.local_ip.get(),
1709 );
1710 assert_eq!(info.port, LOCAL_PORT_1);
1711 assert_eq!(info.device, Some(FakeDeviceId.downgrade()));
1712 });
1713 }
1714
1715 #[ip_test(I)]
1716 fn tcp_info_unbound<I: TcpTestIpExt>()
1717 where
1718 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
1719 I,
1720 TcpBindingsCtx<FakeDeviceId>,
1721 SingleStackConverter = I::SingleStackConverter,
1722 DualStackConverter = I::DualStackConverter,
1723 >,
1724 {
1725 set_logger_for_test();
1726 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1727 I::TEST_ADDRS.local_ip,
1728 I::TEST_ADDRS.remote_ip,
1729 ));
1730 let mut api = ctx.tcp_api::<I>();
1731 let s = api.create(Default::default());
1732 let info = api.get_tcp_info(&s);
1733 assert_eq!(
1734 info,
1735 TcpSocketInfo {
1736 state: netstack3_base::TcpSocketState::Close,
1737 ca_state: CongestionControlState::Open,
1738 rto: None,
1739 rtt: None,
1740 rtt_var: None,
1741 snd_ssthresh: 0,
1742 snd_cwnd: 0,
1743 retransmits: 0,
1744 last_ack_recv: None,
1745 segs_out: 0,
1746 segs_in: 0,
1747 last_data_sent: None,
1748 snd_mss: None,
1749 rcv_mss: None,
1750 }
1751 );
1752 }
1753
1754 #[ip_test(I)]
1755 #[test_case(true, netstack3_base::TcpSocketState::Listen; "listen")]
1756 #[test_case(false, netstack3_base::TcpSocketState::Close; "bound")]
1757 fn tcp_info_bound<I: TcpTestIpExt>(
1758 should_listen: bool,
1759 expected_state: netstack3_base::TcpSocketState,
1760 ) where
1761 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
1762 I,
1763 TcpBindingsCtx<FakeDeviceId>,
1764 SingleStackConverter = I::SingleStackConverter,
1765 DualStackConverter = I::DualStackConverter,
1766 >,
1767 {
1768 set_logger_for_test();
1769 let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1770 I::TEST_ADDRS.local_ip,
1771 I::TEST_ADDRS.remote_ip,
1772 ));
1773 let mut api = ctx.tcp_api::<I>();
1774 let s = api.create(Default::default());
1775 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT_1))
1776 .expect("bind should succeed");
1777 if should_listen {
1778 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
1779 }
1780
1781 let info = api.get_tcp_info(&s);
1782 assert_eq!(
1783 info,
1784 TcpSocketInfo {
1785 state: expected_state,
1786 ca_state: CongestionControlState::Open,
1787 rto: None,
1788 rtt: None,
1789 rtt_var: None,
1790 snd_ssthresh: 0,
1791 snd_cwnd: 0,
1792 retransmits: 0,
1793 last_ack_recv: None,
1794 segs_out: 0,
1795 segs_in: 0,
1796 last_data_sent: None,
1797 snd_mss: None,
1798 rcv_mss: None,
1799 }
1800 );
1801 }
1802
1803 #[ip_test(I)]
1804 fn tcp_info_connected<I: TcpTestIpExt>()
1805 where
1806 TcpCoreCtx<FakeDeviceId, TcpBindingsCtx<FakeDeviceId>>: TcpContext<
1807 I,
1808 TcpBindingsCtx<FakeDeviceId>,
1809 SingleStackConverter = I::SingleStackConverter,
1810 DualStackConverter = I::DualStackConverter,
1811 >,
1812 {
1813 set_logger_for_test();
1814
1815 let mut net = FakeTcpNetworkSpec::new_network(
1816 [
1817 (
1818 LOCAL,
1819 TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1820 I::TEST_ADDRS.local_ip,
1821 I::TEST_ADDRS.remote_ip,
1822 )),
1823 ),
1824 (
1825 REMOTE,
1826 TcpCtx::with_core_ctx(TcpCoreCtx::new::<I>(
1827 I::TEST_ADDRS.remote_ip,
1828 I::TEST_ADDRS.local_ip,
1829 )),
1830 ),
1831 ],
1832 |net, meta| {
1833 if net == LOCAL {
1834 vec![(REMOTE, meta, Some(Duration::from_millis(100)))]
1835 } else {
1836 vec![(LOCAL, meta, Some(Duration::from_millis(100)))]
1837 }
1838 },
1839 );
1840
1841 let client_socket = net.with_context(LOCAL, |ctx| {
1842 let mut api = ctx.tcp_api();
1843 let s: TcpSocketId<I, _, _> = api.create(Default::default());
1844 s
1845 });
1846
1847 let server_socket = net.with_context(REMOTE, |ctx| {
1848 let mut api = ctx.tcp_api::<I>();
1849 let s = api.create(Default::default());
1850 api.set_device(&s, Some(FakeDeviceId)).expect("set device should succeed");
1851 api.bind(&s, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), Some(REMOTE_PORT_1))
1852 .expect("bind should succeed");
1853 api.listen(&s, NonZeroUsize::new(1).unwrap()).expect("listen should succeed");
1854 s
1855 });
1856
1857 net.with_context(LOCAL, |ctx| {
1858 let mut api = ctx.tcp_api();
1859 api.connect(
1860 &client_socket,
1861 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
1862 REMOTE_PORT_1,
1863 )
1864 .expect("should connect");
1865 });
1866
1867 net.run_until_idle();
1868
1869 net.with_context(LOCAL, |ctx| {
1870 let mut api = ctx.tcp_api();
1871 let data = [1u8; 10];
1872 api.with_send_buffer(&client_socket, |buf| {
1873 buf.enqueue_data(&data[..]);
1874 })
1875 .expect("send buffer should be available");
1876 api.do_send(&client_socket);
1877 });
1878
1879 net.run_until_idle();
1880
1881 let accepted_socket = net.with_context(REMOTE, |ctx| {
1882 let mut api = ctx.tcp_api();
1883 let (accepted, _, _) = api.accept(&server_socket).expect("accept should succeed");
1884
1885 let data = [2u8; 10];
1888 api.with_send_buffer(&accepted, |buf| {
1889 buf.enqueue_data(&data[..]);
1890 })
1891 .expect("send buffer should be available");
1892 api.do_send(&accepted);
1893
1894 accepted
1895 });
1896
1897 net.run_until_idle();
1898
1899 net.with_context(LOCAL, |ctx| {
1900 let mut api = ctx.tcp_api();
1901 let info = api.get_tcp_info(&client_socket);
1902
1903 assert_matches!(
1904 info,
1905 TcpSocketInfo {
1906 state: netstack3_base::TcpSocketState::Established,
1907 ca_state: CongestionControlState::Open,
1908 retransmits: 0,
1909 snd_ssthresh: u32::MAX,
1910 segs_out,
1911 segs_in,
1912 snd_cwnd,
1913 rto: Some(rto),
1914 rtt: Some(rtt),
1915 rtt_var: Some(rtt_var),
1916 last_ack_recv: Some(last_ack_recv),
1917 last_data_sent: Some(last_data_sent),
1918 snd_mss: _,
1919 rcv_mss: _,
1920 } => {
1921 assert_eq!(segs_out, 4);
1922 assert_eq!(segs_in, 3);
1923 assert_gt!(snd_cwnd, 0);
1924 assert_eq!(rto, Duration::from_millis(500));
1925 assert_eq!(rtt, Duration::from_millis(200));
1926 assert_eq!(rtt_var, Duration::from_millis(75));
1927 assert_eq!(last_ack_recv, FakeInstant::from(Duration::from_millis(1800)));
1928 assert_eq!(last_data_sent, FakeInstant::from(Duration::from_millis(1100)));
1929 }
1930 );
1931 });
1932
1933 net.with_context(REMOTE, |ctx| {
1934 let mut api = ctx.tcp_api();
1935 let info = api.get_tcp_info(&accepted_socket);
1936
1937 assert_matches!(
1938 info,
1939 TcpSocketInfo {
1940 state: netstack3_base::TcpSocketState::Established,
1941 ca_state: CongestionControlState::Open,
1942 retransmits: 0,
1943 snd_ssthresh: u32::MAX,
1944 segs_out,
1945 segs_in,
1946 snd_cwnd,
1947 rto: Some(rto),
1948 rtt: Some(rtt),
1949 rtt_var: Some(rtt_var),
1950 last_ack_recv: Some(last_ack_recv),
1951 last_data_sent: Some(last_data_sent),
1952 snd_mss: _,
1953 rcv_mss: _,
1954 } => {
1955 assert_eq!(segs_out, 2);
1956 assert_eq!(segs_in, 3);
1957 assert_gt!(snd_cwnd, 0);
1958 assert_eq!(rto, Duration::from_millis(500));
1959 assert_eq!(rtt, Duration::from_millis(200));
1960 assert_eq!(rtt_var, Duration::from_millis(75));
1961 assert_eq!(last_ack_recv, FakeInstant::from(Duration::from_millis(1200)));
1962 assert_eq!(last_data_sent, FakeInstant::from(Duration::from_millis(1700)));
1963 }
1964 );
1965 });
1966 }
1967}