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, SpliceOutputBuffer, 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        security::file_system_resolve_security(current_task, &fs)?;
48        let mode = mode!(IFSOCK, 0o777);
49        let flags = if kernel_private { FsNodeFlags::IS_PRIVATE } else { FsNodeFlags::empty() };
50        let node = fs.create_node_with_flags(
51            None,
52            Anon::new_for_socket(),
53            FsNodeInfo::new(mode, current_task.current_fscred()),
54            flags,
55        );
56        socket.set_fs_node(&node);
57        security::socket_post_create(current_task, &socket);
58        Ok(FileObject::new_anonymous(current_task, SocketFile::new(socket), node, open_flags))
59    }
60
61    /// Shortcut for Socket::new plus SocketFile::from_socket.
62    pub fn new_socket(
63        current_task: &CurrentTask,
64        domain: SocketDomain,
65        socket_type: SocketType,
66        open_flags: OpenFlags,
67        protocol: SocketProtocol,
68        kernel_private: bool,
69    ) -> Result<FileHandle, Errno> {
70        {
71            let socket = Socket::new(current_task, domain, socket_type, protocol, kernel_private)?;
72            SocketFile::from_socket(current_task, socket, open_flags, kernel_private)
73        }
74    }
75
76    pub fn get_from_file(file: &FileHandle) -> Result<DowncastedFile<'_, Self>, Errno> {
77        file.downcast_file::<SocketFile>().ok_or_else(|| errno!(ENOTSOCK))
78    }
79
80    pub fn socket(&self) -> &SocketHandle {
81        &self.socket
82    }
83}
84
85impl FileOps for SocketFile {
86    fileops_impl_nonseekable!();
87    fileops_impl_noop_sync!();
88
89    fn read(
90        &self,
91        file: &FileObject,
92        current_task: &CurrentTask,
93        offset: usize,
94        data: &mut dyn OutputBuffer,
95    ) -> Result<usize, Errno> {
96        debug_assert!(offset == 0);
97        // The behavior of recv differs from read: recv will block if given a zero-size buffer when
98        // there's no data available, but read will immediately return 0.
99        if data.available() == 0 {
100            return Ok(0);
101        }
102        let info = self.recvmsg(current_task, file, data, SocketMessageFlags::empty(), None)?;
103        Ok(info.bytes_read)
104    }
105
106    fn splice_read(
107        &self,
108        file: &FileObject,
109        current_task: &CurrentTask,
110        offset: usize,
111        data: &mut SpliceOutputBuffer<'_>,
112        non_blocking: bool,
113    ) -> Result<usize, Errno> {
114        debug_assert!(offset == 0);
115        if data.available() == 0 {
116            return Ok(0);
117        }
118        let flags = if non_blocking
119            && self.socket.domain == SocketDomain::Unix
120            && self.socket.socket_type == SocketType::Stream
121        {
122            SocketMessageFlags::DONTWAIT
123        } else {
124            SocketMessageFlags::empty()
125        };
126        let info = self.recvmsg(current_task, file, data, flags, None)?;
127        Ok(info.bytes_read)
128    }
129
130    fn write(
131        &self,
132        file: &FileObject,
133        current_task: &CurrentTask,
134        offset: usize,
135        data: &mut dyn InputBuffer,
136    ) -> Result<usize, Errno> {
137        debug_assert!(offset == 0);
138        self.sendmsg(current_task, file, data, None, vec![], SocketMessageFlags::empty())
139    }
140
141    fn wait_async(
142        &self,
143        _file: &FileObject,
144        current_task: &CurrentTask,
145        waiter: &Waiter,
146        events: FdEvents,
147        handler: EventHandler,
148    ) -> Option<WaitCanceler> {
149        Some(self.socket.wait_async(current_task, waiter, events, handler))
150    }
151
152    fn query_events(
153        &self,
154        _file: &FileObject,
155        current_task: &CurrentTask,
156    ) -> Result<FdEvents, Errno> {
157        self.socket.query_events(current_task)
158    }
159
160    fn ioctl(
161        &self,
162        file: &FileObject,
163        current_task: &CurrentTask,
164        request: u32,
165        arg: SyscallArg,
166    ) -> Result<SyscallResult, Errno> {
167        self.socket.ioctl(file, current_task, request, arg)
168    }
169
170    fn close(self: Box<Self>, _file: &FileObjectState, current_task: &CurrentTask) {
171        self.socket.close(current_task);
172    }
173
174    /// Return a handle that allows access to this file descritor through the zxio protocols.
175    ///
176    /// If None is returned, the file will act as if it was a fd to `/dev/null`.
177    fn to_handle(
178        &self,
179        file: &FileObject,
180        current_task: &CurrentTask,
181    ) -> Result<Option<zx::NullableHandle>, Errno> {
182        if let Some(handle) = self.socket.to_handle(file, current_task)? {
183            Ok(Some(handle))
184        } else {
185            serve_file(current_task, file, Credentials::root())
186                .map(|c| Some(c.0.into_channel().into()))
187        }
188    }
189}
190
191impl SocketFile {
192    pub fn new(socket: SocketHandle) -> Box<Self> {
193        Box::new(SocketFile { socket })
194    }
195
196    /// Writes the provided data into the socket in this file.
197    ///
198    /// The provided control message is
199    ///
200    /// # Parameters
201    /// - `task`: The task that the user buffers belong to.
202    /// - `file`: The file that will be used for the `blocking_op`.
203    /// - `data`: The user buffers to read data from.
204    /// - `control_bytes`: Control message bytes to write to the socket.
205    pub fn sendmsg(
206        &self,
207        current_task: &CurrentTask,
208        file: &FileObject,
209        data: &mut dyn InputBuffer,
210        mut dest_address: Option<SocketAddress>,
211        mut ancillary_data: Vec<AncillaryData>,
212        flags: SocketMessageFlags,
213    ) -> Result<usize, Errno> {
214        security::check_socket_sendmsg_access(current_task, &self.socket)?;
215        let bytes_read_before = data.bytes_read();
216
217        // TODO: Implement more `flags`.
218        let mut op = || {
219            let offset_before = data.bytes_read();
220            let sent_bytes = self.socket.write_unchecked(
221                current_task,
222                data,
223                &mut dest_address,
224                &mut ancillary_data,
225            )?;
226            debug_assert!(data.bytes_read() - offset_before == sent_bytes);
227            if data.available() > 0 {
228                return error!(EAGAIN);
229            }
230            Ok(())
231        };
232
233        let result = if flags.contains(SocketMessageFlags::DONTWAIT) {
234            op()
235        } else {
236            let deadline = self.socket.send_timeout().map(zx::MonotonicInstant::after);
237            file.blocking_op(current_task, FdEvents::POLLOUT | FdEvents::POLLHUP, deadline, op)
238        };
239
240        let bytes_written = data.bytes_read() - bytes_read_before;
241        if bytes_written == 0 {
242            // We can only return an error if no data was actually sent. If partial data was
243            // sent, swallow the error and return how much was sent.
244            result?;
245        }
246        Ok(bytes_written)
247    }
248
249    /// Reads data from the socket in this file into `data`.
250    ///
251    /// # Parameters
252    /// - `file`: The file that will be used to wait if necessary.
253    /// - `task`: The task that the user buffers belong to.
254    /// - `data`: The user buffers to write to.
255    ///
256    /// Returns the number of bytes read, as well as any control message that was encountered.
257    pub fn recvmsg(
258        &self,
259        current_task: &CurrentTask,
260        file: &FileObject,
261        data: &mut dyn OutputBuffer,
262        flags: SocketMessageFlags,
263        deadline: Option<zx::MonotonicInstant>,
264    ) -> Result<MessageReadInfo, Errno> {
265        security::check_socket_recvmsg_access(current_task, &self.socket)?;
266        // TODO: Implement more `flags`.
267        let mut read_info = MessageReadInfo::default();
268
269        let mut op = || {
270            let can_wait_all =
271                self.socket.read_and_append_unchecked(current_task, &mut read_info, data, flags)?;
272
273            let should_wait_all = self.socket.socket_type == SocketType::Stream
274                && flags.contains(SocketMessageFlags::WAITALL)
275                && !flags.contains(SocketMessageFlags::PEEK)
276                && can_wait_all
277                && !self.socket.query_events(current_task)?.contains(FdEvents::POLLHUP);
278            if should_wait_all && data.available() > 0 {
279                return error!(EAGAIN);
280            }
281            Ok(())
282        };
283
284        let dont_wait =
285            flags.intersects(SocketMessageFlags::DONTWAIT | SocketMessageFlags::ERRQUEUE);
286        let result = if dont_wait {
287            op()
288        } else {
289            let deadline =
290                deadline.or_else(|| self.socket.receive_timeout().map(zx::MonotonicInstant::after));
291            file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, deadline, op)
292        };
293
294        if read_info.bytes_read == 0 {
295            // We can only return an error if no data was actually read. If partial data was
296            // read, swallow the error and return how much was read.
297            result?;
298        }
299        Ok(read_info)
300    }
301}