1use std::io::{self, IoSlice, IoSliceMut, Read, Write};
4use std::net::{Shutdown, SocketAddr, ToSocketAddrs};
5use std::sync::{Arc, Mutex, PoisonError};
6use std::time::{Duration, Instant};
7
8use crate::accept::{Accepted, Acceptor};
9use crate::driver::DriverKind;
10use crate::error::{CloseReason, ConfigReason, LimitKind, NetError, RefusalCause, TimeoutKind};
11use crate::gate::{AdmitStage, Gate, GateCell, KillHandle, guarded};
12use crate::id::{ConnectionId, ListenerId, WorkerId};
13use crate::info::{ConnectionInfo, Endpoint, Origin, Transport};
14use crate::limits::{Effective, Limits};
15use crate::link::{ClockRef, Got, Link, WakeSource};
16use crate::opts::{ListenOptions, SocketOptions, TcpOptions};
17use crate::proxy::ProxyMode;
18use crate::session::Phase;
19use crate::sys::{self, AddrFailure, AsSock, Interest, KillSlot, Ready};
20
21#[non_exhaustive]
29#[derive(Clone, Debug)]
30pub struct ListenerInfo {
31 pub id: ListenerId,
33 pub name: Option<String>,
35 pub local: Endpoint,
37 pub backlog: Option<u32>,
39 pub transport: Transport,
41 pub proxy: ProxyMode,
43 pub tls: bool,
45}
46
47pub(crate) fn effective_backlog(requested: u32) -> Option<u32> {
49 if cfg!(target_os = "linux") {
50 let cap = std::fs::read_to_string("/proc/sys/net/core/somaxconn")
51 .ok()
52 .and_then(|s| s.trim().parse::<u32>().ok());
53 Some(cap.map_or(requested, |c| requested.min(c)))
54 } else if cfg!(windows) {
55 Some(requested)
56 } else {
57 None
58 }
59}
60
61const OPTIONS_INHERITED: bool = cfg!(any(target_os = "linux", windows));
63
64pub(crate) fn bind_error(addr: SocketAddr, e: io::Error) -> NetError {
65 match sys::classify_addr_error(&e) {
66 AddrFailure::InUse => NetError::AddrInUse { addr },
67 AddrFailure::NotAvailable => NetError::AddrNotAvailable { addr },
68 AddrFailure::Permission => NetError::PermissionDenied { what: "bind" },
69 _ if e.kind() == io::ErrorKind::Unsupported => NetError::Unsupported {
70 feature: "a listen option this OS does not have",
71 platform: std::env::consts::OS,
72 },
73 _ => NetError::Bind { addr, source: e },
74 }
75}
76
77fn connect_error(addr: SocketAddr, after: Duration, e: io::Error) -> NetError {
78 match sys::classify_addr_error(&e) {
79 AddrFailure::Refused => NetError::ConnectionRefused { addr },
80 AddrFailure::HostUnreachable => NetError::HostUnreachable { addr },
81 AddrFailure::NetworkUnreachable => NetError::NetworkUnreachable { addr },
82 AddrFailure::TimedOut => NetError::ConnectTimeout { addr, after },
83 AddrFailure::NotAvailable => NetError::AddrNotAvailable { addr },
84 AddrFailure::Permission => NetError::PermissionDenied { what: "connect" },
85 _ => NetError::Os {
86 op: "connect",
87 source: e,
88 },
89 }
90}
91
92fn resolve<A: ToSocketAddrs>(addr: A) -> Result<Vec<SocketAddr>, NetError> {
93 let addrs: Vec<SocketAddr> = addr
94 .to_socket_addrs()
95 .map_err(|e| NetError::Os {
96 op: "resolve",
97 source: e,
98 })?
99 .collect();
100 if addrs.is_empty() {
101 return Err(NetError::NoAddresses);
102 }
103 Ok(addrs)
104}
105
106#[derive(Debug)]
121pub struct TcpListener {
122 inner: std::net::TcpListener,
123 info: ListenerInfo,
124 tcp: TcpOptions,
125 acceptor: Mutex<Acceptor>,
126}
127
128impl TcpListener {
129 pub fn bind<A: ToSocketAddrs>(addr: A) -> Result<TcpListener, NetError> {
135 TcpListener::bind_with(addr, ListenOptions::new())
136 }
137
138 pub fn bind_with<A: ToSocketAddrs>(
144 addr: A,
145 options: ListenOptions,
146 ) -> Result<TcpListener, NetError> {
147 let mut last = NetError::NoAddresses;
148 for a in resolve(addr)? {
149 match sys::tcp_listener(a, &options.params()) {
150 Ok(l) => return TcpListener::finish(l, options, ListenerId(0), None),
151 Err(e) => last = bind_error(a, e),
152 }
153 }
154 Err(last)
155 }
156
157 pub(crate) fn finish(
158 inner: std::net::TcpListener,
159 options: ListenOptions,
160 id: ListenerId,
161 name: Option<String>,
162 ) -> Result<TcpListener, NetError> {
163 let local = inner
164 .local_addr()
165 .map_err(|e| NetError::from_os("getsockname", e))?;
166 if OPTIONS_INHERITED && !options.tcp.is_empty() {
167 options.tcp.apply(&inner, local.is_ipv6())?;
168 }
169 Ok(TcpListener {
170 info: ListenerInfo {
171 id,
172 name,
173 local: Endpoint::Ip(local),
174 backlog: effective_backlog(options.backlog),
175 transport: Transport::Tcp,
176 proxy: ProxyMode::Off,
177 tls: false,
178 },
179 inner,
180 tcp: options.tcp,
181 acceptor: Mutex::new(Acceptor::new()),
182 })
183 }
184
185 pub fn accept(&self) -> Result<(TcpConnection, ConnectionInfo), NetError> {
192 match self.accept_until(None)? {
193 Some(pair) => Ok(pair),
194 None => Err(NetError::TimedOut {
195 kind: TimeoutKind::Read,
196 }),
197 }
198 }
199
200 pub fn accept_timeout(
213 &self,
214 timeout: Duration,
215 ) -> Result<Option<(TcpConnection, ConnectionInfo)>, NetError> {
216 self.accept_until(Some(Instant::now() + timeout))
217 }
218
219 fn accept_until(
220 &self,
221 deadline: Option<Instant>,
222 ) -> Result<Option<(TcpConnection, ConnectionInfo)>, NetError> {
223 let mut paused_once = false;
224 loop {
225 let outcome = self
226 .acceptor
227 .lock()
228 .unwrap_or_else(PoisonError::into_inner)
229 .accept(&self.inner);
230 match outcome {
231 Accepted::Conn((stream, peer)) => {
232 let conn = TcpConnection::accepted(stream, peer, &self.tcp, self.info.id)?;
233 let info = conn.info().clone();
234 return Ok(Some((conn, info)));
235 }
236 Accepted::Skipped(_) => continue,
237 Accepted::Again => {
238 let timeout = match deadline {
239 None => None,
240 Some(d) => {
241 let left = d.saturating_duration_since(Instant::now());
242 if left.is_zero() {
243 return Ok(None);
244 }
245 Some(left)
246 }
247 };
248 match sys::wait(self.inner.sock(), Interest::Read, None, timeout) {
249 Ok(Ready::TimedOut) => return Ok(None),
250 Ok(_) => continue,
251 Err(e) => return Err(NetError::from_os("poll", e)),
252 }
253 }
254 Accepted::Pause(backoff) => {
255 if paused_once {
256 return Err(NetError::Limit {
257 which: LimitKind::Descriptors,
258 });
259 }
260 paused_once = true;
261 std::thread::sleep(backoff);
262 }
263 Accepted::Failed(e) => return Err(NetError::from_os("accept", e)),
264 }
265 }
266 }
267
268 pub(crate) fn std(&self) -> &std::net::TcpListener {
269 &self.inner
270 }
271
272 pub(crate) fn set_identity(&mut self, id: ListenerId, name: Option<String>) {
274 self.info.id = id;
275 self.info.name = name;
276 }
277
278 pub(crate) fn set_tls(&mut self, on: bool) {
280 self.info.tls = on;
281 }
282
283 pub(crate) fn set_proxy_mode(&mut self, mode: crate::proxy::ProxyMode) {
285 self.info.proxy = mode;
286 }
287
288 pub(crate) fn tcp_options(&self) -> &TcpOptions {
289 &self.tcp
290 }
291
292 #[must_use]
294 pub fn info(&self) -> &ListenerInfo {
295 &self.info
296 }
297
298 pub fn local_addr(&self) -> Result<SocketAddr, NetError> {
304 self.inner
305 .local_addr()
306 .map_err(|e| NetError::from_os("getsockname", e))
307 }
308
309 pub fn from_std(listener: std::net::TcpListener) -> Result<TcpListener, NetError> {
322 match sys::is_listening_stream(listener.sock()) {
323 Ok(true) => {}
324 Ok(false) => {
325 return Err(NetError::InvalidConfig {
326 field: "socket",
327 reason: ConfigReason::NotListening,
328 });
329 }
330 Err(e) => return Err(NetError::from_os("getsockopt", e)),
331 }
332 listener
333 .set_nonblocking(true)
334 .map_err(|e| NetError::from_os("ioctl", e))?;
335 TcpListener::finish(
336 listener,
337 ListenOptions::new().tcp_options(TcpOptions::new()),
338 ListenerId(0),
339 None,
340 )
341 .map(|mut l| {
342 l.info.backlog = None;
343 l
344 })
345 }
346
347 #[must_use]
349 pub fn into_std(self) -> std::net::TcpListener {
350 self.inner
351 }
352
353 pub fn try_clone(&self) -> Result<TcpListener, NetError> {
359 let inner = self
360 .inner
361 .try_clone()
362 .map_err(|e| NetError::from_os("dup", e))?;
363 Ok(TcpListener {
364 inner,
365 info: self.info.clone(),
366 tcp: self.tcp,
367 acceptor: Mutex::new(Acceptor::new()),
368 })
369 }
370}
371
372#[cfg(unix)]
373impl std::os::fd::AsFd for TcpListener {
374 fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
375 self.inner.as_fd()
376 }
377}
378
379#[cfg(unix)]
380impl From<TcpListener> for std::os::fd::OwnedFd {
381 fn from(l: TcpListener) -> std::os::fd::OwnedFd {
382 l.inner.into()
383 }
384}
385
386#[cfg(unix)]
387impl TryFrom<std::os::fd::OwnedFd> for TcpListener {
388 type Error = NetError;
389 fn try_from(fd: std::os::fd::OwnedFd) -> Result<TcpListener, NetError> {
390 TcpListener::from_std(std::net::TcpListener::from(fd))
391 }
392}
393
394#[cfg(windows)]
395impl std::os::windows::io::AsSocket for TcpListener {
396 fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {
397 self.inner.as_socket()
398 }
399}
400
401#[cfg(windows)]
402impl From<TcpListener> for std::os::windows::io::OwnedSocket {
403 fn from(l: TcpListener) -> std::os::windows::io::OwnedSocket {
404 l.inner.into()
405 }
406}
407
408#[cfg(windows)]
409impl TryFrom<std::os::windows::io::OwnedSocket> for TcpListener {
410 type Error = NetError;
411 fn try_from(s: std::os::windows::io::OwnedSocket) -> Result<TcpListener, NetError> {
412 TcpListener::from_std(std::net::TcpListener::from(s))
413 }
414}
415
416#[must_use]
427#[derive(Clone, Debug)]
428pub struct ConnectOptions {
429 timeout: Duration,
430 local_addr: Option<SocketAddr>,
431 tcp: TcpOptions,
432 limits: Limits,
433 happy_eyeballs: bool,
434 attempt_delay: Duration,
435}
436
437impl Default for ConnectOptions {
438 fn default() -> ConnectOptions {
439 ConnectOptions {
440 timeout: Duration::from_secs(10),
441 local_addr: None,
442 tcp: TcpOptions::new().nodelay(true),
443 limits: Limits::default(),
444 happy_eyeballs: false,
445 attempt_delay: Duration::from_millis(250),
446 }
447 }
448}
449
450impl ConnectOptions {
451 pub fn new() -> ConnectOptions {
453 ConnectOptions::default()
454 }
455
456 pub fn timeout(mut self, total: Duration) -> ConnectOptions {
458 self.timeout = total;
459 self
460 }
461
462 pub fn local_addr(mut self, addr: SocketAddr) -> ConnectOptions {
464 self.local_addr = Some(addr);
465 self
466 }
467
468 pub fn tcp_options(mut self, options: TcpOptions) -> ConnectOptions {
470 self.tcp = options;
471 self
472 }
473
474 pub fn limits(mut self, limits: Limits) -> ConnectOptions {
476 self.limits = limits;
477 self
478 }
479
480 pub fn happy_eyeballs(mut self, on: bool) -> ConnectOptions {
485 self.happy_eyeballs = on;
486 self
487 }
488
489 pub fn attempt_delay(mut self, d: Duration) -> ConnectOptions {
492 self.attempt_delay = d.clamp(Duration::from_millis(100), Duration::from_secs(2));
493 self
494 }
495}
496
497pub struct TcpConnection {
521 link: Option<Link>,
522}
523
524impl TcpConnection {
525 pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<TcpConnection, NetError> {
531 TcpConnection::connect_with(addr, ConnectOptions::new())
532 }
533
534 pub fn connect_with<A: ToSocketAddrs>(
540 addr: A,
541 options: ConnectOptions,
542 ) -> Result<TcpConnection, NetError> {
543 let addrs = resolve(addr)?;
544 TcpConnection::connect_addrs(&addrs, &options)
545 }
546
547 pub fn connect_host(
555 host: &str,
556 port: u16,
557 options: ConnectOptions,
558 ) -> Result<TcpConnection, NetError> {
559 let addrs = resolve((host, port))?;
560 TcpConnection::connect_addrs(&addrs, &options)
561 }
562
563 fn connect_addrs(
564 addrs: &[SocketAddr],
565 options: &ConnectOptions,
566 ) -> Result<TcpConnection, NetError> {
567 if options.happy_eyeballs && addrs.len() > 1 {
568 return connect_racing(addrs, options);
569 }
570 let start = Instant::now();
571 let deadline = start + options.timeout;
572 let mut last = NetError::NoAddresses;
573 for (i, addr) in addrs.iter().enumerate() {
574 let left = deadline.saturating_duration_since(Instant::now());
575 if left.is_zero() {
576 break;
577 }
578 let remaining = (addrs.len() - i) as u32;
579 let attempt = (left / remaining).max(Duration::from_secs(1)).min(left);
580 match connect_one(*addr, options, attempt) {
581 Ok(conn) => return Ok(conn),
582 Err(e) => last = e,
583 }
584 }
585 if matches!(last, NetError::NoAddresses) {
586 if let Some(addr) = addrs.first() {
587 last = NetError::ConnectTimeout {
588 addr: *addr,
589 after: options.timeout,
590 };
591 }
592 }
593 Err(last)
594 }
595
596 pub(crate) fn accepted(
597 stream: std::net::TcpStream,
598 peer: SocketAddr,
599 tcp: &TcpOptions,
600 listener: ListenerId,
601 ) -> Result<TcpConnection, NetError> {
602 let local = stream
603 .local_addr()
604 .map_err(|e| NetError::from_os("getsockname", e))?;
605 if !OPTIONS_INHERITED && !tcp.is_empty() {
606 tcp.apply(&stream, local.is_ipv6())?;
607 }
608 let info = ConnectionInfo::new_tcp(
609 crate::id::issue_single(),
610 Some(listener),
611 WorkerId(0),
612 Origin::Accepted,
613 local,
614 peer,
615 Instant::now(),
616 );
617 let limits = Arc::new(Limits::default().effective(DriverKind::Blocking));
618 Ok(TcpConnection::from_link(Link::new(
619 sys::Stream::Tcp(stream),
620 info,
621 limits,
622 ClockRef::Monotonic,
623 Arc::new(KillSlot::new()),
624 WakeSource::Thread,
625 Phase::Idle,
626 )))
627 }
628
629 pub(crate) fn from_link(link: Link) -> TcpConnection {
630 TcpConnection { link: Some(link) }
631 }
632
633 #[cfg(all(windows, feature = "local"))]
635 pub(crate) fn pipe_pid(&self, server: bool) -> Result<u32, NetError> {
636 match &self.link_ref().stream {
637 sys::Stream::Pipe(p) => if server {
638 p.server_pid()
639 } else {
640 p.client_pid()
641 }
642 .map_err(|e| NetError::from_os("GetNamedPipeClientProcessId", e)),
643 _ => Err(NetError::Unsupported {
644 feature: "client_pid on a socket",
645 platform: std::env::consts::OS,
646 }),
647 }
648 }
649
650 pub(crate) fn take_link(&mut self) -> Option<Link> {
651 self.link.take()
652 }
653
654 pub(crate) fn link(&mut self) -> Result<&mut Link, NetError> {
655 self.link.as_mut().ok_or(NetError::Closed)
656 }
657
658 pub(crate) fn link_ref(&self) -> &Link {
659 match &self.link {
660 Some(l) => l,
661 None => unreachable_link(),
663 }
664 }
665
666 pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize, NetError> {
673 let link = self.link()?;
674 loop {
675 match link.read(buf)? {
676 Got::Data(n) => return Ok(n),
677 Got::Eof => return Ok(0),
678 Got::Woken => continue,
679 }
680 }
681 }
682
683 pub fn recv_exact(&mut self, buf: &mut [u8]) -> Result<(), NetError> {
689 let mut filled = 0;
690 while filled < buf.len() {
691 match self.recv(&mut buf[filled..])? {
692 0 => return Err(NetError::Closed),
693 n => filled += n,
694 }
695 }
696 Ok(())
697 }
698
699 pub fn recv_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize, NetError> {
705 match bufs.iter_mut().find(|b| !b.is_empty()) {
706 Some(first) => self.recv(first),
707 None => Ok(0),
708 }
709 }
710
711 pub fn peek(&self, buf: &mut [u8]) -> Result<usize, NetError> {
717 let link = self.link_ref();
718 if buf.is_empty() {
719 return Ok(0);
720 }
721 if link.has_tls() {
722 return Err(NetError::Unsupported {
724 feature: "peek on a TLS connection",
725 platform: std::env::consts::OS,
726 });
727 }
728 let timeout = link.limits.read_timeout;
729 match link.stream.wait(Interest::Read, None, Some(timeout)) {
730 Ok(Ready::TimedOut) => {
731 return Err(NetError::TimedOut {
732 kind: TimeoutKind::Read,
733 });
734 }
735 Ok(_) => {}
736 Err(e) => return Err(NetError::from_os("poll", e)),
737 }
738 link.stream
739 .peek(buf)
740 .map_err(|e| NetError::from_os("recv", e))
741 }
742
743 pub fn send(&mut self, buf: &[u8]) -> Result<usize, NetError> {
749 self.link()?.write(buf)
750 }
751
752 pub fn send_all(&mut self, buf: &[u8]) -> Result<(), NetError> {
759 self.link()?.write_all(buf)
760 }
761
762 pub fn send_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize, NetError> {
768 self.link()?.write_vectored(bufs)
769 }
770
771 pub fn send_file(
781 &mut self,
782 file: &std::fs::File,
783 offset: u64,
784 len: u64,
785 ) -> Result<u64, NetError> {
786 self.link()?.send_file(file, offset, len)
787 }
788
789 pub fn send_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<(), NetError> {
795 self.link()?.write_all_vectored(bufs)
796 }
797
798 pub fn shutdown(&mut self, how: Shutdown) -> Result<(), NetError> {
804 self.link()?.shutdown(how)
805 }
806
807 pub fn close(mut self) -> Result<(), NetError> {
814 if let Some(link) = self.link.take() {
815 let reason = link.reason_or(CloseReason::SessionClosed);
816 link.finish(reason);
817 }
818 Ok(())
819 }
820
821 pub fn abort(mut self) {
823 if let Some(link) = self.link.take() {
824 let reason = link.reason_or(CloseReason::SessionError);
825 let reason = if reason.is_abortive() {
826 reason
827 } else {
828 CloseReason::SessionError
829 };
830 link.finish(reason);
831 }
832 }
833
834 #[must_use]
836 pub fn info(&self) -> &ConnectionInfo {
837 &self.link_ref().info
838 }
839
840 #[must_use]
842 pub fn id(&self) -> ConnectionId {
843 self.link_ref().info.id
844 }
845
846 #[must_use]
848 pub fn peer_addr(&self) -> SocketAddr {
849 self.link_ref()
850 .info
851 .peer
852 .socket_addr()
853 .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], 0)))
854 }
855
856 #[must_use]
858 pub fn local_addr(&self) -> SocketAddr {
859 self.link_ref()
860 .info
861 .local
862 .socket_addr()
863 .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], 0)))
864 }
865
866 #[must_use]
868 pub fn kill_handle(&self) -> KillHandle {
869 let link = self.link_ref();
870 KillHandle {
871 slot: link.slot.clone(),
872 generation: link.generation,
873 id: link.info.id,
874 }
875 }
876
877 pub fn set_limits(&mut self, limits: Limits) {
879 if let Ok(link) = self.link() {
880 let e: Effective = limits.effective(DriverKind::Blocking);
881 link.set_limits(e);
882 }
883 }
884
885 pub fn set_phase(&mut self, phase: Phase) {
887 if let Ok(link) = self.link() {
888 link.set_phase(phase);
889 }
890 }
891
892 pub fn set_exchange_deadline(&mut self, at: Option<Instant>) {
894 if let Ok(link) = self.link() {
895 link.set_exchange_deadline(at);
896 }
897 }
898
899 pub fn set_gate<G: Gate>(&mut self, gate: Arc<G>) -> Result<(), NetError> {
918 let link = self.link()?;
919 if link.gate.is_some() {
920 return Err(NetError::InvalidConfig {
921 field: "gate",
922 reason: ConfigReason::Inconsistent,
923 });
924 }
925 let code = match guarded(|| gate.admit(&link.info, AdmitStage::Dialed)) {
926 Some(Ok(admitted)) => {
927 link.info.lane = admitted.lane;
928 link.info.gate = admitted.tag;
929 link.gate = Some(Box::new(GateCell {
930 gate,
931 ticket: Some(admitted.ticket),
932 }));
933 return Ok(());
934 }
935 Some(Err(refusal)) => refusal.code(),
936 None => 0,
937 };
938 let cause = RefusalCause::Gate(code);
939 if let Some(link) = self.link.take() {
940 link.finish(CloseReason::Refused(cause));
941 }
942 Err(NetError::Refused { cause })
943 }
944
945 #[must_use]
947 pub fn options(&self) -> SocketOptions<'_> {
948 let link = self.link_ref();
949 SocketOptions {
950 sock: link.stream.sock(),
951 v6: link.info.local.socket_addr().is_some_and(|a| a.is_ipv6()),
952 }
953 }
954
955 pub fn take_error(&self) -> Result<Option<io::Error>, NetError> {
961 sys::take_error(self.link_ref().stream.sock())
962 .map_err(|e| NetError::from_os("getsockopt", e))
963 }
964}
965
966#[cold]
967fn unreachable_link() -> ! {
968 std::process::abort()
971}
972
973fn dial_socket(
975 addr: SocketAddr,
976 options: &ConnectOptions,
977) -> Result<std::net::TcpStream, NetError> {
978 let owned = sys::tcp_socket(addr.is_ipv6()).map_err(|e| NetError::from_os("socket", e))?;
979 let stream = std::net::TcpStream::from(owned);
980 stream
981 .set_nonblocking(true)
982 .map_err(|e| NetError::from_os("ioctl", e))?;
983 options.tcp.apply(&stream, addr.is_ipv6())?;
984 if let Some(local) = options.local_addr {
985 sys::bind_to(stream.sock(), local).map_err(|e| bind_error(local, e))?;
986 }
987 Ok(stream)
988}
989
990fn interleaved(addrs: &[SocketAddr]) -> Vec<SocketAddr> {
992 let (v6, v4): (Vec<_>, Vec<_>) = addrs.iter().copied().partition(SocketAddr::is_ipv6);
993 let (mut v6, mut v4) = (v6.into_iter(), v4.into_iter());
994 let mut out = Vec::with_capacity(addrs.len());
995 loop {
996 match (v6.next(), v4.next()) {
997 (None, None) => return out,
998 (a, b) => out.extend(a.into_iter().chain(b)),
999 }
1000 }
1001}
1002
1003const MAX_RACING: usize = 16;
1005const RACE_SPACING: Duration = Duration::from_millis(10);
1006
1007fn connect_racing(
1010 addrs: &[SocketAddr],
1011 options: &ConnectOptions,
1012) -> Result<TcpConnection, NetError> {
1013 let ordered = interleaved(addrs);
1014 let start = Instant::now();
1015 let deadline = start + options.timeout;
1016 let mut racing: Vec<(std::net::TcpStream, SocketAddr, Instant)> = Vec::new();
1017 let mut queue = ordered.iter().copied();
1018 let mut waiting = queue.next();
1019 let mut next_at = start;
1020 let mut last_start: Option<Instant> = None;
1021 let mut last = NetError::NoAddresses;
1022 loop {
1023 let now = Instant::now();
1024 if now >= deadline {
1025 break;
1026 }
1027 let spaced = last_start.map_or(now, |t| t + RACE_SPACING);
1028 if let Some(addr) = waiting.filter(|_| {
1029 racing.len() < MAX_RACING && now >= spaced && (now >= next_at || racing.is_empty())
1030 }) {
1031 waiting = queue.next();
1032 last_start = Some(now);
1033 next_at = now + options.attempt_delay;
1034 let stream = match dial_socket(addr, options) {
1035 Ok(s) => s,
1036 Err(e) => {
1037 last = e;
1038 next_at = now;
1039 continue;
1040 }
1041 };
1042 match sys::connect_start(stream.sock(), addr) {
1043 Ok(false) => return dialed(stream, addr, options),
1044 Ok(true) => racing.push((stream, addr, now)),
1045 Err(e) => {
1046 last = connect_error(addr, Duration::ZERO, e);
1047 next_at = now;
1048 }
1049 }
1050 continue;
1051 }
1052 if racing.is_empty() && waiting.is_none() {
1053 break;
1054 }
1055 let mut until = deadline;
1056 if waiting.is_some() {
1057 until = until.min(next_at.max(spaced).max(now + Duration::from_millis(1)));
1058 }
1059 let wait = until.saturating_duration_since(now);
1060 if racing.is_empty() {
1061 std::thread::sleep(wait);
1062 continue;
1063 }
1064 let socks: Vec<_> = racing.iter().map(|(s, ..)| s.sock()).collect();
1065 let ready = sys::wait_writable(&socks, wait).map_err(|e| NetError::from_os("poll", e))?;
1066 drop(socks);
1067 for i in (0..racing.len()).rev() {
1068 if ready & (1 << i) == 0 {
1069 continue;
1070 }
1071 let (stream, addr, began) = racing.swap_remove(i);
1072 match sys::take_error(stream.sock()) {
1073 Ok(None) => {
1074 for (loser, ..) in &racing {
1075 let _ = sys::set_linger(loser.sock(), Some(Duration::ZERO));
1076 }
1077 return dialed(stream, addr, options);
1078 }
1079 Ok(Some(e)) => {
1080 last = connect_error(addr, began.elapsed(), e);
1081 next_at = Instant::now();
1082 }
1083 Err(e) => last = NetError::from_os("getsockopt", e),
1084 }
1085 }
1086 }
1087 for (loser, ..) in &racing {
1088 let _ = sys::set_linger(loser.sock(), Some(Duration::ZERO));
1089 }
1090 if matches!(last, NetError::NoAddresses) {
1091 if let Some(addr) = ordered.first() {
1092 last = NetError::ConnectTimeout {
1093 addr: *addr,
1094 after: options.timeout,
1095 };
1096 }
1097 }
1098 Err(last)
1099}
1100
1101fn connect_one(
1102 addr: SocketAddr,
1103 options: &ConnectOptions,
1104 attempt: Duration,
1105) -> Result<TcpConnection, NetError> {
1106 let stream = dial_socket(addr, options)?;
1107 let started = Instant::now();
1108 match sys::connect_start(stream.sock(), addr) {
1109 Ok(false) => {}
1110 Ok(true) => {
1111 match sys::wait(stream.sock(), Interest::Write, None, Some(attempt)) {
1112 Ok(Ready::TimedOut) => {
1113 return Err(NetError::ConnectTimeout {
1114 addr,
1115 after: attempt,
1116 });
1117 }
1118 Ok(_) => {}
1119 Err(e) => return Err(NetError::from_os("poll", e)),
1120 }
1121 match sys::take_error(stream.sock()) {
1122 Ok(None) => {}
1123 Ok(Some(e)) => return Err(connect_error(addr, started.elapsed(), e)),
1124 Err(e) => return Err(NetError::from_os("getsockopt", e)),
1125 }
1126 }
1127 Err(e) => return Err(connect_error(addr, started.elapsed(), e)),
1128 }
1129 dialed(stream, addr, options)
1130}
1131
1132fn dialed(
1134 stream: std::net::TcpStream,
1135 addr: SocketAddr,
1136 options: &ConnectOptions,
1137) -> Result<TcpConnection, NetError> {
1138 sys::prepare_dialed(&stream).map_err(|e| NetError::from_os("ioctl", e))?;
1139 let local = stream
1140 .local_addr()
1141 .map_err(|e| NetError::from_os("getsockname", e))?;
1142 let info = ConnectionInfo::new_tcp(
1143 crate::id::issue_single(),
1144 None,
1145 WorkerId(0),
1146 Origin::Dialed,
1147 local,
1148 crate::addr::normalize_socket(addr),
1149 Instant::now(),
1150 );
1151 Ok(TcpConnection::from_link(Link::new(
1152 sys::Stream::Tcp(stream),
1153 info,
1154 Arc::new(options.limits.effective(DriverKind::Blocking)),
1155 ClockRef::Monotonic,
1156 Arc::new(KillSlot::new()),
1157 WakeSource::Thread,
1158 Phase::Receiving,
1159 )))
1160}
1161
1162impl Read for TcpConnection {
1163 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1164 self.recv(buf).map_err(io::Error::from)
1165 }
1166}
1167
1168impl Write for TcpConnection {
1169 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1170 self.send(buf).map_err(io::Error::from)
1171 }
1172
1173 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
1174 self.send_vectored(bufs).map_err(io::Error::from)
1175 }
1176
1177 fn flush(&mut self) -> io::Result<()> {
1178 Ok(())
1179 }
1180}
1181
1182impl Drop for TcpConnection {
1183 fn drop(&mut self) {
1185 if let Some(link) = self.link.take() {
1186 let reason = link.reason_or(CloseReason::SessionClosed);
1187 link.finish_quick(reason);
1188 }
1189 }
1190}
1191
1192impl std::fmt::Debug for TcpConnection {
1193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1194 match &self.link {
1195 Some(l) => f
1196 .debug_struct("TcpConnection")
1197 .field("info", &l.info)
1198 .finish(),
1199 None => f.write_str("TcpConnection(closed)"),
1200 }
1201 }
1202}
1203
1204#[cfg(unix)]
1205impl std::os::fd::AsFd for TcpConnection {
1206 fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
1207 std::os::fd::AsFd::as_fd(&self.link_ref().stream)
1208 }
1209}
1210
1211#[cfg(windows)]
1212impl std::os::windows::io::AsSocket for TcpConnection {
1213 fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {
1214 std::os::windows::io::AsSocket::as_socket(&self.link_ref().stream)
1215 }
1216}
1217
1218#[cfg(test)]
1219mod tests {
1220 use super::*;
1221
1222 #[test]
1223 fn test_listen_accept_echo_round_trip() {
1224 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1225 let addr = l.local_addr().unwrap();
1226 let t = std::thread::spawn(move || {
1227 let (mut c, info) = l.accept().unwrap();
1228 assert_eq!(info.origin, Origin::Accepted);
1229 let mut buf = [0u8; 4];
1230 c.recv_exact(&mut buf).unwrap();
1231 c.send_all(&buf).unwrap();
1232 c.close().unwrap();
1233 });
1234 let mut c = TcpConnection::connect(addr).unwrap();
1235 c.send_all(b"ping").unwrap();
1236 let mut buf = [0u8; 4];
1237 c.recv_exact(&mut buf).unwrap();
1238 assert_eq!(&buf, b"ping");
1239 assert_eq!(c.recv(&mut buf).unwrap(), 0);
1240 t.join().unwrap();
1241 }
1242
1243 #[test]
1244 fn test_connect_refused_maps_to_connection_refused() {
1245 let port = std::net::TcpListener::bind("127.0.0.1:0")
1247 .unwrap()
1248 .local_addr()
1249 .unwrap()
1250 .port();
1251 let err = TcpConnection::connect_with(
1252 ("127.0.0.1", port),
1253 ConnectOptions::new().timeout(Duration::from_secs(5)),
1254 )
1255 .unwrap_err();
1256 assert!(
1257 matches!(
1258 err,
1259 NetError::ConnectionRefused { .. } | NetError::ConnectTimeout { .. }
1260 ),
1261 "{err:?}"
1262 );
1263 }
1264
1265 #[test]
1266 fn test_bind_in_use_maps_to_addr_in_use() {
1267 let a = TcpListener::bind("127.0.0.1:0").unwrap();
1268 let err = TcpListener::bind(a.local_addr().unwrap()).unwrap_err();
1269 assert!(matches!(err, NetError::AddrInUse { .. }), "{err:?}");
1270 }
1271
1272 #[test]
1274 fn test_bind_errors_map_by_class() {
1275 #[cfg(unix)]
1276 use crate::sys::errno::{EACCES as ACCESS, EADDRNOTAVAIL as NOT_AVAILABLE};
1277 #[cfg(windows)]
1278 use crate::sys::errno::{WSAEACCES as ACCESS, WSAEADDRNOTAVAIL as NOT_AVAILABLE};
1279 let addr: SocketAddr = "[::1]:80".parse().unwrap();
1280 let e = bind_error(addr, io::Error::from_raw_os_error(NOT_AVAILABLE));
1281 assert!(matches!(e, NetError::AddrNotAvailable { .. }), "{e:?}");
1282 let e = bind_error(addr, io::Error::from_raw_os_error(ACCESS));
1283 assert!(matches!(e, NetError::PermissionDenied { .. }), "{e:?}");
1284 }
1285
1286 #[test]
1287 fn test_read_timeout_fires() {
1288 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1289 let addr = l.local_addr().unwrap();
1290 let _server = std::thread::spawn(move || {
1291 let (c, _) = l.accept().unwrap();
1292 std::thread::sleep(Duration::from_secs(2));
1293 drop(c);
1294 });
1295 let limits = Limits::builder()
1296 .read_timeout(Duration::from_millis(200))
1297 .min_rate(crate::limits::MinRate::off())
1298 .build()
1299 .unwrap();
1300 let mut c =
1301 TcpConnection::connect_with(addr, ConnectOptions::new().limits(limits)).unwrap();
1302 let mut buf = [0u8; 8];
1303 let start = Instant::now();
1304 let err = c.recv(&mut buf).unwrap_err();
1305 assert!(
1306 matches!(
1307 err,
1308 NetError::TimedOut {
1309 kind: TimeoutKind::Read
1310 }
1311 ),
1312 "{err:?}"
1313 );
1314 assert!(start.elapsed() < Duration::from_secs(2));
1315 }
1316
1317 #[test]
1318 fn test_kill_wakes_blocked_recv() {
1319 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1320 let addr = l.local_addr().unwrap();
1321 let _server = std::thread::spawn(move || {
1322 let (c, _) = l.accept().unwrap();
1323 std::thread::sleep(Duration::from_secs(3));
1324 drop(c);
1325 });
1326 let mut c = TcpConnection::connect(addr).unwrap();
1327 let kill = c.kill_handle();
1328 std::thread::spawn(move || {
1329 std::thread::sleep(Duration::from_millis(100));
1330 assert!(kill.kill(crate::error::KillReason(4)));
1331 });
1332 let mut buf = [0u8; 8];
1333 let start = Instant::now();
1334 let err = c.recv(&mut buf).unwrap_err();
1335 assert!(matches!(err, NetError::Killed { .. }), "{err:?}");
1336 assert!(start.elapsed() < Duration::from_secs(2));
1337 }
1338
1339 #[test]
1340 fn test_interleaved_starts_with_v6_and_takes_turns() {
1341 let a = |t: &str| t.parse::<SocketAddr>().unwrap();
1342 let (v4a, v4b, v4c) = (a("1.1.1.1:1"), a("2.2.2.2:1"), a("3.3.3.3:1"));
1343 let (v6a, v6b) = (a("[::1]:1"), a("[::2]:1"));
1344 assert_eq!(
1345 interleaved(&[v4a, v4b, v4c, v6a, v6b]),
1346 [v6a, v4a, v6b, v4b, v4c]
1347 );
1348 assert_eq!(interleaved(&[v4a, v4b]), [v4a, v4b]);
1349 assert!(interleaved(&[]).is_empty());
1350 }
1351
1352 #[test]
1353 fn test_attempt_delay_is_held_to_its_range() {
1354 let low = ConnectOptions::new().attempt_delay(Duration::from_millis(1));
1355 assert_eq!(low.attempt_delay, Duration::from_millis(100));
1356 let high = ConnectOptions::new().attempt_delay(Duration::from_secs(9));
1357 assert_eq!(high.attempt_delay, Duration::from_secs(2));
1358 }
1359
1360 #[test]
1361 fn test_racing_a_refused_address_moves_on_at_once() {
1362 let closed = {
1363 let l = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
1364 l.local_addr().unwrap()
1365 };
1366 let live = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
1367 let options = ConnectOptions::new()
1368 .happy_eyeballs(true)
1369 .attempt_delay(Duration::from_secs(2));
1370 let started = Instant::now();
1371 let c = TcpConnection::connect_addrs(&[closed, live.local_addr().unwrap()], &options);
1372 assert_eq!(c.unwrap().peer_addr(), live.local_addr().unwrap());
1373 if cfg!(unix) {
1375 assert!(
1376 started.elapsed() < Duration::from_secs(2),
1377 "no attempt delay"
1378 );
1379 }
1380 }
1381
1382 #[test]
1383 fn test_racing_every_address_refused_reports_the_last() {
1384 let closed: Vec<SocketAddr> = (0..2)
1385 .map(|_| {
1386 let l = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
1387 l.local_addr().unwrap()
1388 })
1389 .collect();
1390 let options = ConnectOptions::new()
1391 .timeout(Duration::from_secs(5))
1392 .happy_eyeballs(true);
1393 let e = TcpConnection::connect_addrs(&closed, &options).err();
1394 assert!(
1395 matches!(e, Some(NetError::ConnectionRefused { .. })),
1396 "{e:?}"
1397 );
1398 }
1399
1400 #[test]
1403 fn test_racing_a_silent_address_starts_the_next_after_the_delay() {
1404 let silent: SocketAddr = "192.0.2.1:9".parse().unwrap();
1405 let live = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
1406 let options = ConnectOptions::new()
1407 .timeout(Duration::from_secs(5))
1408 .happy_eyeballs(true)
1409 .attempt_delay(Duration::from_millis(100));
1410 let started = Instant::now();
1411 let c = TcpConnection::connect_addrs(&[silent, live.local_addr().unwrap()], &options);
1412 assert_eq!(c.unwrap().peer_addr(), live.local_addr().unwrap());
1413 assert!(started.elapsed() < Duration::from_secs(2));
1414 }
1415
1416 #[test]
1417 fn test_listen_options_that_an_os_lacks_are_refused() {
1418 let bind = |o: ListenOptions| TcpListener::bind_with("127.0.0.1:0", o);
1419 let defer = ListenOptions::new().defer_accept(Some(Duration::from_secs(1)));
1420 let cpu = ListenOptions::new().incoming_cpu(Some(0));
1421 if cfg!(target_os = "linux") {
1422 assert!(bind(defer).is_ok());
1423 assert!(bind(cpu).is_ok());
1424 } else {
1425 assert!(matches!(bind(defer), Err(NetError::Unsupported { .. })));
1426 assert!(matches!(bind(cpu), Err(NetError::Unsupported { .. })));
1427 }
1428 }
1429
1430 #[test]
1433 fn test_fast_open_listener_still_accepts() {
1434 let options = ListenOptions::new().fast_open(Some(16));
1435 if let Ok(l) = TcpListener::bind_with("127.0.0.1:0", options) {
1436 let addr = l.local_addr().unwrap();
1437 let _c = TcpConnection::connect(addr).unwrap();
1438 assert!(l.accept().is_ok());
1439 }
1440 }
1441
1442 #[test]
1443 fn test_user_timeout_where_the_os_has_it() {
1444 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1445 let options = ConnectOptions::new()
1446 .tcp_options(TcpOptions::new().user_timeout(Duration::from_secs(5)));
1447 let c = TcpConnection::connect_with(l.local_addr().unwrap(), options);
1448 if cfg!(any(target_os = "linux", windows)) {
1449 assert!(c.is_ok());
1450 } else {
1451 assert!(matches!(c, Err(NetError::Unsupported { .. })));
1452 }
1453 }
1454}