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, TimeoutKind};
11use crate::gate::KillHandle;
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
47fn 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: "SO_REUSEPORT",
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 tcp_options(&self) -> &TcpOptions {
273 &self.tcp
274 }
275
276 #[must_use]
278 pub fn info(&self) -> &ListenerInfo {
279 &self.info
280 }
281
282 pub fn local_addr(&self) -> Result<SocketAddr, NetError> {
288 self.inner
289 .local_addr()
290 .map_err(|e| NetError::from_os("getsockname", e))
291 }
292
293 pub fn from_std(listener: std::net::TcpListener) -> Result<TcpListener, NetError> {
306 match sys::is_listening_stream(listener.sock()) {
307 Ok(true) => {}
308 Ok(false) => {
309 return Err(NetError::InvalidConfig {
310 field: "socket",
311 reason: ConfigReason::NotListening,
312 });
313 }
314 Err(e) => return Err(NetError::from_os("getsockopt", e)),
315 }
316 listener
317 .set_nonblocking(true)
318 .map_err(|e| NetError::from_os("ioctl", e))?;
319 TcpListener::finish(
320 listener,
321 ListenOptions::new().tcp_options(TcpOptions::new()),
322 ListenerId(0),
323 None,
324 )
325 .map(|mut l| {
326 l.info.backlog = None;
327 l
328 })
329 }
330
331 #[must_use]
333 pub fn into_std(self) -> std::net::TcpListener {
334 self.inner
335 }
336
337 pub fn try_clone(&self) -> Result<TcpListener, NetError> {
343 let inner = self
344 .inner
345 .try_clone()
346 .map_err(|e| NetError::from_os("dup", e))?;
347 Ok(TcpListener {
348 inner,
349 info: self.info.clone(),
350 tcp: self.tcp,
351 acceptor: Mutex::new(Acceptor::new()),
352 })
353 }
354}
355
356#[cfg(unix)]
357impl std::os::fd::AsFd for TcpListener {
358 fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
359 self.inner.as_fd()
360 }
361}
362
363#[cfg(unix)]
364impl From<TcpListener> for std::os::fd::OwnedFd {
365 fn from(l: TcpListener) -> std::os::fd::OwnedFd {
366 l.inner.into()
367 }
368}
369
370#[cfg(unix)]
371impl TryFrom<std::os::fd::OwnedFd> for TcpListener {
372 type Error = NetError;
373 fn try_from(fd: std::os::fd::OwnedFd) -> Result<TcpListener, NetError> {
374 TcpListener::from_std(std::net::TcpListener::from(fd))
375 }
376}
377
378#[cfg(windows)]
379impl std::os::windows::io::AsSocket for TcpListener {
380 fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {
381 self.inner.as_socket()
382 }
383}
384
385#[cfg(windows)]
386impl From<TcpListener> for std::os::windows::io::OwnedSocket {
387 fn from(l: TcpListener) -> std::os::windows::io::OwnedSocket {
388 l.inner.into()
389 }
390}
391
392#[cfg(windows)]
393impl TryFrom<std::os::windows::io::OwnedSocket> for TcpListener {
394 type Error = NetError;
395 fn try_from(s: std::os::windows::io::OwnedSocket) -> Result<TcpListener, NetError> {
396 TcpListener::from_std(std::net::TcpListener::from(s))
397 }
398}
399
400#[must_use]
411#[derive(Clone, Debug)]
412pub struct ConnectOptions {
413 timeout: Duration,
414 local_addr: Option<SocketAddr>,
415 tcp: TcpOptions,
416 limits: Limits,
417}
418
419impl Default for ConnectOptions {
420 fn default() -> ConnectOptions {
421 ConnectOptions {
422 timeout: Duration::from_secs(10),
423 local_addr: None,
424 tcp: TcpOptions::new().nodelay(true),
425 limits: Limits::default(),
426 }
427 }
428}
429
430impl ConnectOptions {
431 pub fn new() -> ConnectOptions {
433 ConnectOptions::default()
434 }
435
436 pub fn timeout(mut self, total: Duration) -> ConnectOptions {
438 self.timeout = total;
439 self
440 }
441
442 pub fn local_addr(mut self, addr: SocketAddr) -> ConnectOptions {
444 self.local_addr = Some(addr);
445 self
446 }
447
448 pub fn tcp_options(mut self, options: TcpOptions) -> ConnectOptions {
450 self.tcp = options;
451 self
452 }
453
454 pub fn limits(mut self, limits: Limits) -> ConnectOptions {
456 self.limits = limits;
457 self
458 }
459}
460
461pub struct TcpConnection {
485 link: Option<Link>,
486}
487
488impl TcpConnection {
489 pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<TcpConnection, NetError> {
495 TcpConnection::connect_with(addr, ConnectOptions::new())
496 }
497
498 pub fn connect_with<A: ToSocketAddrs>(
504 addr: A,
505 options: ConnectOptions,
506 ) -> Result<TcpConnection, NetError> {
507 let addrs = resolve(addr)?;
508 TcpConnection::connect_addrs(&addrs, &options)
509 }
510
511 pub fn connect_host(
519 host: &str,
520 port: u16,
521 options: ConnectOptions,
522 ) -> Result<TcpConnection, NetError> {
523 let addrs = resolve((host, port))?;
524 TcpConnection::connect_addrs(&addrs, &options)
525 }
526
527 fn connect_addrs(
528 addrs: &[SocketAddr],
529 options: &ConnectOptions,
530 ) -> Result<TcpConnection, NetError> {
531 let start = Instant::now();
532 let deadline = start + options.timeout;
533 let mut last = NetError::NoAddresses;
534 for (i, addr) in addrs.iter().enumerate() {
535 let left = deadline.saturating_duration_since(Instant::now());
536 if left.is_zero() {
537 break;
538 }
539 let remaining = (addrs.len() - i) as u32;
540 let attempt = (left / remaining).max(Duration::from_secs(1)).min(left);
541 match connect_one(*addr, options, attempt) {
542 Ok(conn) => return Ok(conn),
543 Err(e) => last = e,
544 }
545 }
546 if matches!(last, NetError::NoAddresses) {
547 if let Some(addr) = addrs.first() {
548 last = NetError::ConnectTimeout {
549 addr: *addr,
550 after: options.timeout,
551 };
552 }
553 }
554 Err(last)
555 }
556
557 pub(crate) fn accepted(
558 stream: std::net::TcpStream,
559 peer: SocketAddr,
560 tcp: &TcpOptions,
561 listener: ListenerId,
562 ) -> Result<TcpConnection, NetError> {
563 let local = stream
564 .local_addr()
565 .map_err(|e| NetError::from_os("getsockname", e))?;
566 if !OPTIONS_INHERITED && !tcp.is_empty() {
567 tcp.apply(&stream, local.is_ipv6())?;
568 }
569 let info = ConnectionInfo::new_tcp(
570 crate::id::issue_single(),
571 Some(listener),
572 WorkerId(0),
573 Origin::Accepted,
574 local,
575 peer,
576 Instant::now(),
577 );
578 let limits = Limits::default().effective(DriverKind::Blocking);
579 Ok(TcpConnection::from_link(Link::new(
580 stream,
581 info,
582 limits,
583 ClockRef::Monotonic,
584 Arc::new(KillSlot::new()),
585 WakeSource::Thread,
586 Phase::Idle,
587 )))
588 }
589
590 pub(crate) fn from_link(link: Link) -> TcpConnection {
591 TcpConnection { link: Some(link) }
592 }
593
594 pub(crate) fn take_link(&mut self) -> Option<Link> {
595 self.link.take()
596 }
597
598 fn link(&mut self) -> Result<&mut Link, NetError> {
599 self.link.as_mut().ok_or(NetError::Closed)
600 }
601
602 fn link_ref(&self) -> &Link {
603 match &self.link {
604 Some(l) => l,
605 None => unreachable_link(),
607 }
608 }
609
610 pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize, NetError> {
617 let link = self.link()?;
618 loop {
619 match link.read(buf)? {
620 Got::Data(n) => return Ok(n),
621 Got::Eof => return Ok(0),
622 Got::Woken => continue,
623 }
624 }
625 }
626
627 pub fn recv_exact(&mut self, buf: &mut [u8]) -> Result<(), NetError> {
633 let mut filled = 0;
634 while filled < buf.len() {
635 match self.recv(&mut buf[filled..])? {
636 0 => return Err(NetError::Closed),
637 n => filled += n,
638 }
639 }
640 Ok(())
641 }
642
643 pub fn recv_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize, NetError> {
649 match bufs.iter_mut().find(|b| !b.is_empty()) {
650 Some(first) => self.recv(first),
651 None => Ok(0),
652 }
653 }
654
655 pub fn peek(&self, buf: &mut [u8]) -> Result<usize, NetError> {
661 let link = self.link_ref();
662 if buf.is_empty() {
663 return Ok(0);
664 }
665 let timeout = link.limits.read_timeout;
666 match sys::wait(link.stream.sock(), Interest::Read, None, Some(timeout)) {
667 Ok(Ready::TimedOut) => {
668 return Err(NetError::TimedOut {
669 kind: TimeoutKind::Read,
670 });
671 }
672 Ok(_) => {}
673 Err(e) => return Err(NetError::from_os("poll", e)),
674 }
675 link.stream
676 .peek(buf)
677 .map_err(|e| NetError::from_os("recv", e))
678 }
679
680 pub fn send(&mut self, buf: &[u8]) -> Result<usize, NetError> {
686 self.link()?.write(buf)
687 }
688
689 pub fn send_all(&mut self, buf: &[u8]) -> Result<(), NetError> {
696 self.link()?.write_all(buf)
697 }
698
699 pub fn send_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize, NetError> {
705 self.link()?.write_vectored(bufs)
706 }
707
708 pub fn send_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<(), NetError> {
714 self.link()?.write_all_vectored(bufs)
715 }
716
717 pub fn shutdown(&mut self, how: Shutdown) -> Result<(), NetError> {
723 self.link()?.shutdown(how)
724 }
725
726 pub fn close(mut self) -> Result<(), NetError> {
733 if let Some(link) = self.link.take() {
734 let reason = link.reason_or(CloseReason::SessionClosed);
735 link.finish(reason);
736 }
737 Ok(())
738 }
739
740 pub fn abort(mut self) {
742 if let Some(link) = self.link.take() {
743 let reason = link.reason_or(CloseReason::SessionError);
744 let reason = if reason.is_abortive() {
745 reason
746 } else {
747 CloseReason::SessionError
748 };
749 link.finish(reason);
750 }
751 }
752
753 #[must_use]
755 pub fn info(&self) -> &ConnectionInfo {
756 &self.link_ref().info
757 }
758
759 #[must_use]
761 pub fn id(&self) -> ConnectionId {
762 self.link_ref().info.id
763 }
764
765 #[must_use]
767 pub fn peer_addr(&self) -> SocketAddr {
768 self.link_ref()
769 .info
770 .peer
771 .socket_addr()
772 .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], 0)))
773 }
774
775 #[must_use]
777 pub fn local_addr(&self) -> SocketAddr {
778 self.link_ref()
779 .info
780 .local
781 .socket_addr()
782 .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], 0)))
783 }
784
785 #[must_use]
787 pub fn kill_handle(&self) -> KillHandle {
788 let link = self.link_ref();
789 KillHandle {
790 slot: link.slot.clone(),
791 generation: link.generation,
792 id: link.info.id,
793 }
794 }
795
796 pub fn set_limits(&mut self, limits: Limits) {
798 if let Ok(link) = self.link() {
799 let e: Effective = limits.effective(DriverKind::Blocking);
800 link.set_limits(e);
801 }
802 }
803
804 pub fn set_phase(&mut self, phase: Phase) {
806 if let Ok(link) = self.link() {
807 link.set_phase(phase);
808 }
809 }
810
811 pub fn set_exchange_deadline(&mut self, at: Option<Instant>) {
813 if let Ok(link) = self.link() {
814 link.set_exchange_deadline(at);
815 }
816 }
817
818 #[must_use]
820 pub fn options(&self) -> SocketOptions<'_> {
821 let link = self.link_ref();
822 SocketOptions {
823 stream: &link.stream,
824 v6: link.info.local.socket_addr().is_some_and(|a| a.is_ipv6()),
825 }
826 }
827
828 pub fn take_error(&self) -> Result<Option<io::Error>, NetError> {
834 sys::take_error(self.link_ref().stream.sock())
835 .map_err(|e| NetError::from_os("getsockopt", e))
836 }
837}
838
839#[cold]
840fn unreachable_link() -> ! {
841 std::process::abort()
844}
845
846fn connect_one(
847 addr: SocketAddr,
848 options: &ConnectOptions,
849 attempt: Duration,
850) -> Result<TcpConnection, NetError> {
851 let owned = sys::tcp_socket(addr.is_ipv6()).map_err(|e| NetError::from_os("socket", e))?;
852 let stream = std::net::TcpStream::from(owned);
853 stream
854 .set_nonblocking(true)
855 .map_err(|e| NetError::from_os("ioctl", e))?;
856 options.tcp.apply(&stream, addr.is_ipv6())?;
857 if let Some(local) = options.local_addr {
858 sys::bind_to(stream.sock(), local).map_err(|e| bind_error(local, e))?;
859 }
860 let started = Instant::now();
861 match sys::connect_start(stream.sock(), addr) {
862 Ok(false) => {}
863 Ok(true) => {
864 match sys::wait(stream.sock(), Interest::Write, None, Some(attempt)) {
865 Ok(Ready::TimedOut) => {
866 return Err(NetError::ConnectTimeout {
867 addr,
868 after: attempt,
869 });
870 }
871 Ok(_) => {}
872 Err(e) => return Err(NetError::from_os("poll", e)),
873 }
874 match sys::take_error(stream.sock()) {
875 Ok(None) => {}
876 Ok(Some(e)) => return Err(connect_error(addr, started.elapsed(), e)),
877 Err(e) => return Err(NetError::from_os("getsockopt", e)),
878 }
879 }
880 Err(e) => return Err(connect_error(addr, started.elapsed(), e)),
881 }
882 sys::prepare_dialed(&stream).map_err(|e| NetError::from_os("ioctl", e))?;
883 let local = stream
884 .local_addr()
885 .map_err(|e| NetError::from_os("getsockname", e))?;
886 let info = ConnectionInfo::new_tcp(
887 crate::id::issue_single(),
888 None,
889 WorkerId(0),
890 Origin::Dialed,
891 local,
892 crate::addr::normalize_socket(addr),
893 Instant::now(),
894 );
895 Ok(TcpConnection::from_link(Link::new(
896 stream,
897 info,
898 options.limits.effective(DriverKind::Blocking),
899 ClockRef::Monotonic,
900 Arc::new(KillSlot::new()),
901 WakeSource::Thread,
902 Phase::Receiving,
903 )))
904}
905
906impl Read for TcpConnection {
907 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
908 self.recv(buf).map_err(io::Error::from)
909 }
910}
911
912impl Write for TcpConnection {
913 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
914 self.send(buf).map_err(io::Error::from)
915 }
916
917 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
918 self.send_vectored(bufs).map_err(io::Error::from)
919 }
920
921 fn flush(&mut self) -> io::Result<()> {
922 Ok(())
923 }
924}
925
926impl Drop for TcpConnection {
927 fn drop(&mut self) {
929 if let Some(link) = self.link.take() {
930 let reason = link.reason_or(CloseReason::SessionClosed);
931 link.finish_quick(reason);
932 }
933 }
934}
935
936impl std::fmt::Debug for TcpConnection {
937 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
938 match &self.link {
939 Some(l) => f
940 .debug_struct("TcpConnection")
941 .field("info", &l.info)
942 .finish(),
943 None => f.write_str("TcpConnection(closed)"),
944 }
945 }
946}
947
948#[cfg(unix)]
949impl std::os::fd::AsFd for TcpConnection {
950 fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
951 std::os::fd::AsFd::as_fd(&self.link_ref().stream)
952 }
953}
954
955#[cfg(windows)]
956impl std::os::windows::io::AsSocket for TcpConnection {
957 fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {
958 std::os::windows::io::AsSocket::as_socket(&self.link_ref().stream)
959 }
960}
961
962#[cfg(test)]
963mod tests {
964 use super::*;
965
966 #[test]
967 fn test_listen_accept_echo_round_trip() {
968 let l = TcpListener::bind("127.0.0.1:0").unwrap();
969 let addr = l.local_addr().unwrap();
970 let t = std::thread::spawn(move || {
971 let (mut c, info) = l.accept().unwrap();
972 assert_eq!(info.origin, Origin::Accepted);
973 let mut buf = [0u8; 4];
974 c.recv_exact(&mut buf).unwrap();
975 c.send_all(&buf).unwrap();
976 c.close().unwrap();
977 });
978 let mut c = TcpConnection::connect(addr).unwrap();
979 c.send_all(b"ping").unwrap();
980 let mut buf = [0u8; 4];
981 c.recv_exact(&mut buf).unwrap();
982 assert_eq!(&buf, b"ping");
983 assert_eq!(c.recv(&mut buf).unwrap(), 0);
984 t.join().unwrap();
985 }
986
987 #[test]
988 fn test_connect_refused_maps_to_connection_refused() {
989 let port = std::net::TcpListener::bind("127.0.0.1:0")
991 .unwrap()
992 .local_addr()
993 .unwrap()
994 .port();
995 let err = TcpConnection::connect_with(
996 ("127.0.0.1", port),
997 ConnectOptions::new().timeout(Duration::from_secs(5)),
998 )
999 .unwrap_err();
1000 assert!(
1001 matches!(
1002 err,
1003 NetError::ConnectionRefused { .. } | NetError::ConnectTimeout { .. }
1004 ),
1005 "{err:?}"
1006 );
1007 }
1008
1009 #[test]
1010 fn test_bind_in_use_maps_to_addr_in_use() {
1011 let a = TcpListener::bind("127.0.0.1:0").unwrap();
1012 let err = TcpListener::bind(a.local_addr().unwrap()).unwrap_err();
1013 assert!(matches!(err, NetError::AddrInUse { .. }), "{err:?}");
1014 }
1015
1016 #[test]
1018 fn test_bind_errors_map_by_class() {
1019 #[cfg(unix)]
1020 use crate::sys::errno::{EACCES as ACCESS, EADDRNOTAVAIL as NOT_AVAILABLE};
1021 #[cfg(windows)]
1022 use crate::sys::errno::{WSAEACCES as ACCESS, WSAEADDRNOTAVAIL as NOT_AVAILABLE};
1023 let addr: SocketAddr = "[::1]:80".parse().unwrap();
1024 let e = bind_error(addr, io::Error::from_raw_os_error(NOT_AVAILABLE));
1025 assert!(matches!(e, NetError::AddrNotAvailable { .. }), "{e:?}");
1026 let e = bind_error(addr, io::Error::from_raw_os_error(ACCESS));
1027 assert!(matches!(e, NetError::PermissionDenied { .. }), "{e:?}");
1028 }
1029
1030 #[test]
1031 fn test_read_timeout_fires() {
1032 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1033 let addr = l.local_addr().unwrap();
1034 let _server = std::thread::spawn(move || {
1035 let (c, _) = l.accept().unwrap();
1036 std::thread::sleep(Duration::from_secs(2));
1037 drop(c);
1038 });
1039 let limits = Limits::builder()
1040 .read_timeout(Duration::from_millis(200))
1041 .min_rate(crate::limits::MinRate::off())
1042 .build()
1043 .unwrap();
1044 let mut c =
1045 TcpConnection::connect_with(addr, ConnectOptions::new().limits(limits)).unwrap();
1046 let mut buf = [0u8; 8];
1047 let start = Instant::now();
1048 let err = c.recv(&mut buf).unwrap_err();
1049 assert!(
1050 matches!(
1051 err,
1052 NetError::TimedOut {
1053 kind: TimeoutKind::Read
1054 }
1055 ),
1056 "{err:?}"
1057 );
1058 assert!(start.elapsed() < Duration::from_secs(2));
1059 }
1060
1061 #[test]
1062 fn test_kill_wakes_blocked_recv() {
1063 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1064 let addr = l.local_addr().unwrap();
1065 let _server = std::thread::spawn(move || {
1066 let (c, _) = l.accept().unwrap();
1067 std::thread::sleep(Duration::from_secs(3));
1068 drop(c);
1069 });
1070 let mut c = TcpConnection::connect(addr).unwrap();
1071 let kill = c.kill_handle();
1072 std::thread::spawn(move || {
1073 std::thread::sleep(Duration::from_millis(100));
1074 assert!(kill.kill(crate::error::KillReason(4)));
1075 });
1076 let mut buf = [0u8; 8];
1077 let start = Instant::now();
1078 let err = c.recv(&mut buf).unwrap_err();
1079 assert!(matches!(err, NetError::Killed { .. }), "{err:?}");
1080 assert!(start.elapsed() < Duration::from_secs(2));
1081 }
1082}