fuchsia_zircon/
socket.rs

1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Type-safe bindings for Zircon sockets.
6
7use {AsHandleRef, HandleBased, Handle, HandleRef, Peered};
8use {sys, Status, ok};
9
10use std::ptr;
11
12/// An object representing a Zircon
13/// [socket](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Message-Passing_Sockets-and-Channels).
14///
15/// As essentially a subtype of `Handle`, it can be freely interconverted.
16#[derive(Debug, Eq, PartialEq)]
17pub struct Socket(Handle);
18impl_handle_based!(Socket);
19impl Peered for Socket {}
20
21impl Socket {
22    /// Create a socket, accessed through a pair of endpoints. Data written
23    /// into one may be read from the other.
24    ///
25    /// Wraps
26    /// [zx_socket_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_create.md).
27    pub fn create() -> Result<(Socket, Socket), Status> {
28        unsafe {
29            let mut out0 = 0;
30            let mut out1 = 0;
31            let opts = 0;
32            let status = sys::zx_socket_create(opts, &mut out0, &mut out1);
33            ok(status)?;
34            Ok((
35                Self::from(Handle::from_raw(out0)),
36                Self::from(Handle::from_raw(out1))
37            ))
38        }
39    }
40
41    /// Write the given bytes into the socket.
42    /// Return value (on success) is number of bytes actually written.
43    ///
44    /// Wraps
45    /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md).
46    pub fn write(&self, bytes: &[u8]) -> Result<usize, Status> {
47        let mut actual = 0;
48        let opts = 0;
49        let status = unsafe {
50            sys::zx_socket_write(self.raw_handle(), opts, bytes.as_ptr(), bytes.len(),
51                &mut actual)
52        };
53        ok(status).map(|()| actual)
54    }
55
56    /// Read the given bytes from the socket.
57    /// Return value (on success) is number of bytes actually read.
58    ///
59    /// Wraps
60    /// [zx_socket_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_read.md).
61    pub fn read(&self, bytes: &mut [u8]) -> Result<usize, Status> {
62        let mut actual = 0;
63        let opts = 0;
64        let status = unsafe {
65            sys::zx_socket_read(self.raw_handle(), opts, bytes.as_mut_ptr(),
66                bytes.len(), &mut actual)
67        };
68        ok(status)
69            .map(|()| actual)
70            .map_err(|status| {
71                // If an error is returned then actual is undefined, so to be safe
72                // we set it to 0 and ignore any data that is set in bytes.
73                actual = 0;
74                status
75            })
76    }
77
78    /// Close half of the socket, so attempts by the other side to write will fail.
79    ///
80    /// Implements the `ZX_SOCKET_HALF_CLOSE` option of
81    /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md).
82    pub fn half_close(&self) -> Result<(), Status> {
83        let status = unsafe { sys::zx_socket_write(self.raw_handle(), sys::ZX_SOCKET_HALF_CLOSE,
84            ptr::null(), 0, ptr::null_mut()) };
85        ok(status)
86    }
87
88    pub fn outstanding_read_bytes(&self) -> Result<usize, Status> {
89        let mut outstanding = 0;
90        let status = unsafe {
91            sys::zx_socket_read(self.raw_handle(), 0, ptr::null_mut(), 0, &mut outstanding)
92        };
93        ok(status).map(|()| outstanding)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn socket_basic() {
103        let (s1, s2) = Socket::create().unwrap();
104
105        // Write in one end and read it back out the other.
106        assert_eq!(s1.write(b"hello").unwrap(), 5);
107
108        let mut read_vec = vec![0; 8];
109        assert_eq!(s2.read(&mut read_vec).unwrap(), 5);
110        assert_eq!(&read_vec[0..5], b"hello");
111
112        // Try reading when there is nothing to read.
113        assert_eq!(s2.read(&mut read_vec), Err(Status::SHOULD_WAIT));
114
115        // Close the socket from one end.
116        assert!(s1.half_close().is_ok());
117        assert_eq!(s2.read(&mut read_vec), Err(Status::BAD_STATE));
118        assert_eq!(s1.write(b"fail"), Err(Status::BAD_STATE));
119
120        // Writing in the other direction should still work.
121        assert_eq!(s1.read(&mut read_vec), Err(Status::SHOULD_WAIT));
122        assert_eq!(s2.write(b"back").unwrap(), 4);
123        assert_eq!(s1.read(&mut read_vec).unwrap(), 4);
124        assert_eq!(&read_vec[0..4], b"back");
125    }
126}