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 => {
49 if ty != Socktype::Stream {
50 return Ok(Errno::Notsup);
51 }
52 }
53 SockProto::Udp => {
54 if ty != Socktype::Dgram {
55 return Ok(Errno::Notsup);
56 }
57 }
58 _ => {}
59 }
60
61 let (fd1, fd2) = wasi_try_ok!(sock_pair_internal(&mut ctx, None, None));
64
65 #[cfg(feature = "journal")]
66 if ctx.data().enable_journal {
67 JournalEffector::save_sock_pair(&mut ctx, fd1, fd2).map_err(|err| {
68 tracing::error!("failed to save sock_pair event - {}", err);
69 WasiError::Exit(ExitCode::from(Errno::Fault))
70 })?;
71 }
72
73 let env = ctx.data();
74 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
75 wasi_try_mem_ok!(ro_sock1.write(&memory, fd1));
76 wasi_try_mem_ok!(ro_sock2.write(&memory, fd2));
77
78 Ok(Errno::Success)
79}
80
81pub(crate) fn sock_pair_internal(
82 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
83 with_fd1: Option<WasiFd>,
84 with_fd2: Option<WasiFd>,
85) -> Result<(WasiFd, WasiFd), Errno> {
86 let env = ctx.data();
87 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
88 let (end1, end2) = Pipe::channel();
89
90 let inode1 = state.fs.create_inode_with_default_stat(
91 inodes,
92 Kind::DuplexPipe { pipe: end1 },
93 false,
94 "socketpair".into(),
95 );
96 let inode2 = state.fs.create_inode_with_default_stat(
97 inodes,
98 Kind::DuplexPipe { pipe: end2 },
99 false,
100 "socketpair".into(),
101 );
102
103 let rights = Rights::all_socket();
104 let fd1 = if let Some(fd) = with_fd1 {
105 state
106 .fs
107 .with_fd(
108 rights,
109 rights,
110 Fdflags::empty(),
111 Fdflagsext::empty(),
112 0,
113 inode1,
114 fd,
115 )
116 .map(|_| fd)?
117 } else {
118 state.fs.create_fd(
119 rights,
120 rights,
121 Fdflags::empty(),
122 Fdflagsext::empty(),
123 0,
124 inode1,
125 )?
126 };
127 let fd2 = if let Some(fd) = with_fd2 {
128 state
129 .fs
130 .with_fd(
131 rights,
132 rights,
133 Fdflags::empty(),
134 Fdflagsext::empty(),
135 0,
136 inode2,
137 fd,
138 )
139 .map(|_| fd)?
140 } else {
141 state.fs.create_fd(
142 rights,
143 rights,
144 Fdflags::empty(),
145 Fdflagsext::empty(),
146 0,
147 inode2,
148 )?
149 };
150 Span::current().record("end1", fd1);
151 Span::current().record("end2", fd2);
152
153 Ok((fd1, fd2))
154}