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_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 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 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 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 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 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 security::check_socket_sendmsg_access(current_task, &self.socket)?;
190 let bytes_read_before = data.bytes_read();
191
192 let mut op = || {
194 let offset_before = data.bytes_read();
195 let sent_bytes = self.socket.write_unchecked(
196 current_task,
197 data,
198 &mut dest_address,
199 &mut ancillary_data,
200 )?;
201 debug_assert!(data.bytes_read() - offset_before == sent_bytes);
202 if data.available() > 0 {
203 return error!(EAGAIN);
204 }
205 Ok(())
206 };
207
208 let result = if flags.contains(SocketMessageFlags::DONTWAIT) {
209 op()
210 } else {
211 let deadline = self.socket.send_timeout().map(zx::MonotonicInstant::after);
212 file.blocking_op(current_task, FdEvents::POLLOUT | FdEvents::POLLHUP, deadline, op)
213 };
214
215 let bytes_written = data.bytes_read() - bytes_read_before;
216 if bytes_written == 0 {
217 result?;
220 }
221 Ok(bytes_written)
222 }
223
224 pub fn recvmsg(
233 &self,
234 current_task: &CurrentTask,
235 file: &FileObject,
236 data: &mut dyn OutputBuffer,
237 flags: SocketMessageFlags,
238 deadline: Option<zx::MonotonicInstant>,
239 ) -> Result<MessageReadInfo, Errno> {
240 security::check_socket_recvmsg_access(current_task, &self.socket)?;
241 let mut read_info = MessageReadInfo::default();
243
244 let mut op = || {
245 let can_wait_all =
246 self.socket.read_and_append_unchecked(current_task, &mut read_info, data, flags)?;
247
248 let should_wait_all = self.socket.socket_type == SocketType::Stream
249 && flags.contains(SocketMessageFlags::WAITALL)
250 && !flags.contains(SocketMessageFlags::PEEK)
251 && can_wait_all
252 && !self.socket.query_events(current_task)?.contains(FdEvents::POLLHUP);
253 if should_wait_all && data.available() > 0 {
254 return error!(EAGAIN);
255 }
256 Ok(())
257 };
258
259 let dont_wait =
260 flags.intersects(SocketMessageFlags::DONTWAIT | SocketMessageFlags::ERRQUEUE);
261 let result = if dont_wait {
262 op()
263 } else {
264 let deadline =
265 deadline.or_else(|| self.socket.receive_timeout().map(zx::MonotonicInstant::after));
266 file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, deadline, op)
267 };
268
269 if read_info.bytes_read == 0 {
270 result?;
273 }
274 Ok(read_info)
275 }
276}