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: "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 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}
434
435impl Default for ConnectOptions {
436 fn default() -> ConnectOptions {
437 ConnectOptions {
438 timeout: Duration::from_secs(10),
439 local_addr: None,
440 tcp: TcpOptions::new().nodelay(true),
441 limits: Limits::default(),
442 }
443 }
444}
445
446impl ConnectOptions {
447 pub fn new() -> ConnectOptions {
449 ConnectOptions::default()
450 }
451
452 pub fn timeout(mut self, total: Duration) -> ConnectOptions {
454 self.timeout = total;
455 self
456 }
457
458 pub fn local_addr(mut self, addr: SocketAddr) -> ConnectOptions {
460 self.local_addr = Some(addr);
461 self
462 }
463
464 pub fn tcp_options(mut self, options: TcpOptions) -> ConnectOptions {
466 self.tcp = options;
467 self
468 }
469
470 pub fn limits(mut self, limits: Limits) -> ConnectOptions {
472 self.limits = limits;
473 self
474 }
475}
476
477pub struct TcpConnection {
501 link: Option<Link>,
502}
503
504impl TcpConnection {
505 pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<TcpConnection, NetError> {
511 TcpConnection::connect_with(addr, ConnectOptions::new())
512 }
513
514 pub fn connect_with<A: ToSocketAddrs>(
520 addr: A,
521 options: ConnectOptions,
522 ) -> Result<TcpConnection, NetError> {
523 let addrs = resolve(addr)?;
524 TcpConnection::connect_addrs(&addrs, &options)
525 }
526
527 pub fn connect_host(
535 host: &str,
536 port: u16,
537 options: ConnectOptions,
538 ) -> Result<TcpConnection, NetError> {
539 let addrs = resolve((host, port))?;
540 TcpConnection::connect_addrs(&addrs, &options)
541 }
542
543 fn connect_addrs(
544 addrs: &[SocketAddr],
545 options: &ConnectOptions,
546 ) -> Result<TcpConnection, NetError> {
547 let start = Instant::now();
548 let deadline = start + options.timeout;
549 let mut last = NetError::NoAddresses;
550 for (i, addr) in addrs.iter().enumerate() {
551 let left = deadline.saturating_duration_since(Instant::now());
552 if left.is_zero() {
553 break;
554 }
555 let remaining = (addrs.len() - i) as u32;
556 let attempt = (left / remaining).max(Duration::from_secs(1)).min(left);
557 match connect_one(*addr, options, attempt) {
558 Ok(conn) => return Ok(conn),
559 Err(e) => last = e,
560 }
561 }
562 if matches!(last, NetError::NoAddresses) {
563 if let Some(addr) = addrs.first() {
564 last = NetError::ConnectTimeout {
565 addr: *addr,
566 after: options.timeout,
567 };
568 }
569 }
570 Err(last)
571 }
572
573 pub(crate) fn accepted(
574 stream: std::net::TcpStream,
575 peer: SocketAddr,
576 tcp: &TcpOptions,
577 listener: ListenerId,
578 ) -> Result<TcpConnection, NetError> {
579 let local = stream
580 .local_addr()
581 .map_err(|e| NetError::from_os("getsockname", e))?;
582 if !OPTIONS_INHERITED && !tcp.is_empty() {
583 tcp.apply(&stream, local.is_ipv6())?;
584 }
585 let info = ConnectionInfo::new_tcp(
586 crate::id::issue_single(),
587 Some(listener),
588 WorkerId(0),
589 Origin::Accepted,
590 local,
591 peer,
592 Instant::now(),
593 );
594 let limits = Limits::default().effective(DriverKind::Blocking);
595 Ok(TcpConnection::from_link(Link::new(
596 sys::Stream::Tcp(stream),
597 info,
598 limits,
599 ClockRef::Monotonic,
600 Arc::new(KillSlot::new()),
601 WakeSource::Thread,
602 Phase::Idle,
603 )))
604 }
605
606 pub(crate) fn from_link(link: Link) -> TcpConnection {
607 TcpConnection { link: Some(link) }
608 }
609
610 pub(crate) fn take_link(&mut self) -> Option<Link> {
611 self.link.take()
612 }
613
614 pub(crate) fn link(&mut self) -> Result<&mut Link, NetError> {
615 self.link.as_mut().ok_or(NetError::Closed)
616 }
617
618 pub(crate) fn link_ref(&self) -> &Link {
619 match &self.link {
620 Some(l) => l,
621 None => unreachable_link(),
623 }
624 }
625
626 pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize, NetError> {
633 let link = self.link()?;
634 loop {
635 match link.read(buf)? {
636 Got::Data(n) => return Ok(n),
637 Got::Eof => return Ok(0),
638 Got::Woken => continue,
639 }
640 }
641 }
642
643 pub fn recv_exact(&mut self, buf: &mut [u8]) -> Result<(), NetError> {
649 let mut filled = 0;
650 while filled < buf.len() {
651 match self.recv(&mut buf[filled..])? {
652 0 => return Err(NetError::Closed),
653 n => filled += n,
654 }
655 }
656 Ok(())
657 }
658
659 pub fn recv_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize, NetError> {
665 match bufs.iter_mut().find(|b| !b.is_empty()) {
666 Some(first) => self.recv(first),
667 None => Ok(0),
668 }
669 }
670
671 pub fn peek(&self, buf: &mut [u8]) -> Result<usize, NetError> {
677 let link = self.link_ref();
678 if buf.is_empty() {
679 return Ok(0);
680 }
681 if link.has_tls() {
682 return Err(NetError::Unsupported {
684 feature: "peek on a TLS connection",
685 platform: std::env::consts::OS,
686 });
687 }
688 let timeout = link.limits.read_timeout;
689 match sys::wait(link.stream.sock(), Interest::Read, None, Some(timeout)) {
690 Ok(Ready::TimedOut) => {
691 return Err(NetError::TimedOut {
692 kind: TimeoutKind::Read,
693 });
694 }
695 Ok(_) => {}
696 Err(e) => return Err(NetError::from_os("poll", e)),
697 }
698 link.stream
699 .peek(buf)
700 .map_err(|e| NetError::from_os("recv", e))
701 }
702
703 pub fn send(&mut self, buf: &[u8]) -> Result<usize, NetError> {
709 self.link()?.write(buf)
710 }
711
712 pub fn send_all(&mut self, buf: &[u8]) -> Result<(), NetError> {
719 self.link()?.write_all(buf)
720 }
721
722 pub fn send_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize, NetError> {
728 self.link()?.write_vectored(bufs)
729 }
730
731 pub fn send_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<(), NetError> {
737 self.link()?.write_all_vectored(bufs)
738 }
739
740 pub fn shutdown(&mut self, how: Shutdown) -> Result<(), NetError> {
746 self.link()?.shutdown(how)
747 }
748
749 pub fn close(mut self) -> Result<(), NetError> {
756 if let Some(link) = self.link.take() {
757 let reason = link.reason_or(CloseReason::SessionClosed);
758 link.finish(reason);
759 }
760 Ok(())
761 }
762
763 pub fn abort(mut self) {
765 if let Some(link) = self.link.take() {
766 let reason = link.reason_or(CloseReason::SessionError);
767 let reason = if reason.is_abortive() {
768 reason
769 } else {
770 CloseReason::SessionError
771 };
772 link.finish(reason);
773 }
774 }
775
776 #[must_use]
778 pub fn info(&self) -> &ConnectionInfo {
779 &self.link_ref().info
780 }
781
782 #[must_use]
784 pub fn id(&self) -> ConnectionId {
785 self.link_ref().info.id
786 }
787
788 #[must_use]
790 pub fn peer_addr(&self) -> SocketAddr {
791 self.link_ref()
792 .info
793 .peer
794 .socket_addr()
795 .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], 0)))
796 }
797
798 #[must_use]
800 pub fn local_addr(&self) -> SocketAddr {
801 self.link_ref()
802 .info
803 .local
804 .socket_addr()
805 .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], 0)))
806 }
807
808 #[must_use]
810 pub fn kill_handle(&self) -> KillHandle {
811 let link = self.link_ref();
812 KillHandle {
813 slot: link.slot.clone(),
814 generation: link.generation,
815 id: link.info.id,
816 }
817 }
818
819 pub fn set_limits(&mut self, limits: Limits) {
821 if let Ok(link) = self.link() {
822 let e: Effective = limits.effective(DriverKind::Blocking);
823 link.set_limits(e);
824 }
825 }
826
827 pub fn set_phase(&mut self, phase: Phase) {
829 if let Ok(link) = self.link() {
830 link.set_phase(phase);
831 }
832 }
833
834 pub fn set_exchange_deadline(&mut self, at: Option<Instant>) {
836 if let Ok(link) = self.link() {
837 link.set_exchange_deadline(at);
838 }
839 }
840
841 pub fn set_gate<G: Gate>(&mut self, gate: Arc<G>) -> Result<(), NetError> {
860 let link = self.link()?;
861 if link.gate.is_some() {
862 return Err(NetError::InvalidConfig {
863 field: "gate",
864 reason: ConfigReason::Inconsistent,
865 });
866 }
867 let code = match guarded(|| gate.admit(&link.info, AdmitStage::Dialed)) {
868 Some(Ok(admitted)) => {
869 link.info.lane = admitted.lane;
870 link.info.gate = admitted.tag;
871 link.gate = Some(Box::new(GateCell {
872 gate,
873 ticket: Some(admitted.ticket),
874 }));
875 return Ok(());
876 }
877 Some(Err(refusal)) => refusal.code(),
878 None => 0,
879 };
880 let cause = RefusalCause::Gate(code);
881 if let Some(link) = self.link.take() {
882 link.finish(CloseReason::Refused(cause));
883 }
884 Err(NetError::Refused { cause })
885 }
886
887 #[must_use]
889 pub fn options(&self) -> SocketOptions<'_> {
890 let link = self.link_ref();
891 SocketOptions {
892 sock: link.stream.sock(),
893 v6: link.info.local.socket_addr().is_some_and(|a| a.is_ipv6()),
894 }
895 }
896
897 pub fn take_error(&self) -> Result<Option<io::Error>, NetError> {
903 sys::take_error(self.link_ref().stream.sock())
904 .map_err(|e| NetError::from_os("getsockopt", e))
905 }
906}
907
908#[cold]
909fn unreachable_link() -> ! {
910 std::process::abort()
913}
914
915fn connect_one(
916 addr: SocketAddr,
917 options: &ConnectOptions,
918 attempt: Duration,
919) -> Result<TcpConnection, NetError> {
920 let owned = sys::tcp_socket(addr.is_ipv6()).map_err(|e| NetError::from_os("socket", e))?;
921 let stream = std::net::TcpStream::from(owned);
922 stream
923 .set_nonblocking(true)
924 .map_err(|e| NetError::from_os("ioctl", e))?;
925 options.tcp.apply(&stream, addr.is_ipv6())?;
926 if let Some(local) = options.local_addr {
927 sys::bind_to(stream.sock(), local).map_err(|e| bind_error(local, e))?;
928 }
929 let started = Instant::now();
930 match sys::connect_start(stream.sock(), addr) {
931 Ok(false) => {}
932 Ok(true) => {
933 match sys::wait(stream.sock(), Interest::Write, None, Some(attempt)) {
934 Ok(Ready::TimedOut) => {
935 return Err(NetError::ConnectTimeout {
936 addr,
937 after: attempt,
938 });
939 }
940 Ok(_) => {}
941 Err(e) => return Err(NetError::from_os("poll", e)),
942 }
943 match sys::take_error(stream.sock()) {
944 Ok(None) => {}
945 Ok(Some(e)) => return Err(connect_error(addr, started.elapsed(), e)),
946 Err(e) => return Err(NetError::from_os("getsockopt", e)),
947 }
948 }
949 Err(e) => return Err(connect_error(addr, started.elapsed(), e)),
950 }
951 sys::prepare_dialed(&stream).map_err(|e| NetError::from_os("ioctl", e))?;
952 let local = stream
953 .local_addr()
954 .map_err(|e| NetError::from_os("getsockname", e))?;
955 let info = ConnectionInfo::new_tcp(
956 crate::id::issue_single(),
957 None,
958 WorkerId(0),
959 Origin::Dialed,
960 local,
961 crate::addr::normalize_socket(addr),
962 Instant::now(),
963 );
964 Ok(TcpConnection::from_link(Link::new(
965 sys::Stream::Tcp(stream),
966 info,
967 options.limits.effective(DriverKind::Blocking),
968 ClockRef::Monotonic,
969 Arc::new(KillSlot::new()),
970 WakeSource::Thread,
971 Phase::Receiving,
972 )))
973}
974
975impl Read for TcpConnection {
976 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
977 self.recv(buf).map_err(io::Error::from)
978 }
979}
980
981impl Write for TcpConnection {
982 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
983 self.send(buf).map_err(io::Error::from)
984 }
985
986 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
987 self.send_vectored(bufs).map_err(io::Error::from)
988 }
989
990 fn flush(&mut self) -> io::Result<()> {
991 Ok(())
992 }
993}
994
995impl Drop for TcpConnection {
996 fn drop(&mut self) {
998 if let Some(link) = self.link.take() {
999 let reason = link.reason_or(CloseReason::SessionClosed);
1000 link.finish_quick(reason);
1001 }
1002 }
1003}
1004
1005impl std::fmt::Debug for TcpConnection {
1006 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1007 match &self.link {
1008 Some(l) => f
1009 .debug_struct("TcpConnection")
1010 .field("info", &l.info)
1011 .finish(),
1012 None => f.write_str("TcpConnection(closed)"),
1013 }
1014 }
1015}
1016
1017#[cfg(unix)]
1018impl std::os::fd::AsFd for TcpConnection {
1019 fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
1020 std::os::fd::AsFd::as_fd(&self.link_ref().stream)
1021 }
1022}
1023
1024#[cfg(windows)]
1025impl std::os::windows::io::AsSocket for TcpConnection {
1026 fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {
1027 std::os::windows::io::AsSocket::as_socket(&self.link_ref().stream)
1028 }
1029}
1030
1031#[cfg(test)]
1032mod tests {
1033 use super::*;
1034
1035 #[test]
1036 fn test_listen_accept_echo_round_trip() {
1037 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1038 let addr = l.local_addr().unwrap();
1039 let t = std::thread::spawn(move || {
1040 let (mut c, info) = l.accept().unwrap();
1041 assert_eq!(info.origin, Origin::Accepted);
1042 let mut buf = [0u8; 4];
1043 c.recv_exact(&mut buf).unwrap();
1044 c.send_all(&buf).unwrap();
1045 c.close().unwrap();
1046 });
1047 let mut c = TcpConnection::connect(addr).unwrap();
1048 c.send_all(b"ping").unwrap();
1049 let mut buf = [0u8; 4];
1050 c.recv_exact(&mut buf).unwrap();
1051 assert_eq!(&buf, b"ping");
1052 assert_eq!(c.recv(&mut buf).unwrap(), 0);
1053 t.join().unwrap();
1054 }
1055
1056 #[test]
1057 fn test_connect_refused_maps_to_connection_refused() {
1058 let port = std::net::TcpListener::bind("127.0.0.1:0")
1060 .unwrap()
1061 .local_addr()
1062 .unwrap()
1063 .port();
1064 let err = TcpConnection::connect_with(
1065 ("127.0.0.1", port),
1066 ConnectOptions::new().timeout(Duration::from_secs(5)),
1067 )
1068 .unwrap_err();
1069 assert!(
1070 matches!(
1071 err,
1072 NetError::ConnectionRefused { .. } | NetError::ConnectTimeout { .. }
1073 ),
1074 "{err:?}"
1075 );
1076 }
1077
1078 #[test]
1079 fn test_bind_in_use_maps_to_addr_in_use() {
1080 let a = TcpListener::bind("127.0.0.1:0").unwrap();
1081 let err = TcpListener::bind(a.local_addr().unwrap()).unwrap_err();
1082 assert!(matches!(err, NetError::AddrInUse { .. }), "{err:?}");
1083 }
1084
1085 #[test]
1087 fn test_bind_errors_map_by_class() {
1088 #[cfg(unix)]
1089 use crate::sys::errno::{EACCES as ACCESS, EADDRNOTAVAIL as NOT_AVAILABLE};
1090 #[cfg(windows)]
1091 use crate::sys::errno::{WSAEACCES as ACCESS, WSAEADDRNOTAVAIL as NOT_AVAILABLE};
1092 let addr: SocketAddr = "[::1]:80".parse().unwrap();
1093 let e = bind_error(addr, io::Error::from_raw_os_error(NOT_AVAILABLE));
1094 assert!(matches!(e, NetError::AddrNotAvailable { .. }), "{e:?}");
1095 let e = bind_error(addr, io::Error::from_raw_os_error(ACCESS));
1096 assert!(matches!(e, NetError::PermissionDenied { .. }), "{e:?}");
1097 }
1098
1099 #[test]
1100 fn test_read_timeout_fires() {
1101 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1102 let addr = l.local_addr().unwrap();
1103 let _server = std::thread::spawn(move || {
1104 let (c, _) = l.accept().unwrap();
1105 std::thread::sleep(Duration::from_secs(2));
1106 drop(c);
1107 });
1108 let limits = Limits::builder()
1109 .read_timeout(Duration::from_millis(200))
1110 .min_rate(crate::limits::MinRate::off())
1111 .build()
1112 .unwrap();
1113 let mut c =
1114 TcpConnection::connect_with(addr, ConnectOptions::new().limits(limits)).unwrap();
1115 let mut buf = [0u8; 8];
1116 let start = Instant::now();
1117 let err = c.recv(&mut buf).unwrap_err();
1118 assert!(
1119 matches!(
1120 err,
1121 NetError::TimedOut {
1122 kind: TimeoutKind::Read
1123 }
1124 ),
1125 "{err:?}"
1126 );
1127 assert!(start.elapsed() < Duration::from_secs(2));
1128 }
1129
1130 #[test]
1131 fn test_kill_wakes_blocked_recv() {
1132 let l = TcpListener::bind("127.0.0.1:0").unwrap();
1133 let addr = l.local_addr().unwrap();
1134 let _server = std::thread::spawn(move || {
1135 let (c, _) = l.accept().unwrap();
1136 std::thread::sleep(Duration::from_secs(3));
1137 drop(c);
1138 });
1139 let mut c = TcpConnection::connect(addr).unwrap();
1140 let kill = c.kill_handle();
1141 std::thread::spawn(move || {
1142 std::thread::sleep(Duration::from_millis(100));
1143 assert!(kill.kill(crate::error::KillReason(4)));
1144 });
1145 let mut buf = [0u8; 8];
1146 let start = Instant::now();
1147 let err = c.recv(&mut buf).unwrap_err();
1148 assert!(matches!(err, NetError::Killed { .. }), "{err:?}");
1149 assert!(start.elapsed() < Duration::from_secs(2));
1150 }
1151}