1use 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 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 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 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 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 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 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 result?;
257 }
258 Ok(bytes_written)
259 }
260
261 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 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 result?;
318 }
319 Ok(read_info)
320 }
321}