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