Skip to main content

starnix_core/vfs/socket/
socket_file.rs

1// Copyright 2021 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
5use crate::security;
6use crate::task::{CurrentTask, EventHandler, WaitCanceler, Waiter};
7use crate::vfs::buffers::{AncillaryData, InputBuffer, MessageReadInfo, OutputBuffer};
8use crate::vfs::file_server::serve_file;
9use crate::vfs::socket::{
10    Socket, SocketAddress, SocketDomain, SocketHandle, SocketMessageFlags, SocketProtocol,
11    SocketType,
12};
13use crate::vfs::{
14    Anon, DowncastedFile, FileHandle, FileObject, FileObjectState, FileOps, FsNodeFlags,
15    FsNodeInfo, fileops_impl_nonseekable, fileops_impl_noop_sync,
16};
17use starnix_syscalls::{SyscallArg, SyscallResult};
18use starnix_uapi::auth::Credentials;
19use starnix_uapi::error;
20use starnix_uapi::errors::{Errno, errno};
21use starnix_uapi::file_mode::mode;
22use starnix_uapi::open_flags::OpenFlags;
23use starnix_uapi::vfs::FdEvents;
24
25use super::socket_fs;
26
27pub struct SocketFile {
28    pub(super) socket: SocketHandle,
29}
30
31impl SocketFile {
32    /// Creates a `FileHandle` referring to a socket.
33    ///
34    /// # Parameters
35    /// - `current_task`: The current task.
36    /// - `socket`: The socket to refer to.
37    /// - `open_flags`: The `OpenFlags` which are used to create the `FileObject`.
38    /// - `kernel_private`: `true` if the socket will be used internally by the kernel, and should
39    ///   therefore not be security labeled nor access-checked.
40    pub fn from_socket(
41        current_task: &CurrentTask,
42        socket: SocketHandle,
43        open_flags: OpenFlags,
44        kernel_private: bool,
45    ) -> Result<FileHandle, Errno> {
46        let fs = socket_fs(current_task.kernel());
47        let mode = mode!(IFSOCK, 0o777);
48        let flags = if kernel_private { FsNodeFlags::IS_PRIVATE } else { FsNodeFlags::empty() };
49        let node = fs.create_node_with_flags(
50            None,
51            Anon::new_for_socket(),
52            FsNodeInfo::new(mode, current_task.current_fscred()),
53            flags,
54        );
55        socket.set_fs_node(&node);
56        security::socket_post_create(current_task, &socket);
57        Ok(FileObject::new_anonymous(current_task, SocketFile::new(socket), node, open_flags))
58    }
59
60    /// Shortcut for Socket::new plus SocketFile::from_socket.
61    pub fn new_socket(
62        current_task: &CurrentTask,
63        domain: SocketDomain,
64        socket_type: SocketType,
65        open_flags: OpenFlags,
66        protocol: SocketProtocol,
67        kernel_private: bool,
68    ) -> Result<FileHandle, Errno> {
69        {
70            let socket = Socket::new(current_task, domain, socket_type, protocol, kernel_private)?;
71            SocketFile::from_socket(current_task, socket, open_flags, kernel_private)
72        }
73    }
74
75    pub fn get_from_file(file: &FileHandle) -> Result<DowncastedFile<'_, Self>, Errno> {
76        file.downcast_file::<SocketFile>().ok_or_else(|| errno!(ENOTSOCK))
77    }
78
79    pub fn socket(&self) -> &SocketHandle {
80        &self.socket
81    }
82}
83
84impl FileOps for SocketFile {
85    fileops_impl_nonseekable!();
86    fileops_impl_noop_sync!();
87
88    fn read(
89        &self,
90        file: &FileObject,
91        current_task: &CurrentTask,
92        offset: usize,
93        data: &mut dyn OutputBuffer,
94    ) -> Result<usize, Errno> {
95        debug_assert!(offset == 0);
96        // The behavior of recv differs from read: recv will block if given a zero-size buffer when
97        // there's no data available, but read will immediately return 0.
98        if data.available() == 0 {
99            return Ok(0);
100        }
101        let info = self.recvmsg(current_task, file, data, SocketMessageFlags::empty(), None)?;
102        Ok(info.bytes_read)
103    }
104
105    fn write(
106        &self,
107        file: &FileObject,
108        current_task: &CurrentTask,
109        offset: usize,
110        data: &mut dyn InputBuffer,
111    ) -> Result<usize, Errno> {
112        debug_assert!(offset == 0);
113        self.sendmsg(current_task, file, data, None, vec![], SocketMessageFlags::empty())
114    }
115
116    fn wait_async(
117        &self,
118        _file: &FileObject,
119        current_task: &CurrentTask,
120        waiter: &Waiter,
121        events: FdEvents,
122        handler: EventHandler,
123    ) -> Option<WaitCanceler> {
124        Some(self.socket.wait_async(current_task, waiter, events, handler))
125    }
126
127    fn query_events(
128        &self,
129        _file: &FileObject,
130        current_task: &CurrentTask,
131    ) -> Result<FdEvents, Errno> {
132        self.socket.query_events(current_task)
133    }
134
135    fn ioctl(
136        &self,
137        file: &FileObject,
138        current_task: &CurrentTask,
139        request: u32,
140        arg: SyscallArg,
141    ) -> Result<SyscallResult, Errno> {
142        self.socket.ioctl(file, current_task, request, arg)
143    }
144
145    fn close(self: Box<Self>, _file: &FileObjectState, current_task: &CurrentTask) {
146        self.socket.close(current_task);
147    }
148
149    /// Return a handle that allows access to this file descritor through the zxio protocols.
150    ///
151    /// If None is returned, the file will act as if it was a fd to `/dev/null`.
152    fn to_handle(
153        &self,
154        file: &FileObject,
155        current_task: &CurrentTask,
156    ) -> Result<Option<zx::NullableHandle>, Errno> {
157        if let Some(handle) = self.socket.to_handle(file, current_task)? {
158            Ok(Some(handle))
159        } else {
160            serve_file(current_task, file, Credentials::root())
161                .map(|c| Some(c.0.into_channel().into()))
162        }
163    }
164}
165
166impl SocketFile {
167    pub fn new(socket: SocketHandle) -> Box<Self> {
168        Box::new(SocketFile { socket })
169    }
170
171    /// Writes the provided data into the socket in this file.
172    ///
173    /// The provided control message is
174    ///
175    /// # Parameters
176    /// - `task`: The task that the user buffers belong to.
177    /// - `file`: The file that will be used for the `blocking_op`.
178    /// - `data`: The user buffers to read data from.
179    /// - `control_bytes`: Control message bytes to write to the socket.
180    pub fn sendmsg(
181        &self,
182        current_task: &CurrentTask,
183        file: &FileObject,
184        data: &mut dyn InputBuffer,
185        mut dest_address: Option<SocketAddress>,
186        mut ancillary_data: Vec<AncillaryData>,
187        flags: SocketMessageFlags,
188    ) -> Result<usize, Errno> {
189        let bytes_read_before = data.bytes_read();
190
191        // TODO: Implement more `flags`.
192        let mut op = || {
193            let offset_before = data.bytes_read();
194            let sent_bytes =
195                self.socket.write(current_task, data, &mut dest_address, &mut ancillary_data)?;
196            debug_assert!(data.bytes_read() - offset_before == sent_bytes);
197            if data.available() > 0 {
198                return error!(EAGAIN);
199            }
200            Ok(())
201        };
202
203        let result = if flags.contains(SocketMessageFlags::DONTWAIT) {
204            op()
205        } else {
206            let deadline = self.socket.send_timeout().map(zx::MonotonicInstant::after);
207            file.blocking_op(current_task, FdEvents::POLLOUT | FdEvents::POLLHUP, deadline, op)
208        };
209
210        let bytes_written = data.bytes_read() - bytes_read_before;
211        if bytes_written == 0 {
212            // We can only return an error if no data was actually sent. If partial data was
213            // sent, swallow the error and return how much was sent.
214            result?;
215        }
216        Ok(bytes_written)
217    }
218
219    /// Reads data from the socket in this file into `data`.
220    ///
221    /// # Parameters
222    /// - `file`: The file that will be used to wait if necessary.
223    /// - `task`: The task that the user buffers belong to.
224    /// - `data`: The user buffers to write to.
225    ///
226    /// Returns the number of bytes read, as well as any control message that was encountered.
227    pub fn recvmsg(
228        &self,
229        current_task: &CurrentTask,
230        file: &FileObject,
231        data: &mut dyn OutputBuffer,
232        flags: SocketMessageFlags,
233        deadline: Option<zx::MonotonicInstant>,
234    ) -> Result<MessageReadInfo, Errno> {
235        // TODO: Implement more `flags`.
236        let mut read_info = MessageReadInfo::default();
237
238        let mut op = || {
239            let mut info = self.socket.read(current_task, data, flags)?;
240            read_info.append(&mut info);
241            read_info.address = info.address;
242
243            let should_wait_all = self.socket.socket_type == SocketType::Stream
244                && flags.contains(SocketMessageFlags::WAITALL)
245                && !self.socket.query_events(current_task)?.contains(FdEvents::POLLHUP);
246            if should_wait_all && data.available() > 0 {
247                return error!(EAGAIN);
248            }
249            Ok(())
250        };
251
252        let dont_wait =
253            flags.intersects(SocketMessageFlags::DONTWAIT | SocketMessageFlags::ERRQUEUE);
254        let result = if dont_wait {
255            op()
256        } else {
257            let deadline =
258                deadline.or_else(|| self.socket.receive_timeout().map(zx::MonotonicInstant::after));
259            file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, deadline, op)
260        };
261
262        if read_info.bytes_read == 0 {
263            // We can only return an error if no data was actually read. If partial data was
264            // read, swallow the error and return how much was read.
265            result?;
266        }
267        Ok(read_info)
268    }
269}