wasmer_wasix/syscalls/wasix/
sock_pair.rs1use virtual_fs::Pipe;
2
3use super::*;
4use crate::{
5 net::socket::{self, SocketProperties},
6 syscalls::*,
7};
8
9#[instrument(level = "trace", skip_all, fields(?af, ?ty, ?pt, sock1 = field::Empty, sock2 = field::Empty), ret)]
36pub fn sock_pair<M: MemorySize>(
37 mut ctx: FunctionEnvMut<'_, WasiEnv>,
38 af: Addressfamily,
39 ty: Socktype,
40 pt: SockProto,
41 ro_sock1: WasmPtr<WasiFd, M>,
42 ro_sock2: WasmPtr<WasiFd, M>,
43) -> Result<Errno, WasiError> {
44 WasiEnv::do_pending_operations(&mut ctx)?;
45
46 match pt {
48 SockProto::Tcp if ty != Socktype::Stream => {
49 return Ok(Errno::Notsup);
50 }
51 SockProto::Udp if ty != Socktype::Dgram => {
52 return Ok(Errno::Notsup);
53 }
54 _ => {}
55 }
56
57 let (fd1, fd2) = wasi_try_ok!(sock_pair_internal(&mut ctx, None, None));
60
61 #[cfg(feature = "journal")]
62 if ctx.data().enable_journal {
63 JournalEffector::save_sock_pair(&mut ctx, fd1, fd2).map_err(|err| {
64 tracing::error!("failed to save sock_pair event - {}", err);
65 WasiError::Exit(ExitCode::from(Errno::Fault))
66 })?;
67 }
68
69 let env = ctx.data();
70 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
71 wasi_try_mem_ok!(ro_sock1.write(&memory, fd1));
72 wasi_try_mem_ok!(ro_sock2.write(&memory, fd2));
73
74 Ok(Errno::Success)
75}
76
77pub(crate) fn sock_pair_internal(
78 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
79 with_fd1: Option<WasiFd>,
80 with_fd2: Option<WasiFd>,
81) -> Result<(WasiFd, WasiFd), Errno> {
82 let env = ctx.data();
83 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
84 let (end1, end2) = Pipe::channel();
85
86 let inode1 = state.fs.create_inode_with_default_stat(
87 inodes,
88 Kind::DuplexPipe { pipe: end1 },
89 false,
90 "socketpair".into(),
91 );
92 let inode2 = state.fs.create_inode_with_default_stat(
93 inodes,
94 Kind::DuplexPipe { pipe: end2 },
95 false,
96 "socketpair".into(),
97 );
98
99 let rights = Rights::all_socket();
100 let fd1 = if let Some(fd) = with_fd1 {
101 state
102 .fs
103 .with_fd(
104 rights,
105 rights,
106 Fdflags::empty(),
107 Fdflagsext::empty(),
108 0,
109 inode1,
110 fd,
111 )
112 .map(|_| fd)?
113 } else {
114 state.fs.create_fd(
115 rights,
116 rights,
117 Fdflags::empty(),
118 Fdflagsext::empty(),
119 0,
120 inode1,
121 )?
122 };
123 let fd2 = if let Some(fd) = with_fd2 {
124 state
125 .fs
126 .with_fd(
127 rights,
128 rights,
129 Fdflags::empty(),
130 Fdflagsext::empty(),
131 0,
132 inode2,
133 fd,
134 )
135 .map(|_| fd)?
136 } else {
137 state.fs.create_fd(
138 rights,
139 rights,
140 Fdflags::empty(),
141 Fdflagsext::empty(),
142 0,
143 inode2,
144 )?
145 };
146 Span::current().record("end1", fd1);
147 Span::current().record("end2", fd2);
148
149 Ok((fd1, fd2))
150}