From 0d9943e43a5f9333d043cf2f82cb63c50045433e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Feb 2015 11:05:26 -0800 Subject: [PATCH 1/3] Add in std::net text from original RFC --- text/0517-io-os-reform.md | 124 +++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) diff --git a/text/0517-io-os-reform.md b/text/0517-io-os-reform.md index 9528922999c..b89aae0155a 100644 --- a/text/0517-io-os-reform.md +++ b/text/0517-io-os-reform.md @@ -64,7 +64,10 @@ follow-up PRs against this RFC. * [stdin, stdout, stderr] * [std::env] * [std::fs] (stub) - * [std::net] (stub) + * [std::net] + * [TCP] + * [UDP] + * [Addresses] * [std::process] (stub) * [std::os] * [Odds and ends] @@ -1234,7 +1237,124 @@ This brings the constants into line with our naming conventions elsewhere. ### `std::net` [std::net]: #stdnet -> To be added in a follow-up PR. +The contents of `std::io::net` submodules `tcp`, `udp`, `ip` and +`addrinfo` will be retained but moved into a single `std::net` module; +the other modules are being moved or removed and are described +elsewhere. + +#### TCP +[TCP]: #tcp + +For `TcpStream`, the changes are most easily expressed by giving the signatures directly: + +```rust +// TcpStream, which contains both a reader and a writer + +impl TcpStream { + fn connect(addr: A) -> IoResult; + fn connect_deadline(addr: A, deadline: D) -> IoResult where + A: ToSocketAddr, D: IntoDeadline; + + fn reader(&mut self) -> &mut TcpReader; + fn writer(&mut self) -> &mut TcpWriter; + fn split(self) -> (TcpReader, TcpWriter); + + fn peer_addr(&mut self) -> IoResult; + fn socket_addr(&mut self) -> IoResult; +} + +impl Reader for TcpStream { ... } +impl Writer for TcpStream { ... } + +impl Reader for Deadlined { ... } +impl Writer for Deadlined { ... } + +// TcpReader + +impl Reader for TcpReader { ... } +impl Reader for Deadlined { ... } + +impl TcpReader { + fn peer_addr(&mut self) -> IoResult; + fn socket_addr(&mut self) -> IoResult; + + fn shutdown_token(&mut self) -> ShutdownToken; +} + +// TcpWriter + +impl Writer for TcpWriter { ... } +impl Writer for Deadlined { ... } + +impl TcpWriter { + fn peer_addr(&mut self) -> IoResult; + fn socket_addr(&mut self) -> IoResult; + + fn shutdown_token(&mut self) -> ShutdownToken; +} + +// ShutdownToken + +impl ShutdownToken { + fn shutdown(self); +} + +impl Clone for ShutdownToken { ... } +``` + +The idea is that a `TcpStream` provides both a reader and a writer, +and can be used directly as such, just as it can today. However, the +two sides can also be broken apart via the `split` method, which +allows them to be shipped off to separate threads. Moreover, each side +can yield a `ShutdownToken`, a `Clone` and `Send` value that can be +used to shut down that side of the socket, cancelling any in-progress +blocking operations, much like e.g. `close_read` does today. + +The implementation of the `ShutdownToken` infrastructure should ensure +that there is essentially no cost imposed when the feature is not used +-- in particular, if a `ShutdownToken` has not been requested, a +single `read` or `write` should correspond to a single syscall. + +For `TcpListener`, the only change is to rename `socket_name` to +`socket_addr`. + +For `TcpAcceptor` we will: + +* Add a `socket_addr` method. +* Possibly provide a convenience constructor for `bind`. +* Replace `close_accept` with `cancel_token()`. +* Remove `Clone`. +* Rename `IncomingConnecitons` to `Incoming`. + +#### UDP +[UDP]: #udp + +The UDP infrastructure should change to use the new deadline +infrastructure, but should not provide `Clone`, `ShutdownToken`s, or a +reader/writer split. In addition: + +* `recv_from` should become `recv`. +* `send_to` should become `send`. +* `socket_name` should become `socket_addr`. + +Methods like `multicast` and `ttl` are left as `#[experimental]` for +now (they are derived from libuv's design). + +#### Addresses +[Addresses]: #addresses + +For the current `addrinfo` module: + +* The `get_host_addresses` should be renamed to `lookup_host`. +* All other contents should be removed. + +For the current `ip` module: + +* The `ToSocketAddr` trait should become `ToSocketAddrs` +* The default `to_socket_addr_all` method should be removed. + +The actual address structures could use some scrutiny, but any +revisions there are left as an unresolved question. ### `std::process` [std::process]: #stdprocess From 9ba9437e5d37f722f4a70547f8661bc8c6504829 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Feb 2015 12:11:56 -0800 Subject: [PATCH 2/3] Revise text with knowledge learned since proposed --- text/0517-io-os-reform.md | 179 ++++++++++++++++++++++---------------- 1 file changed, 105 insertions(+), 74 deletions(-) diff --git a/text/0517-io-os-reform.md b/text/0517-io-os-reform.md index b89aae0155a..28ceb05506f 100644 --- a/text/0517-io-os-reform.md +++ b/text/0517-io-os-reform.md @@ -1245,100 +1245,131 @@ elsewhere. #### TCP [TCP]: #tcp -For `TcpStream`, the changes are most easily expressed by giving the signatures directly: +The current `TcpStream` struct will be pared back from where it is today to the +following interface: ```rust // TcpStream, which contains both a reader and a writer impl TcpStream { - fn connect(addr: A) -> IoResult; - fn connect_deadline(addr: A, deadline: D) -> IoResult where - A: ToSocketAddr, D: IntoDeadline; - - fn reader(&mut self) -> &mut TcpReader; - fn writer(&mut self) -> &mut TcpWriter; - fn split(self) -> (TcpReader, TcpWriter); - - fn peer_addr(&mut self) -> IoResult; - fn socket_addr(&mut self) -> IoResult; -} - -impl Reader for TcpStream { ... } -impl Writer for TcpStream { ... } - -impl Reader for Deadlined { ... } -impl Writer for Deadlined { ... } - -// TcpReader - -impl Reader for TcpReader { ... } -impl Reader for Deadlined { ... } - -impl TcpReader { - fn peer_addr(&mut self) -> IoResult; - fn socket_addr(&mut self) -> IoResult; - - fn shutdown_token(&mut self) -> ShutdownToken; + fn connect(addr: &A) -> io::Result; + fn peer_addr(&mut self) -> io::Result; + fn socket_addr(&mut self) -> io::Result; + fn shutdown(&mut self, how: Shutdown) -> io::Result<()>; + fn duplicate(&self) -> io::Result; } -// TcpWriter - -impl Writer for TcpWriter { ... } -impl Writer for Deadlined { ... } +impl Read for TcpStream { ... } +impl Write for TcpStream { ... } +impl<'a> Read for &'a TcpStream { ... } +impl<'a> Write for &'a TcpStream { ... } +#[cfg(unix)] impl AsRawFd for TcpStream { ... } +#[cfg(windows)] impl AsRawSocket for TcpStream { ... } +``` -impl TcpWriter { - fn peer_addr(&mut self) -> IoResult; - fn socket_addr(&mut self) -> IoResult; +* `clone` has been replaced with a `duplicate` function. The implementation of + `duplicate` will map to using `dup` on Unix platforms and + `WSADuplicateSocket` on Windows platforms. The `TcpStream` itself will no + longer be reference counted itself under the hood. +* `close_{read,write}` are both removed in favor of binding the `shutdown` + function directly on sockets. This will map to the `shutdown` function on both + Unix and Windows. +* `set_timeout` has been removed for now (as well as other timeout-related + functions). It is likely that this may come back soon as a binding to + `setsockopt` to the `SO_RCVTIMEO` and `SO_SNDTIMEO` options. This RFC does not + currently proposed adding them just yet, however. +* Implementations of `Read` and `Write` are provided for `&TcpStream`. These + implementations are not necessarily ergonomic to call (requires taking an + explicit reference), but they express the ability to concurrently read and + write from a `TcpStream` + +Various other options such as `nodelay` and `keepalive` will be left +`#[unstable]` for now. + +The `TcpAcceptor` struct will be removed and all functionality will be folded +into the `TcpListener` structure. Specifically, this will be the resulting API: - fn shutdown_token(&mut self) -> ShutdownToken; +```rust +impl TcpListener { + fn bind(addr: &A) -> io::Result; + fn socket_addr(&mut self) -> io::Result; + fn duplicate(&self) -> io::Result; + fn accept(&self) -> io::Result<(TcpStream, SocketAddr)>; + fn incoming(&self) -> Incoming; } -// ShutdownToken - -impl ShutdownToken { - fn shutdown(self); +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + ... } - -impl Clone for ShutdownToken { ... } +#[cfg(unix)] impl AsRawFd for TcpListener { ... } +#[cfg(windows)] impl AsRawSocket for TcpListener { ... } ``` -The idea is that a `TcpStream` provides both a reader and a writer, -and can be used directly as such, just as it can today. However, the -two sides can also be broken apart via the `split` method, which -allows them to be shipped off to separate threads. Moreover, each side -can yield a `ShutdownToken`, a `Clone` and `Send` value that can be -used to shut down that side of the socket, cancelling any in-progress -blocking operations, much like e.g. `close_read` does today. - -The implementation of the `ShutdownToken` infrastructure should ensure -that there is essentially no cost imposed when the feature is not used --- in particular, if a `ShutdownToken` has not been requested, a -single `read` or `write` should correspond to a single syscall. - -For `TcpListener`, the only change is to rename `socket_name` to -`socket_addr`. - -For `TcpAcceptor` we will: - -* Add a `socket_addr` method. -* Possibly provide a convenience constructor for `bind`. -* Replace `close_accept` with `cancel_token()`. -* Remove `Clone`. -* Rename `IncomingConnecitons` to `Incoming`. +Some major changes from today's API include: + +* The static distinction between `TcpAcceptor` and `TcpListener` has been + removed (more on this in the [socket][Sockets] section). +* The `clone` functionality has been removed in favor of `duplicate` (same + caveats as `TcpStream`). +* The `close_accept` functionality is removed entirely. This is not currently + implemented via `shutdown` (not supported well across platforms) and is + instead implemented via `select`. This functionality can return at a later + date with a more robust interface. +* The `set_timeout` functionality has also been removed in favor of returning at + a later date in a more robust fashion with `select`. +* The `accept` function no longer takes `&mut self` and returns `SocketAddr`. + The change in mutability is done to express that multiple `accept` calls can + happen concurrently. +* For convenience the iterator does not yield the `SocketAddr` from `accept`. #### UDP [UDP]: #udp -The UDP infrastructure should change to use the new deadline -infrastructure, but should not provide `Clone`, `ShutdownToken`s, or a -reader/writer split. In addition: +The UDP infrastructre will receive a similar face-lift as the TCP infrastructure +will: -* `recv_from` should become `recv`. -* `send_to` should become `send`. -* `socket_name` should become `socket_addr`. +```rust +impl UdpSocket { + fn bind(addr: &A) -> io::Result; + fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)>; + fn send_to(&self, buf: &[u8], addr: &A) -> io::Result; + fn socket_addr(&self) -> io::Result; + fn duplicate(&self) -> io::Result; +} + +#[cfg(unix)] impl AsRawFd for UdpSocket { ... } +#[cfg(windows)] impl AsRawSocket for UdpSocket { ... } +``` -Methods like `multicast` and `ttl` are left as `#[experimental]` for -now (they are derived from libuv's design). +Some important points of note are: + +* The `send` and `recv` function take `&self` instead of `&mut self` to indicate + that they may be called safely in concurrent contexts. +* All configuration options such as `multicast` and `ttl` are left as + `#[unstable]` for now. +* All timeout support is removed. This may come back in the form of `setsockopt` + (as with TCP streams) or with a more general implementation of `select`. +* `clone` functionality has been replaced with `duplicate`. + +#### Sockets +[Sockets]: #sockets + +The current constructors for `TcpStream`, `TcpListener`, and `UdpSocket` are +largely "convenience constructors" as they do not expose the underlying details +that a socket can be configured before it is bound, connected, or listened on. +One of the more frequent configuration options is `SO_REUSEADDR` which is set by +default for `TcpListener` currently. + +This RFC leaves it as an open question how best to implement this +pre-configuration. The constructors today will likely remain no matter what as +convenience constructors and a new structure would implement consuming methods +to transform itself to each of the various `TcpStream`, `TcpListener`, and +`UdpSocket`. + +This RFC does, however, recommend not adding multiple constructors to the +various types to set various configuration options. This pattern is best +expressed via a flexible socket type to be added at a future date. #### Addresses [Addresses]: #addresses From cb10c25968502d27b4f7c62de1d8439ab0505014 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Feb 2015 15:00:48 -0800 Subject: [PATCH 3/3] Clarify that types are Send/Sync Also remove some `&mut self` methods as only `&self` is necessary. --- text/0517-io-os-reform.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/text/0517-io-os-reform.md b/text/0517-io-os-reform.md index 28ceb05506f..ba23db65d47 100644 --- a/text/0517-io-os-reform.md +++ b/text/0517-io-os-reform.md @@ -1253,9 +1253,9 @@ following interface: impl TcpStream { fn connect(addr: &A) -> io::Result; - fn peer_addr(&mut self) -> io::Result; - fn socket_addr(&mut self) -> io::Result; - fn shutdown(&mut self, how: Shutdown) -> io::Result<()>; + fn peer_addr(&self) -> io::Result; + fn socket_addr(&self) -> io::Result; + fn shutdown(&self, how: Shutdown) -> io::Result<()>; fn duplicate(&self) -> io::Result; } @@ -1284,7 +1284,8 @@ impl<'a> Write for &'a TcpStream { ... } write from a `TcpStream` Various other options such as `nodelay` and `keepalive` will be left -`#[unstable]` for now. +`#[unstable]` for now. The `TcpStream` structure will also adhere to both `Send` +and `Sync`. The `TcpAcceptor` struct will be removed and all functionality will be folded into the `TcpListener` structure. Specifically, this will be the resulting API: @@ -1292,7 +1293,7 @@ into the `TcpListener` structure. Specifically, this will be the resulting API: ```rust impl TcpListener { fn bind(addr: &A) -> io::Result; - fn socket_addr(&mut self) -> io::Result; + fn socket_addr(&self) -> io::Result; fn duplicate(&self) -> io::Result; fn accept(&self) -> io::Result<(TcpStream, SocketAddr)>; fn incoming(&self) -> Incoming; @@ -1323,11 +1324,13 @@ Some major changes from today's API include: happen concurrently. * For convenience the iterator does not yield the `SocketAddr` from `accept`. +The `TcpListener` type will also adhere to `Send` and `Sync`. + #### UDP [UDP]: #udp -The UDP infrastructre will receive a similar face-lift as the TCP infrastructure -will: +The UDP infrastructure will receive a similar face-lift as the TCP +infrastructure will: ```rust impl UdpSocket { @@ -1352,6 +1355,8 @@ Some important points of note are: (as with TCP streams) or with a more general implementation of `select`. * `clone` functionality has been replaced with `duplicate`. +The `UdpSocket` type will adhere to both `Send` and `Sync`. + #### Sockets [Sockets]: #sockets