summaryrefslogtreecommitdiffstats
path: root/third_party/rust/mio/src/net/tcp/stream.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/mio/src/net/tcp/stream.rs
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/mio/src/net/tcp/stream.rs')
-rw-r--r--third_party/rust/mio/src/net/tcp/stream.rs334
1 files changed, 334 insertions, 0 deletions
diff --git a/third_party/rust/mio/src/net/tcp/stream.rs b/third_party/rust/mio/src/net/tcp/stream.rs
new file mode 100644
index 0000000000..029f186b42
--- /dev/null
+++ b/third_party/rust/mio/src/net/tcp/stream.rs
@@ -0,0 +1,334 @@
+use std::fmt;
+use std::io::{self, IoSlice, IoSliceMut, Read, Write};
+use std::net::{self, Shutdown, SocketAddr};
+#[cfg(unix)]
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+#[cfg(windows)]
+use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
+
+use crate::io_source::IoSource;
+use crate::sys::tcp::{connect, new_for_addr};
+use crate::{event, Interest, Registry, Token};
+
+/// A non-blocking TCP stream between a local socket and a remote socket.
+///
+/// The socket will be closed when the value is dropped.
+///
+/// # Examples
+///
+#[cfg_attr(feature = "os-poll", doc = "```")]
+#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
+/// # use std::net::{TcpListener, SocketAddr};
+/// # use std::error::Error;
+/// #
+/// # fn main() -> Result<(), Box<dyn Error>> {
+/// let address: SocketAddr = "127.0.0.1:0".parse()?;
+/// let listener = TcpListener::bind(address)?;
+/// use mio::{Events, Interest, Poll, Token};
+/// use mio::net::TcpStream;
+/// use std::time::Duration;
+///
+/// let mut stream = TcpStream::connect(listener.local_addr()?)?;
+///
+/// let mut poll = Poll::new()?;
+/// let mut events = Events::with_capacity(128);
+///
+/// // Register the socket with `Poll`
+/// poll.registry().register(&mut stream, Token(0), Interest::WRITABLE)?;
+///
+/// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
+///
+/// // The socket might be ready at this point
+/// # Ok(())
+/// # }
+/// ```
+pub struct TcpStream {
+ inner: IoSource<net::TcpStream>,
+}
+
+impl TcpStream {
+ /// Create a new TCP stream and issue a non-blocking connect to the
+ /// specified address.
+ ///
+ /// # Notes
+ ///
+ /// The returned `TcpStream` may not be connected (and thus usable), unlike
+ /// the API found in `std::net::TcpStream`. Because Mio issues a
+ /// *non-blocking* connect it will not block the thread and instead return
+ /// an unconnected `TcpStream`.
+ ///
+ /// Ensuring the returned stream is connected is surprisingly complex when
+ /// considering cross-platform support. Doing this properly should follow
+ /// the steps below, an example implementation can be found
+ /// [here](https://github.com/Thomasdezeeuw/heph/blob/0c4f1ab3eaf08bea1d65776528bfd6114c9f8374/src/net/tcp/stream.rs#L560-L622).
+ ///
+ /// 1. Call `TcpStream::connect`
+ /// 2. Register the returned stream with at least [read interest].
+ /// 3. Wait for a (readable) event.
+ /// 4. Check `TcpStream::peer_addr`. If it returns `libc::EINPROGRESS` or
+ /// `ErrorKind::NotConnected` it means the stream is not yet connected,
+ /// go back to step 3. If it returns an address it means the stream is
+ /// connected, go to step 5. If another error is returned something
+ /// whent wrong.
+ /// 5. Now the stream can be used.
+ ///
+ /// [read interest]: Interest::READABLE
+ pub fn connect(addr: SocketAddr) -> io::Result<TcpStream> {
+ let socket = new_for_addr(addr)?;
+ #[cfg(unix)]
+ let stream = unsafe { TcpStream::from_raw_fd(socket) };
+ #[cfg(windows)]
+ let stream = unsafe { TcpStream::from_raw_socket(socket as _) };
+ connect(&stream.inner, addr)?;
+ Ok(stream)
+ }
+
+ /// Creates a new `TcpStream` from a standard `net::TcpStream`.
+ ///
+ /// This function is intended to be used to wrap a TCP stream from the
+ /// standard library in the Mio equivalent. The conversion assumes nothing
+ /// about the underlying stream; it is left up to the user to set it in
+ /// non-blocking mode.
+ ///
+ /// # Note
+ ///
+ /// The TCP stream here will not have `connect` called on it, so it
+ /// should already be connected via some other means (be it manually, or
+ /// the standard library).
+ pub fn from_std(stream: net::TcpStream) -> TcpStream {
+ TcpStream {
+ inner: IoSource::new(stream),
+ }
+ }
+
+ /// Returns the socket address of the remote peer of this TCP connection.
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.inner.peer_addr()
+ }
+
+ /// Returns the socket address of the local half of this TCP connection.
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ self.inner.local_addr()
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O on the specified
+ /// portions to return immediately with an appropriate value (see the
+ /// documentation of `Shutdown`).
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.inner.shutdown(how)
+ }
+
+ /// Sets the value of the `TCP_NODELAY` option on this socket.
+ ///
+ /// If set, this option disables the Nagle algorithm. This means that
+ /// segments are always sent as soon as possible, even if there is only a
+ /// small amount of data. When not set, data is buffered until there is a
+ /// sufficient amount to send out, thereby avoiding the frequent sending of
+ /// small packets.
+ ///
+ /// # Notes
+ ///
+ /// On Windows make sure the stream is connected before calling this method,
+ /// by receiving an (writable) event. Trying to set `nodelay` on an
+ /// unconnected `TcpStream` is unspecified behavior.
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ self.inner.set_nodelay(nodelay)
+ }
+
+ /// Gets the value of the `TCP_NODELAY` option on this socket.
+ ///
+ /// For more information about this option, see [`set_nodelay`][link].
+ ///
+ /// [link]: #method.set_nodelay
+ ///
+ /// # Notes
+ ///
+ /// On Windows make sure the stream is connected before calling this method,
+ /// by receiving an (writable) event. Trying to get `nodelay` on an
+ /// unconnected `TcpStream` is unspecified behavior.
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.inner.nodelay()
+ }
+
+ /// Sets the value for the `IP_TTL` option on this socket.
+ ///
+ /// This value sets the time-to-live field that is used in every packet sent
+ /// from this socket.
+ ///
+ /// # Notes
+ ///
+ /// On Windows make sure the stream is connected before calling this method,
+ /// by receiving an (writable) event. Trying to set `ttl` on an
+ /// unconnected `TcpStream` is unspecified behavior.
+ pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+ self.inner.set_ttl(ttl)
+ }
+
+ /// Gets the value of the `IP_TTL` option for this socket.
+ ///
+ /// For more information about this option, see [`set_ttl`][link].
+ ///
+ /// # Notes
+ ///
+ /// On Windows make sure the stream is connected before calling this method,
+ /// by receiving an (writable) event. Trying to get `ttl` on an
+ /// unconnected `TcpStream` is unspecified behavior.
+ ///
+ /// [link]: #method.set_ttl
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.inner.ttl()
+ }
+
+ /// Get the value of the `SO_ERROR` option on this socket.
+ ///
+ /// This will retrieve the stored error in the underlying socket, clearing
+ /// the field in the process. This can be useful for checking errors between
+ /// calls.
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.inner.take_error()
+ }
+
+ /// Receives data on the socket from the remote address to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying recv system call.
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.peek(buf)
+ }
+}
+
+impl Read for TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).read(buf))
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).read_vectored(bufs))
+ }
+}
+
+impl<'a> Read for &'a TcpStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).read(buf))
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).read_vectored(bufs))
+ }
+}
+
+impl Write for TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).write(buf))
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).write_vectored(bufs))
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.do_io(|inner| (&*inner).flush())
+ }
+}
+
+impl<'a> Write for &'a TcpStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).write(buf))
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.inner.do_io(|inner| (&*inner).write_vectored(bufs))
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.do_io(|inner| (&*inner).flush())
+ }
+}
+
+impl event::Source for TcpStream {
+ fn register(
+ &mut self,
+ registry: &Registry,
+ token: Token,
+ interests: Interest,
+ ) -> io::Result<()> {
+ self.inner.register(registry, token, interests)
+ }
+
+ fn reregister(
+ &mut self,
+ registry: &Registry,
+ token: Token,
+ interests: Interest,
+ ) -> io::Result<()> {
+ self.inner.reregister(registry, token, interests)
+ }
+
+ fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
+ self.inner.deregister(registry)
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+#[cfg(unix)]
+impl IntoRawFd for TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.inner.into_inner().into_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl AsRawFd for TcpStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.inner.as_raw_fd()
+ }
+}
+
+#[cfg(unix)]
+impl FromRawFd for TcpStream {
+ /// Converts a `RawFd` to a `TcpStream`.
+ ///
+ /// # Notes
+ ///
+ /// The caller is responsible for ensuring that the socket is in
+ /// non-blocking mode.
+ unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
+ TcpStream::from_std(FromRawFd::from_raw_fd(fd))
+ }
+}
+
+#[cfg(windows)]
+impl IntoRawSocket for TcpStream {
+ fn into_raw_socket(self) -> RawSocket {
+ self.inner.into_inner().into_raw_socket()
+ }
+}
+
+#[cfg(windows)]
+impl AsRawSocket for TcpStream {
+ fn as_raw_socket(&self) -> RawSocket {
+ self.inner.as_raw_socket()
+ }
+}
+
+#[cfg(windows)]
+impl FromRawSocket for TcpStream {
+ /// Converts a `RawSocket` to a `TcpStream`.
+ ///
+ /// # Notes
+ ///
+ /// The caller is responsible for ensuring that the socket is in
+ /// non-blocking mode.
+ unsafe fn from_raw_socket(socket: RawSocket) -> TcpStream {
+ TcpStream::from_std(FromRawSocket::from_raw_socket(socket))
+ }
+}