summaryrefslogtreecommitdiffstats
path: root/third_party/rust/fuchsia-zircon/src/socket.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/fuchsia-zircon/src/socket.rs')
-rw-r--r--third_party/rust/fuchsia-zircon/src/socket.rs126
1 files changed, 126 insertions, 0 deletions
diff --git a/third_party/rust/fuchsia-zircon/src/socket.rs b/third_party/rust/fuchsia-zircon/src/socket.rs
new file mode 100644
index 0000000000..c93e98cb73
--- /dev/null
+++ b/third_party/rust/fuchsia-zircon/src/socket.rs
@@ -0,0 +1,126 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Type-safe bindings for Zircon sockets.
+
+use {AsHandleRef, HandleBased, Handle, HandleRef, Peered};
+use {sys, Status, ok};
+
+use std::ptr;
+
+/// An object representing a Zircon
+/// [socket](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Message-Passing_Sockets-and-Channels).
+///
+/// As essentially a subtype of `Handle`, it can be freely interconverted.
+#[derive(Debug, Eq, PartialEq)]
+pub struct Socket(Handle);
+impl_handle_based!(Socket);
+impl Peered for Socket {}
+
+impl Socket {
+ /// Create a socket, accessed through a pair of endpoints. Data written
+ /// into one may be read from the other.
+ ///
+ /// Wraps
+ /// [zx_socket_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_create.md).
+ pub fn create() -> Result<(Socket, Socket), Status> {
+ unsafe {
+ let mut out0 = 0;
+ let mut out1 = 0;
+ let opts = 0;
+ let status = sys::zx_socket_create(opts, &mut out0, &mut out1);
+ ok(status)?;
+ Ok((
+ Self::from(Handle::from_raw(out0)),
+ Self::from(Handle::from_raw(out1))
+ ))
+ }
+ }
+
+ /// Write the given bytes into the socket.
+ /// Return value (on success) is number of bytes actually written.
+ ///
+ /// Wraps
+ /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md).
+ pub fn write(&self, bytes: &[u8]) -> Result<usize, Status> {
+ let mut actual = 0;
+ let opts = 0;
+ let status = unsafe {
+ sys::zx_socket_write(self.raw_handle(), opts, bytes.as_ptr(), bytes.len(),
+ &mut actual)
+ };
+ ok(status).map(|()| actual)
+ }
+
+ /// Read the given bytes from the socket.
+ /// Return value (on success) is number of bytes actually read.
+ ///
+ /// Wraps
+ /// [zx_socket_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_read.md).
+ pub fn read(&self, bytes: &mut [u8]) -> Result<usize, Status> {
+ let mut actual = 0;
+ let opts = 0;
+ let status = unsafe {
+ sys::zx_socket_read(self.raw_handle(), opts, bytes.as_mut_ptr(),
+ bytes.len(), &mut actual)
+ };
+ ok(status)
+ .map(|()| actual)
+ .map_err(|status| {
+ // If an error is returned then actual is undefined, so to be safe
+ // we set it to 0 and ignore any data that is set in bytes.
+ actual = 0;
+ status
+ })
+ }
+
+ /// Close half of the socket, so attempts by the other side to write will fail.
+ ///
+ /// Implements the `ZX_SOCKET_HALF_CLOSE` option of
+ /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md).
+ pub fn half_close(&self) -> Result<(), Status> {
+ let status = unsafe { sys::zx_socket_write(self.raw_handle(), sys::ZX_SOCKET_HALF_CLOSE,
+ ptr::null(), 0, ptr::null_mut()) };
+ ok(status)
+ }
+
+ pub fn outstanding_read_bytes(&self) -> Result<usize, Status> {
+ let mut outstanding = 0;
+ let status = unsafe {
+ sys::zx_socket_read(self.raw_handle(), 0, ptr::null_mut(), 0, &mut outstanding)
+ };
+ ok(status).map(|()| outstanding)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn socket_basic() {
+ let (s1, s2) = Socket::create().unwrap();
+
+ // Write in one end and read it back out the other.
+ assert_eq!(s1.write(b"hello").unwrap(), 5);
+
+ let mut read_vec = vec![0; 8];
+ assert_eq!(s2.read(&mut read_vec).unwrap(), 5);
+ assert_eq!(&read_vec[0..5], b"hello");
+
+ // Try reading when there is nothing to read.
+ assert_eq!(s2.read(&mut read_vec), Err(Status::SHOULD_WAIT));
+
+ // Close the socket from one end.
+ assert!(s1.half_close().is_ok());
+ assert_eq!(s2.read(&mut read_vec), Err(Status::BAD_STATE));
+ assert_eq!(s1.write(b"fail"), Err(Status::BAD_STATE));
+
+ // Writing in the other direction should still work.
+ assert_eq!(s1.read(&mut read_vec), Err(Status::SHOULD_WAIT));
+ assert_eq!(s2.write(b"back").unwrap(), 4);
+ assert_eq!(s1.read(&mut read_vec).unwrap(), 4);
+ assert_eq!(&read_vec[0..4], b"back");
+ }
+}