1use super::{
6 NetlinkFamily, QipcrtrSocket, SocketAddress, SocketDomain, SocketFile, SocketMessageFlags,
7 SocketProtocol, SocketShutdownFlags, SocketType, UnixSocket, VsockSocket, ZxioBackedSocket,
8 new_netlink_socket,
9};
10use crate::mm::MemoryAccessorExt;
11use crate::security;
12use crate::syscalls::time::TimeValPtr;
13use crate::task::{CurrentTask, EventHandler, WaitCanceler, Waiter};
14use crate::vfs::buffers::{AncillaryData, InputBuffer, MessageReadInfo, OutputBuffer};
15use crate::vfs::{DowncastedFile, FileHandle, FileObject, FsNodeHandle, default_ioctl};
16use starnix_logging::track_stub;
17use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, Mutex, Unlocked};
18use starnix_syscalls::{SyscallArg, SyscallResult};
19use starnix_types::time::{duration_from_timeval, timeval_from_duration};
20use starnix_types::user_buffer::UserBuffer;
21use starnix_uapi::as_any::AsAny;
22use starnix_uapi::auth::CAP_NET_RAW;
23use starnix_uapi::errors::{ENOTTY, Errno};
24use starnix_uapi::user_address::MappingMultiArchUserRef;
25use starnix_uapi::vfs::FdEvents;
26use starnix_uapi::{
27 SO_DOMAIN, SO_PROTOCOL, SO_RCVTIMEO, SO_SNDTIMEO, SO_TYPE, SOL_SOCKET, errno, error, uapi,
28};
29use std::collections::VecDeque;
30use std::sync::Arc;
31use std::sync::atomic::Ordering;
32use zerocopy::FromBytes;
33
34pub const DEFAULT_LISTEN_BACKLOG: usize = 1024;
35
36pub trait SocketOps: Send + Sync + AsAny {
37 fn get_socket_info(&self) -> Result<(SocketDomain, SocketType, SocketProtocol), Errno> {
41 error!(EINVAL)
44 }
45
46 fn connect(
49 &self,
50 locked: &mut Locked<FileOpsCore>,
51 socket: &SocketHandle,
52 current_task: &CurrentTask,
53 peer: SocketPeer,
54 ) -> Result<(), Errno>;
55
56 fn listen(
58 &self,
59 locked: &mut Locked<FileOpsCore>,
60 socket: &Socket,
61 backlog: i32,
62 credentials: uapi::ucred,
63 ) -> Result<(), Errno>;
64
65 fn accept(
68 &self,
69 locked: &mut Locked<FileOpsCore>,
70 socket: &Socket,
71 current_task: &CurrentTask,
72 ) -> Result<SocketHandle, Errno>;
73
74 fn bind(
78 &self,
79 locked: &mut Locked<FileOpsCore>,
80 socket: &Socket,
81 current_task: &CurrentTask,
82 socket_address: SocketAddress,
83 ) -> Result<(), Errno>;
84
85 fn read(
95 &self,
96 locked: &mut Locked<FileOpsCore>,
97 socket: &Socket,
98 current_task: &CurrentTask,
99 data: &mut dyn OutputBuffer,
100 flags: SocketMessageFlags,
101 ) -> Result<MessageReadInfo, Errno>;
102
103 fn write(
112 &self,
113 locked: &mut Locked<FileOpsCore>,
114 socket: &Socket,
115 current_task: &CurrentTask,
116 data: &mut dyn InputBuffer,
117 dest_address: &mut Option<SocketAddress>,
118 ancillary_data: &mut Vec<AncillaryData>,
119 ) -> Result<usize, Errno>;
120
121 fn wait_async(
132 &self,
133 locked: &mut Locked<FileOpsCore>,
134 socket: &Socket,
135 current_task: &CurrentTask,
136 waiter: &Waiter,
137 events: FdEvents,
138 handler: EventHandler,
139 ) -> WaitCanceler;
140
141 fn query_events(
143 &self,
144 locked: &mut Locked<FileOpsCore>,
145 socket: &Socket,
146 current_task: &CurrentTask,
147 ) -> Result<FdEvents, Errno>;
148
149 fn shutdown(
153 &self,
154 locked: &mut Locked<FileOpsCore>,
155 socket: &Socket,
156 how: SocketShutdownFlags,
157 ) -> Result<(), Errno>;
158
159 fn close(&self, locked: &mut Locked<FileOpsCore>, current_task: &CurrentTask, socket: &Socket);
170
171 fn getsockname(
176 &self,
177 locked: &mut Locked<FileOpsCore>,
178 socket: &Socket,
179 ) -> Result<SocketAddress, Errno>;
180
181 fn getpeername(
185 &self,
186 locked: &mut Locked<FileOpsCore>,
187 socket: &Socket,
188 ) -> Result<SocketAddress, Errno>;
189
190 fn setsockopt(
192 &self,
193 _locked: &mut Locked<FileOpsCore>,
194 _socket: &Socket,
195 _current_task: &CurrentTask,
196 _level: u32,
197 _optname: u32,
198 _optval: SockOptValue,
199 ) -> Result<(), Errno> {
200 error!(ENOPROTOOPT)
201 }
202
203 fn getsockopt(
205 &self,
206 _locked: &mut Locked<FileOpsCore>,
207 _socket: &Socket,
208 _current_task: &CurrentTask,
209 _level: u32,
210 _optname: u32,
211 _optlen: u32,
212 ) -> Result<Vec<u8>, Errno> {
213 error!(ENOPROTOOPT)
214 }
215
216 fn ioctl(
218 &self,
219 locked: &mut Locked<Unlocked>,
220 _socket: &Socket,
221 file: &FileObject,
222 current_task: &CurrentTask,
223 request: u32,
224 arg: SyscallArg,
225 ) -> Result<SyscallResult, Errno> {
226 default_ioctl(file, locked, current_task, request, arg)
227 }
228
229 fn to_handle(
233 &self,
234 _socket: &Socket,
235 _current_task: &CurrentTask,
236 ) -> Result<Option<zx::NullableHandle>, Errno> {
237 Ok(None)
238 }
239}
240
241pub struct Socket {
243 pub(super) ops: Box<dyn SocketOps>,
244
245 pub domain: SocketDomain,
247
248 pub socket_type: SocketType,
250
251 pub protocol: SocketProtocol,
253
254 state: Mutex<SocketState>,
255
256 pub security: security::SocketState,
259}
260
261#[derive(Default)]
262struct SocketState {
263 receive_timeout: Option<zx::MonotonicDuration>,
265
266 send_timeout: Option<zx::MonotonicDuration>,
268
269 fs_node: Option<FsNodeHandle>,
273}
274
275pub type SocketHandle = Arc<Socket>;
276
277#[derive(Clone)]
278pub enum SocketPeer {
279 Handle(SocketHandle),
280 Address(SocketAddress),
281}
282
283fn resolve_protocol(
287 domain: SocketDomain,
288 socket_type: SocketType,
289 protocol: SocketProtocol,
290) -> SocketProtocol {
291 if domain.is_inet() && protocol.as_raw() == 0 {
292 match socket_type {
293 SocketType::Stream => SocketProtocol::TCP,
294 SocketType::Datagram => SocketProtocol::UDP,
295 _ => protocol,
296 }
297 } else {
298 protocol
299 }
300}
301
302fn create_socket_ops(
303 locked: &mut Locked<FileOpsCore>,
304 current_task: &CurrentTask,
305 domain: SocketDomain,
306 socket_type: SocketType,
307 protocol: SocketProtocol,
308) -> Result<Box<dyn SocketOps>, Errno> {
309 match domain {
310 SocketDomain::Unix => Ok(Box::new(UnixSocket::new(socket_type))),
311 SocketDomain::Vsock => Ok(Box::new(VsockSocket::new(socket_type))),
312 SocketDomain::Inet | SocketDomain::Inet6 => {
313 if socket_type == SocketType::Raw {
316 security::check_task_capable(current_task, CAP_NET_RAW)?;
317 }
318 Ok(Box::new(ZxioBackedSocket::new(
319 locked,
320 current_task,
321 domain,
322 socket_type,
323 protocol,
324 )?))
325 }
326 SocketDomain::Netlink => {
327 let netlink_family = NetlinkFamily::from_raw(protocol.as_raw());
328 new_netlink_socket(current_task.kernel(), socket_type, netlink_family)
329 }
330 SocketDomain::Packet => {
331 security::check_task_capable(current_task, CAP_NET_RAW)?;
334 Ok(Box::new(ZxioBackedSocket::new(
335 locked,
336 current_task,
337 domain,
338 socket_type,
339 protocol,
340 )?))
341 }
342 SocketDomain::Key => {
343 track_stub!(
344 TODO("https://fxbug.dev/323365389"),
345 "Returning a UnixSocket instead of a KeySocket"
346 );
347 Ok(Box::new(UnixSocket::new(SocketType::Datagram)))
348 }
349 SocketDomain::Qipcrtr => Ok(Box::new(QipcrtrSocket::new(socket_type))),
350 }
351}
352
353#[derive(Debug)]
354pub enum SockOptValue {
355 Value(Vec<u8>),
356 User(UserBuffer),
357}
358
359impl From<Vec<u8>> for SockOptValue {
360 fn from(buffer: Vec<u8>) -> Self {
361 Self::Value(buffer)
362 }
363}
364
365impl From<UserBuffer> for SockOptValue {
366 fn from(buffer: UserBuffer) -> Self {
367 Self::User(buffer)
368 }
369}
370
371impl SockOptValue {
372 pub fn len(&self) -> usize {
373 match self {
374 Self::Value(buffer) => buffer.len(),
375 Self::User(user_buffer) => user_buffer.length,
376 }
377 }
378
379 pub fn read<T: FromBytes>(&self, current_task: &CurrentTask) -> Result<T, Errno> {
380 match self {
381 Self::Value(buffer) => {
382 T::read_from_prefix(&buffer).map_err(|_| errno!(EINVAL)).map(|(v, _)| v)
383 }
384 Self::User(user_buffer) => {
385 current_task.read_object::<T>(user_buffer.clone().try_into()?)
386 }
387 }
388 }
389
390 pub fn read_bytes(
391 &self,
392 current_task: &CurrentTask,
393 max_bytes: usize,
394 ) -> Result<Vec<u8>, Errno> {
395 match self {
396 Self::Value(buffer) => {
397 let bytes = std::cmp::min(max_bytes, buffer.len());
398 Ok(buffer[..bytes].to_owned())
399 }
400 Self::User(user_buffer) => {
401 let bytes = std::cmp::min(max_bytes, user_buffer.length);
402 current_task
403 .read_buffer(&UserBuffer { address: user_buffer.address, length: bytes })
404 }
405 }
406 }
407
408 pub fn to_vec(self, current_task: &CurrentTask) -> Result<Vec<u8>, Errno> {
409 match self {
410 Self::Value(buffer) => Ok(buffer),
411 Self::User(user_buffer) => current_task.read_buffer(&user_buffer),
412 }
413 }
414}
415
416pub trait ReadFromSockOptValue {
418 type Result;
419 fn read_from_sockopt_value(
420 current_task: &CurrentTask,
421 buffer: &SockOptValue,
422 ) -> Result<Self::Result, Errno>;
423}
424
425impl<T, T64, T32> ReadFromSockOptValue for MappingMultiArchUserRef<T, T64, T32>
426where
427 T64: FromBytes + TryInto<T>,
428 T32: FromBytes + TryInto<T>,
429{
430 type Result = T;
431 fn read_from_sockopt_value(
432 current_task: &CurrentTask,
433 buffer: &SockOptValue,
434 ) -> Result<T, Errno> {
435 match buffer {
436 SockOptValue::Value(buffer) => {
437 Self::read_from_prefix(current_task, &buffer).map_err(|_| errno!(EINVAL))
438 }
439 SockOptValue::User(user_buffer) => {
440 let user_ref = Self::new_with_ref(current_task, user_buffer.clone())?;
441 current_task.read_multi_arch_object(user_ref)
442 }
443 }
444 }
445}
446
447impl Socket {
448 pub fn new<L>(
453 locked: &mut Locked<L>,
454 current_task: &CurrentTask,
455 domain: SocketDomain,
456 socket_type: SocketType,
457 protocol: SocketProtocol,
458 kernel_private: bool,
459 ) -> Result<SocketHandle, Errno>
460 where
461 L: LockEqualOrBefore<FileOpsCore>,
462 {
463 let protocol = resolve_protocol(domain, socket_type, protocol);
464 security::check_socket_create_access(
468 locked,
469 current_task,
470 domain,
471 socket_type,
472 protocol,
473 kernel_private,
474 )?;
475 let ops =
476 create_socket_ops(locked.cast_locked(), current_task, domain, socket_type, protocol)?;
477 Ok(Self::new_with_ops_and_info(ops, domain, socket_type, protocol))
478 }
479
480 pub fn new_with_ops(ops: Box<dyn SocketOps>) -> Result<SocketHandle, Errno> {
481 let (domain, socket_type, protocol) = ops.get_socket_info()?;
482 Ok(Self::new_with_ops_and_info(ops, domain, socket_type, protocol))
483 }
484
485 pub fn new_with_ops_and_info(
486 ops: Box<dyn SocketOps>,
487 domain: SocketDomain,
488 socket_type: SocketType,
489 protocol: SocketProtocol,
490 ) -> SocketHandle {
491 Arc::new(Socket {
492 ops,
493 domain,
494 socket_type,
495 protocol,
496 state: Mutex::default(),
497 security: security::SocketState::default(),
498 })
499 }
500
501 pub(super) fn set_fs_node(&self, node: &FsNodeHandle) {
502 let mut locked_state = self.state.lock();
503 assert!(locked_state.fs_node.is_none());
504 locked_state.fs_node = Some(node.clone());
505 }
506
507 pub fn get_from_file(file: &FileHandle) -> Result<&SocketHandle, Errno> {
510 let socket_file = file.downcast_file::<SocketFile>().ok_or_else(|| errno!(ENOTSOCK))?;
511 Ok(&socket_file.socket)
512 }
513
514 pub fn downcast_socket<T>(&self) -> Option<&T>
515 where
516 T: 'static,
517 {
518 let ops = &*self.ops;
519 ops.as_any().downcast_ref::<T>()
520 }
521
522 pub fn getsockname<L>(&self, locked: &mut Locked<L>) -> Result<SocketAddress, Errno>
523 where
524 L: LockEqualOrBefore<FileOpsCore>,
525 {
526 self.ops.getsockname(locked.cast_locked::<FileOpsCore>(), self)
527 }
528
529 pub fn getpeername<L>(&self, locked: &mut Locked<L>) -> Result<SocketAddress, Errno>
530 where
531 L: LockEqualOrBefore<FileOpsCore>,
532 {
533 self.ops.getpeername(locked.cast_locked::<FileOpsCore>(), self)
534 }
535
536 pub fn setsockopt<L>(
537 &self,
538 locked: &mut Locked<L>,
539 current_task: &CurrentTask,
540 level: u32,
541 optname: u32,
542 optval: SockOptValue,
543 ) -> Result<(), Errno>
544 where
545 L: LockEqualOrBefore<FileOpsCore>,
546 {
547 let locked = locked.cast_locked::<FileOpsCore>();
548 let read_timeval = || {
549 let timeval = TimeValPtr::read_from_sockopt_value(current_task, &optval)?;
550 let duration = duration_from_timeval(timeval)?;
551 Ok(if duration == zx::MonotonicDuration::default() { None } else { Some(duration) })
552 };
553
554 security::check_socket_setsockopt_access(current_task, self, level, optname)?;
555 match (level, optname) {
556 (SOL_SOCKET, SO_RCVTIMEO) => self.state.lock().receive_timeout = read_timeval()?,
557 (SOL_SOCKET, SO_SNDTIMEO) => self.state.lock().send_timeout = read_timeval()?,
558 _ => self.ops.setsockopt(locked, self, current_task, level, optname, optval)?,
559 }
560 Ok(())
561 }
562
563 pub fn getsockopt<L>(
564 &self,
565 locked: &mut Locked<L>,
566 current_task: &CurrentTask,
567 level: u32,
568 optname: u32,
569 optlen: u32,
570 ) -> Result<Vec<u8>, Errno>
571 where
572 L: LockEqualOrBefore<FileOpsCore>,
573 {
574 let locked = locked.cast_locked::<FileOpsCore>();
575 security::check_socket_getsockopt_access(current_task, self, level, optname)?;
576 let value = match level {
577 SOL_SOCKET => match optname {
578 SO_TYPE => self.socket_type.as_raw().to_ne_bytes().to_vec(),
579 SO_DOMAIN => {
580 let domain = self.domain.as_raw() as u32;
581 domain.to_ne_bytes().to_vec()
582 }
583 SO_PROTOCOL => self.protocol.as_raw().to_ne_bytes().to_vec(),
584 SO_RCVTIMEO => {
585 let duration = self.receive_timeout().unwrap_or_default();
586 TimeValPtr::into_bytes(current_task, timeval_from_duration(duration))
587 .map_err(|_| errno!(EINVAL))?
588 }
589 SO_SNDTIMEO => {
590 let duration = self.send_timeout().unwrap_or_default();
591 TimeValPtr::into_bytes(current_task, timeval_from_duration(duration))
592 .map_err(|_| errno!(EINVAL))?
593 }
594 _ => self.ops.getsockopt(locked, self, current_task, level, optname, optlen)?,
595 },
596 _ => self.ops.getsockopt(locked, self, current_task, level, optname, optlen)?,
597 };
598 Ok(value)
599 }
600
601 pub fn receive_timeout(&self) -> Option<zx::MonotonicDuration> {
602 self.state.lock().receive_timeout
603 }
604
605 pub fn send_timeout(&self) -> Option<zx::MonotonicDuration> {
606 self.state.lock().send_timeout
607 }
608
609 pub fn ioctl(
610 &self,
611 locked: &mut Locked<Unlocked>,
612 file: &FileObject,
613 current_task: &CurrentTask,
614 request: u32,
615 arg: SyscallArg,
616 ) -> Result<SyscallResult, Errno> {
617 let res = super::netlink_ioctl::netlink_ioctl(locked, current_task, request, arg);
618 match &res {
619 Err(e) if e.code == ENOTTY => {}
620 _ => return res,
621 }
622 self.ops.ioctl(locked, self, file, current_task, request, arg)
623 }
624
625 pub fn bind<L>(
626 &self,
627 locked: &mut Locked<L>,
628 current_task: &CurrentTask,
629 socket_address: SocketAddress,
630 ) -> Result<(), Errno>
631 where
632 L: LockEqualOrBefore<FileOpsCore>,
633 {
634 self.ops.bind(locked.cast_locked::<FileOpsCore>(), self, current_task, socket_address)
635 }
636
637 pub fn listen<L>(
638 &self,
639 locked: &mut Locked<L>,
640 current_task: &CurrentTask,
641 backlog: i32,
642 ) -> Result<(), Errno>
643 where
644 L: LockEqualOrBefore<FileOpsCore>,
645 {
646 security::check_socket_listen_access(current_task, self, backlog)?;
647 let max_connections =
648 current_task.kernel().system_limits.socket.max_connections.load(Ordering::Relaxed);
649 let backlog = std::cmp::min(backlog, max_connections);
650 let credentials = current_task.current_ucred();
651 self.ops.listen(locked.cast_locked::<FileOpsCore>(), self, backlog, credentials)
652 }
653
654 pub fn accept<L>(
655 &self,
656 locked: &mut Locked<L>,
657 current_task: &CurrentTask,
658 ) -> Result<SocketHandle, Errno>
659 where
660 L: LockEqualOrBefore<FileOpsCore>,
661 {
662 self.ops.accept(locked.cast_locked::<FileOpsCore>(), self, current_task)
663 }
664
665 pub fn read<L>(
666 &self,
667 locked: &mut Locked<L>,
668 current_task: &CurrentTask,
669 data: &mut dyn OutputBuffer,
670 flags: SocketMessageFlags,
671 ) -> Result<MessageReadInfo, Errno>
672 where
673 L: LockEqualOrBefore<FileOpsCore>,
674 {
675 security::check_socket_recvmsg_access(current_task, self)?;
676 let locked = locked.cast_locked::<FileOpsCore>();
677 self.ops.read(locked, self, current_task, data, flags)
678 }
679
680 pub fn write<L>(
681 &self,
682 locked: &mut Locked<L>,
683 current_task: &CurrentTask,
684 data: &mut dyn InputBuffer,
685 dest_address: &mut Option<SocketAddress>,
686 ancillary_data: &mut Vec<AncillaryData>,
687 ) -> Result<usize, Errno>
688 where
689 L: LockEqualOrBefore<FileOpsCore>,
690 {
691 security::check_socket_sendmsg_access(current_task, self)?;
692 let locked = locked.cast_locked::<FileOpsCore>();
693 self.ops.write(locked, self, current_task, data, dest_address, ancillary_data)
694 }
695
696 pub fn wait_async<L>(
697 &self,
698 locked: &mut Locked<L>,
699 current_task: &CurrentTask,
700 waiter: &Waiter,
701 events: FdEvents,
702 handler: EventHandler,
703 ) -> WaitCanceler
704 where
705 L: LockEqualOrBefore<FileOpsCore>,
706 {
707 let locked = locked.cast_locked::<FileOpsCore>();
708 self.ops.wait_async(locked, self, current_task, waiter, events, handler)
709 }
710
711 pub fn query_events<L>(
712 &self,
713 locked: &mut Locked<L>,
714 current_task: &CurrentTask,
715 ) -> Result<FdEvents, Errno>
716 where
717 L: LockEqualOrBefore<FileOpsCore>,
718 {
719 self.ops.query_events(locked.cast_locked::<FileOpsCore>(), self, current_task)
720 }
721
722 pub fn shutdown<L>(
723 &self,
724 locked: &mut Locked<L>,
725 current_task: &CurrentTask,
726 how: SocketShutdownFlags,
727 ) -> Result<(), Errno>
728 where
729 L: LockEqualOrBefore<FileOpsCore>,
730 {
731 security::check_socket_shutdown_access(current_task, self, how)?;
732 self.ops.shutdown(locked.cast_locked::<FileOpsCore>(), self, how)
733 }
734
735 pub fn close<L>(&self, locked: &mut Locked<L>, current_task: &CurrentTask)
736 where
737 L: LockEqualOrBefore<FileOpsCore>,
738 {
739 self.ops.close(locked.cast_locked::<FileOpsCore>(), current_task, self)
740 }
741
742 pub fn to_handle(
743 &self,
744 _file: &FileObject,
745 current_task: &CurrentTask,
746 ) -> Result<Option<zx::NullableHandle>, Errno> {
747 self.ops.to_handle(self, current_task)
748 }
749
750 pub fn fs_node(&self) -> Option<FsNodeHandle> {
754 self.state.lock().fs_node.clone()
755 }
756}
757
758impl DowncastedFile<'_, SocketFile> {
759 pub fn connect<L>(
760 self,
761 locked: &mut Locked<L>,
762 current_task: &CurrentTask,
763 peer: SocketPeer,
764 ) -> Result<(), Errno>
765 where
766 L: LockEqualOrBefore<FileOpsCore>,
767 {
768 security::check_socket_connect_access(current_task, self, &peer)?;
769 self.socket.ops.connect(locked.cast_locked(), &self.socket, current_task, peer)
770 }
771}
772
773pub struct AcceptQueue {
774 pub sockets: VecDeque<SocketHandle>,
775 pub backlog: usize,
776}
777
778impl AcceptQueue {
779 pub fn new(backlog: usize) -> AcceptQueue {
780 AcceptQueue { sockets: VecDeque::with_capacity(backlog), backlog }
781 }
782
783 pub fn set_backlog(&mut self, backlog: usize) -> Result<(), Errno> {
784 if self.sockets.len() > backlog {
785 return error!(EINVAL);
786 }
787 self.backlog = backlog;
788 Ok(())
789 }
790}
791
792#[cfg(test)]
793mod tests {
794 use super::*;
795 use crate::testing::{map_memory, spawn_kernel_and_run};
796 use crate::vfs::{UnixControlData, VecInputBuffer, VecOutputBuffer};
797 use starnix_uapi::SO_PASSCRED;
798 use starnix_uapi::user_address::{UserAddress, UserRef};
799
800 #[fuchsia::test]
801 async fn test_dgram_socket() {
802 spawn_kernel_and_run(async |locked, current_task| {
803 let bind_address = SocketAddress::Unix(b"dgram_test".into());
804 let rec_dgram = Socket::new(
805 locked,
806 ¤t_task,
807 SocketDomain::Unix,
808 SocketType::Datagram,
809 SocketProtocol::default(),
810 false,
811 )
812 .expect("Failed to create socket.");
813 let passcred: u32 = 1;
814 let opt_size = std::mem::size_of::<u32>();
815 let user_address =
816 map_memory(locked, ¤t_task, UserAddress::default(), opt_size as u64);
817 let opt_ref = UserRef::<u32>::new(user_address);
818 current_task.write_object(opt_ref, &passcred).unwrap();
819 let opt_buf = UserBuffer { address: user_address, length: opt_size };
820 rec_dgram
821 .setsockopt(locked, ¤t_task, SOL_SOCKET, SO_PASSCRED, opt_buf.into())
822 .unwrap();
823
824 rec_dgram
825 .bind(locked, ¤t_task, bind_address)
826 .expect("failed to bind datagram socket");
827
828 let xfer_value: u64 = 1234567819;
829 let xfer_bytes = xfer_value.to_ne_bytes();
830
831 let send = Socket::new(
832 locked,
833 ¤t_task,
834 SocketDomain::Unix,
835 SocketType::Datagram,
836 SocketProtocol::default(),
837 false,
838 )
839 .expect("Failed to connect socket.");
840 send.ops
841 .connect(
842 locked.cast_locked(),
843 &send,
844 ¤t_task,
845 SocketPeer::Handle(rec_dgram.clone()),
846 )
847 .unwrap();
848 let mut source_iter = VecInputBuffer::new(&xfer_bytes);
849 send.write(locked, ¤t_task, &mut source_iter, &mut None, &mut vec![]).unwrap();
850 assert_eq!(source_iter.available(), 0);
851 send.close(locked, ¤t_task);
854
855 let mut rec_buffer = VecOutputBuffer::new(8);
856 let read_info = rec_dgram
857 .read(locked, ¤t_task, &mut rec_buffer, SocketMessageFlags::empty())
858 .unwrap();
859 assert_eq!(read_info.bytes_read, xfer_bytes.len());
860 assert_eq!(rec_buffer.data(), xfer_bytes);
861 assert_eq!(1, read_info.ancillary_data.len());
862 assert_eq!(
863 read_info.ancillary_data[0],
864 AncillaryData::Unix(UnixControlData::Credentials(uapi::ucred {
865 pid: current_task.get_pid(),
866 uid: 0,
867 gid: 0
868 }))
869 );
870
871 rec_dgram.close(locked, ¤t_task);
872 })
873 .await;
874 }
875}