aboutsummaryrefslogtreecommitdiff
path: root/src/net/tcp/socket.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/tcp/socket.rs')
-rw-r--r--src/net/tcp/socket.rs145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/net/tcp/socket.rs b/src/net/tcp/socket.rs
new file mode 100644
index 0000000..0094de9
--- /dev/null
+++ b/src/net/tcp/socket.rs
@@ -0,0 +1,145 @@
+use crate::net::{TcpStream, TcpListener};
+use crate::sys;
+
+use std::io;
+use std::mem;
+use std::net::SocketAddr;
+#[cfg(unix)]
+use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
+#[cfg(windows)]
+use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
+
+/// A non-blocking TCP socket used to configure a stream or listener.
+///
+/// The `TcpSocket` type wraps the operating-system's socket handle. This type
+/// is used to configure the socket before establishing a connection or start
+/// listening for inbound connections.
+///
+/// The socket will be closed when the value is dropped.
+#[derive(Debug)]
+pub struct TcpSocket {
+ sys: sys::tcp::TcpSocket,
+}
+
+impl TcpSocket {
+ /// Create a new IPv4 TCP socket.
+ ///
+ /// This calls `socket(2)`.
+ pub fn new_v4() -> io::Result<TcpSocket> {
+ sys::tcp::new_v4_socket().map(|sys| TcpSocket {
+ sys
+ })
+ }
+
+ /// Create a new IPv6 TCP socket.
+ ///
+ /// This calls `socket(2)`.
+ pub fn new_v6() -> io::Result<TcpSocket> {
+ sys::tcp::new_v6_socket().map(|sys| TcpSocket {
+ sys
+ })
+ }
+
+ pub(crate) fn new_for_addr(addr: SocketAddr) -> io::Result<TcpSocket> {
+ if addr.is_ipv4() {
+ TcpSocket::new_v4()
+ } else {
+ TcpSocket::new_v6()
+ }
+ }
+
+ /// Bind `addr` to the TCP socket.
+ pub fn bind(&self, addr: SocketAddr) -> io::Result<()> {
+ sys::tcp::bind(self.sys, addr)
+ }
+
+ /// Connect the socket to `addr`.
+ ///
+ /// This consumes the socket and performs the connect operation. Once the
+ /// connection completes, the socket is now a non-blocking `TcpStream` and
+ /// can be used as such.
+ pub fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> {
+ let stream = sys::tcp::connect(self.sys, addr)?;
+
+ // Don't close the socket
+ mem::forget(self);
+ Ok(TcpStream::from_std(stream))
+ }
+
+ /// Listen for inbound connections, converting the socket to a
+ /// `TcpListener`.
+ pub fn listen(self, backlog: u32) -> io::Result<TcpListener> {
+ let listener = sys::tcp::listen(self.sys, backlog)?;
+
+ // Don't close the socket
+ mem::forget(self);
+ Ok(TcpListener::from_std(listener))
+ }
+
+ /// Sets the value of `SO_REUSEADDR` on this socket.
+ pub fn set_reuseaddr(&self, reuseaddr: bool) -> io::Result<()> {
+ sys::tcp::set_reuseaddr(self.sys, reuseaddr)
+ }
+}
+
+impl Drop for TcpSocket {
+ fn drop(&mut self) {
+ sys::tcp::close(self.sys);
+ }
+}
+
+#[cfg(unix)]
+impl AsRawFd for TcpSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.sys
+ }
+}
+
+#[cfg(unix)]
+impl FromRawFd for TcpSocket {
+ /// Converts a `RawFd` to a `TcpSocket`.
+ ///
+ /// # Notes
+ ///
+ /// The caller is responsible for ensuring that the socket is in
+ /// non-blocking mode.
+ unsafe fn from_raw_fd(fd: RawFd) -> TcpSocket {
+ TcpSocket { sys: fd }
+ }
+}
+
+#[cfg(windows)]
+impl IntoRawSocket for TcpSocket {
+ fn into_raw_socket(self) -> RawSocket {
+ // The winapi crate defines `SOCKET` as `usize`. The Rust std
+ // conditionally defines `RawSocket` as a fixed size unsigned integer
+ // matching the pointer width. These end up being the same type but we
+ // must cast between them.
+ let ret = self.sys as RawSocket;
+
+ // Avoid closing the socket
+ mem::forget(self);
+
+ ret
+ }
+}
+
+#[cfg(windows)]
+impl AsRawSocket for TcpSocket {
+ fn as_raw_socket(&self) -> RawSocket {
+ self.sys as RawSocket
+ }
+}
+
+#[cfg(windows)]
+impl FromRawSocket for TcpSocket {
+ /// Converts a `RawSocket` to a `TcpSocket`.
+ ///
+ /// # Notes
+ ///
+ /// The caller is responsible for ensuring that the socket is in
+ /// non-blocking mode.
+ unsafe fn from_raw_socket(socket: RawSocket) -> TcpSocket {
+ TcpSocket { sys: socket as sys::tcp::TcpSocket }
+ }
+}