1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2024 Google LLC
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker
15*cf78ab8cSAndroid Build Coastguard Worker //! # This module provides a safe Rust wrapper for the libslirp library.
16*cf78ab8cSAndroid Build Coastguard Worker
17*cf78ab8cSAndroid Build Coastguard Worker //! It allows to embed a virtual network stack within your Rust applications.
18*cf78ab8cSAndroid Build Coastguard Worker //!
19*cf78ab8cSAndroid Build Coastguard Worker //! ## Features
20*cf78ab8cSAndroid Build Coastguard Worker //!
21*cf78ab8cSAndroid Build Coastguard Worker //! * **Safe API:** Wraps the libslirp C API in a safe and idiomatic Rust interface.
22*cf78ab8cSAndroid Build Coastguard Worker //! * **Networking:** Provides functionality for virtual networking, including TCP/IP, UDP, and ICMP.
23*cf78ab8cSAndroid Build Coastguard Worker //! * **Proxy Support:** Allows integration with proxy managers for handling external connections.
24*cf78ab8cSAndroid Build Coastguard Worker //! * **Threading:** Handles communication between the Rust application and the libslirp event loop.
25*cf78ab8cSAndroid Build Coastguard Worker //!
26*cf78ab8cSAndroid Build Coastguard Worker //! ## Usage
27*cf78ab8cSAndroid Build Coastguard Worker //!
28*cf78ab8cSAndroid Build Coastguard Worker //! ```
29*cf78ab8cSAndroid Build Coastguard Worker //! use bytes::Bytes;
30*cf78ab8cSAndroid Build Coastguard Worker //! use libslirp_rs::libslirp_config::SlirpConfig;
31*cf78ab8cSAndroid Build Coastguard Worker //! use libslirp_rs::libslirp::LibSlirp;
32*cf78ab8cSAndroid Build Coastguard Worker //! use std::net::Ipv4Addr;
33*cf78ab8cSAndroid Build Coastguard Worker //! use std::sync::mpsc;
34*cf78ab8cSAndroid Build Coastguard Worker //!
35*cf78ab8cSAndroid Build Coastguard Worker //! let (tx_cmds, _) = mpsc::channel();
36*cf78ab8cSAndroid Build Coastguard Worker //! // Create a LibSlirp instance with default configuration
37*cf78ab8cSAndroid Build Coastguard Worker //! let libslirp = LibSlirp::new(
38*cf78ab8cSAndroid Build Coastguard Worker //! SlirpConfig::default(),
39*cf78ab8cSAndroid Build Coastguard Worker //! tx_cmds,
40*cf78ab8cSAndroid Build Coastguard Worker //! None
41*cf78ab8cSAndroid Build Coastguard Worker //! );
42*cf78ab8cSAndroid Build Coastguard Worker //!
43*cf78ab8cSAndroid Build Coastguard Worker //! let data = vec![0x01, 0x02, 0x03];
44*cf78ab8cSAndroid Build Coastguard Worker //! // Input network data into libslirp
45*cf78ab8cSAndroid Build Coastguard Worker //! libslirp.input(Bytes::from(data));
46*cf78ab8cSAndroid Build Coastguard Worker //!
47*cf78ab8cSAndroid Build Coastguard Worker //! // ... other operations ...
48*cf78ab8cSAndroid Build Coastguard Worker //!
49*cf78ab8cSAndroid Build Coastguard Worker //! // Shutdown libslirp
50*cf78ab8cSAndroid Build Coastguard Worker //! libslirp.shutdown();
51*cf78ab8cSAndroid Build Coastguard Worker //! ```
52*cf78ab8cSAndroid Build Coastguard Worker //!
53*cf78ab8cSAndroid Build Coastguard Worker //! ## Example with Proxy
54*cf78ab8cSAndroid Build Coastguard Worker //!
55*cf78ab8cSAndroid Build Coastguard Worker //! ```
56*cf78ab8cSAndroid Build Coastguard Worker //! use libslirp_rs::libslirp::LibSlirp;
57*cf78ab8cSAndroid Build Coastguard Worker //! use libslirp_rs::libslirp_config::SlirpConfig;
58*cf78ab8cSAndroid Build Coastguard Worker //! use libslirp_rs::libslirp::{ProxyManager, ProxyConnect};
59*cf78ab8cSAndroid Build Coastguard Worker //! use std::sync::mpsc;
60*cf78ab8cSAndroid Build Coastguard Worker //! use std::net::SocketAddr;
61*cf78ab8cSAndroid Build Coastguard Worker //! // Implement the ProxyManager trait for your proxy logic
62*cf78ab8cSAndroid Build Coastguard Worker //! struct MyProxyManager;
63*cf78ab8cSAndroid Build Coastguard Worker //!
64*cf78ab8cSAndroid Build Coastguard Worker //! impl ProxyManager for MyProxyManager {
65*cf78ab8cSAndroid Build Coastguard Worker //! // ... implementation ...
66*cf78ab8cSAndroid Build Coastguard Worker //! fn try_connect(
67*cf78ab8cSAndroid Build Coastguard Worker //! &self,
68*cf78ab8cSAndroid Build Coastguard Worker //! sockaddr: SocketAddr,
69*cf78ab8cSAndroid Build Coastguard Worker //! connect_id: usize,
70*cf78ab8cSAndroid Build Coastguard Worker //! connect_func: Box<dyn ProxyConnect + Send>,
71*cf78ab8cSAndroid Build Coastguard Worker //! ) -> bool {
72*cf78ab8cSAndroid Build Coastguard Worker //! todo!()
73*cf78ab8cSAndroid Build Coastguard Worker //! }
74*cf78ab8cSAndroid Build Coastguard Worker //! fn remove(&self, connect_id: usize) {
75*cf78ab8cSAndroid Build Coastguard Worker //! todo!()
76*cf78ab8cSAndroid Build Coastguard Worker //! }
77*cf78ab8cSAndroid Build Coastguard Worker //! }
78*cf78ab8cSAndroid Build Coastguard Worker //! let (tx_cmds, _) = mpsc::channel();
79*cf78ab8cSAndroid Build Coastguard Worker //! // Create a LibSlirp instance with a proxy manager
80*cf78ab8cSAndroid Build Coastguard Worker //! let libslirp = LibSlirp::new(
81*cf78ab8cSAndroid Build Coastguard Worker //! SlirpConfig::default(),
82*cf78ab8cSAndroid Build Coastguard Worker //! tx_cmds,
83*cf78ab8cSAndroid Build Coastguard Worker //! Some(Box::new(MyProxyManager)),
84*cf78ab8cSAndroid Build Coastguard Worker //! );
85*cf78ab8cSAndroid Build Coastguard Worker //!
86*cf78ab8cSAndroid Build Coastguard Worker //! // ...
87*cf78ab8cSAndroid Build Coastguard Worker //! ```
88*cf78ab8cSAndroid Build Coastguard Worker //!
89*cf78ab8cSAndroid Build Coastguard Worker //! This module abstracts away the complexities of interacting with the libslirp C library,
90*cf78ab8cSAndroid Build Coastguard Worker //! providing a more convenient and reliable way to use it in your Rust projects.
91*cf78ab8cSAndroid Build Coastguard Worker
92*cf78ab8cSAndroid Build Coastguard Worker use crate::libslirp_config;
93*cf78ab8cSAndroid Build Coastguard Worker use crate::libslirp_config::SlirpConfigs;
94*cf78ab8cSAndroid Build Coastguard Worker use crate::libslirp_sys;
95*cf78ab8cSAndroid Build Coastguard Worker
96*cf78ab8cSAndroid Build Coastguard Worker use bytes::Bytes;
97*cf78ab8cSAndroid Build Coastguard Worker use core::sync::atomic::{AtomicUsize, Ordering};
98*cf78ab8cSAndroid Build Coastguard Worker use log::{debug, info, warn};
99*cf78ab8cSAndroid Build Coastguard Worker use std::cell::RefCell;
100*cf78ab8cSAndroid Build Coastguard Worker use std::collections::HashMap;
101*cf78ab8cSAndroid Build Coastguard Worker use std::ffi::{c_char, c_int, c_void, CStr};
102*cf78ab8cSAndroid Build Coastguard Worker use std::mem::ManuallyDrop;
103*cf78ab8cSAndroid Build Coastguard Worker use std::net::SocketAddr;
104*cf78ab8cSAndroid Build Coastguard Worker use std::rc::Rc;
105*cf78ab8cSAndroid Build Coastguard Worker use std::sync::mpsc;
106*cf78ab8cSAndroid Build Coastguard Worker use std::thread;
107*cf78ab8cSAndroid Build Coastguard Worker use std::time::Duration;
108*cf78ab8cSAndroid Build Coastguard Worker use std::time::Instant;
109*cf78ab8cSAndroid Build Coastguard Worker
110*cf78ab8cSAndroid Build Coastguard Worker type TimerOpaque = usize;
111*cf78ab8cSAndroid Build Coastguard Worker
112*cf78ab8cSAndroid Build Coastguard Worker const TIMEOUT_SECS: u64 = 1;
113*cf78ab8cSAndroid Build Coastguard Worker
114*cf78ab8cSAndroid Build Coastguard Worker struct TimerManager {
115*cf78ab8cSAndroid Build Coastguard Worker clock: RefCell<Instant>,
116*cf78ab8cSAndroid Build Coastguard Worker map: RefCell<HashMap<TimerOpaque, Timer>>,
117*cf78ab8cSAndroid Build Coastguard Worker timers: AtomicUsize,
118*cf78ab8cSAndroid Build Coastguard Worker }
119*cf78ab8cSAndroid Build Coastguard Worker
120*cf78ab8cSAndroid Build Coastguard Worker #[derive(Clone)]
121*cf78ab8cSAndroid Build Coastguard Worker struct Timer {
122*cf78ab8cSAndroid Build Coastguard Worker id: libslirp_sys::SlirpTimerId,
123*cf78ab8cSAndroid Build Coastguard Worker cb_opaque: usize,
124*cf78ab8cSAndroid Build Coastguard Worker expire_time: u64,
125*cf78ab8cSAndroid Build Coastguard Worker }
126*cf78ab8cSAndroid Build Coastguard Worker
127*cf78ab8cSAndroid Build Coastguard Worker // The operations performed on the slirp thread
128*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug)]
129*cf78ab8cSAndroid Build Coastguard Worker enum SlirpCmd {
130*cf78ab8cSAndroid Build Coastguard Worker Input(Bytes),
131*cf78ab8cSAndroid Build Coastguard Worker PollResult(Vec<PollFd>, c_int),
132*cf78ab8cSAndroid Build Coastguard Worker TimerModified,
133*cf78ab8cSAndroid Build Coastguard Worker Shutdown,
134*cf78ab8cSAndroid Build Coastguard Worker ProxyConnect(libslirp_sys::SlirpProxyConnectFunc, usize, i32, i32),
135*cf78ab8cSAndroid Build Coastguard Worker }
136*cf78ab8cSAndroid Build Coastguard Worker
137*cf78ab8cSAndroid Build Coastguard Worker /// Alias for io::fd::RawFd on Unix or RawSocket on Windows (converted to i32)
138*cf78ab8cSAndroid Build Coastguard Worker pub type RawFd = i32;
139*cf78ab8cSAndroid Build Coastguard Worker
140*cf78ab8cSAndroid Build Coastguard Worker /// HTTP Proxy callback trait
141*cf78ab8cSAndroid Build Coastguard Worker pub trait ProxyManager: Send {
try_connect( &self, sockaddr: SocketAddr, connect_id: usize, connect_func: Box<dyn ProxyConnect + Send>, ) -> bool142*cf78ab8cSAndroid Build Coastguard Worker fn try_connect(
143*cf78ab8cSAndroid Build Coastguard Worker &self,
144*cf78ab8cSAndroid Build Coastguard Worker sockaddr: SocketAddr,
145*cf78ab8cSAndroid Build Coastguard Worker connect_id: usize,
146*cf78ab8cSAndroid Build Coastguard Worker connect_func: Box<dyn ProxyConnect + Send>,
147*cf78ab8cSAndroid Build Coastguard Worker ) -> bool;
remove(&self, connect_id: usize)148*cf78ab8cSAndroid Build Coastguard Worker fn remove(&self, connect_id: usize);
149*cf78ab8cSAndroid Build Coastguard Worker }
150*cf78ab8cSAndroid Build Coastguard Worker
151*cf78ab8cSAndroid Build Coastguard Worker struct CallbackContext {
152*cf78ab8cSAndroid Build Coastguard Worker tx_bytes: mpsc::Sender<Bytes>,
153*cf78ab8cSAndroid Build Coastguard Worker tx_cmds: mpsc::Sender<SlirpCmd>,
154*cf78ab8cSAndroid Build Coastguard Worker poll_fds: Rc<RefCell<Vec<PollFd>>>,
155*cf78ab8cSAndroid Build Coastguard Worker proxy_manager: Option<Box<dyn ProxyManager>>,
156*cf78ab8cSAndroid Build Coastguard Worker timer_manager: Rc<TimerManager>,
157*cf78ab8cSAndroid Build Coastguard Worker }
158*cf78ab8cSAndroid Build Coastguard Worker
159*cf78ab8cSAndroid Build Coastguard Worker // A poll thread request has a poll_fds and a timeout
160*cf78ab8cSAndroid Build Coastguard Worker type PollRequest = (Vec<PollFd>, u32);
161*cf78ab8cSAndroid Build Coastguard Worker
162*cf78ab8cSAndroid Build Coastguard Worker /// API to LibSlirp
163*cf78ab8cSAndroid Build Coastguard Worker
164*cf78ab8cSAndroid Build Coastguard Worker pub struct LibSlirp {
165*cf78ab8cSAndroid Build Coastguard Worker tx_cmds: mpsc::Sender<SlirpCmd>,
166*cf78ab8cSAndroid Build Coastguard Worker }
167*cf78ab8cSAndroid Build Coastguard Worker
168*cf78ab8cSAndroid Build Coastguard Worker impl TimerManager {
next_timer(&self) -> TimerOpaque169*cf78ab8cSAndroid Build Coastguard Worker fn next_timer(&self) -> TimerOpaque {
170*cf78ab8cSAndroid Build Coastguard Worker self.timers.fetch_add(1, Ordering::SeqCst) as TimerOpaque
171*cf78ab8cSAndroid Build Coastguard Worker }
172*cf78ab8cSAndroid Build Coastguard Worker
173*cf78ab8cSAndroid Build Coastguard Worker // Finds expired Timers, clears then clones them
collect_expired(&self) -> Vec<Timer>174*cf78ab8cSAndroid Build Coastguard Worker fn collect_expired(&self) -> Vec<Timer> {
175*cf78ab8cSAndroid Build Coastguard Worker let now_ms = self.get_elapsed().as_millis() as u64;
176*cf78ab8cSAndroid Build Coastguard Worker self.map
177*cf78ab8cSAndroid Build Coastguard Worker .borrow_mut()
178*cf78ab8cSAndroid Build Coastguard Worker .iter_mut()
179*cf78ab8cSAndroid Build Coastguard Worker .filter(|(_, timer)| timer.expire_time < now_ms)
180*cf78ab8cSAndroid Build Coastguard Worker .map(|(_, &mut ref mut timer)| {
181*cf78ab8cSAndroid Build Coastguard Worker timer.expire_time = u64::MAX;
182*cf78ab8cSAndroid Build Coastguard Worker timer.clone()
183*cf78ab8cSAndroid Build Coastguard Worker })
184*cf78ab8cSAndroid Build Coastguard Worker .collect()
185*cf78ab8cSAndroid Build Coastguard Worker }
186*cf78ab8cSAndroid Build Coastguard Worker
187*cf78ab8cSAndroid Build Coastguard Worker // Return the minimum duration until the next timer
min_duration(&self) -> Duration188*cf78ab8cSAndroid Build Coastguard Worker fn min_duration(&self) -> Duration {
189*cf78ab8cSAndroid Build Coastguard Worker match self.map.borrow().iter().min_by_key(|(_, timer)| timer.expire_time) {
190*cf78ab8cSAndroid Build Coastguard Worker Some((_, timer)) => {
191*cf78ab8cSAndroid Build Coastguard Worker let now_ms = self.get_elapsed().as_millis() as u64;
192*cf78ab8cSAndroid Build Coastguard Worker // Duration is >= 0
193*cf78ab8cSAndroid Build Coastguard Worker Duration::from_millis(timer.expire_time.saturating_sub(now_ms))
194*cf78ab8cSAndroid Build Coastguard Worker }
195*cf78ab8cSAndroid Build Coastguard Worker None => Duration::from_millis(u64::MAX),
196*cf78ab8cSAndroid Build Coastguard Worker }
197*cf78ab8cSAndroid Build Coastguard Worker }
198*cf78ab8cSAndroid Build Coastguard Worker
get_elapsed(&self) -> Duration199*cf78ab8cSAndroid Build Coastguard Worker fn get_elapsed(&self) -> Duration {
200*cf78ab8cSAndroid Build Coastguard Worker self.clock.borrow().elapsed()
201*cf78ab8cSAndroid Build Coastguard Worker }
202*cf78ab8cSAndroid Build Coastguard Worker
remove(&self, timer_key: &TimerOpaque) -> Option<Timer>203*cf78ab8cSAndroid Build Coastguard Worker fn remove(&self, timer_key: &TimerOpaque) -> Option<Timer> {
204*cf78ab8cSAndroid Build Coastguard Worker self.map.borrow_mut().remove(timer_key)
205*cf78ab8cSAndroid Build Coastguard Worker }
206*cf78ab8cSAndroid Build Coastguard Worker
insert(&self, timer_key: TimerOpaque, value: Timer)207*cf78ab8cSAndroid Build Coastguard Worker fn insert(&self, timer_key: TimerOpaque, value: Timer) {
208*cf78ab8cSAndroid Build Coastguard Worker self.map.borrow_mut().insert(timer_key, value);
209*cf78ab8cSAndroid Build Coastguard Worker }
210*cf78ab8cSAndroid Build Coastguard Worker
timer_mod(&self, timer_key: &TimerOpaque, expire_time: u64)211*cf78ab8cSAndroid Build Coastguard Worker fn timer_mod(&self, timer_key: &TimerOpaque, expire_time: u64) {
212*cf78ab8cSAndroid Build Coastguard Worker if let Some(&mut ref mut timer) = self.map.borrow_mut().get_mut(&timer_key) {
213*cf78ab8cSAndroid Build Coastguard Worker // expire_time is >= 0
214*cf78ab8cSAndroid Build Coastguard Worker timer.expire_time = expire_time;
215*cf78ab8cSAndroid Build Coastguard Worker } else {
216*cf78ab8cSAndroid Build Coastguard Worker warn!("Unknown timer {timer_key}");
217*cf78ab8cSAndroid Build Coastguard Worker }
218*cf78ab8cSAndroid Build Coastguard Worker }
219*cf78ab8cSAndroid Build Coastguard Worker }
220*cf78ab8cSAndroid Build Coastguard Worker
221*cf78ab8cSAndroid Build Coastguard Worker impl LibSlirp {
new( config: libslirp_config::SlirpConfig, tx_bytes: mpsc::Sender<Bytes>, proxy_manager: Option<Box<dyn ProxyManager>>, ) -> LibSlirp222*cf78ab8cSAndroid Build Coastguard Worker pub fn new(
223*cf78ab8cSAndroid Build Coastguard Worker config: libslirp_config::SlirpConfig,
224*cf78ab8cSAndroid Build Coastguard Worker tx_bytes: mpsc::Sender<Bytes>,
225*cf78ab8cSAndroid Build Coastguard Worker proxy_manager: Option<Box<dyn ProxyManager>>,
226*cf78ab8cSAndroid Build Coastguard Worker ) -> LibSlirp {
227*cf78ab8cSAndroid Build Coastguard Worker let (tx_cmds, rx_cmds) = mpsc::channel::<SlirpCmd>();
228*cf78ab8cSAndroid Build Coastguard Worker let (tx_poll, rx_poll) = mpsc::channel::<PollRequest>();
229*cf78ab8cSAndroid Build Coastguard Worker
230*cf78ab8cSAndroid Build Coastguard Worker // Create channels for polling thread and launch
231*cf78ab8cSAndroid Build Coastguard Worker let tx_cmds_poll = tx_cmds.clone();
232*cf78ab8cSAndroid Build Coastguard Worker if let Err(e) = thread::Builder::new()
233*cf78ab8cSAndroid Build Coastguard Worker .name("slirp_poll".to_string())
234*cf78ab8cSAndroid Build Coastguard Worker .spawn(move || slirp_poll_thread(rx_poll, tx_cmds_poll))
235*cf78ab8cSAndroid Build Coastguard Worker {
236*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to start slirp poll thread: {}", e);
237*cf78ab8cSAndroid Build Coastguard Worker }
238*cf78ab8cSAndroid Build Coastguard Worker
239*cf78ab8cSAndroid Build Coastguard Worker let tx_cmds_slirp = tx_cmds.clone();
240*cf78ab8cSAndroid Build Coastguard Worker // Create channels for command processor thread and launch
241*cf78ab8cSAndroid Build Coastguard Worker if let Err(e) = thread::Builder::new().name("slirp".to_string()).spawn(move || {
242*cf78ab8cSAndroid Build Coastguard Worker slirp_thread(config, tx_bytes, tx_cmds_slirp, rx_cmds, tx_poll, proxy_manager)
243*cf78ab8cSAndroid Build Coastguard Worker }) {
244*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to start slirp thread: {}", e);
245*cf78ab8cSAndroid Build Coastguard Worker }
246*cf78ab8cSAndroid Build Coastguard Worker
247*cf78ab8cSAndroid Build Coastguard Worker LibSlirp { tx_cmds }
248*cf78ab8cSAndroid Build Coastguard Worker }
249*cf78ab8cSAndroid Build Coastguard Worker
shutdown(self)250*cf78ab8cSAndroid Build Coastguard Worker pub fn shutdown(self) {
251*cf78ab8cSAndroid Build Coastguard Worker if let Err(e) = self.tx_cmds.send(SlirpCmd::Shutdown) {
252*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to send Shutdown cmd: {}", e);
253*cf78ab8cSAndroid Build Coastguard Worker }
254*cf78ab8cSAndroid Build Coastguard Worker }
255*cf78ab8cSAndroid Build Coastguard Worker
input(&self, bytes: Bytes)256*cf78ab8cSAndroid Build Coastguard Worker pub fn input(&self, bytes: Bytes) {
257*cf78ab8cSAndroid Build Coastguard Worker if let Err(e) = self.tx_cmds.send(SlirpCmd::Input(bytes)) {
258*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to send Input cmd: {}", e);
259*cf78ab8cSAndroid Build Coastguard Worker }
260*cf78ab8cSAndroid Build Coastguard Worker }
261*cf78ab8cSAndroid Build Coastguard Worker }
262*cf78ab8cSAndroid Build Coastguard Worker
263*cf78ab8cSAndroid Build Coastguard Worker struct ConnectRequest {
264*cf78ab8cSAndroid Build Coastguard Worker tx_cmds: mpsc::Sender<SlirpCmd>,
265*cf78ab8cSAndroid Build Coastguard Worker connect_func: libslirp_sys::SlirpProxyConnectFunc,
266*cf78ab8cSAndroid Build Coastguard Worker connect_id: usize,
267*cf78ab8cSAndroid Build Coastguard Worker af: i32,
268*cf78ab8cSAndroid Build Coastguard Worker start: Instant,
269*cf78ab8cSAndroid Build Coastguard Worker }
270*cf78ab8cSAndroid Build Coastguard Worker
271*cf78ab8cSAndroid Build Coastguard Worker pub trait ProxyConnect: Send {
proxy_connect(&self, fd: i32, addr: SocketAddr)272*cf78ab8cSAndroid Build Coastguard Worker fn proxy_connect(&self, fd: i32, addr: SocketAddr);
273*cf78ab8cSAndroid Build Coastguard Worker }
274*cf78ab8cSAndroid Build Coastguard Worker
275*cf78ab8cSAndroid Build Coastguard Worker impl ProxyConnect for ConnectRequest {
proxy_connect(&self, fd: i32, addr: SocketAddr)276*cf78ab8cSAndroid Build Coastguard Worker fn proxy_connect(&self, fd: i32, addr: SocketAddr) {
277*cf78ab8cSAndroid Build Coastguard Worker // Send it to Slirp after try_connect() completed
278*cf78ab8cSAndroid Build Coastguard Worker let duration = self.start.elapsed().as_secs();
279*cf78ab8cSAndroid Build Coastguard Worker if duration > TIMEOUT_SECS {
280*cf78ab8cSAndroid Build Coastguard Worker warn!(
281*cf78ab8cSAndroid Build Coastguard Worker "ConnectRequest for connection ID {} to {} took too long: {:?}",
282*cf78ab8cSAndroid Build Coastguard Worker self.connect_id, addr, duration
283*cf78ab8cSAndroid Build Coastguard Worker );
284*cf78ab8cSAndroid Build Coastguard Worker }
285*cf78ab8cSAndroid Build Coastguard Worker let _ = self.tx_cmds.send(SlirpCmd::ProxyConnect(
286*cf78ab8cSAndroid Build Coastguard Worker self.connect_func,
287*cf78ab8cSAndroid Build Coastguard Worker self.connect_id,
288*cf78ab8cSAndroid Build Coastguard Worker fd,
289*cf78ab8cSAndroid Build Coastguard Worker self.af,
290*cf78ab8cSAndroid Build Coastguard Worker ));
291*cf78ab8cSAndroid Build Coastguard Worker }
292*cf78ab8cSAndroid Build Coastguard Worker }
293*cf78ab8cSAndroid Build Coastguard Worker
294*cf78ab8cSAndroid Build Coastguard Worker // Converts a libslirp callback's `opaque` handle into a
295*cf78ab8cSAndroid Build Coastguard Worker // `CallbackContext.`
296*cf78ab8cSAndroid Build Coastguard Worker //
297*cf78ab8cSAndroid Build Coastguard Worker // Wrapped in a `ManuallyDrop` because we do not want to release the
298*cf78ab8cSAndroid Build Coastguard Worker // storage when the callback returns.
299*cf78ab8cSAndroid Build Coastguard Worker //
300*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
301*cf78ab8cSAndroid Build Coastguard Worker //
302*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext passed to the slirp API
callback_context_from_raw(opaque: *mut c_void) -> ManuallyDrop<Box<CallbackContext>>303*cf78ab8cSAndroid Build Coastguard Worker unsafe fn callback_context_from_raw(opaque: *mut c_void) -> ManuallyDrop<Box<CallbackContext>> {
304*cf78ab8cSAndroid Build Coastguard Worker ManuallyDrop::new(unsafe { Box::from_raw(opaque as *mut CallbackContext) })
305*cf78ab8cSAndroid Build Coastguard Worker }
306*cf78ab8cSAndroid Build Coastguard Worker
307*cf78ab8cSAndroid Build Coastguard Worker // A Rust struct for the fields held by `slirp` C library through it's
308*cf78ab8cSAndroid Build Coastguard Worker // lifetime.
309*cf78ab8cSAndroid Build Coastguard Worker //
310*cf78ab8cSAndroid Build Coastguard Worker // All libslirp C calls are impl on this struct.
311*cf78ab8cSAndroid Build Coastguard Worker struct Slirp {
312*cf78ab8cSAndroid Build Coastguard Worker slirp: *mut libslirp_sys::Slirp,
313*cf78ab8cSAndroid Build Coastguard Worker // These fields are held by slirp C library
314*cf78ab8cSAndroid Build Coastguard Worker #[allow(dead_code)]
315*cf78ab8cSAndroid Build Coastguard Worker configs: Box<SlirpConfigs>,
316*cf78ab8cSAndroid Build Coastguard Worker #[allow(dead_code)]
317*cf78ab8cSAndroid Build Coastguard Worker callbacks: Box<libslirp_sys::SlirpCb>,
318*cf78ab8cSAndroid Build Coastguard Worker // Passed to API calls and then to callbacks
319*cf78ab8cSAndroid Build Coastguard Worker callback_context: Box<CallbackContext>,
320*cf78ab8cSAndroid Build Coastguard Worker }
321*cf78ab8cSAndroid Build Coastguard Worker
322*cf78ab8cSAndroid Build Coastguard Worker impl Slirp {
new(config: libslirp_config::SlirpConfig, callback_context: Box<CallbackContext>) -> Slirp323*cf78ab8cSAndroid Build Coastguard Worker fn new(config: libslirp_config::SlirpConfig, callback_context: Box<CallbackContext>) -> Slirp {
324*cf78ab8cSAndroid Build Coastguard Worker let callbacks = Box::new(libslirp_sys::SlirpCb {
325*cf78ab8cSAndroid Build Coastguard Worker send_packet: Some(send_packet_cb),
326*cf78ab8cSAndroid Build Coastguard Worker guest_error: Some(guest_error_cb),
327*cf78ab8cSAndroid Build Coastguard Worker clock_get_ns: Some(clock_get_ns_cb),
328*cf78ab8cSAndroid Build Coastguard Worker timer_new: None,
329*cf78ab8cSAndroid Build Coastguard Worker timer_free: Some(timer_free_cb),
330*cf78ab8cSAndroid Build Coastguard Worker timer_mod: Some(timer_mod_cb),
331*cf78ab8cSAndroid Build Coastguard Worker register_poll_fd: Some(register_poll_fd_cb),
332*cf78ab8cSAndroid Build Coastguard Worker unregister_poll_fd: Some(unregister_poll_fd_cb),
333*cf78ab8cSAndroid Build Coastguard Worker notify: Some(notify_cb),
334*cf78ab8cSAndroid Build Coastguard Worker init_completed: Some(init_completed_cb),
335*cf78ab8cSAndroid Build Coastguard Worker timer_new_opaque: Some(timer_new_opaque_cb),
336*cf78ab8cSAndroid Build Coastguard Worker try_connect: Some(try_connect_cb),
337*cf78ab8cSAndroid Build Coastguard Worker remove: Some(remove_cb),
338*cf78ab8cSAndroid Build Coastguard Worker });
339*cf78ab8cSAndroid Build Coastguard Worker let configs = Box::new(SlirpConfigs::new(&config));
340*cf78ab8cSAndroid Build Coastguard Worker
341*cf78ab8cSAndroid Build Coastguard Worker // Call libslrip "C" library to create a new instance of a slirp
342*cf78ab8cSAndroid Build Coastguard Worker // protocol stack.
343*cf78ab8cSAndroid Build Coastguard Worker //
344*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: We ensure that:
345*cf78ab8cSAndroid Build Coastguard Worker //
346*cf78ab8cSAndroid Build Coastguard Worker // * config is a valid pointer to the "C" config struct. It is
347*cf78ab8cSAndroid Build Coastguard Worker // held by the "C" slirp library for lifetime of the slirp
348*cf78ab8cSAndroid Build Coastguard Worker // instance.
349*cf78ab8cSAndroid Build Coastguard Worker //
350*cf78ab8cSAndroid Build Coastguard Worker // * callbacks is a valid pointer to an array of callback
351*cf78ab8cSAndroid Build Coastguard Worker // functions. It is held by the "C" slirp library for the lifetime
352*cf78ab8cSAndroid Build Coastguard Worker // of the slirp instance.
353*cf78ab8cSAndroid Build Coastguard Worker //
354*cf78ab8cSAndroid Build Coastguard Worker // * callback_context is an arbitrary opaque type passed back
355*cf78ab8cSAndroid Build Coastguard Worker // to callback functions by libslirp.
356*cf78ab8cSAndroid Build Coastguard Worker let slirp = unsafe {
357*cf78ab8cSAndroid Build Coastguard Worker libslirp_sys::slirp_new(
358*cf78ab8cSAndroid Build Coastguard Worker &configs.c_slirp_config,
359*cf78ab8cSAndroid Build Coastguard Worker &*callbacks,
360*cf78ab8cSAndroid Build Coastguard Worker &*callback_context as *const CallbackContext as *mut c_void,
361*cf78ab8cSAndroid Build Coastguard Worker )
362*cf78ab8cSAndroid Build Coastguard Worker };
363*cf78ab8cSAndroid Build Coastguard Worker
364*cf78ab8cSAndroid Build Coastguard Worker Slirp { slirp, configs, callbacks, callback_context }
365*cf78ab8cSAndroid Build Coastguard Worker }
366*cf78ab8cSAndroid Build Coastguard Worker
handle_timer(&self, timer: Timer)367*cf78ab8cSAndroid Build Coastguard Worker fn handle_timer(&self, timer: Timer) {
368*cf78ab8cSAndroid Build Coastguard Worker unsafe {
369*cf78ab8cSAndroid Build Coastguard Worker //
370*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: We ensure that:
371*cf78ab8cSAndroid Build Coastguard Worker //
372*cf78ab8cSAndroid Build Coastguard Worker // *self.slirp is a valid state returned by `slirp_new()`
373*cf78ab8cSAndroid Build Coastguard Worker //
374*cf78ab8cSAndroid Build Coastguard Worker // * timer.id is a valid c_uint from "C" slirp library calling `timer_new_opaque_cb()`
375*cf78ab8cSAndroid Build Coastguard Worker //
376*cf78ab8cSAndroid Build Coastguard Worker // * timer.cb_opaque is an usize representing a pointer to callback function from
377*cf78ab8cSAndroid Build Coastguard Worker // "C" slirp library calling `timer_new_opaque_cb()`
378*cf78ab8cSAndroid Build Coastguard Worker libslirp_sys::slirp_handle_timer(self.slirp, timer.id, timer.cb_opaque as *mut c_void);
379*cf78ab8cSAndroid Build Coastguard Worker };
380*cf78ab8cSAndroid Build Coastguard Worker }
381*cf78ab8cSAndroid Build Coastguard Worker }
382*cf78ab8cSAndroid Build Coastguard Worker
383*cf78ab8cSAndroid Build Coastguard Worker impl Drop for Slirp {
drop(&mut self)384*cf78ab8cSAndroid Build Coastguard Worker fn drop(&mut self) {
385*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
386*cf78ab8cSAndroid Build Coastguard Worker //
387*cf78ab8cSAndroid Build Coastguard Worker // * self.slirp is a slirp pointer initialized by slirp_new;
388*cf78ab8cSAndroid Build Coastguard Worker // it's private to the struct and is only constructed that
389*cf78ab8cSAndroid Build Coastguard Worker // way.
390*cf78ab8cSAndroid Build Coastguard Worker unsafe { libslirp_sys::slirp_cleanup(self.slirp) };
391*cf78ab8cSAndroid Build Coastguard Worker }
392*cf78ab8cSAndroid Build Coastguard Worker }
393*cf78ab8cSAndroid Build Coastguard Worker
slirp_thread( config: libslirp_config::SlirpConfig, tx_bytes: mpsc::Sender<Bytes>, tx_cmds: mpsc::Sender<SlirpCmd>, rx: mpsc::Receiver<SlirpCmd>, tx_poll: mpsc::Sender<PollRequest>, proxy_manager: Option<Box<dyn ProxyManager>>, )394*cf78ab8cSAndroid Build Coastguard Worker fn slirp_thread(
395*cf78ab8cSAndroid Build Coastguard Worker config: libslirp_config::SlirpConfig,
396*cf78ab8cSAndroid Build Coastguard Worker tx_bytes: mpsc::Sender<Bytes>,
397*cf78ab8cSAndroid Build Coastguard Worker tx_cmds: mpsc::Sender<SlirpCmd>,
398*cf78ab8cSAndroid Build Coastguard Worker rx: mpsc::Receiver<SlirpCmd>,
399*cf78ab8cSAndroid Build Coastguard Worker tx_poll: mpsc::Sender<PollRequest>,
400*cf78ab8cSAndroid Build Coastguard Worker proxy_manager: Option<Box<dyn ProxyManager>>,
401*cf78ab8cSAndroid Build Coastguard Worker ) {
402*cf78ab8cSAndroid Build Coastguard Worker // Data structures wrapped in an RC are referenced through the
403*cf78ab8cSAndroid Build Coastguard Worker // libslirp callbacks and this code (both in the same thread).
404*cf78ab8cSAndroid Build Coastguard Worker
405*cf78ab8cSAndroid Build Coastguard Worker let timer_manager = Rc::new(TimerManager {
406*cf78ab8cSAndroid Build Coastguard Worker clock: RefCell::new(Instant::now()),
407*cf78ab8cSAndroid Build Coastguard Worker map: RefCell::new(HashMap::new()),
408*cf78ab8cSAndroid Build Coastguard Worker timers: AtomicUsize::new(1),
409*cf78ab8cSAndroid Build Coastguard Worker });
410*cf78ab8cSAndroid Build Coastguard Worker
411*cf78ab8cSAndroid Build Coastguard Worker let poll_fds = Rc::new(RefCell::new(Vec::new()));
412*cf78ab8cSAndroid Build Coastguard Worker
413*cf78ab8cSAndroid Build Coastguard Worker let callback_context = Box::new(CallbackContext {
414*cf78ab8cSAndroid Build Coastguard Worker tx_bytes,
415*cf78ab8cSAndroid Build Coastguard Worker tx_cmds,
416*cf78ab8cSAndroid Build Coastguard Worker poll_fds: poll_fds.clone(),
417*cf78ab8cSAndroid Build Coastguard Worker proxy_manager,
418*cf78ab8cSAndroid Build Coastguard Worker timer_manager: timer_manager.clone(),
419*cf78ab8cSAndroid Build Coastguard Worker });
420*cf78ab8cSAndroid Build Coastguard Worker
421*cf78ab8cSAndroid Build Coastguard Worker let slirp = Slirp::new(config, callback_context);
422*cf78ab8cSAndroid Build Coastguard Worker
423*cf78ab8cSAndroid Build Coastguard Worker slirp.pollfds_fill_and_send(&poll_fds, &tx_poll);
424*cf78ab8cSAndroid Build Coastguard Worker
425*cf78ab8cSAndroid Build Coastguard Worker let min_duration = timer_manager.min_duration();
426*cf78ab8cSAndroid Build Coastguard Worker loop {
427*cf78ab8cSAndroid Build Coastguard Worker let command = rx.recv_timeout(min_duration);
428*cf78ab8cSAndroid Build Coastguard Worker let start = Instant::now();
429*cf78ab8cSAndroid Build Coastguard Worker
430*cf78ab8cSAndroid Build Coastguard Worker let cmd_str = format!("{:?}", command);
431*cf78ab8cSAndroid Build Coastguard Worker match command {
432*cf78ab8cSAndroid Build Coastguard Worker // The dance to tell libslirp which FDs have IO ready
433*cf78ab8cSAndroid Build Coastguard Worker // starts with a response from a worker thread sending a
434*cf78ab8cSAndroid Build Coastguard Worker // PollResult, followed by pollfds_poll forwarding the FDs
435*cf78ab8cSAndroid Build Coastguard Worker // to libslirp, followed by giving the worker thread
436*cf78ab8cSAndroid Build Coastguard Worker // another set of fds to poll (and block).
437*cf78ab8cSAndroid Build Coastguard Worker Ok(SlirpCmd::PollResult(poll_fds_result, select_error)) => {
438*cf78ab8cSAndroid Build Coastguard Worker poll_fds.borrow_mut().clone_from_slice(&poll_fds_result);
439*cf78ab8cSAndroid Build Coastguard Worker slirp.pollfds_poll(select_error);
440*cf78ab8cSAndroid Build Coastguard Worker slirp.pollfds_fill_and_send(&poll_fds, &tx_poll);
441*cf78ab8cSAndroid Build Coastguard Worker }
442*cf78ab8cSAndroid Build Coastguard Worker Ok(SlirpCmd::Input(bytes)) => slirp.input(&bytes),
443*cf78ab8cSAndroid Build Coastguard Worker
444*cf78ab8cSAndroid Build Coastguard Worker // A timer has been modified, new expired_time value
445*cf78ab8cSAndroid Build Coastguard Worker Ok(SlirpCmd::TimerModified) => continue,
446*cf78ab8cSAndroid Build Coastguard Worker
447*cf78ab8cSAndroid Build Coastguard Worker // Exit the while loop and shutdown
448*cf78ab8cSAndroid Build Coastguard Worker Ok(SlirpCmd::Shutdown) => break,
449*cf78ab8cSAndroid Build Coastguard Worker
450*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: we ensure that func (`SlirpProxyConnectFunc`)
451*cf78ab8cSAndroid Build Coastguard Worker // and `connect_opaque` are valid because they originated
452*cf78ab8cSAndroid Build Coastguard Worker // from the libslirp call to `try_connect_cb.`
453*cf78ab8cSAndroid Build Coastguard Worker //
454*cf78ab8cSAndroid Build Coastguard Worker // Parameter `fd` will be >= 0 and the descriptor for the
455*cf78ab8cSAndroid Build Coastguard Worker // active socket to use, `af` will be either AF_INET or
456*cf78ab8cSAndroid Build Coastguard Worker // AF_INET6. On failure `fd` will be negative.
457*cf78ab8cSAndroid Build Coastguard Worker Ok(SlirpCmd::ProxyConnect(func, connect_id, fd, af)) => match func {
458*cf78ab8cSAndroid Build Coastguard Worker Some(func) => unsafe { func(connect_id as *mut c_void, fd as c_int, af as c_int) },
459*cf78ab8cSAndroid Build Coastguard Worker None => warn!("Proxy connect function not found"),
460*cf78ab8cSAndroid Build Coastguard Worker },
461*cf78ab8cSAndroid Build Coastguard Worker
462*cf78ab8cSAndroid Build Coastguard Worker // Timeout... process any timers
463*cf78ab8cSAndroid Build Coastguard Worker Err(mpsc::RecvTimeoutError::Timeout) => continue,
464*cf78ab8cSAndroid Build Coastguard Worker
465*cf78ab8cSAndroid Build Coastguard Worker // Error
466*cf78ab8cSAndroid Build Coastguard Worker _ => break,
467*cf78ab8cSAndroid Build Coastguard Worker }
468*cf78ab8cSAndroid Build Coastguard Worker
469*cf78ab8cSAndroid Build Coastguard Worker // Explicitly store expired timers to release lock
470*cf78ab8cSAndroid Build Coastguard Worker let timers = timer_manager.collect_expired();
471*cf78ab8cSAndroid Build Coastguard Worker // Handle any expired timers' callback in the slirp thread
472*cf78ab8cSAndroid Build Coastguard Worker for timer in timers {
473*cf78ab8cSAndroid Build Coastguard Worker slirp.handle_timer(timer);
474*cf78ab8cSAndroid Build Coastguard Worker }
475*cf78ab8cSAndroid Build Coastguard Worker let duration = start.elapsed().as_secs();
476*cf78ab8cSAndroid Build Coastguard Worker if duration > TIMEOUT_SECS {
477*cf78ab8cSAndroid Build Coastguard Worker warn!("libslirp command '{cmd_str}' took too long to complete: {duration:?}");
478*cf78ab8cSAndroid Build Coastguard Worker }
479*cf78ab8cSAndroid Build Coastguard Worker }
480*cf78ab8cSAndroid Build Coastguard Worker // Shuts down the instance of a slirp stack and release slirp storage. No callbacks
481*cf78ab8cSAndroid Build Coastguard Worker // occur after this since it calls slirp_cleanup.
482*cf78ab8cSAndroid Build Coastguard Worker drop(slirp);
483*cf78ab8cSAndroid Build Coastguard Worker
484*cf78ab8cSAndroid Build Coastguard Worker // Shutdown slirp_poll_thread -- worst case it sends a PollResult that is ignored
485*cf78ab8cSAndroid Build Coastguard Worker // since this thread is no longer processing Slirp commands.
486*cf78ab8cSAndroid Build Coastguard Worker drop(tx_poll);
487*cf78ab8cSAndroid Build Coastguard Worker }
488*cf78ab8cSAndroid Build Coastguard Worker
489*cf78ab8cSAndroid Build Coastguard Worker #[derive(Clone, Debug)]
490*cf78ab8cSAndroid Build Coastguard Worker struct PollFd {
491*cf78ab8cSAndroid Build Coastguard Worker fd: c_int,
492*cf78ab8cSAndroid Build Coastguard Worker events: libslirp_sys::SlirpPollType,
493*cf78ab8cSAndroid Build Coastguard Worker revents: libslirp_sys::SlirpPollType,
494*cf78ab8cSAndroid Build Coastguard Worker }
495*cf78ab8cSAndroid Build Coastguard Worker
496*cf78ab8cSAndroid Build Coastguard Worker // Fill the pollfds from libslirp and pass the request to the polling thread.
497*cf78ab8cSAndroid Build Coastguard Worker //
498*cf78ab8cSAndroid Build Coastguard Worker // This is called by the application when it is about to sleep through
499*cf78ab8cSAndroid Build Coastguard Worker // poll(). *timeout is set to the amount of virtual time (in ms) that
500*cf78ab8cSAndroid Build Coastguard Worker // the application intends to wait (UINT32_MAX if
501*cf78ab8cSAndroid Build Coastguard Worker // infinite). slirp_pollfds_fill updates it according to e.g. TCP
502*cf78ab8cSAndroid Build Coastguard Worker // timers, so the application knows it should sleep a smaller amount
503*cf78ab8cSAndroid Build Coastguard Worker // of time. slirp_pollfds_fill calls add_poll for each file descriptor
504*cf78ab8cSAndroid Build Coastguard Worker // that should be monitored along the sleep. The opaque pointer is
505*cf78ab8cSAndroid Build Coastguard Worker // passed as such to add_poll, and add_poll returns an index.
506*cf78ab8cSAndroid Build Coastguard Worker //
507*cf78ab8cSAndroid Build Coastguard Worker // # Safety
508*cf78ab8cSAndroid Build Coastguard Worker //
509*cf78ab8cSAndroid Build Coastguard Worker // `slirp` must be a valid Slirp state returned by `slirp_new()`
510*cf78ab8cSAndroid Build Coastguard Worker impl Slirp {
pollfds_fill_and_send( &self, poll_fds: &RefCell<Vec<PollFd>>, tx: &mpsc::Sender<PollRequest>, )511*cf78ab8cSAndroid Build Coastguard Worker fn pollfds_fill_and_send(
512*cf78ab8cSAndroid Build Coastguard Worker &self,
513*cf78ab8cSAndroid Build Coastguard Worker poll_fds: &RefCell<Vec<PollFd>>,
514*cf78ab8cSAndroid Build Coastguard Worker tx: &mpsc::Sender<PollRequest>,
515*cf78ab8cSAndroid Build Coastguard Worker ) {
516*cf78ab8cSAndroid Build Coastguard Worker let mut timeout: u32 = u32::MAX;
517*cf78ab8cSAndroid Build Coastguard Worker poll_fds.borrow_mut().clear();
518*cf78ab8cSAndroid Build Coastguard Worker
519*cf78ab8cSAndroid Build Coastguard Worker // Call libslrip "C" library to fill poll information using
520*cf78ab8cSAndroid Build Coastguard Worker // slirp_add_poll_cb callback function.
521*cf78ab8cSAndroid Build Coastguard Worker //
522*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: we ensure that:
523*cf78ab8cSAndroid Build Coastguard Worker //
524*cf78ab8cSAndroid Build Coastguard Worker // * self.slirp has a slirp pointer initialized by slirp_new,
525*cf78ab8cSAndroid Build Coastguard Worker // as it's private to the struct is only constructed that way
526*cf78ab8cSAndroid Build Coastguard Worker //
527*cf78ab8cSAndroid Build Coastguard Worker // * timeout is a valid ptr to a mutable u32. The "C" slirp
528*cf78ab8cSAndroid Build Coastguard Worker // library stores into timeout.
529*cf78ab8cSAndroid Build Coastguard Worker //
530*cf78ab8cSAndroid Build Coastguard Worker // * slirp_add_poll_cb is a valid `SlirpAddPollCb` function.
531*cf78ab8cSAndroid Build Coastguard Worker //
532*cf78ab8cSAndroid Build Coastguard Worker // * self.callback_context is a CallbackContext
533*cf78ab8cSAndroid Build Coastguard Worker unsafe {
534*cf78ab8cSAndroid Build Coastguard Worker libslirp_sys::slirp_pollfds_fill(
535*cf78ab8cSAndroid Build Coastguard Worker self.slirp,
536*cf78ab8cSAndroid Build Coastguard Worker &mut timeout,
537*cf78ab8cSAndroid Build Coastguard Worker Some(slirp_add_poll_cb),
538*cf78ab8cSAndroid Build Coastguard Worker &*self.callback_context as *const CallbackContext as *mut c_void,
539*cf78ab8cSAndroid Build Coastguard Worker );
540*cf78ab8cSAndroid Build Coastguard Worker }
541*cf78ab8cSAndroid Build Coastguard Worker if let Err(e) = tx.send((poll_fds.borrow().to_vec(), timeout)) {
542*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to send poll fds: {}", e);
543*cf78ab8cSAndroid Build Coastguard Worker }
544*cf78ab8cSAndroid Build Coastguard Worker }
545*cf78ab8cSAndroid Build Coastguard Worker }
546*cf78ab8cSAndroid Build Coastguard Worker
547*cf78ab8cSAndroid Build Coastguard Worker // "C" library callback that is called for each file descriptor that
548*cf78ab8cSAndroid Build Coastguard Worker // should be monitored.
549*cf78ab8cSAndroid Build Coastguard Worker //
550*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
551*cf78ab8cSAndroid Build Coastguard Worker //
552*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
slirp_add_poll_cb(fd: c_int, events: c_int, opaque: *mut c_void) -> c_int553*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn slirp_add_poll_cb(fd: c_int, events: c_int, opaque: *mut c_void) -> c_int {
554*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.add_poll(fd, events)
555*cf78ab8cSAndroid Build Coastguard Worker }
556*cf78ab8cSAndroid Build Coastguard Worker
557*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
add_poll(&mut self, fd: c_int, events: c_int) -> c_int558*cf78ab8cSAndroid Build Coastguard Worker fn add_poll(&mut self, fd: c_int, events: c_int) -> c_int {
559*cf78ab8cSAndroid Build Coastguard Worker let idx = self.poll_fds.borrow().len();
560*cf78ab8cSAndroid Build Coastguard Worker self.poll_fds.borrow_mut().push(PollFd {
561*cf78ab8cSAndroid Build Coastguard Worker fd,
562*cf78ab8cSAndroid Build Coastguard Worker events: events as libslirp_sys::SlirpPollType,
563*cf78ab8cSAndroid Build Coastguard Worker revents: 0,
564*cf78ab8cSAndroid Build Coastguard Worker });
565*cf78ab8cSAndroid Build Coastguard Worker idx as i32
566*cf78ab8cSAndroid Build Coastguard Worker }
567*cf78ab8cSAndroid Build Coastguard Worker }
568*cf78ab8cSAndroid Build Coastguard Worker
569*cf78ab8cSAndroid Build Coastguard Worker // Pass the result from the polling thread back to libslirp
570*cf78ab8cSAndroid Build Coastguard Worker
571*cf78ab8cSAndroid Build Coastguard Worker // This is called by the application when it is about to sleep through
572*cf78ab8cSAndroid Build Coastguard Worker // poll(). *timeout is set to the amount of virtual time (in ms) that
573*cf78ab8cSAndroid Build Coastguard Worker // the application intends to wait (UINT32_MAX if
574*cf78ab8cSAndroid Build Coastguard Worker // infinite). slirp_pollfds_fill updates it according to e.g. TCP
575*cf78ab8cSAndroid Build Coastguard Worker // timers, so the application knows it should sleep a smaller amount
576*cf78ab8cSAndroid Build Coastguard Worker // of time. slirp_pollfds_fill calls add_poll for each file descriptor
577*cf78ab8cSAndroid Build Coastguard Worker // that should be monitored along the sleep. The opaque pointer is
578*cf78ab8cSAndroid Build Coastguard Worker // passed as such to add_poll, and add_poll returns an index.
579*cf78ab8cSAndroid Build Coastguard Worker //
580*cf78ab8cSAndroid Build Coastguard Worker // * select_error should be 1 if poll() returned an error, else 0.
581*cf78ab8cSAndroid Build Coastguard Worker
582*cf78ab8cSAndroid Build Coastguard Worker impl Slirp {
pollfds_poll(&self, select_error: c_int)583*cf78ab8cSAndroid Build Coastguard Worker fn pollfds_poll(&self, select_error: c_int) {
584*cf78ab8cSAndroid Build Coastguard Worker // Call libslrip "C" library to fill poll return event information
585*cf78ab8cSAndroid Build Coastguard Worker // using slirp_get_revents_cb callback function.
586*cf78ab8cSAndroid Build Coastguard Worker //
587*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: we ensure that:
588*cf78ab8cSAndroid Build Coastguard Worker //
589*cf78ab8cSAndroid Build Coastguard Worker // * self.slirp has a slirp pointer initialized by slirp_new,
590*cf78ab8cSAndroid Build Coastguard Worker // as it's private to the struct is only constructed that way
591*cf78ab8cSAndroid Build Coastguard Worker //
592*cf78ab8cSAndroid Build Coastguard Worker // * slirp_get_revents_cb is a valid `SlirpGetREventsCb` callback
593*cf78ab8cSAndroid Build Coastguard Worker // function.
594*cf78ab8cSAndroid Build Coastguard Worker //
595*cf78ab8cSAndroid Build Coastguard Worker // * select_error should be 1 if poll() returned an error, else 0.
596*cf78ab8cSAndroid Build Coastguard Worker //
597*cf78ab8cSAndroid Build Coastguard Worker // * self.callback_context is a CallbackContext
598*cf78ab8cSAndroid Build Coastguard Worker unsafe {
599*cf78ab8cSAndroid Build Coastguard Worker libslirp_sys::slirp_pollfds_poll(
600*cf78ab8cSAndroid Build Coastguard Worker self.slirp,
601*cf78ab8cSAndroid Build Coastguard Worker select_error,
602*cf78ab8cSAndroid Build Coastguard Worker Some(slirp_get_revents_cb),
603*cf78ab8cSAndroid Build Coastguard Worker &*self.callback_context as *const CallbackContext as *mut c_void,
604*cf78ab8cSAndroid Build Coastguard Worker );
605*cf78ab8cSAndroid Build Coastguard Worker }
606*cf78ab8cSAndroid Build Coastguard Worker }
607*cf78ab8cSAndroid Build Coastguard Worker }
608*cf78ab8cSAndroid Build Coastguard Worker
609*cf78ab8cSAndroid Build Coastguard Worker // "C" library callback that is called on each file descriptor, giving
610*cf78ab8cSAndroid Build Coastguard Worker // it the index that add_poll returned.
611*cf78ab8cSAndroid Build Coastguard Worker //
612*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
613*cf78ab8cSAndroid Build Coastguard Worker //
614*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
slirp_get_revents_cb(idx: c_int, opaque: *mut c_void) -> c_int615*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn slirp_get_revents_cb(idx: c_int, opaque: *mut c_void) -> c_int {
616*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.get_events(idx)
617*cf78ab8cSAndroid Build Coastguard Worker }
618*cf78ab8cSAndroid Build Coastguard Worker
619*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
get_events(&self, idx: c_int) -> c_int620*cf78ab8cSAndroid Build Coastguard Worker fn get_events(&self, idx: c_int) -> c_int {
621*cf78ab8cSAndroid Build Coastguard Worker if let Some(poll_fd) = self.poll_fds.borrow().get(idx as usize) {
622*cf78ab8cSAndroid Build Coastguard Worker poll_fd.revents as c_int
623*cf78ab8cSAndroid Build Coastguard Worker } else {
624*cf78ab8cSAndroid Build Coastguard Worker 0
625*cf78ab8cSAndroid Build Coastguard Worker }
626*cf78ab8cSAndroid Build Coastguard Worker }
627*cf78ab8cSAndroid Build Coastguard Worker }
628*cf78ab8cSAndroid Build Coastguard Worker
629*cf78ab8cSAndroid Build Coastguard Worker macro_rules! ternary {
630*cf78ab8cSAndroid Build Coastguard Worker ($cond:expr, $true_expr:expr) => {
631*cf78ab8cSAndroid Build Coastguard Worker if $cond != 0 {
632*cf78ab8cSAndroid Build Coastguard Worker $true_expr
633*cf78ab8cSAndroid Build Coastguard Worker } else {
634*cf78ab8cSAndroid Build Coastguard Worker 0
635*cf78ab8cSAndroid Build Coastguard Worker }
636*cf78ab8cSAndroid Build Coastguard Worker };
637*cf78ab8cSAndroid Build Coastguard Worker }
638*cf78ab8cSAndroid Build Coastguard Worker
639*cf78ab8cSAndroid Build Coastguard Worker // Worker thread loops issuing blocking poll requests, sending the
640*cf78ab8cSAndroid Build Coastguard Worker // results into the slirp thread
641*cf78ab8cSAndroid Build Coastguard Worker
slirp_poll_thread(rx: mpsc::Receiver<PollRequest>, tx: mpsc::Sender<SlirpCmd>)642*cf78ab8cSAndroid Build Coastguard Worker fn slirp_poll_thread(rx: mpsc::Receiver<PollRequest>, tx: mpsc::Sender<SlirpCmd>) {
643*cf78ab8cSAndroid Build Coastguard Worker #[cfg(any(target_os = "linux", target_os = "macos"))]
644*cf78ab8cSAndroid Build Coastguard Worker use libc::{
645*cf78ab8cSAndroid Build Coastguard Worker nfds_t as OsPollFdsLenType, poll, pollfd, POLLERR, POLLHUP, POLLIN, POLLOUT, POLLPRI,
646*cf78ab8cSAndroid Build Coastguard Worker };
647*cf78ab8cSAndroid Build Coastguard Worker #[cfg(target_os = "windows")]
648*cf78ab8cSAndroid Build Coastguard Worker use winapi::{
649*cf78ab8cSAndroid Build Coastguard Worker shared::minwindef::ULONG as OsPollFdsLenType,
650*cf78ab8cSAndroid Build Coastguard Worker um::winsock2::{
651*cf78ab8cSAndroid Build Coastguard Worker WSAPoll as poll, POLLERR, POLLHUP, POLLOUT, POLLPRI, POLLRDBAND, POLLRDNORM,
652*cf78ab8cSAndroid Build Coastguard Worker SOCKET as FdType, WSAPOLLFD as pollfd,
653*cf78ab8cSAndroid Build Coastguard Worker },
654*cf78ab8cSAndroid Build Coastguard Worker };
655*cf78ab8cSAndroid Build Coastguard Worker #[cfg(any(target_os = "linux", target_os = "macos"))]
656*cf78ab8cSAndroid Build Coastguard Worker type FdType = c_int;
657*cf78ab8cSAndroid Build Coastguard Worker
658*cf78ab8cSAndroid Build Coastguard Worker #[cfg(any(target_os = "linux", target_os = "macos"))]
659*cf78ab8cSAndroid Build Coastguard Worker fn to_os_events(events: libslirp_sys::SlirpPollType) -> i16 {
660*cf78ab8cSAndroid Build Coastguard Worker ternary!(events & libslirp_sys::SLIRP_POLL_IN, POLLIN)
661*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & libslirp_sys::SLIRP_POLL_OUT, POLLOUT)
662*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & libslirp_sys::SLIRP_POLL_PRI, POLLPRI)
663*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & libslirp_sys::SLIRP_POLL_ERR, POLLERR)
664*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & libslirp_sys::SLIRP_POLL_HUP, POLLHUP)
665*cf78ab8cSAndroid Build Coastguard Worker }
666*cf78ab8cSAndroid Build Coastguard Worker
667*cf78ab8cSAndroid Build Coastguard Worker #[cfg(any(target_os = "linux", target_os = "macos"))]
668*cf78ab8cSAndroid Build Coastguard Worker fn to_slirp_events(events: i16) -> libslirp_sys::SlirpPollType {
669*cf78ab8cSAndroid Build Coastguard Worker ternary!(events & POLLIN, libslirp_sys::SLIRP_POLL_IN)
670*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLOUT, libslirp_sys::SLIRP_POLL_OUT)
671*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLPRI, libslirp_sys::SLIRP_POLL_PRI)
672*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLOUT, libslirp_sys::SLIRP_POLL_ERR)
673*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLHUP, libslirp_sys::SLIRP_POLL_HUP)
674*cf78ab8cSAndroid Build Coastguard Worker }
675*cf78ab8cSAndroid Build Coastguard Worker
676*cf78ab8cSAndroid Build Coastguard Worker #[cfg(target_os = "windows")]
677*cf78ab8cSAndroid Build Coastguard Worker fn to_os_events(events: libslirp_sys::SlirpPollType) -> i16 {
678*cf78ab8cSAndroid Build Coastguard Worker ternary!(events & libslirp_sys::SLIRP_POLL_IN, POLLRDNORM)
679*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & libslirp_sys::SLIRP_POLL_OUT, POLLOUT)
680*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & libslirp_sys::SLIRP_POLL_PRI, POLLRDBAND)
681*cf78ab8cSAndroid Build Coastguard Worker }
682*cf78ab8cSAndroid Build Coastguard Worker
683*cf78ab8cSAndroid Build Coastguard Worker #[cfg(target_os = "windows")]
684*cf78ab8cSAndroid Build Coastguard Worker fn to_slirp_events(events: i16) -> libslirp_sys::SlirpPollType {
685*cf78ab8cSAndroid Build Coastguard Worker ternary!(events & POLLRDNORM, libslirp_sys::SLIRP_POLL_IN)
686*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLERR, libslirp_sys::SLIRP_POLL_IN)
687*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLHUP, libslirp_sys::SLIRP_POLL_IN)
688*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLOUT, libslirp_sys::SLIRP_POLL_OUT)
689*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLERR, libslirp_sys::SLIRP_POLL_PRI)
690*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLHUP, libslirp_sys::SLIRP_POLL_PRI)
691*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLPRI, libslirp_sys::SLIRP_POLL_PRI)
692*cf78ab8cSAndroid Build Coastguard Worker | ternary!(events & POLLRDBAND, libslirp_sys::SLIRP_POLL_PRI)
693*cf78ab8cSAndroid Build Coastguard Worker }
694*cf78ab8cSAndroid Build Coastguard Worker
695*cf78ab8cSAndroid Build Coastguard Worker let mut prev_poll_fds_len = 0;
696*cf78ab8cSAndroid Build Coastguard Worker while let Ok((poll_fds, timeout)) = rx.recv() {
697*cf78ab8cSAndroid Build Coastguard Worker if poll_fds.len() != prev_poll_fds_len {
698*cf78ab8cSAndroid Build Coastguard Worker prev_poll_fds_len = poll_fds.len();
699*cf78ab8cSAndroid Build Coastguard Worker debug!("slirp_poll_thread recv poll_fds.len(): {:?}", prev_poll_fds_len);
700*cf78ab8cSAndroid Build Coastguard Worker }
701*cf78ab8cSAndroid Build Coastguard Worker // Create a c format array with the same size as poll
702*cf78ab8cSAndroid Build Coastguard Worker let mut os_poll_fds: Vec<pollfd> = Vec::with_capacity(poll_fds.len());
703*cf78ab8cSAndroid Build Coastguard Worker for fd in &poll_fds {
704*cf78ab8cSAndroid Build Coastguard Worker os_poll_fds.push(pollfd {
705*cf78ab8cSAndroid Build Coastguard Worker fd: fd.fd as FdType,
706*cf78ab8cSAndroid Build Coastguard Worker events: to_os_events(fd.events),
707*cf78ab8cSAndroid Build Coastguard Worker revents: 0,
708*cf78ab8cSAndroid Build Coastguard Worker });
709*cf78ab8cSAndroid Build Coastguard Worker }
710*cf78ab8cSAndroid Build Coastguard Worker
711*cf78ab8cSAndroid Build Coastguard Worker let mut poll_result = 0;
712*cf78ab8cSAndroid Build Coastguard Worker #[cfg(any(target_os = "linux", target_os = "macos"))]
713*cf78ab8cSAndroid Build Coastguard Worker {
714*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: we ensure that:
715*cf78ab8cSAndroid Build Coastguard Worker //
716*cf78ab8cSAndroid Build Coastguard Worker // `os_poll_fds` is a valid ptr to a vector of pollfd which
717*cf78ab8cSAndroid Build Coastguard Worker // the `poll` system call can write into. Note `os_poll_fds`
718*cf78ab8cSAndroid Build Coastguard Worker // is created and allocated above.
719*cf78ab8cSAndroid Build Coastguard Worker poll_result = unsafe {
720*cf78ab8cSAndroid Build Coastguard Worker poll(
721*cf78ab8cSAndroid Build Coastguard Worker os_poll_fds.as_mut_ptr(),
722*cf78ab8cSAndroid Build Coastguard Worker os_poll_fds.len() as OsPollFdsLenType,
723*cf78ab8cSAndroid Build Coastguard Worker timeout as i32,
724*cf78ab8cSAndroid Build Coastguard Worker )
725*cf78ab8cSAndroid Build Coastguard Worker };
726*cf78ab8cSAndroid Build Coastguard Worker }
727*cf78ab8cSAndroid Build Coastguard Worker // WSAPoll requires an array of one or more POLLFD structures.
728*cf78ab8cSAndroid Build Coastguard Worker // When nfds == 0, WSAPoll returns immediately with result -1, ignoring the timeout.
729*cf78ab8cSAndroid Build Coastguard Worker // This is different from poll on Linux/macOS, which will wait for the timeout.
730*cf78ab8cSAndroid Build Coastguard Worker // Therefore, on Windows, we don't call WSAPoll when nfds == 0, and instead explicitly sleep for the timeout.
731*cf78ab8cSAndroid Build Coastguard Worker #[cfg(target_os = "windows")]
732*cf78ab8cSAndroid Build Coastguard Worker if os_poll_fds.is_empty() {
733*cf78ab8cSAndroid Build Coastguard Worker // If there are no FDs to poll, sleep for the specified timeout.
734*cf78ab8cSAndroid Build Coastguard Worker thread::sleep(Duration::from_millis(timeout as u64));
735*cf78ab8cSAndroid Build Coastguard Worker } else {
736*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: we ensure that:
737*cf78ab8cSAndroid Build Coastguard Worker //
738*cf78ab8cSAndroid Build Coastguard Worker // `os_poll_fds` is a valid ptr to a vector of pollfd which
739*cf78ab8cSAndroid Build Coastguard Worker // the `poll` system call can write into. Note `os_poll_fds`
740*cf78ab8cSAndroid Build Coastguard Worker // is created and allocated above.
741*cf78ab8cSAndroid Build Coastguard Worker poll_result = unsafe {
742*cf78ab8cSAndroid Build Coastguard Worker poll(
743*cf78ab8cSAndroid Build Coastguard Worker os_poll_fds.as_mut_ptr(),
744*cf78ab8cSAndroid Build Coastguard Worker os_poll_fds.len() as OsPollFdsLenType,
745*cf78ab8cSAndroid Build Coastguard Worker timeout as i32,
746*cf78ab8cSAndroid Build Coastguard Worker )
747*cf78ab8cSAndroid Build Coastguard Worker };
748*cf78ab8cSAndroid Build Coastguard Worker }
749*cf78ab8cSAndroid Build Coastguard Worker
750*cf78ab8cSAndroid Build Coastguard Worker let mut slirp_poll_fds: Vec<PollFd> = Vec::with_capacity(poll_fds.len());
751*cf78ab8cSAndroid Build Coastguard Worker #[cfg(any(target_os = "linux", target_os = "macos"))]
752*cf78ab8cSAndroid Build Coastguard Worker for &fd in &os_poll_fds {
753*cf78ab8cSAndroid Build Coastguard Worker slirp_poll_fds.push(PollFd {
754*cf78ab8cSAndroid Build Coastguard Worker fd: fd.fd as c_int,
755*cf78ab8cSAndroid Build Coastguard Worker events: to_slirp_events(fd.events),
756*cf78ab8cSAndroid Build Coastguard Worker revents: to_slirp_events(fd.revents) & to_slirp_events(fd.events),
757*cf78ab8cSAndroid Build Coastguard Worker });
758*cf78ab8cSAndroid Build Coastguard Worker }
759*cf78ab8cSAndroid Build Coastguard Worker #[cfg(target_os = "windows")]
760*cf78ab8cSAndroid Build Coastguard Worker for (fd, poll_fd) in os_poll_fds.iter().zip(poll_fds.iter()) {
761*cf78ab8cSAndroid Build Coastguard Worker slirp_poll_fds.push(PollFd {
762*cf78ab8cSAndroid Build Coastguard Worker fd: fd.fd as c_int,
763*cf78ab8cSAndroid Build Coastguard Worker events: poll_fd.events,
764*cf78ab8cSAndroid Build Coastguard Worker revents: to_slirp_events(fd.revents) & poll_fd.events,
765*cf78ab8cSAndroid Build Coastguard Worker });
766*cf78ab8cSAndroid Build Coastguard Worker }
767*cf78ab8cSAndroid Build Coastguard Worker
768*cf78ab8cSAndroid Build Coastguard Worker // 'select_error' should be 1 if poll() returned an error, else 0.
769*cf78ab8cSAndroid Build Coastguard Worker if let Err(e) = tx.send(SlirpCmd::PollResult(slirp_poll_fds, (poll_result < 0) as i32)) {
770*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to send slirp PollResult cmd: {}", e);
771*cf78ab8cSAndroid Build Coastguard Worker }
772*cf78ab8cSAndroid Build Coastguard Worker }
773*cf78ab8cSAndroid Build Coastguard Worker }
774*cf78ab8cSAndroid Build Coastguard Worker
775*cf78ab8cSAndroid Build Coastguard Worker // Call libslrip "C" library to send input.
776*cf78ab8cSAndroid Build Coastguard Worker //
777*cf78ab8cSAndroid Build Coastguard Worker // This is called by the application when the guest emits a packet on
778*cf78ab8cSAndroid Build Coastguard Worker // the guest network, to be interpreted by slirp.
779*cf78ab8cSAndroid Build Coastguard Worker impl Slirp {
input(&self, bytes: &[u8])780*cf78ab8cSAndroid Build Coastguard Worker fn input(&self, bytes: &[u8]) {
781*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: The "C" library ensure that the memory is not
782*cf78ab8cSAndroid Build Coastguard Worker // referenced after the call and `bytes` does not need to remain
783*cf78ab8cSAndroid Build Coastguard Worker // valid after the function returns.
784*cf78ab8cSAndroid Build Coastguard Worker unsafe { libslirp_sys::slirp_input(self.slirp, bytes.as_ptr(), bytes.len() as i32) };
785*cf78ab8cSAndroid Build Coastguard Worker }
786*cf78ab8cSAndroid Build Coastguard Worker }
787*cf78ab8cSAndroid Build Coastguard Worker
788*cf78ab8cSAndroid Build Coastguard Worker // "C" library callback that is called to send an ethernet frame to
789*cf78ab8cSAndroid Build Coastguard Worker // the guest network. If the guest is not ready to receive a frame,
790*cf78ab8cSAndroid Build Coastguard Worker // the function can just drop the data. TCP will then handle
791*cf78ab8cSAndroid Build Coastguard Worker // retransmissions at a lower pace. A return of < 0 reports an IO
792*cf78ab8cSAndroid Build Coastguard Worker // error.
793*cf78ab8cSAndroid Build Coastguard Worker //
794*cf78ab8cSAndroid Build Coastguard Worker // # Safety:
795*cf78ab8cSAndroid Build Coastguard Worker //
796*cf78ab8cSAndroid Build Coastguard Worker // * buf must be a valid pointer to `len` bytes of memory. The
797*cf78ab8cSAndroid Build Coastguard Worker // contents of buf must be valid for the duration of this call.
798*cf78ab8cSAndroid Build Coastguard Worker //
799*cf78ab8cSAndroid Build Coastguard Worker // * len is > 0
800*cf78ab8cSAndroid Build Coastguard Worker //
801*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
send_packet_cb( buf: *const c_void, len: usize, opaque: *mut c_void, ) -> libslirp_sys::slirp_ssize_t802*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn send_packet_cb(
803*cf78ab8cSAndroid Build Coastguard Worker buf: *const c_void,
804*cf78ab8cSAndroid Build Coastguard Worker len: usize,
805*cf78ab8cSAndroid Build Coastguard Worker opaque: *mut c_void,
806*cf78ab8cSAndroid Build Coastguard Worker ) -> libslirp_sys::slirp_ssize_t {
807*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.send_packet(buf, len)
808*cf78ab8cSAndroid Build Coastguard Worker }
809*cf78ab8cSAndroid Build Coastguard Worker
810*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
send_packet(&self, buf: *const c_void, len: usize) -> libslirp_sys::slirp_ssize_t811*cf78ab8cSAndroid Build Coastguard Worker fn send_packet(&self, buf: *const c_void, len: usize) -> libslirp_sys::slirp_ssize_t {
812*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: The caller ensures that `buf` is contains `len` bytes of data.
813*cf78ab8cSAndroid Build Coastguard Worker let c_slice = unsafe { std::slice::from_raw_parts(buf as *const u8, len) };
814*cf78ab8cSAndroid Build Coastguard Worker // Bytes::from(slice: &'static [u8]) creates a Bytes object without copying the data.
815*cf78ab8cSAndroid Build Coastguard Worker // To own its data, copy &'static [u8] to Vec<u8> before converting to Bytes.
816*cf78ab8cSAndroid Build Coastguard Worker let _ = self.tx_bytes.send(Bytes::from(c_slice.to_vec()));
817*cf78ab8cSAndroid Build Coastguard Worker len as libslirp_sys::slirp_ssize_t
818*cf78ab8cSAndroid Build Coastguard Worker }
819*cf78ab8cSAndroid Build Coastguard Worker }
820*cf78ab8cSAndroid Build Coastguard Worker
821*cf78ab8cSAndroid Build Coastguard Worker // "C" library callback to print a message for an error due to guest
822*cf78ab8cSAndroid Build Coastguard Worker // misbehavior.
823*cf78ab8cSAndroid Build Coastguard Worker //
824*cf78ab8cSAndroid Build Coastguard Worker // # Safety:
825*cf78ab8cSAndroid Build Coastguard Worker //
826*cf78ab8cSAndroid Build Coastguard Worker // * msg must be a valid nul-terminated utf8 string.
827*cf78ab8cSAndroid Build Coastguard Worker //
828*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
guest_error_cb(msg: *const c_char, opaque: *mut c_void)829*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn guest_error_cb(msg: *const c_char, opaque: *mut c_void) {
830*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: The caller ensures that `msg` is a nul-terminated string.
831*cf78ab8cSAndroid Build Coastguard Worker let msg = String::from_utf8_lossy(unsafe { CStr::from_ptr(msg) }.to_bytes());
832*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.guest_error(msg.to_string());
833*cf78ab8cSAndroid Build Coastguard Worker }
834*cf78ab8cSAndroid Build Coastguard Worker
835*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
guest_error(&self, msg: String)836*cf78ab8cSAndroid Build Coastguard Worker fn guest_error(&self, msg: String) {
837*cf78ab8cSAndroid Build Coastguard Worker warn!("libslirp: {msg}");
838*cf78ab8cSAndroid Build Coastguard Worker }
839*cf78ab8cSAndroid Build Coastguard Worker }
840*cf78ab8cSAndroid Build Coastguard Worker
841*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
842*cf78ab8cSAndroid Build Coastguard Worker //
843*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
clock_get_ns_cb(opaque: *mut c_void) -> i64844*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn clock_get_ns_cb(opaque: *mut c_void) -> i64 {
845*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.clock_get_ns()
846*cf78ab8cSAndroid Build Coastguard Worker }
847*cf78ab8cSAndroid Build Coastguard Worker
848*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
clock_get_ns(&self) -> i64849*cf78ab8cSAndroid Build Coastguard Worker fn clock_get_ns(&self) -> i64 {
850*cf78ab8cSAndroid Build Coastguard Worker self.timer_manager.get_elapsed().as_nanos() as i64
851*cf78ab8cSAndroid Build Coastguard Worker }
852*cf78ab8cSAndroid Build Coastguard Worker }
853*cf78ab8cSAndroid Build Coastguard Worker
854*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
855*cf78ab8cSAndroid Build Coastguard Worker //
856*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
init_completed_cb(_slirp: *mut libslirp_sys::Slirp, opaque: *mut c_void)857*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn init_completed_cb(_slirp: *mut libslirp_sys::Slirp, opaque: *mut c_void) {
858*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.init_completed();
859*cf78ab8cSAndroid Build Coastguard Worker }
860*cf78ab8cSAndroid Build Coastguard Worker
861*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
init_completed(&self)862*cf78ab8cSAndroid Build Coastguard Worker fn init_completed(&self) {
863*cf78ab8cSAndroid Build Coastguard Worker info!("libslirp: initialization completed.");
864*cf78ab8cSAndroid Build Coastguard Worker }
865*cf78ab8cSAndroid Build Coastguard Worker }
866*cf78ab8cSAndroid Build Coastguard Worker
867*cf78ab8cSAndroid Build Coastguard Worker // Create a new timer
868*cf78ab8cSAndroid Build Coastguard Worker //
869*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
870*cf78ab8cSAndroid Build Coastguard Worker //
871*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
timer_new_opaque_cb( id: libslirp_sys::SlirpTimerId, cb_opaque: *mut c_void, opaque: *mut c_void, ) -> *mut c_void872*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn timer_new_opaque_cb(
873*cf78ab8cSAndroid Build Coastguard Worker id: libslirp_sys::SlirpTimerId,
874*cf78ab8cSAndroid Build Coastguard Worker cb_opaque: *mut c_void,
875*cf78ab8cSAndroid Build Coastguard Worker opaque: *mut c_void,
876*cf78ab8cSAndroid Build Coastguard Worker ) -> *mut c_void {
877*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.timer_new_opaque(id, cb_opaque)
878*cf78ab8cSAndroid Build Coastguard Worker }
879*cf78ab8cSAndroid Build Coastguard Worker
880*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
881*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
882*cf78ab8cSAndroid Build Coastguard Worker //
883*cf78ab8cSAndroid Build Coastguard Worker // * cb_opaque is only passed back to libslirp
timer_new_opaque( &self, id: libslirp_sys::SlirpTimerId, cb_opaque: *mut c_void, ) -> *mut c_void884*cf78ab8cSAndroid Build Coastguard Worker unsafe fn timer_new_opaque(
885*cf78ab8cSAndroid Build Coastguard Worker &self,
886*cf78ab8cSAndroid Build Coastguard Worker id: libslirp_sys::SlirpTimerId,
887*cf78ab8cSAndroid Build Coastguard Worker cb_opaque: *mut c_void,
888*cf78ab8cSAndroid Build Coastguard Worker ) -> *mut c_void {
889*cf78ab8cSAndroid Build Coastguard Worker let timer = self.timer_manager.next_timer();
890*cf78ab8cSAndroid Build Coastguard Worker self.timer_manager
891*cf78ab8cSAndroid Build Coastguard Worker .insert(timer, Timer { expire_time: u64::MAX, id, cb_opaque: cb_opaque as usize });
892*cf78ab8cSAndroid Build Coastguard Worker timer as *mut c_void
893*cf78ab8cSAndroid Build Coastguard Worker }
894*cf78ab8cSAndroid Build Coastguard Worker }
895*cf78ab8cSAndroid Build Coastguard Worker
896*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
897*cf78ab8cSAndroid Build Coastguard Worker //
898*cf78ab8cSAndroid Build Coastguard Worker // * timer is a TimerOpaque key for timer manager
899*cf78ab8cSAndroid Build Coastguard Worker //
900*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
timer_free_cb(timer: *mut c_void, opaque: *mut c_void)901*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn timer_free_cb(timer: *mut c_void, opaque: *mut c_void) {
902*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.timer_free(timer);
903*cf78ab8cSAndroid Build Coastguard Worker }
904*cf78ab8cSAndroid Build Coastguard Worker
905*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
timer_free(&self, timer: *mut c_void)906*cf78ab8cSAndroid Build Coastguard Worker fn timer_free(&self, timer: *mut c_void) {
907*cf78ab8cSAndroid Build Coastguard Worker let timer = timer as TimerOpaque;
908*cf78ab8cSAndroid Build Coastguard Worker if self.timer_manager.remove(&timer).is_none() {
909*cf78ab8cSAndroid Build Coastguard Worker warn!("Unknown timer {timer}");
910*cf78ab8cSAndroid Build Coastguard Worker }
911*cf78ab8cSAndroid Build Coastguard Worker }
912*cf78ab8cSAndroid Build Coastguard Worker }
913*cf78ab8cSAndroid Build Coastguard Worker
914*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
915*cf78ab8cSAndroid Build Coastguard Worker //
916*cf78ab8cSAndroid Build Coastguard Worker // * timer is a TimerOpaque key for timer manager
917*cf78ab8cSAndroid Build Coastguard Worker //
918*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
timer_mod_cb(timer: *mut c_void, expire_time: i64, opaque: *mut c_void)919*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn timer_mod_cb(timer: *mut c_void, expire_time: i64, opaque: *mut c_void) {
920*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.timer_mod(timer, expire_time);
921*cf78ab8cSAndroid Build Coastguard Worker }
922*cf78ab8cSAndroid Build Coastguard Worker
923*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
timer_mod(&self, timer: *mut c_void, expire_time: i64)924*cf78ab8cSAndroid Build Coastguard Worker fn timer_mod(&self, timer: *mut c_void, expire_time: i64) {
925*cf78ab8cSAndroid Build Coastguard Worker let timer_key = timer as TimerOpaque;
926*cf78ab8cSAndroid Build Coastguard Worker let expire_time = std::cmp::max(expire_time, 0) as u64;
927*cf78ab8cSAndroid Build Coastguard Worker self.timer_manager.timer_mod(&timer_key, expire_time);
928*cf78ab8cSAndroid Build Coastguard Worker // Wake up slirp command thread to reset sleep duration
929*cf78ab8cSAndroid Build Coastguard Worker let _ = self.tx_cmds.send(SlirpCmd::TimerModified);
930*cf78ab8cSAndroid Build Coastguard Worker }
931*cf78ab8cSAndroid Build Coastguard Worker }
932*cf78ab8cSAndroid Build Coastguard Worker
register_poll_fd_cb(_fd: c_int, _opaque: *mut c_void)933*cf78ab8cSAndroid Build Coastguard Worker extern "C" fn register_poll_fd_cb(_fd: c_int, _opaque: *mut c_void) {
934*cf78ab8cSAndroid Build Coastguard Worker //TODO: Need implementation for Windows
935*cf78ab8cSAndroid Build Coastguard Worker }
936*cf78ab8cSAndroid Build Coastguard Worker
unregister_poll_fd_cb(_fd: c_int, _opaque: *mut c_void)937*cf78ab8cSAndroid Build Coastguard Worker extern "C" fn unregister_poll_fd_cb(_fd: c_int, _opaque: *mut c_void) {
938*cf78ab8cSAndroid Build Coastguard Worker //TODO: Need implementation for Windows
939*cf78ab8cSAndroid Build Coastguard Worker }
940*cf78ab8cSAndroid Build Coastguard Worker
notify_cb(_opaque: *mut c_void)941*cf78ab8cSAndroid Build Coastguard Worker extern "C" fn notify_cb(_opaque: *mut c_void) {
942*cf78ab8cSAndroid Build Coastguard Worker //TODO: Un-implemented
943*cf78ab8cSAndroid Build Coastguard Worker }
944*cf78ab8cSAndroid Build Coastguard Worker
945*cf78ab8cSAndroid Build Coastguard Worker // Called by libslirp to initiate a proxy connection to address
946*cf78ab8cSAndroid Build Coastguard Worker // `addr.` Eventually this will notify libslirp with a result by
947*cf78ab8cSAndroid Build Coastguard Worker // calling the passed `connect_func.`
948*cf78ab8cSAndroid Build Coastguard Worker //
949*cf78ab8cSAndroid Build Coastguard Worker // SAFETY:
950*cf78ab8cSAndroid Build Coastguard Worker //
951*cf78ab8cSAndroid Build Coastguard Worker // * opaque is a CallbackContext
try_connect_cb( addr: *const libslirp_sys::sockaddr_storage, connect_func: libslirp_sys::SlirpProxyConnectFunc, connect_opaque: *mut c_void, opaque: *mut c_void, ) -> bool952*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn try_connect_cb(
953*cf78ab8cSAndroid Build Coastguard Worker addr: *const libslirp_sys::sockaddr_storage,
954*cf78ab8cSAndroid Build Coastguard Worker connect_func: libslirp_sys::SlirpProxyConnectFunc,
955*cf78ab8cSAndroid Build Coastguard Worker connect_opaque: *mut c_void,
956*cf78ab8cSAndroid Build Coastguard Worker opaque: *mut c_void,
957*cf78ab8cSAndroid Build Coastguard Worker ) -> bool {
958*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.try_connect(
959*cf78ab8cSAndroid Build Coastguard Worker addr,
960*cf78ab8cSAndroid Build Coastguard Worker connect_func,
961*cf78ab8cSAndroid Build Coastguard Worker connect_opaque as usize,
962*cf78ab8cSAndroid Build Coastguard Worker )
963*cf78ab8cSAndroid Build Coastguard Worker }
964*cf78ab8cSAndroid Build Coastguard Worker
965*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
try_connect( &self, addr: *const libslirp_sys::sockaddr_storage, connect_func: libslirp_sys::SlirpProxyConnectFunc, connect_id: usize, ) -> bool966*cf78ab8cSAndroid Build Coastguard Worker fn try_connect(
967*cf78ab8cSAndroid Build Coastguard Worker &self,
968*cf78ab8cSAndroid Build Coastguard Worker addr: *const libslirp_sys::sockaddr_storage,
969*cf78ab8cSAndroid Build Coastguard Worker connect_func: libslirp_sys::SlirpProxyConnectFunc,
970*cf78ab8cSAndroid Build Coastguard Worker connect_id: usize,
971*cf78ab8cSAndroid Build Coastguard Worker ) -> bool {
972*cf78ab8cSAndroid Build Coastguard Worker if let Some(proxy_manager) = &self.proxy_manager {
973*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: We ensure that addr is valid when `try_connect` is called from libslirp
974*cf78ab8cSAndroid Build Coastguard Worker let storage = unsafe { *addr };
975*cf78ab8cSAndroid Build Coastguard Worker let af = storage.ss_family as i32;
976*cf78ab8cSAndroid Build Coastguard Worker let socket_addr: SocketAddr = storage.into();
977*cf78ab8cSAndroid Build Coastguard Worker proxy_manager.try_connect(
978*cf78ab8cSAndroid Build Coastguard Worker socket_addr,
979*cf78ab8cSAndroid Build Coastguard Worker connect_id,
980*cf78ab8cSAndroid Build Coastguard Worker Box::new(ConnectRequest {
981*cf78ab8cSAndroid Build Coastguard Worker tx_cmds: self.tx_cmds.clone(),
982*cf78ab8cSAndroid Build Coastguard Worker connect_func,
983*cf78ab8cSAndroid Build Coastguard Worker connect_id,
984*cf78ab8cSAndroid Build Coastguard Worker af,
985*cf78ab8cSAndroid Build Coastguard Worker start: Instant::now(),
986*cf78ab8cSAndroid Build Coastguard Worker }),
987*cf78ab8cSAndroid Build Coastguard Worker )
988*cf78ab8cSAndroid Build Coastguard Worker } else {
989*cf78ab8cSAndroid Build Coastguard Worker false
990*cf78ab8cSAndroid Build Coastguard Worker }
991*cf78ab8cSAndroid Build Coastguard Worker }
992*cf78ab8cSAndroid Build Coastguard Worker }
993*cf78ab8cSAndroid Build Coastguard Worker
remove_cb(connect_opaque: *mut c_void, opaque: *mut c_void)994*cf78ab8cSAndroid Build Coastguard Worker unsafe extern "C" fn remove_cb(connect_opaque: *mut c_void, opaque: *mut c_void) {
995*cf78ab8cSAndroid Build Coastguard Worker unsafe { callback_context_from_raw(opaque) }.remove(connect_opaque as usize);
996*cf78ab8cSAndroid Build Coastguard Worker }
997*cf78ab8cSAndroid Build Coastguard Worker
998*cf78ab8cSAndroid Build Coastguard Worker impl CallbackContext {
remove(&self, connect_id: usize)999*cf78ab8cSAndroid Build Coastguard Worker fn remove(&self, connect_id: usize) {
1000*cf78ab8cSAndroid Build Coastguard Worker if let Some(proxy_connector) = &self.proxy_manager {
1001*cf78ab8cSAndroid Build Coastguard Worker proxy_connector.remove(connect_id);
1002*cf78ab8cSAndroid Build Coastguard Worker }
1003*cf78ab8cSAndroid Build Coastguard Worker }
1004*cf78ab8cSAndroid Build Coastguard Worker }
1005*cf78ab8cSAndroid Build Coastguard Worker
1006*cf78ab8cSAndroid Build Coastguard Worker #[cfg(test)]
1007*cf78ab8cSAndroid Build Coastguard Worker mod tests {
1008*cf78ab8cSAndroid Build Coastguard Worker use super::*;
1009*cf78ab8cSAndroid Build Coastguard Worker
1010*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_version_string()1011*cf78ab8cSAndroid Build Coastguard Worker fn test_version_string() {
1012*cf78ab8cSAndroid Build Coastguard Worker // Safety
1013*cf78ab8cSAndroid Build Coastguard Worker // Function returns a constant c_str
1014*cf78ab8cSAndroid Build Coastguard Worker let c_version_str = unsafe { CStr::from_ptr(crate::libslirp_sys::slirp_version_string()) };
1015*cf78ab8cSAndroid Build Coastguard Worker assert_eq!("4.7.0", c_version_str.to_str().unwrap());
1016*cf78ab8cSAndroid Build Coastguard Worker }
1017*cf78ab8cSAndroid Build Coastguard Worker }
1018