1use std::cell::{Cell, RefCell};
2use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
3use std::{io, iter};
4
5use mio::Interest;
6use mio::event::Source;
7use mio::net::{TcpListener, TcpStream};
8use rustc_abi::Size;
9use rustc_const_eval::interpret::{InterpResult, interp_ok};
10use rustc_middle::throw_unsup_format;
11use rustc_target::spec::Os;
12
13use crate::shims::files::{FdId, FileDescription, FileDescriptionRef};
14use crate::{OpTy, Scalar, *};
15
16#[derive(Debug, PartialEq)]
17enum SocketFamily {
18 IPv4,
20 IPv6,
22}
23
24enum SocketIoError {
25 NotReady,
27 Other(io::Error),
29}
30
31impl From<io::Error> for SocketIoError {
32 fn from(value: io::Error) -> Self {
33 match value.kind() {
34 io::ErrorKind::InProgress | io::ErrorKind::NotConnected => Self::NotReady,
35 _ => Self::Other(value),
36 }
37 }
38}
39
40#[derive(Debug)]
41enum SocketState {
42 Initial,
44 Bound(SocketAddr),
47 Listening(TcpListener),
50 Connecting(TcpStream),
54 Connected(TcpStream),
60}
61
62impl SocketState {
63 pub fn try_set_connected(&mut self) -> Result<(), SocketIoError> {
74 let SocketState::Connecting(stream) = self else { return Ok(()) };
80
81 if let Ok(Some(e)) = stream.take_error() {
82 let e = SocketIoError::from(e);
84 assert!(matches!(e, SocketIoError::Other(_)));
87 *self = SocketState::Initial;
90 return Err(e);
91 }
92
93 if let Err(e) = stream.peer_addr() {
94 let e = SocketIoError::from(e);
95 if let SocketIoError::Other(_) = &e {
96 *self = SocketState::Initial;
98 }
99 return Err(e);
100 };
101
102 let SocketState::Connecting(stream) = std::mem::replace(self, SocketState::Initial) else {
107 unreachable!()
109 };
110 *self = SocketState::Connected(stream);
111 Ok(())
112 }
113}
114
115#[derive(Debug)]
116struct Socket {
117 family: SocketFamily,
120 state: RefCell<SocketState>,
122 is_non_block: Cell<bool>,
124}
125
126impl FileDescription for Socket {
127 fn name(&self) -> &'static str {
128 "socket"
129 }
130
131 fn destroy<'tcx>(
132 self,
133 _self_id: FdId,
134 _communicate_allowed: bool,
135 _ecx: &mut MiriInterpCx<'tcx>,
136 ) -> InterpResult<'tcx, std::io::Result<()>>
137 where
138 Self: Sized,
139 {
140 interp_ok(Ok(()))
141 }
142
143 fn get_flags<'tcx>(&self, ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, Scalar> {
144 let mut flags = ecx.eval_libc_i32("O_RDWR");
145
146 if self.is_non_block.get() {
147 flags |= ecx.eval_libc_i32("O_NONBLOCK");
148 }
149
150 interp_ok(Scalar::from_i32(flags))
151 }
152
153 fn set_flags<'tcx>(
154 &self,
155 mut _flag: i32,
156 _ecx: &mut MiriInterpCx<'tcx>,
157 ) -> InterpResult<'tcx, Scalar> {
158 throw_unsup_format!("fcntl: socket flags aren't supported")
159 }
160}
161
162impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
163pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
164 fn socket(
167 &mut self,
168 domain: &OpTy<'tcx>,
169 type_: &OpTy<'tcx>,
170 protocol: &OpTy<'tcx>,
171 ) -> InterpResult<'tcx, Scalar> {
172 let this = self.eval_context_mut();
173
174 let domain = this.read_scalar(domain)?.to_i32()?;
175 let mut flags = this.read_scalar(type_)?.to_i32()?;
176 let protocol = this.read_scalar(protocol)?.to_i32()?;
177
178 if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
180 this.reject_in_isolation("`socket`", reject_with)?;
181 return this.set_last_error_and_return_i32(LibcError("EACCES"));
182 }
183
184 let mut is_sock_nonblock = false;
185
186 if matches!(
189 this.tcx.sess.target.os,
190 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
191 ) {
192 let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK");
195 let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC");
196 if flags & sock_nonblock == sock_nonblock {
197 is_sock_nonblock = true;
198 flags &= !sock_nonblock;
199 }
200 if flags & sock_cloexec == sock_cloexec {
201 flags &= !sock_cloexec;
203 }
204 }
205
206 let family = if domain == this.eval_libc_i32("AF_INET") {
207 SocketFamily::IPv4
208 } else if domain == this.eval_libc_i32("AF_INET6") {
209 SocketFamily::IPv6
210 } else {
211 throw_unsup_format!(
212 "socket: domain {:#x} is unsupported, only AF_INET and \
213 AF_INET6 are allowed.",
214 domain
215 );
216 };
217
218 if flags != this.eval_libc_i32("SOCK_STREAM") {
219 throw_unsup_format!(
220 "socket: type {:#x} is unsupported, only SOCK_STREAM, \
221 SOCK_CLOEXEC and SOCK_NONBLOCK are allowed",
222 flags
223 );
224 }
225 if protocol != 0 {
226 throw_unsup_format!(
227 "socket: socket protocol {protocol} is unsupported, \
228 only 0 is allowed"
229 );
230 }
231
232 let fds = &mut this.machine.fds;
233 let fd = fds.new_ref(Socket {
234 family,
235 state: RefCell::new(SocketState::Initial),
236 is_non_block: Cell::new(is_sock_nonblock),
237 });
238
239 interp_ok(Scalar::from_i32(fds.insert(fd)))
240 }
241
242 fn bind(
243 &mut self,
244 socket: &OpTy<'tcx>,
245 address: &OpTy<'tcx>,
246 address_len: &OpTy<'tcx>,
247 ) -> InterpResult<'tcx, Scalar> {
248 let this = self.eval_context_mut();
249
250 let socket = this.read_scalar(socket)?.to_i32()?;
251 let address = match this.socket_address(address, address_len, "bind")? {
252 Ok(addr) => addr,
253 Err(e) => return this.set_last_error_and_return_i32(e),
254 };
255
256 let Some(fd) = this.machine.fds.get(socket) else {
258 return this.set_last_error_and_return_i32(LibcError("EBADF"));
259 };
260
261 let Some(socket) = fd.downcast::<Socket>() else {
262 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
264 };
265
266 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
267
268 let mut state = socket.state.borrow_mut();
269
270 match *state {
271 SocketState::Initial => {
272 let address_family = match &address {
273 SocketAddr::V4(_) => SocketFamily::IPv4,
274 SocketAddr::V6(_) => SocketFamily::IPv6,
275 };
276
277 if socket.family != address_family {
278 let err = if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) {
281 LibcError("EINVAL")
284 } else {
285 LibcError("EAFNOSUPPORT")
289 };
290 return this.set_last_error_and_return_i32(err);
291 }
292
293 *state = SocketState::Bound(address);
294 }
295 SocketState::Connecting(_) | SocketState::Connected(_) =>
296 throw_unsup_format!(
297 "bind: socket is already connected and binding a
298 connected socket is unsupported"
299 ),
300 SocketState::Bound(_) | SocketState::Listening(_) =>
301 throw_unsup_format!(
302 "bind: socket is already bound and binding a socket \
303 multiple times is unsupported"
304 ),
305 }
306
307 interp_ok(Scalar::from_i32(0))
308 }
309
310 fn listen(&mut self, socket: &OpTy<'tcx>, backlog: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
311 let this = self.eval_context_mut();
312
313 let socket = this.read_scalar(socket)?.to_i32()?;
314 let _backlog = this.read_scalar(backlog)?.to_i32()?;
316
317 let Some(fd) = this.machine.fds.get(socket) else {
319 return this.set_last_error_and_return_i32(LibcError("EBADF"));
320 };
321
322 let Some(socket) = fd.downcast::<Socket>() else {
323 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
325 };
326
327 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
328
329 let mut state = socket.state.borrow_mut();
330
331 match *state {
332 SocketState::Bound(socket_addr) =>
333 match TcpListener::bind(socket_addr) {
334 Ok(listener) => *state = SocketState::Listening(listener),
335 Err(e) => return this.set_last_error_and_return_i32(e),
336 },
337 SocketState::Initial => {
338 throw_unsup_format!(
339 "listen: listening on a socket which isn't bound is unsupported"
340 )
341 }
342 SocketState::Listening(_) => {
343 throw_unsup_format!("listen: listening on a socket multiple times is unsupported")
344 }
345 SocketState::Connecting(_) | SocketState::Connected(_) => {
346 throw_unsup_format!("listen: listening on a connected socket is unsupported")
347 }
348 }
349
350 interp_ok(Scalar::from_i32(0))
351 }
352
353 fn accept4(
356 &mut self,
357 socket: &OpTy<'tcx>,
358 address: &OpTy<'tcx>,
359 address_len: &OpTy<'tcx>,
360 flags: Option<&OpTy<'tcx>>,
361 dest: &MPlaceTy<'tcx>,
363 ) -> InterpResult<'tcx> {
364 let this = self.eval_context_mut();
365
366 let socket = this.read_scalar(socket)?.to_i32()?;
367 let address_ptr = this.read_pointer(address)?;
368 let address_len_ptr = this.read_pointer(address_len)?;
369 let mut flags =
370 if let Some(flags) = flags { this.read_scalar(flags)?.to_i32()? } else { 0 };
371
372 let Some(fd) = this.machine.fds.get(socket) else {
374 return this.set_last_error_and_return(LibcError("EBADF"), dest);
375 };
376
377 let Some(socket) = fd.downcast::<Socket>() else {
378 return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
380 };
381
382 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
383
384 if !matches!(*socket.state.borrow(), SocketState::Listening(_)) {
385 throw_unsup_format!(
386 "accept4: accepting incoming connections is only allowed when socket is listening"
387 )
388 };
389
390 let mut is_client_sock_nonblock = false;
391
392 if matches!(
395 this.tcx.sess.target.os,
396 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
397 ) {
398 let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK");
401 let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC");
402 if flags & sock_nonblock == sock_nonblock {
403 is_client_sock_nonblock = true;
404 flags &= !sock_nonblock;
405 }
406 if flags & sock_cloexec == sock_cloexec {
407 flags &= !sock_cloexec;
409 }
410 }
411
412 if flags != 0 {
413 throw_unsup_format!(
414 "accept4: flag {flags:#x} is unsupported, only SOCK_CLOEXEC \
415 and SOCK_NONBLOCK are allowed",
416 );
417 }
418
419 if socket.is_non_block.get() {
420 throw_unsup_format!("accept4: non-blocking accept is unsupported")
421 }
422
423 this.block_for_accept(
426 address_ptr,
427 address_len_ptr,
428 is_client_sock_nonblock,
429 socket,
430 dest.clone(),
431 );
432 interp_ok(())
433 }
434
435 fn connect(
436 &mut self,
437 socket: &OpTy<'tcx>,
438 address: &OpTy<'tcx>,
439 address_len: &OpTy<'tcx>,
440 dest: &MPlaceTy<'tcx>,
442 ) -> InterpResult<'tcx> {
443 let this = self.eval_context_mut();
444
445 let socket = this.read_scalar(socket)?.to_i32()?;
446 let address = match this.socket_address(address, address_len, "connect")? {
447 Ok(address) => address,
448 Err(e) => return this.set_last_error_and_return(e, dest),
449 };
450
451 let Some(fd) = this.machine.fds.get(socket) else {
453 return this.set_last_error_and_return(LibcError("EBADF"), dest);
454 };
455
456 let Some(socket) = fd.downcast::<Socket>() else {
457 return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
459 };
460
461 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
462
463 match &*socket.state.borrow() {
464 SocketState::Initial => { }
465 SocketState::Connecting(_) =>
467 return this.set_last_error_and_return(LibcError("EALREADY"), dest),
468 _ =>
472 throw_unsup_format!(
473 "connect: connecting is only supported for sockets which are neither \
474 bound, listening nor already connected"
475 ),
476 }
477
478 match TcpStream::connect(address) {
485 Ok(stream) => *socket.state.borrow_mut() = SocketState::Connecting(stream),
486 Err(e) => return this.set_last_error_and_return(e, dest),
487 };
488
489 if socket.is_non_block.get() {
490 throw_unsup_format!("connect: non-blocking connect is unsupported");
491 }
492
493 this.block_for_connect(socket, dest.clone());
496 interp_ok(())
497 }
498
499 fn setsockopt(
500 &mut self,
501 socket: &OpTy<'tcx>,
502 level: &OpTy<'tcx>,
503 option_name: &OpTy<'tcx>,
504 option_value: &OpTy<'tcx>,
505 option_len: &OpTy<'tcx>,
506 ) -> InterpResult<'tcx, Scalar> {
507 let this = self.eval_context_mut();
508
509 let socket = this.read_scalar(socket)?.to_i32()?;
510 let level = this.read_scalar(level)?.to_i32()?;
511 let option_name = this.read_scalar(option_name)?.to_i32()?;
512 let socklen_layout = this.libc_ty_layout("socklen_t");
513 let option_len = this.read_scalar(option_len)?.to_int(socklen_layout.size)?;
514
515 let Some(fd) = this.machine.fds.get(socket) else {
517 return this.set_last_error_and_return_i32(LibcError("EBADF"));
518 };
519
520 let Some(_socket) = fd.downcast::<Socket>() else {
521 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
523 };
524
525 if level == this.eval_libc_i32("SOL_SOCKET") {
526 let opt_so_reuseaddr = this.eval_libc_i32("SO_REUSEADDR");
527
528 if matches!(this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd | Os::NetBsd) {
529 let opt_so_nosigpipe = this.eval_libc_i32("SO_NOSIGPIPE");
531
532 if option_name == opt_so_nosigpipe {
533 if option_len != 4 {
534 return this.set_last_error_and_return_i32(LibcError("EINVAL"));
536 }
537 let option_value =
538 this.deref_pointer_as(option_value, this.machine.layouts.i32)?;
539 let _val = this.read_scalar(&option_value)?.to_i32()?;
540 return interp_ok(Scalar::from_i32(0));
543 }
544 }
545
546 if option_name == opt_so_reuseaddr {
547 if option_len != 4 {
548 return this.set_last_error_and_return_i32(LibcError("EINVAL"));
550 }
551 let option_value = this.deref_pointer_as(option_value, this.machine.layouts.i32)?;
552 let _val = this.read_scalar(&option_value)?.to_i32()?;
553 return interp_ok(Scalar::from_i32(0));
556 } else {
557 throw_unsup_format!(
558 "setsockopt: option {option_name:#x} is unsupported for level SOL_SOCKET",
559 );
560 }
561 }
562
563 throw_unsup_format!(
564 "setsockopt: level {level:#x} is unsupported, only SOL_SOCKET is allowed"
565 );
566 }
567
568 fn getsockname(
569 &mut self,
570 socket: &OpTy<'tcx>,
571 address: &OpTy<'tcx>,
572 address_len: &OpTy<'tcx>,
573 ) -> InterpResult<'tcx, Scalar> {
574 let this = self.eval_context_mut();
575
576 let socket = this.read_scalar(socket)?.to_i32()?;
577 let address_ptr = this.read_pointer(address)?;
578 let address_len_ptr = this.read_pointer(address_len)?;
579
580 let Some(fd) = this.machine.fds.get(socket) else {
582 return this.set_last_error_and_return_i32(LibcError("EBADF"));
583 };
584
585 let Some(socket) = fd.downcast::<Socket>() else {
586 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
588 };
589
590 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
591
592 let state = socket.state.borrow();
593
594 let address = match &*state {
595 SocketState::Bound(address) => {
596 if address.port() == 0 {
597 throw_unsup_format!(
601 "getsockname: when the port is 0, getting the socket address before \
602 calling `listen` or `connect` is unsupported"
603 )
604 }
605
606 *address
607 }
608 SocketState::Listening(listener) =>
609 match listener.local_addr() {
610 Ok(address) => address,
611 Err(e) => return this.set_last_error_and_return_i32(e),
612 },
613 _ => SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0)),
616 };
617
618 match this.write_socket_address(&address, address_ptr, address_len_ptr, "getsockname")? {
619 Ok(_) => interp_ok(Scalar::from_i32(0)),
620 Err(e) => this.set_last_error_and_return_i32(e),
621 }
622 }
623
624 fn getpeername(
625 &mut self,
626 socket: &OpTy<'tcx>,
627 address: &OpTy<'tcx>,
628 address_len: &OpTy<'tcx>,
629 ) -> InterpResult<'tcx, Scalar> {
630 let this = self.eval_context_mut();
631
632 let socket = this.read_scalar(socket)?.to_i32()?;
633 let address_ptr = this.read_pointer(address)?;
634 let address_len_ptr = this.read_pointer(address_len)?;
635
636 let Some(fd) = this.machine.fds.get(socket) else {
638 return this.set_last_error_and_return_i32(LibcError("EBADF"));
639 };
640
641 let Some(socket) = fd.downcast::<Socket>() else {
642 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
644 };
645
646 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
647
648 let state = socket.state.borrow();
649
650 let SocketState::Connected(stream) = &*state else {
651 return this.set_last_error_and_return_i32(LibcError("ENOTCONN"));
653 };
654
655 let address = match stream.peer_addr() {
656 Ok(address) => address,
657 Err(e) => return this.set_last_error_and_return_i32(e),
658 };
659
660 match this.write_socket_address(&address, address_ptr, address_len_ptr, "getpeername")? {
661 Ok(_) => interp_ok(Scalar::from_i32(0)),
662 Err(e) => this.set_last_error_and_return_i32(e),
663 }
664 }
665}
666
667impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {}
668trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
669 fn socket_address(
673 &self,
674 address: &OpTy<'tcx>,
675 address_len: &OpTy<'tcx>,
676 foreign_name: &'static str,
677 ) -> InterpResult<'tcx, Result<SocketAddr, IoError>> {
678 let this = self.eval_context_ref();
679
680 let socklen_layout = this.libc_ty_layout("socklen_t");
681 let address_len: u64 =
684 this.read_scalar(address_len)?.to_int(socklen_layout.size)?.try_into().unwrap();
685
686 let sockaddr_layout = this.libc_ty_layout("sockaddr");
688 if address_len < sockaddr_layout.size.bytes() {
689 return interp_ok(Err(LibcError("EINVAL")));
691 }
692 let address = this.deref_pointer_as(address, sockaddr_layout)?;
693
694 let family_field = this.project_field_named(&address, "sa_family")?;
695 let family_layout = this.libc_ty_layout("sa_family_t");
696 let family = this.read_scalar(&family_field)?.to_int(family_layout.size)?;
697
698 let socket_addr = if family == this.eval_libc_i32("AF_INET").into() {
701 let sockaddr_in_layout = this.libc_ty_layout("sockaddr_in");
702 if address_len != sockaddr_in_layout.size.bytes() {
703 return interp_ok(Err(LibcError("EINVAL")));
705 }
706 let address = address.transmute(sockaddr_in_layout, this)?;
707
708 let port_field = this.project_field_named(&address, "sin_port")?;
709 let port_bytes: [u8; 2] = this
711 .read_bytes_ptr_strip_provenance(port_field.ptr(), Size::from_bytes(2))?
712 .try_into()
713 .unwrap();
714 let port = u16::from_be_bytes(port_bytes);
715
716 let addr_field = this.project_field_named(&address, "sin_addr")?;
717 let s_addr_field = this.project_field_named(&addr_field, "s_addr")?;
718 let addr_bytes: [u8; 4] = this
720 .read_bytes_ptr_strip_provenance(s_addr_field.ptr(), Size::from_bytes(4))?
721 .try_into()
722 .unwrap();
723 let addr_bits = u32::from_be_bytes(addr_bytes);
724
725 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_bits(addr_bits), port))
726 } else if family == this.eval_libc_i32("AF_INET6").into() {
727 let sockaddr_in6_layout = this.libc_ty_layout("sockaddr_in6");
728 if address_len != sockaddr_in6_layout.size.bytes() {
729 return interp_ok(Err(LibcError("EINVAL")));
731 }
732 let address = address.offset(Size::ZERO, sockaddr_in6_layout, this)?;
734
735 let port_field = this.project_field_named(&address, "sin6_port")?;
736 let port_bytes: [u8; 2] = this
738 .read_bytes_ptr_strip_provenance(port_field.ptr(), Size::from_bytes(2))?
739 .try_into()
740 .unwrap();
741 let port = u16::from_be_bytes(port_bytes);
742
743 let addr_field = this.project_field_named(&address, "sin6_addr")?;
744 let s_addr_field = this
745 .project_field_named(&addr_field, "s6_addr")?
746 .transmute(this.machine.layouts.u128, this)?;
747 let addr_bytes: [u8; 16] = this
749 .read_bytes_ptr_strip_provenance(s_addr_field.ptr(), Size::from_bytes(16))?
750 .try_into()
751 .unwrap();
752 let addr_bits = u128::from_be_bytes(addr_bytes);
753
754 let flowinfo_field = this.project_field_named(&address, "sin6_flowinfo")?;
755 let flowinfo = this.read_scalar(&flowinfo_field)?.to_u32()?;
758
759 let scope_id_field = this.project_field_named(&address, "sin6_scope_id")?;
760 let scope_id = this.read_scalar(&scope_id_field)?.to_u32()?;
763
764 SocketAddr::V6(SocketAddrV6::new(
765 Ipv6Addr::from_bits(addr_bits),
766 port,
767 flowinfo,
768 scope_id,
769 ))
770 } else {
771 throw_unsup_format!(
774 "{foreign_name}: address family {family:#x} is unsupported, \
775 only AF_INET and AF_INET6 are allowed"
776 );
777 };
778
779 interp_ok(Ok(socket_addr))
780 }
781
782 fn write_socket_address(
792 &mut self,
793 address: &SocketAddr,
794 address_ptr: Pointer,
795 address_len_ptr: Pointer,
796 foreign_name: &'static str,
797 ) -> InterpResult<'tcx, Result<(), IoError>> {
798 let this = self.eval_context_mut();
799
800 if address_ptr == Pointer::null() || address_len_ptr == Pointer::null() {
801 throw_ub_format!(
804 "{foreign_name}: writing a socket address but the address or the length pointer is a null pointer"
805 )
806 }
807
808 let socklen_layout = this.libc_ty_layout("socklen_t");
809 let address_buffer_len_place = this.ptr_to_mplace(address_len_ptr, socklen_layout);
810 let address_buffer_len: u64 = this
813 .read_scalar(&address_buffer_len_place)?
814 .to_int(socklen_layout.size)?
815 .try_into()
816 .unwrap();
817
818 let (address_buffer, address_layout) = match address {
819 SocketAddr::V4(address) => {
820 let address_bytes = address.ip().octets();
822 let port = address.port().to_be();
824
825 let sockaddr_in_layout = this.libc_ty_layout("sockaddr_in");
826 let address_buffer = this.allocate(sockaddr_in_layout, MemoryKind::Stack)?;
830 this.write_bytes_ptr(
833 address_buffer.ptr(),
834 iter::repeat_n(0, address_buffer.layout.size.bytes_usize()),
835 )?;
836
837 let sin_family_field = this.project_field_named(&address_buffer, "sin_family")?;
838 let af_inet = this.eval_libc("AF_INET");
843 let address_family =
844 Scalar::from_int(af_inet.to_int(af_inet.size())?, sin_family_field.layout.size);
845 this.write_scalar(address_family, &sin_family_field)?;
846
847 let sin_port_field = this.project_field_named(&address_buffer, "sin_port")?;
848 this.write_bytes_ptr(sin_port_field.ptr(), port.to_ne_bytes())?;
851
852 let sin_addr_field = this.project_field_named(&address_buffer, "sin_addr")?;
853 let s_addr_field = this.project_field_named(&sin_addr_field, "s_addr")?;
854 this.write_bytes_ptr(s_addr_field.ptr(), address_bytes)?;
855
856 (address_buffer, sockaddr_in_layout)
857 }
858 SocketAddr::V6(address) => {
859 let address_bytes = address.ip().octets();
861 let port = address.port().to_be();
863 let flowinfo = address.flowinfo();
865 let scope_id = address.scope_id();
867
868 let sockaddr_in6_layout = this.libc_ty_layout("sockaddr_in6");
869 let address_buffer = this.allocate(sockaddr_in6_layout, MemoryKind::Stack)?;
873 this.write_bytes_ptr(
876 address_buffer.ptr(),
877 iter::repeat_n(0, address_buffer.layout.size.bytes_usize()),
878 )?;
879
880 let sin6_family_field = this.project_field_named(&address_buffer, "sin6_family")?;
881 let af_inet6 = this.eval_libc("AF_INET6");
886 let address_family = Scalar::from_int(
887 af_inet6.to_int(af_inet6.size())?,
888 sin6_family_field.layout.size,
889 );
890 this.write_scalar(address_family, &sin6_family_field)?;
891
892 let sin6_port_field = this.project_field_named(&address_buffer, "sin6_port")?;
893 this.write_bytes_ptr(sin6_port_field.ptr(), port.to_ne_bytes())?;
896
897 let sin6_flowinfo_field =
898 this.project_field_named(&address_buffer, "sin6_flowinfo")?;
899 this.write_scalar(Scalar::from_u32(flowinfo), &sin6_flowinfo_field)?;
900
901 let sin6_scope_id_field =
902 this.project_field_named(&address_buffer, "sin6_scope_id")?;
903 this.write_scalar(Scalar::from_u32(scope_id), &sin6_scope_id_field)?;
904
905 let sin6_addr_field = this.project_field_named(&address_buffer, "sin6_addr")?;
906 let s6_addr_field = this.project_field_named(&sin6_addr_field, "s6_addr")?;
907 this.write_bytes_ptr(s6_addr_field.ptr(), address_bytes)?;
908
909 (address_buffer, sockaddr_in6_layout)
910 }
911 };
912
913 this.mem_copy(
915 address_buffer.ptr(),
916 address_ptr,
917 address_layout.size.min(Size::from_bytes(address_buffer_len)),
919 true,
922 )?;
923 this.deallocate_ptr(address_buffer.ptr(), None, MemoryKind::Stack)?;
926 let address_len = address_layout.size.bytes();
928
929 this.write_scalar(
930 Scalar::from_uint(address_len, socklen_layout.size),
931 &address_buffer_len_place,
932 )?;
933
934 interp_ok(Ok(()))
935 }
936
937 fn block_for_accept(
941 &mut self,
942 address_ptr: Pointer,
943 address_len_ptr: Pointer,
944 is_client_sock_nonblock: bool,
945 socket: FileDescriptionRef<Socket>,
946 dest: MPlaceTy<'tcx>,
947 ) {
948 let this = self.eval_context_mut();
949 this.block_thread_for_io(
950 socket.clone(),
951 Interest::READABLE,
952 None,
953 callback!(@capture<'tcx> {
954 address_ptr: Pointer,
955 address_len_ptr: Pointer,
956 is_client_sock_nonblock: bool,
957 socket: FileDescriptionRef<Socket>,
958 dest: MPlaceTy<'tcx>,
959 } |this, kind: UnblockKind| {
960 assert_eq!(kind, UnblockKind::Ready);
961
962 let state = socket.state.borrow();
963
964 let SocketState::Listening(listener) = &*state else {
965 unreachable!()
969 };
970
971 let (stream, addr) = match listener.accept() {
972 Ok(peer) => peer,
973 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
974 drop(state);
976 this.block_for_accept(address_ptr, address_len_ptr, is_client_sock_nonblock, socket, dest);
977 return interp_ok(())
978 },
979 Err(e) => return this.set_last_error_and_return(e, &dest),
980 };
981
982 let family = match addr {
983 SocketAddr::V4(_) => SocketFamily::IPv4,
984 SocketAddr::V6(_) => SocketFamily::IPv6,
985 };
986
987 if address_ptr != Pointer::null() {
988 if let Err(e) = this.write_socket_address(&addr, address_ptr, address_len_ptr, "accept4")? {
992 return this.set_last_error_and_return(e, &dest);
993 };
994 }
995
996 let fd = this.machine.fds.new_ref(Socket {
997 family,
998 state: RefCell::new(SocketState::Connected(stream)),
999 is_non_block: Cell::new(is_client_sock_nonblock),
1000 });
1001 let sockfd = this.machine.fds.insert(fd);
1002 this.write_scalar(Scalar::from_int(sockfd, dest.layout.size), &dest)
1007 }),
1008 );
1009 }
1010
1011 fn block_for_connect(&mut self, socket: FileDescriptionRef<Socket>, dest: MPlaceTy<'tcx>) {
1013 let this = self.eval_context_mut();
1014 this.block_thread_for_io(
1015 socket.clone(),
1016 Interest::WRITABLE,
1017 None,
1018 callback!(@capture<'tcx> {
1019 socket: FileDescriptionRef<Socket>,
1020 dest: MPlaceTy<'tcx>,
1021 } |this, kind: UnblockKind| {
1022 assert_eq!(kind, UnblockKind::Ready);
1023
1024 let mut state = socket.state.borrow_mut();
1025
1026 match state.try_set_connected() {
1028 Ok(_) => this.write_scalar(Scalar::from_i32(0), &dest),
1029 Err(SocketIoError::NotReady) => {
1030 drop(state);
1032 this.block_for_connect(socket, dest);
1033 return interp_ok(())
1034 },
1035 Err(SocketIoError::Other(e)) => return this.set_last_error_and_return(e, &dest)
1036 }
1037 }),
1038 );
1039 }
1040}
1041
1042impl VisitProvenance for FileDescriptionRef<Socket> {
1043 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
1046}
1047
1048impl WithSource for FileDescriptionRef<Socket> {
1049 fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()> {
1050 let mut state = self.state.borrow_mut();
1051 match &mut *state {
1052 SocketState::Listening(listener) => f(listener),
1053 SocketState::Connecting(stream) | SocketState::Connected(stream) => f(stream),
1054 _ => unreachable!(),
1056 }
1057 }
1058}