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