1use crate::task::{CurrentTask, EventHandler, WaitCanceler, WaitQueue, Waiter};
6use crate::vfs::FileHandle;
7use crate::vfs::buffers::{AncillaryData, InputBuffer, MessageReadInfo, OutputBuffer};
8use crate::vfs::socket::{
9 AcceptQueue, DEFAULT_LISTEN_BACKLOG, Socket, SocketAddress, SocketDomain, SocketHandle,
10 SocketMessageFlags, SocketOps, SocketPeer, SocketProtocol, SocketShutdownFlags, SocketType,
11};
12use starnix_sync::{
13 FileOpsCore, LockDepGuard, LockDepMutex, LockEqualOrBefore, Locked, VsockSocketInnerLock,
14 allow_subclass,
15};
16use starnix_uapi::auth::Credentials;
17use starnix_uapi::errors::Errno;
18use starnix_uapi::open_flags::OpenFlags;
19use starnix_uapi::vfs::FdEvents;
20use starnix_uapi::{errno, error, ucred};
21
22pub struct VsockSocket {
26 inner: LockDepMutex<VsockSocketInner, VsockSocketInnerLock>,
27}
28
29struct VsockSocketInner {
30 address: Option<SocketAddress>,
32
33 waiters: WaitQueue,
35
36 state: VsockSocketState,
38}
39
40enum VsockSocketState {
41 Disconnected,
43
44 Listening(AcceptQueue),
46
47 Connected { file: FileHandle, peer_addr: SocketAddress },
49
50 Closed,
52}
53
54fn downcast_socket_to_vsock(socket: &Socket) -> &VsockSocket {
55 socket.downcast_socket::<VsockSocket>().unwrap()
60}
61
62impl VsockSocket {
63 pub fn new(_socket_type: SocketType) -> VsockSocket {
64 VsockSocket {
65 inner: VsockSocketInner {
66 address: None,
67 waiters: WaitQueue::default(),
68 state: VsockSocketState::Disconnected,
69 }
70 .into(),
71 }
72 }
73
74 fn lock(&self) -> LockDepGuard<'_, VsockSocketInner> {
76 self.inner.lock()
77 }
78}
79
80impl SocketOps for VsockSocket {
81 fn connect(
84 &self,
85 _locked: &mut Locked<FileOpsCore>,
86 _socket: &SocketHandle,
87 _current_task: &CurrentTask,
88 _peer: SocketPeer,
89 ) -> Result<(), Errno> {
90 error!(EPROTOTYPE)
91 }
92
93 fn listen(
94 &self,
95 _locked: &mut Locked<FileOpsCore>,
96 _socket: &Socket,
97 backlog: i32,
98 _credentials: ucred,
99 ) -> Result<(), Errno> {
100 let mut inner = self.lock();
101 let is_bound = inner.address.is_some();
102 let backlog = if backlog < 0 { DEFAULT_LISTEN_BACKLOG } else { backlog as usize };
103 match &mut inner.state {
104 VsockSocketState::Disconnected if is_bound => {
105 inner.state = VsockSocketState::Listening(AcceptQueue::new(backlog));
106 Ok(())
107 }
108 VsockSocketState::Listening(queue) => {
109 queue.set_backlog(backlog)?;
110 Ok(())
111 }
112 _ => error!(EINVAL),
113 }
114 }
115
116 fn accept(
117 &self,
118 _locked: &mut Locked<FileOpsCore>,
119 socket: &Socket,
120 _current_task: &CurrentTask,
121 ) -> Result<SocketHandle, Errno> {
122 match socket.socket_type {
123 SocketType::Stream | SocketType::SeqPacket => {}
124 _ => return error!(EOPNOTSUPP),
125 }
126 let mut inner = self.lock();
127 let queue = match &mut inner.state {
128 VsockSocketState::Listening(queue) => queue,
129 _ => return error!(EINVAL),
130 };
131 let socket = queue.sockets.pop_front().ok_or_else(|| errno!(EAGAIN))?;
132 Ok(socket)
133 }
134
135 fn bind(
136 &self,
137 _locked: &mut Locked<FileOpsCore>,
138 _socket: &Socket,
139 _current_task: &CurrentTask,
140 socket_address: SocketAddress,
141 ) -> Result<(), Errno> {
142 match socket_address {
143 SocketAddress::Vsock { .. } => {}
144 _ => return error!(EINVAL),
145 }
146 let mut inner = self.lock();
147 if inner.address.is_some() {
148 return error!(EINVAL);
149 }
150 inner.address = Some(socket_address);
151 Ok(())
152 }
153
154 fn read(
155 &self,
156 locked: &mut Locked<FileOpsCore>,
157 _socket: &Socket,
158 current_task: &CurrentTask,
159 data: &mut dyn OutputBuffer,
160 _flags: SocketMessageFlags,
161 ) -> Result<MessageReadInfo, Errno> {
162 let (address, file) = {
163 let inner = self.lock();
164 let address = inner.address.clone();
165
166 match &inner.state {
167 VsockSocketState::Connected { file, .. } => (address, file.clone()),
168 _ => return error!(EBADF),
169 }
170 };
171 let bytes_read = current_task
172 .override_creds(Credentials::root(), || file.read(locked, current_task, data))?;
173 Ok(MessageReadInfo {
174 bytes_read,
175 message_length: bytes_read,
176 address,
177 ancillary_data: vec![],
178 })
179 }
180
181 fn write(
182 &self,
183 locked: &mut Locked<FileOpsCore>,
184 _socket: &Socket,
185 current_task: &CurrentTask,
186 data: &mut dyn InputBuffer,
187 _dest_address: &mut Option<SocketAddress>,
188 _ancillary_data: &mut Vec<AncillaryData>,
189 ) -> Result<usize, Errno> {
190 let file = {
191 let inner = self.lock();
192 match &inner.state {
193 VsockSocketState::Connected { file, .. } => file.clone(),
194 _ => return error!(EBADF),
195 }
196 };
197 current_task.override_creds(Credentials::root(), || file.write(locked, current_task, data))
198 }
199
200 fn wait_async(
201 &self,
202 locked: &mut Locked<FileOpsCore>,
203 _socket: &Socket,
204 current_task: &CurrentTask,
205 waiter: &Waiter,
206 events: FdEvents,
207 handler: EventHandler,
208 ) -> WaitCanceler {
209 let inner = self.lock();
210 match &inner.state {
211 VsockSocketState::Connected { file, .. } => file
212 .wait_async(locked, current_task, waiter, events, handler)
213 .expect("vsock socket should be connected to a file that can be waited on"),
214 _ => inner.waiters.wait_async_fd_events(waiter, events, handler),
215 }
216 }
217
218 fn query_events(
219 &self,
220 locked: &mut Locked<FileOpsCore>,
221 _socket: &Socket,
222 current_task: &CurrentTask,
223 ) -> Result<FdEvents, Errno> {
224 self.lock().query_events(locked, current_task)
225 }
226
227 fn shutdown(
228 &self,
229 _locked: &mut Locked<FileOpsCore>,
230 _socket: &Socket,
231 _how: SocketShutdownFlags,
232 ) -> Result<(), Errno> {
233 self.lock().state = VsockSocketState::Closed;
234 Ok(())
235 }
236
237 fn close(
238 &self,
239 locked: &mut Locked<FileOpsCore>,
240 _current_task: &CurrentTask,
241 socket: &Socket,
242 ) {
243 self.shutdown(locked, socket, SocketShutdownFlags::READ | SocketShutdownFlags::WRITE)
245 .unwrap();
246 }
247
248 fn getsockname(
249 &self,
250 _locked: &mut Locked<FileOpsCore>,
251 socket: &Socket,
252 ) -> Result<SocketAddress, Errno> {
253 let inner = self.lock();
254 if let Some(address) = &inner.address {
255 Ok(address.clone())
256 } else {
257 Ok(SocketAddress::default_for_domain(socket.domain))
258 }
259 }
260
261 fn getpeername(
262 &self,
263 _locked: &mut Locked<FileOpsCore>,
264 _socket: &Socket,
265 ) -> Result<SocketAddress, Errno> {
266 let inner = self.lock();
267 match &inner.state {
268 VsockSocketState::Connected { peer_addr, .. } => Ok(peer_addr.clone()),
269 _ => {
270 error!(ENOTCONN)
271 }
272 }
273 }
274}
275
276impl VsockSocket {
277 pub fn remote_connection<L>(
278 &self,
279 locked: &mut Locked<L>,
280 socket: &Socket,
281 current_task: &CurrentTask,
282 file: FileHandle,
283 ) -> Result<(), Errno>
284 where
285 L: LockEqualOrBefore<FileOpsCore>,
286 {
287 assert!(file.flags().contains(OpenFlags::NONBLOCK));
290 if socket.socket_type != SocketType::Stream {
291 return error!(ENOTSUP);
292 }
293 if socket.domain != SocketDomain::Vsock {
294 return error!(EINVAL);
295 }
296
297 let mut inner = self.lock();
298 match &mut inner.state {
299 VsockSocketState::Listening(queue) => {
300 if queue.sockets.len() >= queue.backlog {
301 return error!(EAGAIN);
302 }
303 let remote_socket = Socket::new(
304 locked,
305 current_task,
306 SocketDomain::Vsock,
307 SocketType::Stream,
308 SocketProtocol::default(),
309 true,
310 )?;
311 let _token = allow_subclass();
314 downcast_socket_to_vsock(&remote_socket).lock().state =
315 VsockSocketState::Connected {
316 file,
317 peer_addr: SocketAddress::Vsock {
318 port: u32::MAX,
319 cid: starnix_uapi::VMADDR_CID_HOST,
320 },
321 };
322 queue.sockets.push_back(remote_socket);
323 inner.waiters.notify_fd_events(FdEvents::POLLIN);
324 Ok(())
325 }
326 _ => error!(EINVAL),
327 }
328 }
329}
330
331impl VsockSocketInner {
332 fn query_events<L>(
333 &self,
334 locked: &mut Locked<L>,
335 current_task: &CurrentTask,
336 ) -> Result<FdEvents, Errno>
337 where
338 L: LockEqualOrBefore<FileOpsCore>,
339 {
340 Ok(match &self.state {
341 VsockSocketState::Disconnected => FdEvents::empty(),
342 VsockSocketState::Connected { file, .. } => current_task
343 .override_creds(Credentials::root(), || file.query_events(locked, current_task))?,
344 VsockSocketState::Listening(queue) => {
345 if !queue.sockets.is_empty() {
346 FdEvents::POLLIN
347 } else {
348 FdEvents::empty()
349 }
350 }
351 VsockSocketState::Closed => FdEvents::POLLHUP,
352 })
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359 use crate::fs::fuchsia::create_fuchsia_pipe;
360 use crate::mm::PAGE_SIZE;
361 use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
362 use crate::testing::spawn_kernel_and_run;
363 use crate::vfs::EpollFileObject;
364 use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
365 use crate::vfs::socket::SocketFile;
366 use futures::executor::block_on;
367 use starnix_sync::Unlocked;
368 use starnix_uapi::vfs::EpollEvent;
369 use syncio::Zxio;
370
371 #[::fuchsia::test]
372 async fn test_vsock_socket() {
373 spawn_kernel_and_run(async |locked, current_task| {
374 let (fs1, fs2) = fidl::Socket::create_stream();
375 const VSOCK_PORT: u32 = 5555;
376
377 let listen_socket = Socket::new(
378 locked,
379 ¤t_task,
380 SocketDomain::Vsock,
381 SocketType::Stream,
382 SocketProtocol::default(),
383 false,
384 )
385 .expect("Failed to create socket.");
386 let vsock_ns = current_task.running_state().abstract_vsock_namespace.clone();
387 vsock_ns
388 .bind(locked, ¤t_task, VSOCK_PORT, &listen_socket)
389 .expect("Failed to bind socket.");
390 listen_socket.listen(locked, ¤t_task, 10).expect("Failed to listen.");
391
392 let listen_socket =
393 vsock_ns.lookup(&VSOCK_PORT).expect("Failed to look up listening socket.");
394 let remote = create_fuchsia_pipe(
395 locked,
396 ¤t_task,
397 fs2,
398 OpenFlags::RDWR | OpenFlags::NONBLOCK,
399 )
400 .unwrap();
401 listen_socket
402 .downcast_socket::<VsockSocket>()
403 .unwrap()
404 .remote_connection(locked, &listen_socket, ¤t_task, remote)
405 .unwrap();
406
407 let server_socket = listen_socket.accept(locked, ¤t_task).unwrap();
408
409 let test_bytes_in: [u8; 5] = [0, 1, 2, 3, 4];
410 assert_eq!(fs1.write(&test_bytes_in[..]).unwrap(), test_bytes_in.len());
411 let mut buffer_iterator = VecOutputBuffer::new(*PAGE_SIZE as usize);
412 let read_message_info = server_socket
413 .read(locked, ¤t_task, &mut buffer_iterator, SocketMessageFlags::empty())
414 .unwrap();
415 assert_eq!(read_message_info.bytes_read, test_bytes_in.len());
416 assert_eq!(buffer_iterator.data(), test_bytes_in);
417
418 let test_bytes_out: [u8; 10] = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
419 let mut buffer_iterator = VecInputBuffer::new(&test_bytes_out);
420 server_socket
421 .write(locked, ¤t_task, &mut buffer_iterator, &mut None, &mut vec![])
422 .unwrap();
423 assert_eq!(buffer_iterator.bytes_read(), test_bytes_out.len());
424
425 let mut read_back_buf = [0u8; 100];
426 assert_eq!(test_bytes_out.len(), fs1.read(&mut read_back_buf).unwrap());
427 assert_eq!(&read_back_buf[..test_bytes_out.len()], &test_bytes_out);
428
429 server_socket.close(locked, ¤t_task);
430 listen_socket.close(locked, ¤t_task);
431 })
432 .await;
433 }
434
435 #[::fuchsia::test]
436 async fn test_vsock_write_while_read() {
437 spawn_kernel_and_run(async |locked, current_task| {
438 let kernel = current_task.kernel();
439 let (fs1, fs2) = fidl::Socket::create_stream();
440 let socket = Socket::new(
441 locked,
442 ¤t_task,
443 SocketDomain::Vsock,
444 SocketType::Stream,
445 SocketProtocol::default(),
446 false,
447 )
448 .expect("Failed to create socket.");
449 let remote = create_fuchsia_pipe(
450 locked,
451 ¤t_task,
452 fs2,
453 OpenFlags::RDWR | OpenFlags::NONBLOCK,
454 )
455 .unwrap();
456 downcast_socket_to_vsock(&socket).lock().state = VsockSocketState::Connected {
457 file: remote,
458 peer_addr: SocketAddress::Vsock {
459 port: u32::MAX,
460 cid: starnix_uapi::VMADDR_CID_HOST,
461 },
462 };
463 let socket_file =
464 SocketFile::from_socket(locked, ¤t_task, socket, OpenFlags::RDWR, false)
465 .expect("Failed to create socket file.");
466
467 const XFER_SIZE: usize = 42;
468
469 let socket_clone = socket_file.clone();
470 let closure = move |locked: &mut Locked<Unlocked>, current_task: &CurrentTask| {
471 let bytes_read = socket_clone
472 .read(locked, current_task, &mut VecOutputBuffer::new(XFER_SIZE))
473 .unwrap();
474 assert_eq!(XFER_SIZE, bytes_read);
475 };
476 let (result, req) =
477 SpawnRequestBuilder::new().with_sync_closure(closure).build_with_async_result();
478 kernel.kthreads.spawner().spawn_from_request(req);
479
480 std::thread::sleep(std::time::Duration::from_secs(2));
482
483 socket_file
484 .write(locked, ¤t_task, &mut VecInputBuffer::new(&[0; XFER_SIZE]))
485 .unwrap();
486
487 let mut buffer = [0u8; 1024];
488 assert_eq!(XFER_SIZE, fs1.read(&mut buffer).unwrap());
489 assert_eq!(XFER_SIZE, fs1.write(&buffer[..XFER_SIZE]).unwrap());
490 block_on(result).unwrap();
491 })
492 .await;
493 }
494
495 #[::fuchsia::test]
496 async fn test_vsock_poll() {
497 spawn_kernel_and_run(async |locked, current_task| {
498 let (client, server) = zx::Socket::create_stream();
499 let pipe = create_fuchsia_pipe(locked, ¤t_task, client, OpenFlags::RDWR)
500 .expect("create_fuchsia_pipe");
501 let server_zxio = Zxio::create(server.into_handle()).expect("Zxio::create");
502 let socket_object = Socket::new(
503 locked,
504 ¤t_task,
505 SocketDomain::Vsock,
506 SocketType::Stream,
507 SocketProtocol::default(),
508 false,
509 )
510 .expect("Failed to create socket.");
511 downcast_socket_to_vsock(&socket_object).lock().state = VsockSocketState::Connected {
512 file: pipe,
513 peer_addr: SocketAddress::Vsock {
514 port: u32::MAX,
515 cid: starnix_uapi::VMADDR_CID_HOST,
516 },
517 };
518 let socket = SocketFile::from_socket(
519 locked,
520 ¤t_task,
521 socket_object.clone(),
522 OpenFlags::RDWR,
523 false,
524 )
525 .expect("Failed to create socket file.");
526
527 assert_eq!(
528 socket.query_events(locked, ¤t_task),
529 Ok(FdEvents::POLLOUT | FdEvents::POLLWRNORM)
530 );
531
532 let epoll_object = EpollFileObject::new_file(locked, ¤t_task);
533 let epoll_file = epoll_object.downcast_file::<EpollFileObject>().unwrap();
534 let event = EpollEvent::new(FdEvents::POLLIN, 0);
535 epoll_file
536 .add(locked, ¤t_task, &socket, &epoll_object, event)
537 .expect("poll_file.add");
538
539 let fds = epoll_file
540 .wait(locked, ¤t_task, 1, zx::MonotonicInstant::ZERO)
541 .expect("wait");
542 assert!(fds.is_empty());
543
544 assert_eq!(server_zxio.write(&[0]).expect("write"), 1);
545
546 assert_eq!(
547 socket.query_events(locked, ¤t_task),
548 Ok(FdEvents::POLLOUT
549 | FdEvents::POLLWRNORM
550 | FdEvents::POLLIN
551 | FdEvents::POLLRDNORM)
552 );
553 let fds = epoll_file
554 .wait(locked, ¤t_task, 1, zx::MonotonicInstant::ZERO)
555 .expect("wait");
556 assert_eq!(fds.len(), 1);
557
558 assert_eq!(
559 socket.read(locked, ¤t_task, &mut VecOutputBuffer::new(64)).expect("read"),
560 1
561 );
562
563 assert_eq!(
564 socket.query_events(locked, ¤t_task),
565 Ok(FdEvents::POLLOUT | FdEvents::POLLWRNORM)
566 );
567 let fds = epoll_file
568 .wait(locked, ¤t_task, 1, zx::MonotonicInstant::ZERO)
569 .expect("wait");
570 assert!(fds.is_empty());
571 })
572 .await;
573 }
574}