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