1use std::net::{Ipv4Addr, SocketAddrV4};
2use std::sync::{Arc, Weak};
3
4use atomic_refcell::AtomicRefCell;
5use linux_api::errno::Errno;
6use linux_api::ioctls::IoctlRequest;
7use linux_api::socket::Shutdown;
8use shadow_shim_helper_rs::emulated_time::EmulatedTime;
9use shadow_shim_helper_rs::syscall_types::ForeignPtr;
10
11use crate::cshadow as c;
12use crate::host::descriptor::listener::{StateListenHandle, StateListenerFilter};
13use crate::host::descriptor::socket::{RecvmsgArgs, RecvmsgReturn, SendmsgArgs};
14use crate::host::descriptor::{
15 FileMode, FileSignals, FileState, FileStatus, OpenFile, SyscallResult,
16};
17use crate::host::memory_manager::MemoryManager;
18use crate::host::network::interface::FifoPacketPriority;
19use crate::host::network::namespace::{AssociationHandle, NetworkNamespace};
20use crate::host::syscall::io::IoVec;
21use crate::host::syscall::types::SyscallError;
22use crate::network::packet::{IanaProtocol, PacketRc};
23use crate::utility::HostTreePointer;
24use crate::utility::callback_queue::CallbackQueue;
25use crate::utility::sockaddr::SockaddrStorage;
26
27use self::legacy_tcp::LegacyTcpSocket;
28use self::tcp::TcpSocket;
29use self::udp::UdpSocket;
30
31pub mod legacy_tcp;
32pub mod tcp;
33pub mod udp;
34
35#[derive(Clone)]
36pub enum InetSocket {
37 LegacyTcp(Arc<AtomicRefCell<LegacyTcpSocket>>),
38 Tcp(Arc<AtomicRefCell<TcpSocket>>),
39 Udp(Arc<AtomicRefCell<UdpSocket>>),
40}
41
42impl InetSocket {
43 pub fn borrow(&self) -> InetSocketRef {
44 match self {
45 Self::LegacyTcp(f) => InetSocketRef::LegacyTcp(f.borrow()),
46 Self::Tcp(f) => InetSocketRef::Tcp(f.borrow()),
47 Self::Udp(f) => InetSocketRef::Udp(f.borrow()),
48 }
49 }
50
51 pub fn try_borrow(&self) -> Result<InetSocketRef, atomic_refcell::BorrowError> {
52 Ok(match self {
53 Self::LegacyTcp(f) => InetSocketRef::LegacyTcp(f.try_borrow()?),
54 Self::Tcp(f) => InetSocketRef::Tcp(f.try_borrow()?),
55 Self::Udp(f) => InetSocketRef::Udp(f.try_borrow()?),
56 })
57 }
58
59 pub fn borrow_mut(&self) -> InetSocketRefMut {
60 match self {
61 Self::LegacyTcp(f) => InetSocketRefMut::LegacyTcp(f.borrow_mut()),
62 Self::Tcp(f) => InetSocketRefMut::Tcp(f.borrow_mut()),
63 Self::Udp(f) => InetSocketRefMut::Udp(f.borrow_mut()),
64 }
65 }
66
67 pub fn try_borrow_mut(&self) -> Result<InetSocketRefMut, atomic_refcell::BorrowMutError> {
68 Ok(match self {
69 Self::LegacyTcp(f) => InetSocketRefMut::LegacyTcp(f.try_borrow_mut()?),
70 Self::Tcp(f) => InetSocketRefMut::Tcp(f.try_borrow_mut()?),
71 Self::Udp(f) => InetSocketRefMut::Udp(f.try_borrow_mut()?),
72 })
73 }
74
75 pub fn downgrade(&self) -> InetSocketWeak {
76 match self {
77 Self::LegacyTcp(x) => InetSocketWeak::LegacyTcp(Arc::downgrade(x)),
78 Self::Tcp(x) => InetSocketWeak::Tcp(Arc::downgrade(x)),
79 Self::Udp(x) => InetSocketWeak::Udp(Arc::downgrade(x)),
80 }
81 }
82
83 pub fn canonical_handle(&self) -> usize {
87 match self {
88 Self::LegacyTcp(f) => f.borrow().canonical_handle(),
91 Self::Tcp(f) => Arc::as_ptr(f) as usize,
92 Self::Udp(f) => Arc::as_ptr(f) as usize,
93 }
94 }
95
96 pub fn bind(
97 &self,
98 addr: Option<&SockaddrStorage>,
99 net_ns: &NetworkNamespace,
100 rng: impl rand::Rng,
101 ) -> Result<(), SyscallError> {
102 match self {
103 Self::LegacyTcp(socket) => LegacyTcpSocket::bind(socket, addr, net_ns, rng),
104 Self::Tcp(socket) => TcpSocket::bind(socket, addr, net_ns, rng),
105 Self::Udp(socket) => UdpSocket::bind(socket, addr, net_ns, rng),
106 }
107 }
108
109 pub fn listen(
110 &self,
111 backlog: i32,
112 net_ns: &NetworkNamespace,
113 rng: impl rand::Rng,
114 cb_queue: &mut CallbackQueue,
115 ) -> Result<(), Errno> {
116 match self {
117 Self::LegacyTcp(socket) => {
118 LegacyTcpSocket::listen(socket, backlog, net_ns, rng, cb_queue)
119 }
120 Self::Tcp(socket) => TcpSocket::listen(socket, backlog, net_ns, rng, cb_queue),
121 Self::Udp(socket) => UdpSocket::listen(socket, backlog, net_ns, rng, cb_queue),
122 }
123 }
124
125 pub fn connect(
126 &self,
127 addr: &SockaddrStorage,
128 net_ns: &NetworkNamespace,
129 rng: impl rand::Rng,
130 cb_queue: &mut CallbackQueue,
131 ) -> Result<(), SyscallError> {
132 match self {
133 Self::LegacyTcp(socket) => {
134 LegacyTcpSocket::connect(socket, addr, net_ns, rng, cb_queue)
135 }
136 Self::Tcp(socket) => TcpSocket::connect(socket, addr, net_ns, rng, cb_queue),
137 Self::Udp(socket) => UdpSocket::connect(socket, addr, net_ns, rng, cb_queue),
138 }
139 }
140
141 pub fn sendmsg(
142 &self,
143 args: SendmsgArgs,
144 memory_manager: &mut MemoryManager,
145 net_ns: &NetworkNamespace,
146 rng: impl rand::Rng,
147 cb_queue: &mut CallbackQueue,
148 ) -> Result<libc::ssize_t, SyscallError> {
149 match self {
150 Self::LegacyTcp(socket) => {
151 LegacyTcpSocket::sendmsg(socket, args, memory_manager, net_ns, rng, cb_queue)
152 }
153 Self::Tcp(socket) => {
154 TcpSocket::sendmsg(socket, args, memory_manager, net_ns, rng, cb_queue)
155 }
156 Self::Udp(socket) => {
157 UdpSocket::sendmsg(socket, args, memory_manager, net_ns, rng, cb_queue)
158 }
159 }
160 }
161
162 pub fn recvmsg(
163 &self,
164 args: RecvmsgArgs,
165 memory_manager: &mut MemoryManager,
166 cb_queue: &mut CallbackQueue,
167 ) -> Result<RecvmsgReturn, SyscallError> {
168 match self {
169 Self::LegacyTcp(socket) => {
170 LegacyTcpSocket::recvmsg(socket, args, memory_manager, cb_queue)
171 }
172 Self::Tcp(socket) => TcpSocket::recvmsg(socket, args, memory_manager, cb_queue),
173 Self::Udp(socket) => UdpSocket::recvmsg(socket, args, memory_manager, cb_queue),
174 }
175 }
176}
177
178impl std::fmt::Debug for InetSocket {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 match self {
181 Self::LegacyTcp(_) => write!(f, "LegacyTcp")?,
182 Self::Tcp(_) => write!(f, "Tcp")?,
183 Self::Udp(_) => write!(f, "Udp")?,
184 }
185
186 if let Ok(file) = self.try_borrow() {
187 write!(
188 f,
189 "(state: {:?}, status: {:?})",
190 file.state(),
191 file.status()
192 )
193 } else {
194 write!(f, "(already borrowed)")
195 }
196 }
197}
198
199impl PartialEq for InetSocket {
200 fn eq(&self, other: &Self) -> bool {
209 if std::ptr::eq(self, other) {
211 return true;
212 }
213
214 match (self, other) {
215 (Self::LegacyTcp(self_), Self::LegacyTcp(other)) => Arc::ptr_eq(self_, other),
216 (Self::Tcp(self_), Self::Tcp(other)) => Arc::ptr_eq(self_, other),
217 (Self::Udp(self_), Self::Udp(other)) => Arc::ptr_eq(self_, other),
218 _ => false,
219 }
220 }
221}
222
223impl Eq for InetSocket {}
224
225impl std::hash::Hash for InetSocket {
226 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
230 match self {
238 Self::LegacyTcp(x) => Arc::as_ptr(x).cast::<libc::c_void>(),
239 Self::Tcp(x) => Arc::as_ptr(x).cast(),
240 Self::Udp(x) => Arc::as_ptr(x).cast(),
241 }
242 .hash(state);
243 }
244}
245
246pub enum InetSocketRef<'a> {
247 LegacyTcp(atomic_refcell::AtomicRef<'a, LegacyTcpSocket>),
248 Tcp(atomic_refcell::AtomicRef<'a, TcpSocket>),
249 Udp(atomic_refcell::AtomicRef<'a, UdpSocket>),
250}
251
252pub enum InetSocketRefMut<'a> {
253 LegacyTcp(atomic_refcell::AtomicRefMut<'a, LegacyTcpSocket>),
254 Tcp(atomic_refcell::AtomicRefMut<'a, TcpSocket>),
255 Udp(atomic_refcell::AtomicRefMut<'a, UdpSocket>),
256}
257
258impl InetSocketRef<'_> {
260 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
261 pub fn state(&self) -> FileState
262 );
263 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
264 pub fn mode(&self) -> FileMode
265 );
266 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
267 pub fn status(&self) -> FileStatus
268 );
269 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
270 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
271 );
272 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
273 pub fn has_open_file(&self) -> bool
274 );
275 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
276 pub fn supports_sa_restart(&self) -> bool
277 );
278}
279
280impl InetSocketRef<'_> {
282 pub fn getpeername(&self) -> Result<Option<SockaddrStorage>, Errno> {
283 match self {
284 Self::LegacyTcp(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
285 Self::Tcp(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
286 Self::Udp(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
287 }
288 }
289
290 pub fn getsockname(&self) -> Result<Option<SockaddrStorage>, Errno> {
291 match self {
292 Self::LegacyTcp(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
293 Self::Tcp(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
294 Self::Udp(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
295 }
296 }
297
298 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
299 pub fn address_family(&self) -> linux_api::socket::AddressFamily
300 );
301}
302
303impl InetSocketRef<'_> {
305 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
306 pub fn peek_next_packet_priority(&self) -> Option<FifoPacketPriority>
307 );
308 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
309 pub fn has_data_to_send(&self) -> bool
310 );
311}
312
313impl InetSocketRefMut<'_> {
315 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
316 pub fn state(&self) -> FileState
317 );
318 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
319 pub fn mode(&self) -> FileMode
320 );
321 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
322 pub fn status(&self) -> FileStatus
323 );
324 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
325 pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError>
326 );
327 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
328 pub fn has_open_file(&self) -> bool
329 );
330 enum_passthrough!(self, (val), LegacyTcp, Tcp, Udp;
331 pub fn set_has_open_file(&mut self, val: bool)
332 );
333 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
334 pub fn supports_sa_restart(&self) -> bool
335 );
336 enum_passthrough!(self, (cb_queue), LegacyTcp, Tcp, Udp;
337 pub fn close(&mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError>
338 );
339 enum_passthrough!(self, (status), LegacyTcp, Tcp, Udp;
340 pub fn set_status(&mut self, status: FileStatus)
341 );
342 enum_passthrough!(self, (request, arg_ptr, memory_manager), LegacyTcp, Tcp, Udp;
343 pub fn ioctl(&mut self, request: IoctlRequest, arg_ptr: ForeignPtr<()>, memory_manager: &mut MemoryManager) -> SyscallResult
344 );
345 enum_passthrough!(self, (monitoring_state, monitoring_signals, filter, notify_fn), LegacyTcp, Tcp, Udp;
346 pub fn add_listener(
347 &mut self,
348 monitoring_state: FileState,
349 monitoring_signals: FileSignals,
350 filter: StateListenerFilter,
351 notify_fn: impl Fn(FileState, FileState, FileSignals, &mut CallbackQueue) + Send + Sync + 'static,
352 ) -> StateListenHandle
353 );
354 enum_passthrough!(self, (ptr), LegacyTcp, Tcp, Udp;
355 pub fn add_legacy_listener(&mut self, ptr: HostTreePointer<c::StatusListener>)
356 );
357 enum_passthrough!(self, (ptr), LegacyTcp, Tcp, Udp;
358 pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener)
359 );
360 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), LegacyTcp, Tcp, Udp;
361 pub fn readv(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
362 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
363 );
364 enum_passthrough!(self, (iovs, offset, flags, mem, cb_queue), LegacyTcp, Tcp, Udp;
365 pub fn writev(&mut self, iovs: &[IoVec], offset: Option<libc::off_t>, flags: libc::c_int,
366 mem: &mut MemoryManager, cb_queue: &mut CallbackQueue) -> Result<libc::ssize_t, SyscallError>
367 );
368}
369
370impl InetSocketRefMut<'_> {
372 pub fn getpeername(&self) -> Result<Option<SockaddrStorage>, Errno> {
373 match self {
374 Self::LegacyTcp(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
375 Self::Tcp(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
376 Self::Udp(socket) => socket.getpeername().map(|opt| opt.map(Into::into)),
377 }
378 }
379
380 pub fn getsockname(&self) -> Result<Option<SockaddrStorage>, Errno> {
381 match self {
382 Self::LegacyTcp(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
383 Self::Tcp(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
384 Self::Udp(socket) => socket.getsockname().map(|opt| opt.map(Into::into)),
385 }
386 }
387
388 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
389 pub fn address_family(&self) -> linux_api::socket::AddressFamily
390 );
391
392 enum_passthrough!(self, (level, optname, optval_ptr, optlen, memory_manager, cb_queue), LegacyTcp, Tcp, Udp;
393 pub fn getsockopt(&mut self, level: libc::c_int, optname: libc::c_int, optval_ptr: ForeignPtr<()>,
394 optlen: libc::socklen_t, memory_manager: &mut MemoryManager, cb_queue: &mut CallbackQueue)
395 -> Result<libc::socklen_t, SyscallError>
396 );
397
398 enum_passthrough!(self, (level, optname, optval_ptr, optlen, memory_manager), LegacyTcp, Tcp, Udp;
399 pub fn setsockopt(&mut self, level: libc::c_int, optname: libc::c_int, optval_ptr: ForeignPtr<()>,
400 optlen: libc::socklen_t, memory_manager: &MemoryManager)
401 -> Result<(), SyscallError>
402 );
403
404 pub fn accept(
405 &mut self,
406 net_ns: &NetworkNamespace,
407 rng: impl rand::Rng,
408 cb_queue: &mut CallbackQueue,
409 ) -> Result<OpenFile, SyscallError> {
410 match self {
411 Self::LegacyTcp(socket) => socket.accept(net_ns, rng, cb_queue),
412 Self::Tcp(socket) => socket.accept(net_ns, rng, cb_queue),
413 Self::Udp(socket) => socket.accept(net_ns, rng, cb_queue),
414 }
415 }
416
417 enum_passthrough!(self, (how, cb_queue), LegacyTcp, Tcp, Udp;
418 pub fn shutdown(&mut self, how: Shutdown, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError>
419 );
420}
421
422impl InetSocketRefMut<'_> {
424 enum_passthrough!(self, (packet, cb_queue, recv_time), LegacyTcp, Tcp, Udp;
425 pub fn push_in_packet(&mut self, packet: PacketRc, cb_queue: &mut CallbackQueue, recv_time: EmulatedTime)
426 );
427 enum_passthrough!(self, (cb_queue), LegacyTcp, Tcp, Udp;
428 pub fn pull_out_packet(&mut self, cb_queue: &mut CallbackQueue) -> Option<PacketRc>
429 );
430 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
431 pub fn peek_next_packet_priority(&self) -> Option<FifoPacketPriority>
432 );
433 enum_passthrough!(self, (), LegacyTcp, Tcp, Udp;
434 pub fn has_data_to_send(&self) -> bool
435 );
436}
437
438impl std::fmt::Debug for InetSocketRef<'_> {
439 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
440 match self {
441 Self::LegacyTcp(_) => write!(f, "LegacyTcp")?,
442 Self::Tcp(_) => write!(f, "Tcp")?,
443 Self::Udp(_) => write!(f, "Udp")?,
444 }
445
446 write!(
447 f,
448 "(state: {:?}, status: {:?})",
449 self.state(),
450 self.status()
451 )
452 }
453}
454
455impl std::fmt::Debug for InetSocketRefMut<'_> {
456 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
457 match self {
458 Self::LegacyTcp(_) => write!(f, "LegacyTcp")?,
459 Self::Tcp(_) => write!(f, "Tcp")?,
460 Self::Udp(_) => write!(f, "Udp")?,
461 }
462
463 write!(
464 f,
465 "(state: {:?}, status: {:?})",
466 self.state(),
467 self.status()
468 )
469 }
470}
471
472#[derive(Clone)]
473pub enum InetSocketWeak {
474 LegacyTcp(Weak<AtomicRefCell<LegacyTcpSocket>>),
475 Tcp(Weak<AtomicRefCell<TcpSocket>>),
476 Udp(Weak<AtomicRefCell<UdpSocket>>),
477}
478
479impl InetSocketWeak {
480 pub fn upgrade(&self) -> Option<InetSocket> {
481 match self {
482 Self::LegacyTcp(x) => x.upgrade().map(InetSocket::LegacyTcp),
483 Self::Tcp(x) => x.upgrade().map(InetSocket::Tcp),
484 Self::Udp(x) => x.upgrade().map(InetSocket::Udp),
485 }
486 }
487}
488
489fn associate_socket(
497 socket: InetSocket,
498 local_addr: SocketAddrV4,
499 peer_addr: SocketAddrV4,
500 check_generic_peer: bool,
501 net_ns: &NetworkNamespace,
502 rng: impl rand::Rng,
503) -> Result<(SocketAddrV4, AssociationHandle), Errno> {
504 log::trace!("Trying to associate socket with addresses (local={local_addr}, peer={peer_addr})");
505
506 if !local_addr.ip().is_unspecified() && net_ns.interface_borrow(*local_addr.ip()).is_none() {
507 log::debug!(
508 "No network interface exists for the provided local address {}",
509 local_addr.ip(),
510 );
511 return Err(Errno::EINVAL);
512 };
513
514 let protocol = match socket {
515 InetSocket::LegacyTcp(_) => IanaProtocol::Tcp,
516 InetSocket::Tcp(_) => IanaProtocol::Tcp,
517 InetSocket::Udp(_) => IanaProtocol::Udp,
518 };
519
520 let local_addr = if local_addr.port() != 0 {
522 local_addr
523 } else {
524 let Some(new_port) =
525 net_ns.get_random_free_port(protocol, *local_addr.ip(), peer_addr, rng)
526 else {
527 log::debug!("Association required an ephemeral port but none are available");
528 return Err(Errno::EADDRINUSE);
529 };
530
531 log::debug!("Associating with generated ephemeral port {new_port}");
532
533 SocketAddrV4::new(*local_addr.ip(), new_port)
535 };
536
537 match net_ns.is_addr_in_use(protocol, local_addr, peer_addr) {
539 Ok(true) => {
540 log::debug!(
541 "The provided addresses (local={local_addr}, peer={peer_addr}) are not available"
542 );
543 return Err(Errno::EADDRINUSE);
544 }
545 Err(_e) => return Err(Errno::EADDRNOTAVAIL),
546 Ok(false) => {}
547 }
548
549 if check_generic_peer {
550 match net_ns.is_addr_in_use(
551 protocol,
552 local_addr,
553 SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0),
554 ) {
555 Ok(true) => {
556 log::debug!(
557 "The generic addresses (local={local_addr}, peer={}) are not available",
558 SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0)
559 );
560 return Err(Errno::EADDRINUSE);
561 }
562 Err(_e) => return Err(Errno::EADDRNOTAVAIL),
563 Ok(false) => {}
564 }
565 }
566
567 let handle = unsafe { net_ns.associate_interface(&socket, protocol, local_addr, peer_addr) };
569
570 Ok((local_addr, handle))
571}
572
573mod export {
574 use super::*;
575
576 #[unsafe(no_mangle)]
579 pub extern "C-unwind" fn inetsocket_drop(socket: *const InetSocket) {
580 assert!(!socket.is_null());
581 drop(unsafe { Box::from_raw(socket.cast_mut()) });
582 }
583
584 #[unsafe(no_mangle)]
586 pub extern "C-unwind" fn inetsocket_dropVoid(socket: *mut libc::c_void) {
587 inetsocket_drop(socket.cast_const().cast())
588 }
589
590 #[unsafe(no_mangle)]
593 pub extern "C-unwind" fn inetsocket_asLegacyTcp(socket: *const InetSocket) -> *mut c::TCP {
594 let socket = unsafe { socket.as_ref() }.unwrap();
595
596 #[allow(irrefutable_let_patterns)]
597 let InetSocket::LegacyTcp(socket) = socket else {
598 panic!("Socket was not a legacy TCP socket: {socket:?}");
599 };
600
601 let ptr = socket.borrow().as_legacy_tcp();
602 assert!(!ptr.is_null());
604
605 ptr
606 }
607
608 #[unsafe(no_mangle)]
611 pub extern "C-unwind" fn inetsocketweak_drop(socket: *mut InetSocketWeak) {
612 assert!(!socket.is_null());
613 drop(unsafe { Box::from_raw(socket) });
614 }
615
616 #[unsafe(no_mangle)]
620 pub extern "C-unwind" fn inetsocketweak_upgrade(
621 socket: *const InetSocketWeak,
622 ) -> *mut InetSocket {
623 let socket = unsafe { socket.as_ref() }.unwrap();
624 socket
625 .upgrade()
626 .map(Box::new)
627 .map(Box::into_raw)
628 .unwrap_or(std::ptr::null_mut())
629 }
630}