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 stat = Filestat {
90 st_filetype: Filetype::SocketStream,
91 ..Filestat::default()
92 };
93 let inode1 = state.fs.create_inode_with_stat(
94 inodes,
95 Kind::DuplexPipe { pipe: end1 },
96 false,
97 "socketpair".into(),
98 stat,
99 );
100 let inode2 = state.fs.create_inode_with_stat(
101 inodes,
102 Kind::DuplexPipe { pipe: end2 },
103 false,
104 "socketpair".into(),
105 stat,
106 );
107
108 let rights = Rights::all_socket();
109 let fd1 = if let Some(fd) = with_fd1 {
110 state
111 .fs
112 .with_fd(
113 rights,
114 rights,
115 Fdflags::empty(),
116 Fdflagsext::empty(),
117 0,
118 inode1,
119 fd,
120 )
121 .map(|_| fd)?
122 } else {
123 state.fs.create_fd(
124 rights,
125 rights,
126 Fdflags::empty(),
127 Fdflagsext::empty(),
128 0,
129 inode1,
130 )?
131 };
132 let fd2 = if let Some(fd) = with_fd2 {
133 state
134 .fs
135 .with_fd(
136 rights,
137 rights,
138 Fdflags::empty(),
139 Fdflagsext::empty(),
140 0,
141 inode2,
142 fd,
143 )
144 .map(|_| fd)?
145 } else {
146 state.fs.create_fd(
147 rights,
148 rights,
149 Fdflags::empty(),
150 Fdflagsext::empty(),
151 0,
152 inode2,
153 )?
154 };
155 Span::current().record("end1", fd1);
156 Span::current().record("end2", fd2);
157
158 Ok((fd1, fd2))
159}