1use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
4use std::collections::BTreeMap;
5use std::ffi::{CStr, CString, OsString};
6use std::net::{Ipv4Addr, SocketAddrV4};
7use std::ops::{Deref, DerefMut};
8use std::os::unix::prelude::OsStringExt;
9use std::path::{Path, PathBuf};
10use std::sync::{Arc, Mutex};
11
12use asm_util::tsc::Tsc;
13use atomic_refcell::AtomicRefCell;
14use linux_api::signal::{Signal, siginfo_t};
15use log::{debug, trace};
16use logger::LogLevel;
17use once_cell::unsync::OnceCell;
18use rand::SeedableRng;
19use rand_xoshiro::Xoshiro256PlusPlus;
20use shadow_shim_helper_rs::HostId;
21use shadow_shim_helper_rs::emulated_time::EmulatedTime;
22use shadow_shim_helper_rs::explicit_drop::ExplicitDropper;
23use shadow_shim_helper_rs::rootedcell::Root;
24use shadow_shim_helper_rs::rootedcell::cell::RootedCell;
25use shadow_shim_helper_rs::rootedcell::rc::RootedRc;
26use shadow_shim_helper_rs::rootedcell::refcell::RootedRefCell;
27use shadow_shim_helper_rs::shim_shmem::{HostShmem, HostShmemProtected, ManagerShmem};
28use shadow_shim_helper_rs::simulation_time::SimulationTime;
29use shadow_shmem::allocator::ShMemBlock;
30use vasi_sync::scmutex::SelfContainedMutexGuard;
31
32use crate::core::configuration::{ProcessFinalState, QDiscMode};
33use crate::core::sim_config::PcapConfig;
34use crate::core::work::event::{Event, EventData};
35use crate::core::work::event_queue::EventQueue;
36use crate::core::work::task::TaskRef;
37use crate::core::worker::Worker;
38use crate::cshadow;
39use crate::host::descriptor::socket::abstract_unix_ns::AbstractUnixNamespace;
40use crate::host::descriptor::socket::inet::InetSocket;
41use crate::host::futex_table::FutexTable;
42use crate::host::network::interface::{FifoPacketPriority, NetworkInterface, PcapOptions};
43use crate::host::network::namespace::NetworkNamespace;
44use crate::host::process::Process;
45use crate::host::thread::{Thread, ThreadId};
46use crate::network::PacketDevice;
47use crate::network::relay::{RateLimit, Relay};
48use crate::network::router::Router;
49use crate::utility;
50#[cfg(feature = "perf_timers")]
51use crate::utility::perf_timer::PerfTimer;
52
53pub struct HostParameters {
54 pub id: HostId,
55 pub node_seed: u64,
56 pub hostname: CString,
59 pub node_id: u32,
60 pub ip_addr: libc::in_addr_t,
61 pub sim_end_time: EmulatedTime,
62 pub requested_bw_down_bits: u64,
63 pub requested_bw_up_bits: u64,
64 pub cpu_frequency: u64,
65 pub cpu_threshold: Option<SimulationTime>,
66 pub cpu_precision: Option<SimulationTime>,
67 pub log_level: LogLevel,
68 pub pcap_config: Option<PcapConfig>,
69 pub qdisc: QDiscMode,
70 pub init_sock_recv_buf_size: u64,
71 pub autotune_recv_buf: bool,
72 pub init_sock_send_buf_size: u64,
73 pub autotune_send_buf: bool,
74 pub native_tsc_frequency: u64,
75 pub model_unblocked_syscall_latency: bool,
76 pub max_unapplied_cpu_latency: SimulationTime,
77 pub unblocked_syscall_latency: SimulationTime,
78 pub unblocked_vdso_latency: SimulationTime,
79 pub strace_logging_options: Option<FmtOptions>,
80 pub shim_log_level: LogLevel,
81 pub use_new_tcp: bool,
82 pub use_mem_mapper: bool,
83 pub use_syscall_counters: bool,
84}
85
86use super::cpu::Cpu;
87use super::process::ProcessId;
88use super::syscall::formatter::FmtOptions;
89
90#[derive(Debug, Clone)]
92pub struct HostInfo {
93 pub id: HostId,
94 pub name: String,
95 pub default_ip: Ipv4Addr,
96 pub log_level: Option<log::LevelFilter>,
97}
98
99pub struct Host {
101 info: OnceCell<Arc<HostInfo>>,
108
109 root: Root,
114
115 event_queue: Arc<Mutex<EventQueue>>,
116
117 random: RefCell<Xoshiro256PlusPlus>,
118
119 router: RefCell<Router>,
123
124 relay_inet_out: Arc<Relay>,
126 relay_inet_in: Arc<Relay>,
128 relay_loopback: Arc<Relay>,
130
131 futex_table: RefCell<FutexTable>,
133
134 #[cfg(feature = "perf_timers")]
135 execution_timer: RefCell<PerfTimer>,
136
137 pub params: HostParameters,
138
139 cpu: RefCell<Cpu>,
140
141 net_ns: NetworkNamespace,
142
143 data_dir_path: PathBuf,
149 data_dir_path_cstring: CString,
150
151 thread_id_counter: Cell<libc::pid_t>,
153 event_id_counter: Cell<u64>,
154 packet_id_counter: Cell<u64>,
155
156 determinism_sequence_counter: Cell<u64>,
158
159 packet_priority_counter: Cell<FifoPacketPriority>,
161
162 processes: RefCell<BTreeMap<ProcessId, RootedRc<RootedRefCell<Process>>>>,
164
165 tsc: Tsc,
166 shim_shmem_lock:
177 RefCell<Option<UnsafeCell<SelfContainedMutexGuard<'static, HostShmemProtected>>>>,
178 shim_shmem: UnsafeCell<ShMemBlock<'static, HostShmem>>,
190
191 in_notify_socket_has_packets: RootedCell<bool>,
192
193 preload_paths: Arc<Vec<PathBuf>>,
195}
196
197impl crate::utility::IsSend for Host {}
199
200impl std::fmt::Debug for Host {
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 f.debug_struct("Host")
204 .field("info", &self.info)
205 .finish_non_exhaustive()
206 }
207}
208
209impl Host {
210 pub fn new(
211 params: HostParameters,
212 host_root_path: &Path,
213 raw_cpu_freq_khz: u64,
214 manager_shmem: &ShMemBlock<ManagerShmem>,
215 preload_paths: Arc<Vec<PathBuf>>,
216 ) -> Self {
217 #[cfg(feature = "perf_timers")]
218 let execution_timer = RefCell::new(PerfTimer::new_started());
219
220 let root = Root::new();
221 let random = RefCell::new(Xoshiro256PlusPlus::seed_from_u64(params.node_seed));
222 let cpu = RefCell::new(Cpu::new(
223 params.cpu_frequency,
224 raw_cpu_freq_khz,
225 params.cpu_threshold,
226 params.cpu_precision,
227 ));
228 let data_dir_path = Self::make_data_dir_path(¶ms.hostname, host_root_path);
229 let data_dir_path_cstring = utility::pathbuf_to_nul_term_cstring(data_dir_path.clone());
230
231 let host_shmem = HostShmem::new(
232 params.id,
233 params.model_unblocked_syscall_latency,
234 params.max_unapplied_cpu_latency,
235 params.unblocked_syscall_latency,
236 params.unblocked_vdso_latency,
237 nix::unistd::getpid().as_raw(),
238 params.native_tsc_frequency,
239 params.shim_log_level,
240 manager_shmem,
241 );
242 let shim_shmem = UnsafeCell::new(shadow_shmem::allocator::shmalloc(host_shmem));
243
244 let thread_id_counter = Cell::new(1000);
246 let event_id_counter = Cell::new(0);
247 let packet_id_counter = Cell::new(0);
248 let determinism_sequence_counter = Cell::new(0);
249 let packet_priority_counter = Cell::new(1);
251 let tsc = Tsc::new(params.native_tsc_frequency);
252
253 std::fs::create_dir_all(&data_dir_path).unwrap();
254
255 let public_ip: Ipv4Addr = u32::from_be(params.ip_addr).into();
259
260 let pcap_options = params.pcap_config.as_ref().map(|x| PcapOptions {
261 path: data_dir_path.clone(),
262 capture_size_bytes: x.capture_size.try_into().unwrap(),
263 });
264
265 let net_ns = NetworkNamespace::new(public_ip, pcap_options, params.qdisc);
266
267 let router = Router::new(Ipv4Addr::UNSPECIFIED);
271 let relay_inet_out = Relay::new(
272 RateLimit::BytesPerSecond(params.requested_bw_up_bits / 8),
273 net_ns.internet.borrow().get_address(),
274 );
275 let relay_inet_in = Relay::new(
276 RateLimit::BytesPerSecond(params.requested_bw_down_bits / 8),
277 router.get_address(),
278 );
279 let relay_loopback = Relay::new(
280 RateLimit::Unlimited,
281 net_ns.localhost.borrow().get_address(),
282 );
283
284 let in_notify_socket_has_packets = RootedCell::new(&root, false);
285
286 let res = Self {
287 info: OnceCell::new(),
288 root,
289 event_queue: Arc::new(Mutex::new(EventQueue::new())),
290 params,
291 router: RefCell::new(router),
292 relay_inet_out: Arc::new(relay_inet_out),
293 relay_inet_in: Arc::new(relay_inet_in),
294 relay_loopback: Arc::new(relay_loopback),
295 futex_table: RefCell::new(FutexTable::new()),
296 random,
297 shim_shmem,
298 shim_shmem_lock: RefCell::new(None),
299 cpu,
300 net_ns,
301 data_dir_path,
302 data_dir_path_cstring,
303 thread_id_counter,
304 event_id_counter,
305 packet_id_counter,
306 packet_priority_counter,
307 determinism_sequence_counter,
308 tsc,
309 processes: RefCell::new(BTreeMap::new()),
310 #[cfg(feature = "perf_timers")]
311 execution_timer,
312 in_notify_socket_has_packets,
313 preload_paths,
314 };
315
316 res.stop_execution_timer();
317
318 debug!(
319 concat!(
320 "Setup host id '{:?}'",
321 " name '{name}'",
322 " with seed {seed},",
323 " {bw_up_kiBps} bwUpKiBps,",
324 " {bw_down_kiBps} bwDownKiBps,",
325 " {init_sock_send_buf_size} initSockSendBufSize,",
326 " {init_sock_recv_buf_size} initSockRecvBufSize, ",
327 " {cpu_frequency:?} cpuFrequency, ",
328 " {cpu_threshold:?} cpuThreshold, ",
329 " {cpu_precision:?} cpuPrecision"
330 ),
331 res.id(),
332 name = res.info().name,
333 seed = res.params.node_seed,
334 bw_up_kiBps = res.bw_up_kiBps(),
335 bw_down_kiBps = res.bw_down_kiBps(),
336 init_sock_send_buf_size = res.params.init_sock_send_buf_size,
337 init_sock_recv_buf_size = res.params.init_sock_recv_buf_size,
338 cpu_frequency = res.params.cpu_frequency,
339 cpu_threshold = res.params.cpu_threshold,
340 cpu_precision = res.params.cpu_precision,
341 );
342
343 res
344 }
345
346 pub fn root(&self) -> &Root {
347 &self.root
348 }
349
350 fn make_data_dir_path(hostname: &CStr, host_root_path: &Path) -> PathBuf {
351 let hostname: OsString = { OsString::from_vec(hostname.to_bytes().to_vec()) };
352
353 let mut data_dir_path = PathBuf::new();
354 data_dir_path.push(host_root_path);
355 data_dir_path.push(&hostname);
356 data_dir_path
357 }
358
359 pub fn data_dir_path(&self) -> &Path {
360 &self.data_dir_path
361 }
362
363 pub fn add_application(
364 &self,
365 start_time: SimulationTime,
366 shutdown_time: Option<SimulationTime>,
367 shutdown_signal: nix::sys::signal::Signal,
368 plugin_name: CString,
369 plugin_path: CString,
370 argv: Vec<CString>,
371 envv: Vec<CString>,
372 pause_for_debugging: bool,
373 expected_final_state: ProcessFinalState,
374 ) {
375 debug_assert!(shutdown_time.is_none() || shutdown_time.unwrap() > start_time);
376
377 let task = TaskRef::new(move |host| {
379 let envv = envv.clone();
383 let argv = argv.clone();
384
385 let process = Process::spawn(
386 host,
387 plugin_name.clone(),
388 &plugin_path,
389 argv,
390 envv,
391 pause_for_debugging,
392 host.params.strace_logging_options,
393 expected_final_state,
394 )
395 .unwrap_or_else(|e| panic!("Failed to initialize application {plugin_name:?}: {e:?}"));
396 let (process_id, thread_id) = {
397 let process = process.borrow(host.root());
398 (process.id(), process.thread_group_leader_id())
399 };
400 host.processes.borrow_mut().insert(process_id, process);
401
402 if let Some(shutdown_time) = shutdown_time {
403 let task = TaskRef::new(move |host| {
404 let Some(process) = host.process_borrow(process_id) else {
405 debug!(
406 "Can't send shutdown signal to process {process_id}; it no longer exists"
407 );
408 return;
409 };
410 let process = process.borrow(host.root());
411 let siginfo_t = siginfo_t::new_for_kill(
412 Signal::try_from(shutdown_signal as i32).unwrap(),
413 1,
414 0,
415 );
416 process.signal(host, None, &siginfo_t);
417 });
418 host.schedule_task_at_emulated_time(
419 task,
420 EmulatedTime::SIMULATION_START + shutdown_time,
421 );
422 }
423
424 host.resume(process_id, thread_id);
425 });
426 self.schedule_task_at_emulated_time(task, EmulatedTime::SIMULATION_START + start_time);
427 }
428
429 pub fn add_and_schedule_forked_process(
430 &self,
431 host: &Host,
432 process: RootedRc<RootedRefCell<Process>>,
433 ) {
434 let (process_id, thread_id) = {
435 let process = process.borrow(&self.root);
436 (process.id(), process.thread_group_leader_id())
437 };
438 host.processes.borrow_mut().insert(process_id, process);
439 let task = TaskRef::new(move |host| {
441 host.resume(process_id, thread_id);
442 });
443 self.schedule_task_with_delay(task, SimulationTime::ZERO);
444 }
445
446 pub fn resume(&self, pid: ProcessId, tid: ThreadId) {
447 let Some(processrc) = self
448 .process_borrow(pid)
449 .map(|p| RootedRc::clone(&p, &self.root))
450 else {
451 trace!("{pid:?} doesn't exist");
452 return;
453 };
454 let processrc = ExplicitDropper::new(processrc, |p| {
455 p.explicit_drop_recursive(&self.root, self);
456 });
457 let died;
458 let is_orphan;
459 {
460 Worker::set_active_process(&processrc);
461 let process = processrc.borrow(self.root());
462 process.resume(self, tid);
463 Worker::clear_active_process();
464 let zombie_state = process.borrow_as_zombie();
465 if let Some(zombie) = zombie_state {
466 died = true;
467 is_orphan = zombie.reaper(self).is_none();
468 } else {
469 died = false;
470 is_orphan = false;
471 }
472 };
473
474 if !died {
475 return;
476 }
477
478 let child_pids: Vec<_> = self
479 .processes
480 .borrow()
481 .iter()
482 .filter_map(|(other_pid, processrc)| {
483 let process = processrc.borrow(&self.root);
484 if process.parent_id() != pid {
485 return None;
487 }
488 Some(*other_pid)
489 })
490 .collect();
491
492 let mut orphaned_zombie_pids: Vec<ProcessId> = Vec::new();
498 for child_pid in child_pids {
499 let parent_death_signal = {
500 let Some(processrc) = self.process_borrow(child_pid) else {
501 continue;
502 };
503 let process = processrc.borrow(&self.root);
504 process.parent_death_signal()
505 };
506
507 if let Some(signal) = parent_death_signal {
508 let siginfo = siginfo_t::new_for_kill(signal, pid.into(), 0);
509 let Some(processrc) = self.process_borrow(child_pid) else {
510 continue;
511 };
512 let process = processrc.borrow(&self.root);
513 process.signal(self, None, &siginfo);
514 }
515
516 let is_zombie = {
517 let Some(processrc) = self.process_borrow(child_pid) else {
518 continue;
519 };
520 let process = processrc.borrow(&self.root);
521 process.set_parent_id(ProcessId::INIT);
522 process.borrow_as_zombie().is_some()
523 };
524 if is_zombie {
525 orphaned_zombie_pids.push(child_pid);
526 }
527 }
528
529 debug_assert!(died);
531 if is_orphan {
532 orphaned_zombie_pids.push(pid);
533 }
534
535 let mut processes = self.processes.borrow_mut();
537 for pid in orphaned_zombie_pids {
538 trace!("Dropping orphan zombie process {pid:?}");
539 let processrc = processes.remove(&pid).unwrap();
540 RootedRc::explicit_drop_recursive(processrc, &self.root, self);
541 }
542 }
543
544 #[track_caller]
545 pub fn process_borrow(
546 &self,
547 id: ProcessId,
548 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Process>>> + '_> {
549 Ref::filter_map(self.processes.borrow(), |processes| processes.get(&id)).ok()
550 }
551
552 #[track_caller]
554 pub fn process_remove(&self, id: ProcessId) -> Option<RootedRc<RootedRefCell<Process>>> {
555 self.processes.borrow_mut().remove(&id)
556 }
557
558 #[track_caller]
567 pub fn processes_borrow(
568 &self,
569 ) -> impl Deref<Target = BTreeMap<ProcessId, RootedRc<RootedRefCell<Process>>>> + '_ {
570 self.processes.borrow()
571 }
572
573 pub fn cpu_borrow(&self) -> impl Deref<Target = Cpu> + '_ {
574 self.cpu.borrow()
575 }
576
577 pub fn cpu_borrow_mut(&self) -> impl DerefMut<Target = Cpu> + '_ {
578 self.cpu.borrow_mut()
579 }
580
581 pub fn info(&self) -> &Arc<HostInfo> {
586 self.info.get_or_init(|| {
587 Arc::new(HostInfo {
588 id: self.id(),
589 name: self.params.hostname.to_str().unwrap().to_owned(),
590 default_ip: self.default_ip(),
591 log_level: self.log_level(),
592 })
593 })
594 }
595
596 pub fn id(&self) -> HostId {
597 self.params.id
598 }
599
600 pub fn name(&self) -> &str {
601 &self.info().name
602 }
603
604 pub fn default_ip(&self) -> Ipv4Addr {
605 self.net_ns.default_ip
606 }
607
608 pub fn abstract_unix_namespace(
609 &self,
610 ) -> impl Deref<Target = Arc<AtomicRefCell<AbstractUnixNamespace>>> + '_ {
611 &self.net_ns.unix
612 }
613
614 pub fn log_level(&self) -> Option<log::LevelFilter> {
615 let level = self.params.log_level;
616 log_c2rust::c_to_rust_log_level(level).map(|l| l.to_level_filter())
617 }
618
619 #[track_caller]
620 pub fn upstream_router_borrow_mut(&self) -> impl DerefMut<Target = Router> + '_ {
621 self.router.borrow_mut()
622 }
623
624 #[track_caller]
625 pub fn network_namespace_borrow(&self) -> impl Deref<Target = NetworkNamespace> + '_ {
626 &self.net_ns
627 }
628
629 #[track_caller]
630 pub fn futextable_borrow(&self) -> impl Deref<Target = FutexTable> + '_ {
631 self.futex_table.borrow()
632 }
633
634 #[track_caller]
635 pub fn futextable_borrow_mut(&self) -> impl DerefMut<Target = FutexTable> + '_ {
636 self.futex_table.borrow_mut()
637 }
638
639 #[allow(non_snake_case)]
640 pub fn bw_up_kiBps(&self) -> u64 {
641 self.params.requested_bw_up_bits / (8 * 1024)
642 }
643
644 #[allow(non_snake_case)]
645 pub fn bw_down_kiBps(&self) -> u64 {
646 self.params.requested_bw_down_bits / (8 * 1024)
647 }
648
649 pub fn interface_borrow_mut(
653 &self,
654 addr: Ipv4Addr,
655 ) -> Option<impl DerefMut<Target = NetworkInterface> + '_> {
656 self.net_ns.interface_borrow_mut(addr)
657 }
658
659 pub fn interface_borrow(
663 &self,
664 addr: Ipv4Addr,
665 ) -> Option<impl Deref<Target = NetworkInterface> + '_> {
666 self.net_ns.interface_borrow(addr)
667 }
668
669 #[track_caller]
670 pub fn random_mut(&self) -> impl DerefMut<Target = Xoshiro256PlusPlus> + '_ {
671 self.random.borrow_mut()
672 }
673
674 pub fn get_new_event_id(&self) -> u64 {
675 let res = self.event_id_counter.get();
676 self.event_id_counter.set(res + 1);
677 res
678 }
679
680 pub fn get_new_thread_id(&self) -> ThreadId {
681 let res = self.thread_id_counter.get();
682 self.thread_id_counter.set(res + 1);
683 res.try_into().unwrap()
684 }
685
686 pub fn get_new_packet_id(&self) -> u64 {
687 let res = self.packet_id_counter.get();
688 self.packet_id_counter.set(res + 1);
689 res
690 }
691
692 pub fn get_next_deterministic_sequence_value(&self) -> u64 {
693 let res = self.determinism_sequence_counter.get();
694 self.determinism_sequence_counter.set(res + 1);
695 res
696 }
697
698 pub fn get_next_packet_priority(&self) -> FifoPacketPriority {
699 let res = self.packet_priority_counter.get();
700 self.packet_priority_counter
701 .set(res.checked_add(1).unwrap());
702 res
703 }
704
705 pub fn continue_execution_timer(&self) {
706 #[cfg(feature = "perf_timers")]
707 self.execution_timer.borrow_mut().start();
708 }
709
710 pub fn stop_execution_timer(&self) {
711 #[cfg(feature = "perf_timers")]
712 self.execution_timer.borrow_mut().stop();
713 }
714
715 pub fn schedule_task_at_emulated_time(&self, task: TaskRef, t: EmulatedTime) -> bool {
716 let event = Event::new_local(task, t, self);
717 self.push_local_event(event)
718 }
719
720 pub fn schedule_task_with_delay(&self, task: TaskRef, t: SimulationTime) -> bool {
721 self.schedule_task_at_emulated_time(task, Worker::current_time().unwrap() + t)
722 }
723
724 pub fn event_queue(&self) -> &Arc<Mutex<EventQueue>> {
725 &self.event_queue
726 }
727
728 pub fn push_local_event(&self, event: Event) -> bool {
729 if event.time() >= self.params.sim_end_time {
730 return false;
731 }
732 self.event_queue.lock().unwrap().push(event);
733 true
734 }
735
736 pub fn shutdown(&self) {
738 self.continue_execution_timer();
739
740 debug!("shutting down host {}", self.name());
741
742 self.net_ns.cleanup();
744
745 assert!(self.processes.borrow().is_empty());
746
747 self.stop_execution_timer();
748 #[cfg(feature = "perf_timers")]
749 debug!(
750 "host '{}' has been shut down, total execution time was {:?}",
751 self.name(),
752 self.execution_timer.borrow().elapsed()
753 );
754 }
755
756 pub fn free_all_applications(&self) {
757 trace!("start freeing applications for host '{}'", self.name());
758 let processes = std::mem::take(&mut *self.processes.borrow_mut());
759 for (_id, processrc) in processes.into_iter() {
760 let processrc = ExplicitDropper::new(processrc, |p| {
761 p.explicit_drop_recursive(self.root(), self);
762 });
763 Worker::set_active_process(&processrc);
764 let process = processrc.borrow(self.root());
765 process.stop(self);
766 Worker::clear_active_process();
767 process.set_parent_id(ProcessId::INIT);
770 }
771 trace!("done freeing application for host '{}'", self.name());
772 }
773
774 pub fn execute(&self, until: EmulatedTime) {
775 loop {
776 let mut event = {
777 let mut event_queue = self.event_queue.lock().unwrap();
778 match event_queue.next_event_time() {
779 Some(t) if t < until => {}
780 _ => break,
781 };
782 event_queue.pop().unwrap()
783 };
784
785 {
786 let mut cpu = self.cpu.borrow_mut();
787 cpu.update_time(event.time());
788 let cpu_delay = cpu.delay();
789 if cpu_delay > SimulationTime::ZERO {
790 trace!("event blocked on CPU, rescheduled for {cpu_delay:?} from now");
791
792 event.set_time(event.time() + cpu_delay);
794 self.push_local_event(event);
795
796 continue;
798 }
799 }
800
801 Worker::set_current_time(event.time());
803 self.continue_execution_timer();
804 match event.data() {
805 EventData::Packet(data) => {
806 self.upstream_router_borrow_mut()
807 .route_incoming_packet(data.into());
808 self.notify_router_has_packets();
809 }
810 EventData::Local(data) => TaskRef::from(data).execute(self),
811 }
812 self.stop_execution_timer();
813 Worker::clear_current_time();
814 }
815 }
816
817 pub fn next_event_time(&self) -> Option<EmulatedTime> {
818 self.event_queue.lock().unwrap().next_event_time()
819 }
820
821 pub fn shim_shmem(&self) -> &ShMemBlock<'static, HostShmem> {
827 unsafe { &*self.shim_shmem.get() }
828 }
829
830 pub fn thread_cloned_rc(
833 &self,
834 virtual_tid: ThreadId,
835 ) -> Option<RootedRc<RootedRefCell<Thread>>> {
836 for process in self.processes.borrow().values() {
837 let process = process.borrow(self.root());
838 if let Some(thread) = process.thread_borrow(virtual_tid) {
839 return Some(RootedRc::clone(&*thread, self.root()));
840 };
841 }
842
843 None
844 }
845
846 pub fn has_thread(&self, virtual_tid: ThreadId) -> bool {
848 for process in self.processes.borrow().values() {
849 let process = process.borrow(self.root());
850 if process.thread_borrow(virtual_tid).is_some() {
851 return true;
852 }
853 }
854
855 false
856 }
857
858 pub fn lock_shmem(&self) {
864 let shim_shmem: &'static ShMemBlock<HostShmem> =
876 unsafe { self.shim_shmem.get().as_ref().unwrap() };
877 let lock = shim_shmem.protected().lock();
878 let prev = self
879 .shim_shmem_lock
880 .borrow_mut()
881 .replace(UnsafeCell::new(lock));
882 assert!(prev.is_none());
883 }
884
885 pub fn unlock_shmem(&self) {
888 let prev = self.shim_shmem_lock.borrow_mut().take();
889 assert!(prev.is_some());
890 }
891
892 pub fn shim_shmem_lock_borrow(&self) -> Option<impl Deref<Target = HostShmemProtected> + '_> {
893 Ref::filter_map(self.shim_shmem_lock.borrow(), |l| {
894 l.as_ref().map(|l| {
895 let guard = unsafe { &*l.get() };
899 guard.deref()
900 })
901 })
902 .ok()
903 }
904
905 pub fn shim_shmem_lock_borrow_mut(
906 &self,
907 ) -> Option<impl DerefMut<Target = HostShmemProtected> + '_> {
908 RefMut::filter_map(self.shim_shmem_lock.borrow_mut(), |l| {
909 l.as_ref().map(|l| {
910 let guard = unsafe { &mut *l.get() };
914 guard.deref_mut()
915 })
916 })
917 .ok()
918 }
919
920 pub fn tsc(&self) -> &Tsc {
923 &self.tsc
924 }
925
926 pub fn get_packet_device(&self, address: Ipv4Addr) -> Ref<'_, dyn PacketDevice> {
932 if address == Ipv4Addr::LOCALHOST {
933 self.net_ns.localhost.borrow()
934 } else if address == self.default_ip() {
935 self.net_ns.internet.borrow()
936 } else {
937 self.router.borrow()
938 }
939 }
940
941 pub fn notify_router_has_packets(&self) {
944 self.relay_inet_in.notify(self);
945 }
946
947 pub fn notify_socket_has_packets(&self, addr: Ipv4Addr, socket: &InetSocket) {
955 if self.in_notify_socket_has_packets.replace(&self.root, true) {
956 panic!("Recursively calling host.notify_socket_has_packets()");
957 }
958
959 if let Some(iface) = self.interface_borrow(addr) {
960 iface.add_data_source(socket);
961 match addr {
962 Ipv4Addr::LOCALHOST => self.relay_loopback.notify(self),
963 _ => self.relay_inet_out.notify(self),
964 };
965 }
966
967 self.in_notify_socket_has_packets.set(&self.root, false);
968 }
969
970 pub fn process_session_id_of_group_id(&self, group_id: ProcessId) -> Option<ProcessId> {
972 let processes = self.processes.borrow();
973 for processrc in processes.values() {
974 let process = processrc.borrow(&self.root);
975 if process.group_id() == group_id {
976 return Some(process.session_id());
977 }
978 }
979 None
980 }
981
982 pub fn preload_paths(&self) -> &[PathBuf] {
984 &self.preload_paths
985 }
986}
987
988impl Drop for Host {
989 fn drop(&mut self) {
990 assert!(self.shim_shmem_lock.borrow().is_none());
994 }
995}
996
997mod export {
998 use std::{os::raw::c_char, time::Duration};
999
1000 use libc::{in_addr_t, in_port_t};
1001 use rand::{Rng, RngCore};
1002 use shadow_shim_helper_rs::shim_shmem;
1003
1004 use super::*;
1005 use crate::cshadow::{CEmulatedTime, CSimulationTime};
1006 use crate::network::packet::IanaProtocol;
1007
1008 #[unsafe(no_mangle)]
1009 pub unsafe extern "C-unwind" fn host_execute(hostrc: *const Host, until: CEmulatedTime) {
1010 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1011 let until = EmulatedTime::from_c_emutime(until).unwrap();
1012 hostrc.execute(until)
1013 }
1014
1015 #[unsafe(no_mangle)]
1016 pub unsafe extern "C-unwind" fn host_nextEventTime(hostrc: *const Host) -> CEmulatedTime {
1017 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1018 EmulatedTime::to_c_emutime(hostrc.next_event_time())
1019 }
1020
1021 #[unsafe(no_mangle)]
1022 pub unsafe extern "C-unwind" fn host_getNewPacketID(hostrc: *const Host) -> u64 {
1023 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1024 hostrc.get_new_packet_id()
1025 }
1026
1027 #[unsafe(no_mangle)]
1028 pub unsafe extern "C-unwind" fn host_freeAllApplications(hostrc: *const Host) {
1029 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1030 hostrc.free_all_applications()
1031 }
1032
1033 #[unsafe(no_mangle)]
1034 pub unsafe extern "C-unwind" fn host_getID(hostrc: *const Host) -> HostId {
1035 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1036 hostrc.id()
1037 }
1038
1039 #[unsafe(no_mangle)]
1042 pub unsafe extern "C-unwind" fn host_getTsc(host: *const Host) -> *const Tsc {
1043 let hostrc = unsafe { host.as_ref().unwrap() };
1044 hostrc.tsc()
1045 }
1046
1047 #[unsafe(no_mangle)]
1048 pub unsafe extern "C-unwind" fn host_getName(hostrc: *const Host) -> *const c_char {
1049 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1050 hostrc.params.hostname.as_ptr()
1051 }
1052
1053 #[unsafe(no_mangle)]
1054 pub unsafe extern "C-unwind" fn host_getDefaultIP(hostrc: *const Host) -> in_addr_t {
1055 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1056 let ip = hostrc.default_ip();
1057 u32::from(ip).to_be()
1058 }
1059
1060 #[unsafe(no_mangle)]
1061 pub unsafe extern "C-unwind" fn host_getNextPacketPriority(
1062 hostrc: *const Host,
1063 ) -> FifoPacketPriority {
1064 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1065 hostrc.get_next_packet_priority()
1066 }
1067
1068 #[unsafe(no_mangle)]
1069 pub unsafe extern "C-unwind" fn host_autotuneReceiveBuffer(hostrc: *const Host) -> bool {
1070 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1071 hostrc.params.autotune_recv_buf
1072 }
1073
1074 #[unsafe(no_mangle)]
1075 pub unsafe extern "C-unwind" fn host_autotuneSendBuffer(hostrc: *const Host) -> bool {
1076 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1077 hostrc.params.autotune_send_buf
1078 }
1079
1080 #[unsafe(no_mangle)]
1081 pub unsafe extern "C-unwind" fn host_getConfiguredRecvBufSize(hostrc: *const Host) -> u64 {
1082 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1083 hostrc.params.init_sock_recv_buf_size
1084 }
1085
1086 #[unsafe(no_mangle)]
1087 pub unsafe extern "C-unwind" fn host_getConfiguredSendBufSize(hostrc: *const Host) -> u64 {
1088 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1089 hostrc.params.init_sock_send_buf_size
1090 }
1091
1092 #[unsafe(no_mangle)]
1093 pub unsafe extern "C-unwind" fn host_getUpstreamRouter(hostrc: *const Host) -> *mut Router {
1094 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1095 &mut *hostrc.upstream_router_borrow_mut()
1096 }
1097
1098 #[unsafe(no_mangle)]
1099 pub unsafe extern "C-unwind" fn host_get_bw_down_kiBps(hostrc: *const Host) -> u64 {
1100 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1101 hostrc.bw_down_kiBps()
1102 }
1103
1104 #[unsafe(no_mangle)]
1105 pub unsafe extern "C-unwind" fn host_get_bw_up_kiBps(hostrc: *const Host) -> u64 {
1106 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1107 hostrc.bw_up_kiBps()
1108 }
1109
1110 #[unsafe(no_mangle)]
1113 pub unsafe extern "C-unwind" fn host_getDataPath(hostrc: *const Host) -> *const c_char {
1114 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1115 hostrc.data_dir_path_cstring.as_ptr()
1116 }
1117
1118 #[unsafe(no_mangle)]
1119 pub unsafe extern "C-unwind" fn host_disassociateInterface(
1120 hostrc: *const Host,
1121 c_protocol: cshadow::ProtocolType,
1122 bind_ip: in_addr_t,
1123 bind_port: in_port_t,
1124 peer_ip: in_addr_t,
1125 peer_port: in_port_t,
1126 ) {
1127 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1128
1129 let bind_ip = Ipv4Addr::from(u32::from_be(bind_ip));
1130 let peer_ip = Ipv4Addr::from(u32::from_be(peer_ip));
1131 let bind_port = u16::from_be(bind_port);
1132 let peer_port = u16::from_be(peer_port);
1133
1134 let bind_addr = SocketAddrV4::new(bind_ip, bind_port);
1135 let peer_addr = SocketAddrV4::new(peer_ip, peer_port);
1136
1137 let protocol = IanaProtocol::from(c_protocol);
1138
1139 hostrc
1141 .net_ns
1142 .disassociate_interface(protocol, bind_addr, peer_addr);
1143 }
1144
1145 #[unsafe(no_mangle)]
1146 pub unsafe extern "C-unwind" fn host_getRandomFreePort(
1147 hostrc: *const Host,
1148 c_protocol: cshadow::ProtocolType,
1149 interface_ip: in_addr_t,
1150 peer_ip: in_addr_t,
1151 peer_port: in_port_t,
1152 ) -> in_port_t {
1153 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1154
1155 let interface_ip = Ipv4Addr::from(u32::from_be(interface_ip));
1156 let peer_addr = SocketAddrV4::new(
1157 Ipv4Addr::from(u32::from_be(peer_ip)),
1158 u16::from_be(peer_port),
1159 );
1160
1161 let protocol = IanaProtocol::from(c_protocol);
1162
1163 hostrc
1164 .net_ns
1165 .get_random_free_port(
1166 protocol,
1167 interface_ip,
1168 peer_addr,
1169 hostrc.random.borrow_mut().deref_mut(),
1170 )
1171 .unwrap_or(0)
1172 .to_be()
1173 }
1174
1175 #[unsafe(no_mangle)]
1181 pub unsafe extern "C-unwind" fn host_getFutexTable(hostrc: *const Host) -> *mut FutexTable {
1182 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1183 &mut *hostrc.futextable_borrow_mut()
1184 }
1185
1186 #[unsafe(no_mangle)]
1188 pub unsafe extern "C-unwind" fn host_getProcess(
1189 host: *const Host,
1190 virtual_pid: libc::pid_t,
1191 ) -> *const Process {
1192 let host = unsafe { host.as_ref().unwrap() };
1193 let virtual_pid = ProcessId::try_from(virtual_pid).unwrap();
1194 host.process_borrow(virtual_pid)
1195 .map(|x| std::ptr::from_ref(&*x.borrow(host.root())))
1196 .unwrap_or(std::ptr::null_mut())
1197 }
1198
1199 #[unsafe(no_mangle)]
1208 pub unsafe extern "C-unwind" fn host_getThread(
1209 host: *const Host,
1210 virtual_tid: libc::pid_t,
1211 ) -> *const Thread {
1212 let host = unsafe { host.as_ref().unwrap() };
1213 let tid = ThreadId::try_from(virtual_tid).unwrap();
1214 for process in host.processes.borrow().values() {
1215 let process = process.borrow(host.root());
1216 if let Some(thread) = process.thread_borrow(tid) {
1217 let thread = thread.borrow(host.root());
1228 return std::ptr::from_ref(&*thread);
1229 };
1230 }
1231 std::ptr::null_mut()
1232 }
1233
1234 #[unsafe(no_mangle)]
1246 pub unsafe extern "C-unwind" fn host_getShimShmemLock(
1247 hostrc: *const Host,
1248 ) -> *mut shim_shmem::export::ShimShmemHostLock {
1249 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1250 let mut opt_lock = hostrc.shim_shmem_lock.borrow_mut();
1251 let lock = opt_lock.as_mut().unwrap();
1252 unsafe { lock.get().as_mut().unwrap().deref_mut() }
1255 }
1256
1257 #[unsafe(no_mangle)]
1259 pub unsafe extern "C-unwind" fn host_lockShimShmemLock(hostrc: *const Host) {
1260 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1261 hostrc.lock_shmem()
1262 }
1263
1264 #[unsafe(no_mangle)]
1266 pub unsafe extern "C-unwind" fn host_unlockShimShmemLock(hostrc: *const Host) {
1267 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1268 hostrc.unlock_shmem()
1269 }
1270
1271 #[unsafe(no_mangle)]
1276 pub unsafe extern "C-unwind" fn host_getNextDeterministicSequenceValue(
1277 hostrc: *const Host,
1278 ) -> u64 {
1279 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1280 hostrc.get_next_deterministic_sequence_value()
1281 }
1282
1283 #[unsafe(no_mangle)]
1285 pub unsafe extern "C-unwind" fn host_scheduleTaskAtEmulatedTime(
1286 hostrc: *const Host,
1287 task: *mut TaskRef,
1288 time: CEmulatedTime,
1289 ) -> bool {
1290 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1291 let task = unsafe { task.as_ref().unwrap().clone() };
1292 let time = EmulatedTime::from_c_emutime(time).unwrap();
1293 hostrc.schedule_task_at_emulated_time(task, time)
1294 }
1295
1296 #[unsafe(no_mangle)]
1298 pub unsafe extern "C-unwind" fn host_scheduleTaskWithDelay(
1299 hostrc: *const Host,
1300 task: *mut TaskRef,
1301 delay: CSimulationTime,
1302 ) -> bool {
1303 let hostrc = unsafe { hostrc.as_ref().unwrap() };
1304 let task = unsafe { task.as_ref().unwrap().clone() };
1305 let delay = SimulationTime::from_c_simtime(delay).unwrap();
1306 hostrc.schedule_task_with_delay(task, delay)
1307 }
1308
1309 #[unsafe(no_mangle)]
1310 pub unsafe extern "C-unwind" fn host_rngDouble(host: *const Host) -> f64 {
1311 let host = unsafe { host.as_ref().unwrap() };
1312 host.random_mut().random()
1313 }
1314
1315 #[unsafe(no_mangle)]
1317 pub extern "C-unwind" fn host_rngNextNBytes(host: *const Host, buf: *mut u8, len: usize) {
1318 let host = unsafe { host.as_ref().unwrap() };
1319 let buf = unsafe { std::slice::from_raw_parts_mut(buf, len) };
1320 host.random_mut().fill_bytes(buf);
1321 }
1322
1323 #[unsafe(no_mangle)]
1324 pub extern "C-unwind" fn host_paramsCpuFrequencyHz(host: *const Host) -> u64 {
1325 let host = unsafe { host.as_ref().unwrap() };
1326 host.params.cpu_frequency
1327 }
1328
1329 #[unsafe(no_mangle)]
1330 pub extern "C-unwind" fn host_addDelayNanos(host: *const Host, delay_nanos: u64) {
1331 let host = unsafe { host.as_ref().unwrap() };
1332 let delay = Duration::from_nanos(delay_nanos);
1333 host.cpu.borrow_mut().add_delay(delay);
1334 }
1335
1336 #[unsafe(no_mangle)]
1337 pub unsafe extern "C-unwind" fn host_socketWantsToSend(
1338 hostrc: *const Host,
1339 socket: *const InetSocket,
1340 addr: in_addr_t,
1341 ) {
1342 let host = unsafe { hostrc.as_ref().unwrap() };
1343 let socket = unsafe { socket.as_ref().unwrap() };
1344 let addr = u32::from_be(addr).into();
1345 host.notify_socket_has_packets(addr, socket);
1346 }
1347
1348 #[unsafe(no_mangle)]
1349 pub unsafe extern "C-unwind" fn host_continue(
1350 host: *const Host,
1351 pid: libc::pid_t,
1352 tid: libc::pid_t,
1353 ) {
1354 let host = unsafe { host.as_ref().unwrap() };
1355 host.resume(pid.try_into().unwrap(), tid.try_into().unwrap())
1356 }
1357}