1use std::net::{Shutdown, SocketAddr};
2
3use rustc_abi::Size;
4use rustc_target::spec::Os;
5
6use crate::shims::FileDescriptionRef;
7use crate::shims::files::FdNum;
8use crate::shims::unix::UnixFileDescription;
9use crate::shims::unix::socket_address::EvalContextExt as _;
10use crate::shims::unix::tcp_socket::TcpSocket;
11use crate::*;
12
13#[derive(Debug, PartialEq)]
14pub enum SocketFamily {
15 IPv4,
17 IPv6,
19}
20
21pub trait UnixSocketFileDescription: UnixFileDescription {
25 fn bind<'tcx>(
27 self: FileDescriptionRef<Self>,
28 _communicate_allowed: bool,
29 _address: SocketAddr,
30 _ecx: &mut MiriInterpCx<'tcx>,
31 ) -> InterpResult<'tcx, Result<(), IoError>> {
32 throw_unsup_format!("cannot bind {}", self.name());
33 }
34
35 fn listen<'tcx>(
39 self: FileDescriptionRef<Self>,
40 _communicate_allowed: bool,
41 _backlog: i32,
42 _ecx: &mut MiriInterpCx<'tcx>,
43 ) -> InterpResult<'tcx, Result<(), IoError>> {
44 throw_unsup_format!("cannot listen on {}", self.name());
45 }
46
47 fn accept<'tcx>(
53 self: FileDescriptionRef<Self>,
54 _communicate_allowed: bool,
55 _is_client_sock_non_block: bool,
56 _ecx: &mut MiriInterpCx<'tcx>,
57 _finish: DynMachineCallback<'tcx, Result<(FdNum, SocketAddr), IoError>>,
58 ) -> InterpResult<'tcx> {
59 throw_unsup_format!("cannot accept {}", self.name());
60 }
61
62 fn connect<'tcx>(
64 self: FileDescriptionRef<Self>,
65 _communicate_allowed: bool,
66 _address: SocketAddr,
67 _ecx: &mut MiriInterpCx<'tcx>,
68 _finish: DynMachineCallback<'tcx, Result<(), IoError>>,
69 ) -> InterpResult<'tcx> {
70 throw_unsup_format!("cannot connect {}", self.name());
71 }
72
73 fn recv<'tcx>(
80 self: FileDescriptionRef<Self>,
81 _communicate_allowed: bool,
82 _ptr: Pointer,
83 _len: usize,
84 _is_peek: bool,
85 _is_non_block: bool,
86 _ecx: &mut MiriInterpCx<'tcx>,
87 _finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
88 ) -> InterpResult<'tcx> {
89 throw_unsup_format!("cannot receive from {}", self.name());
90 }
91
92 fn send<'tcx>(
97 self: FileDescriptionRef<Self>,
98 _communicate_allowed: bool,
99 _ptr: Pointer,
100 _len: usize,
101 _is_non_block: bool,
102 _ecx: &mut MiriInterpCx<'tcx>,
103 _finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
104 ) -> InterpResult<'tcx> {
105 throw_unsup_format!("cannot send to {}", self.name());
106 }
107
108 fn setsockopt<'tcx>(
112 self: FileDescriptionRef<Self>,
113 _level: i32,
114 _option: i32,
115 _value_ptr: Pointer,
116 _value_len: u64,
117 _ecx: &mut MiriInterpCx<'tcx>,
118 ) -> InterpResult<'tcx, Result<(), IoError>> {
119 throw_unsup_format!("cannot set socket option on {}", self.name());
120 }
121
122 fn getsockopt<'tcx>(
124 self: FileDescriptionRef<Self>,
125 _level: i32,
126 _option: i32,
127 _ecx: &mut MiriInterpCx<'tcx>,
128 ) -> InterpResult<'tcx, Result<MPlaceTy<'tcx>, IoError>> {
129 throw_unsup_format!("cannot get socket option for {}", self.name());
130 }
131
132 fn getsockname<'tcx>(
134 self: FileDescriptionRef<Self>,
135 _communicate_allowed: bool,
136 _ecx: &mut MiriInterpCx<'tcx>,
137 ) -> InterpResult<'tcx, Result<SocketAddr, IoError>> {
138 throw_unsup_format!("cannot get socket name for {}", self.name());
139 }
140
141 fn getpeername<'tcx>(
143 self: FileDescriptionRef<Self>,
144 _communicate_allowed: bool,
145 _ecx: &mut MiriInterpCx<'tcx>,
146 _finish: DynMachineCallback<'tcx, Result<SocketAddr, IoError>>,
147 ) -> InterpResult<'tcx> {
148 throw_unsup_format!("cannot get peer name for {}", self.name());
149 }
150
151 fn shutdown<'tcx>(
153 self: FileDescriptionRef<Self>,
154 _communicate_allowed: bool,
155 _how: Shutdown,
156 _ecx: &mut MiriInterpCx<'tcx>,
157 ) -> InterpResult<'tcx, Result<(), IoError>> {
158 throw_unsup_format!("cannot shut down {}", self.name());
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_errno_and_return_neg1_i32(LibcError("EACCES"));
182 }
183
184 let mut is_non_block = 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_non_block = 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 && protocol != this.eval_libc_i32("IPPROTO_TCP") {
226 throw_unsup_format!(
227 "socket: socket protocol {protocol} is unsupported, \
228 only IPPROTO_TCP and 0 are allowed"
229 );
230 }
231
232 let fds = &mut this.machine.fds;
233 let fd = fds.new_ref(TcpSocket::new(family, is_non_block));
234
235 interp_ok(Scalar::from_i32(fds.insert(fd)))
236 }
237
238 fn bind(
239 &mut self,
240 socket: &OpTy<'tcx>,
241 address: &OpTy<'tcx>,
242 address_len: &OpTy<'tcx>,
243 ) -> InterpResult<'tcx, Scalar> {
244 let this = self.eval_context_mut();
245
246 let socket = this.read_scalar(socket)?.to_i32()?;
247 let address = match this.read_socket_address(address, address_len, "bind")? {
248 Ok(addr) => addr,
249 Err(e) => return this.set_errno_and_return_neg1_i32(e),
250 };
251
252 let Some(fd) = this.machine.fds.get(socket) else {
254 return this.set_errno_and_return_neg1_i32(LibcError("EBADF"));
255 };
256
257 let Some(socket) = fd.as_unix(this).as_socket(this) else {
258 return this.set_errno_and_return_neg1_i32(LibcError("ENOTSOCK"));
259 };
260
261 match socket.bind(this.machine.communicate(), address, this)? {
262 Ok(_) => interp_ok(Scalar::from_i32(0)),
263 Err(e) => this.set_errno_and_return_neg1_i32(e),
264 }
265 }
266
267 fn listen(&mut self, socket: &OpTy<'tcx>, backlog: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
268 let this = self.eval_context_mut();
269
270 let socket = this.read_scalar(socket)?.to_i32()?;
271 let backlog = this.read_scalar(backlog)?.to_i32()?;
272
273 let Some(fd) = this.machine.fds.get(socket) else {
275 return this.set_errno_and_return_neg1_i32(LibcError("EBADF"));
276 };
277
278 let Some(socket) = fd.as_unix(this).as_socket(this) else {
279 return this.set_errno_and_return_neg1_i32(LibcError("ENOTSOCK"));
280 };
281
282 match socket.listen(this.machine.communicate(), backlog, this)? {
283 Ok(_) => interp_ok(Scalar::from_i32(0)),
284 Err(e) => this.set_errno_and_return_neg1_i32(e),
285 }
286 }
287
288 fn accept4(
291 &mut self,
292 socket: &OpTy<'tcx>,
293 address: &OpTy<'tcx>,
294 address_len: &OpTy<'tcx>,
295 flags: Option<&OpTy<'tcx>>,
296 dest: &MPlaceTy<'tcx>,
298 ) -> InterpResult<'tcx> {
299 let this = self.eval_context_mut();
300
301 let socket = this.read_scalar(socket)?.to_i32()?;
302 let address_ptr = this.read_pointer(address)?;
303 let address_len_ptr = this.read_pointer(address_len)?;
304 let mut flags =
305 if let Some(flags) = flags { this.read_scalar(flags)?.to_i32()? } else { 0 };
306
307 let Some(fd) = this.machine.fds.get(socket) else {
309 return this.set_errno_and_return_neg1(LibcError("EBADF"), dest);
310 };
311
312 let Some(socket) = fd.as_unix(this).as_socket(this) else {
313 return this.set_errno_and_return_neg1(LibcError("ENOTSOCK"), dest);
314 };
315
316 let mut is_client_sock_nonblock = false;
317
318 if matches!(
321 this.tcx.sess.target.os,
322 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
323 ) {
324 let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK");
327 let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC");
328 if flags & sock_nonblock == sock_nonblock {
329 is_client_sock_nonblock = true;
330 flags &= !sock_nonblock;
331 }
332 if flags & sock_cloexec == sock_cloexec {
333 flags &= !sock_cloexec;
335 }
336 }
337
338 if flags != 0 {
339 throw_unsup_format!(
340 "accept4: flag {flags:#x} is unsupported, only SOCK_CLOEXEC \
341 and SOCK_NONBLOCK are allowed",
342 );
343 }
344
345 let dest = dest.clone();
346 socket.accept(
347 this.machine.communicate(),
348 is_client_sock_nonblock,
349 this,
350 callback!(
351 @capture<'tcx> {
352 address_ptr: Pointer,
353 address_len_ptr: Pointer,
354 dest: MPlaceTy<'tcx>
355 } |this, result: Result<(FdNum, SocketAddr), IoError>| {
356 let (client_sockfd, address) = match result {
357 Ok(data) => data,
358 Err(e) => return this.set_errno_and_return_neg1(e, &dest),
359 };
360
361 if address_ptr != Pointer::null() {
362 this.write_socket_address(&address, address_ptr, address_len_ptr, "accept4")?;
366 }
367
368 this.write_scalar(Scalar::from_int(client_sockfd, dest.layout.size), &dest)
373 }
374 ),
375 )
376 }
377
378 fn connect(
379 &mut self,
380 socket: &OpTy<'tcx>,
381 address: &OpTy<'tcx>,
382 address_len: &OpTy<'tcx>,
383 dest: &MPlaceTy<'tcx>,
385 ) -> InterpResult<'tcx> {
386 let this = self.eval_context_mut();
387
388 let socket = this.read_scalar(socket)?.to_i32()?;
389 let address = match this.read_socket_address(address, address_len, "connect")? {
390 Ok(address) => address,
391 Err(e) => return this.set_errno_and_return_neg1(e, dest),
392 };
393
394 let Some(fd) = this.machine.fds.get(socket) else {
396 return this.set_errno_and_return_neg1(LibcError("EBADF"), dest);
397 };
398
399 let Some(socket) = fd.as_unix(this).as_socket(this) else {
400 return this.set_errno_and_return_neg1(LibcError("ENOTSOCK"), dest);
401 };
402
403 let dest = dest.clone();
404
405 socket.connect(
406 this.machine.communicate(),
407 address,
408 this,
409 callback!(
410 @capture<'tcx> {
411 dest: MPlaceTy<'tcx>
412 } |this, result: Result<(), IoError>| {
413 match result {
414 Ok(()) => this.write_null(&dest),
415 Err(e) => this.set_errno_and_return_neg1(e, &dest)
416 }
417 }
418 ),
419 )
420 }
421
422 fn send(
423 &mut self,
424 socket: &OpTy<'tcx>,
425 buffer: &OpTy<'tcx>,
426 length: &OpTy<'tcx>,
427 flags: &OpTy<'tcx>,
428 dest: &MPlaceTy<'tcx>,
430 ) -> InterpResult<'tcx> {
431 let this = self.eval_context_mut();
432
433 let socket = this.read_scalar(socket)?.to_i32()?;
434 let buffer_ptr = this.read_pointer(buffer)?;
435 let size_layout = this.libc_ty_layout("size_t");
436 let length: usize =
437 this.read_scalar(length)?.to_uint(size_layout.size)?.try_into().unwrap();
438 let mut flags = this.read_scalar(flags)?.to_i32()?;
439
440 let Some(fd) = this.machine.fds.get(socket) else {
442 return this.set_errno_and_return_neg1(LibcError("EBADF"), dest);
443 };
444
445 let Some(socket) = fd.as_unix(this).as_socket(this) else {
446 return this.set_errno_and_return_neg1(LibcError("ENOTSOCK"), dest);
447 };
448
449 let mut is_non_block = false;
450
451 if matches!(
454 this.tcx.sess.target.os,
455 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
456 ) {
457 let msg_nosignal = this.eval_libc_i32("MSG_NOSIGNAL");
460 let msg_dontwait = this.eval_libc_i32("MSG_DONTWAIT");
461 if flags & msg_nosignal == msg_nosignal {
462 flags &= !msg_nosignal;
466 }
467 if flags & msg_dontwait == msg_dontwait {
468 flags &= !msg_dontwait;
469 is_non_block = true;
470 }
471 }
472
473 if flags != 0 {
474 throw_unsup_format!(
475 "send: flag {flags:#x} is unsupported, only MSG_NOSIGNAL and MSG_DONTWAIT are allowed",
476 );
477 }
478
479 let dest = dest.clone();
480
481 socket.send(
482 this.machine.communicate(),
483 buffer_ptr,
484 length,
485 is_non_block,
486 this,
487 callback!(
488 @capture<'tcx> {
489 dest: MPlaceTy<'tcx>,
490 } |this, result: Result<usize, IoError>| {
491 match result {
492 Ok(bytes_sent) =>
493 this.write_scalar(Scalar::from_target_usize(bytes_sent.try_into().unwrap(), this), &dest),
494 Err(e) => this.set_errno_and_return_neg1(e, &dest)
495 }
496 }
497 )
498 )
499 }
500
501 fn recv(
502 &mut self,
503 socket: &OpTy<'tcx>,
504 buffer: &OpTy<'tcx>,
505 length: &OpTy<'tcx>,
506 flags: &OpTy<'tcx>,
507 dest: &MPlaceTy<'tcx>,
509 ) -> InterpResult<'tcx> {
510 let this = self.eval_context_mut();
511
512 let socket = this.read_scalar(socket)?.to_i32()?;
513 let buffer_ptr = this.read_pointer(buffer)?;
514 let size_layout = this.libc_ty_layout("size_t");
515 let length: usize =
516 this.read_scalar(length)?.to_uint(size_layout.size)?.try_into().unwrap();
517 let mut flags = this.read_scalar(flags)?.to_i32()?;
518
519 let Some(fd) = this.machine.fds.get(socket) else {
521 return this.set_errno_and_return_neg1(LibcError("EBADF"), dest);
522 };
523
524 let Some(socket) = fd.as_unix(this).as_socket(this) else {
525 return this.set_errno_and_return_neg1(LibcError("ENOTSOCK"), dest);
526 };
527
528 let mut is_peek = false;
529 let mut is_non_block = false;
530
531 let msg_peek = this.eval_libc_i32("MSG_PEEK");
535 if flags & msg_peek == msg_peek {
536 is_peek = true;
537 flags &= !msg_peek;
538 }
539
540 if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android | Os::FreeBsd | Os::Illumos) {
541 let msg_cmsg_cloexec = this.eval_libc_i32("MSG_CMSG_CLOEXEC");
544 if flags & msg_cmsg_cloexec == msg_cmsg_cloexec {
545 flags &= !msg_cmsg_cloexec;
547 }
548 }
549
550 if matches!(
551 this.tcx.sess.target.os,
552 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
553 ) {
554 let msg_dontwait = this.eval_libc_i32("MSG_DONTWAIT");
557 if flags & msg_dontwait == msg_dontwait {
558 flags &= !msg_dontwait;
559 is_non_block = true;
560 }
561 }
562
563 if flags != 0 {
564 throw_unsup_format!(
565 "recv: flag {flags:#x} is unsupported, only MSG_PEEK, MSG_DONTWAIT \
566 and MSG_CMSG_CLOEXEC are allowed",
567 );
568 }
569
570 let dest = dest.clone();
571
572 socket.recv(
573 this.machine.communicate(),
574 buffer_ptr,
575 length,
576 is_peek,
577 is_non_block,
578 this,
579 callback!(
580 @capture<'tcx> {
581 dest: MPlaceTy<'tcx>,
582 } |this, result: Result<usize, IoError>| {
583 match result {
584 Ok(bytes_sent) =>
585 this.write_scalar(Scalar::from_target_usize(bytes_sent.try_into().unwrap(), this), &dest),
586 Err(e) => this.set_errno_and_return_neg1(e, &dest)
587 }
588 }
589 ),
590 )
591 }
592
593 fn setsockopt(
594 &mut self,
595 socket: &OpTy<'tcx>,
596 level: &OpTy<'tcx>,
597 option_name: &OpTy<'tcx>,
598 option_value: &OpTy<'tcx>,
599 option_len: &OpTy<'tcx>,
600 ) -> InterpResult<'tcx, Scalar> {
601 let this = self.eval_context_mut();
602
603 let socket = this.read_scalar(socket)?.to_i32()?;
604 let level = this.read_scalar(level)?.to_i32()?;
605 let option_name = this.read_scalar(option_name)?.to_i32()?;
606 let option_value_ptr = this.read_pointer(option_value)?;
607 let socklen_layout = this.libc_ty_layout("socklen_t");
608 let option_len: u64 =
609 this.read_scalar(option_len)?.to_int(socklen_layout.size)?.try_into().unwrap();
610
611 let Some(fd) = this.machine.fds.get(socket) else {
613 return this.set_errno_and_return_neg1_i32(LibcError("EBADF"));
614 };
615
616 let Some(socket) = fd.as_unix(this).as_socket(this) else {
617 return this.set_errno_and_return_neg1_i32(LibcError("ENOTSOCK"));
618 };
619
620 let result = socket.setsockopt(level, option_name, option_value_ptr, option_len, this)?;
621 match result {
622 Ok(_) => interp_ok(Scalar::from_i32(0)),
623 Err(e) => this.set_errno_and_return_neg1_i32(e),
624 }
625 }
626
627 fn getsockopt(
628 &mut self,
629 socket: &OpTy<'tcx>,
630 level: &OpTy<'tcx>,
631 option_name: &OpTy<'tcx>,
632 option_value: &OpTy<'tcx>,
633 option_len: &OpTy<'tcx>,
634 ) -> InterpResult<'tcx, Scalar> {
635 let this = self.eval_context_mut();
636
637 let socket = this.read_scalar(socket)?.to_i32()?;
638 let level = this.read_scalar(level)?.to_i32()?;
639 let option_name = this.read_scalar(option_name)?.to_i32()?;
640 let option_value_ptr = this.read_pointer(option_value)?;
646 let option_len_ptr = this.read_pointer(option_len)?;
647
648 let Some(fd) = this.machine.fds.get(socket) else {
650 return this.set_errno_and_return_neg1_i32(LibcError("EBADF"));
651 };
652
653 let Some(socket) = fd.as_unix(this).as_socket(this) else {
654 return this.set_errno_and_return_neg1_i32(LibcError("ENOTSOCK"));
655 };
656
657 if option_value_ptr == Pointer::null() || option_len_ptr == Pointer::null() {
658 return this.set_errno_and_return_neg1_i32(LibcError("EFAULT"));
661 }
662
663 let socklen_layout = this.libc_ty_layout("socklen_t");
664 let option_len_ptr_mplace = this.ptr_to_mplace(option_len_ptr, socklen_layout);
665 let option_len: usize = this
666 .read_scalar(&option_len_ptr_mplace)?
667 .to_int(socklen_layout.size)?
668 .try_into()
669 .unwrap();
670
671 let value_mplace = match socket.getsockopt(level, option_name, this)? {
674 Ok(value_mplace) => value_mplace,
675 Err(e) => return this.set_errno_and_return_neg1_i32(e),
676 };
677
678 let output_value_len = value_mplace.layout.size.min(Size::from_bytes(option_len));
680 this.mem_copy(
682 value_mplace.ptr(),
683 option_value_ptr,
684 output_value_len,
686 true,
689 )?;
690 this.deallocate_ptr(value_mplace.ptr(), None, MemoryKind::Stack)?;
693
694 this.write_scalar(
697 Scalar::from_uint(output_value_len.bytes(), socklen_layout.size),
698 &option_len_ptr_mplace,
699 )?;
700
701 interp_ok(Scalar::from_i32(0))
702 }
703
704 fn getsockname(
705 &mut self,
706 socket: &OpTy<'tcx>,
707 address: &OpTy<'tcx>,
708 address_len: &OpTy<'tcx>,
709 ) -> InterpResult<'tcx, Scalar> {
710 let this = self.eval_context_mut();
711
712 let socket = this.read_scalar(socket)?.to_i32()?;
713 let address_ptr = this.read_pointer(address)?;
714 let address_len_ptr = this.read_pointer(address_len)?;
715
716 let Some(fd) = this.machine.fds.get(socket) else {
718 return this.set_errno_and_return_neg1_i32(LibcError("EBADF"));
719 };
720
721 let Some(socket) = fd.as_unix(this).as_socket(this) else {
722 return this.set_errno_and_return_neg1_i32(LibcError("ENOTSOCK"));
723 };
724
725 let address = match socket.getsockname(this.machine.communicate(), this)? {
726 Ok(address) => address,
727 Err(e) => return this.set_errno_and_return_neg1_i32(e),
728 };
729
730 this.write_socket_address(&address, address_ptr, address_len_ptr, "getsockname")
731 .map(|_| Scalar::from_i32(0))
732 }
733
734 fn getpeername(
735 &mut self,
736 socket: &OpTy<'tcx>,
737 address: &OpTy<'tcx>,
738 address_len: &OpTy<'tcx>,
739 dest: &MPlaceTy<'tcx>,
741 ) -> InterpResult<'tcx> {
742 let this = self.eval_context_mut();
743
744 let socket = this.read_scalar(socket)?.to_i32()?;
745 let address_ptr = this.read_pointer(address)?;
746 let address_len_ptr = this.read_pointer(address_len)?;
747
748 let Some(fd) = this.machine.fds.get(socket) else {
750 return this.set_errno_and_return_neg1(LibcError("EBADF"), dest);
751 };
752
753 let Some(socket) = fd.as_unix(this).as_socket(this) else {
754 return this.set_errno_and_return_neg1(LibcError("ENOTSOCK"), dest);
755 };
756
757 let dest = dest.clone();
758
759 socket.getpeername(
760 this.machine.communicate(),
761 this,
762 callback!(
763 @capture<'tcx> {
764 address_ptr: Pointer,
765 address_len_ptr: Pointer,
766 dest: MPlaceTy<'tcx>,
767 } |this, result: Result<SocketAddr, IoError>| {
768 let address = match result {
769 Ok(address) => address,
770 Err(e) => return this.set_errno_and_return_neg1(e, &dest)
771 };
772
773 this.write_socket_address(
774 &address,
775 address_ptr,
776 address_len_ptr,
777 "getpeername",
778 )?;
779 this.write_scalar(Scalar::from_i32(0), &dest)
780 }
781 ),
782 )
783 }
784
785 fn shutdown(&mut self, socket: &OpTy<'tcx>, how: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
786 let this = self.eval_context_mut();
787
788 let socket = this.read_scalar(socket)?.to_i32()?;
789 let how = this.read_scalar(how)?.to_i32()?;
790
791 let Some(fd) = this.machine.fds.get(socket) else {
793 return this.set_errno_and_return_neg1_i32(LibcError("EBADF"));
794 };
795
796 let Some(socket) = fd.as_unix(this).as_socket(this) else {
797 return this.set_errno_and_return_neg1_i32(LibcError("ENOTSOCK"));
798 };
799
800 let is_read_shutdown = how == this.eval_libc_i32("SHUT_RD");
801 let is_write_shutdown = how == this.eval_libc_i32("SHUT_WR");
802 let is_read_write_shutdown = how == this.eval_libc_i32("SHUT_RDWR");
803
804 let how = match () {
805 _ if is_read_shutdown => Shutdown::Read,
806 _ if is_write_shutdown => Shutdown::Write,
807 _ if is_read_write_shutdown => Shutdown::Both,
808 _ => return this.set_errno_and_return_neg1_i32(LibcError("EINVAL")),
810 };
811
812 match socket.shutdown(this.machine.communicate(), how, this)? {
813 Ok(_) => interp_ok(Scalar::from_i32(0)),
814 Err(e) => this.set_errno_and_return_neg1_i32(e),
815 }
816 }
817}