Skip to content

MBE-1302 intproxy compiles on windows #3445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: windows-support
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 25 additions & 25 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
[workspace]

members = [
"mirrord/*",
"mirrord/agent/env",
"mirrord/agent/iptables",
"mirrord/layer/tests/apps/fileops",
"mirrord/layer/tests/apps/outgoing",
"mirrord/layer/tests/apps/listen_ports",
"mirrord/layer/tests/apps/dns_resolve",
"mirrord/layer/tests/apps/recv_from",
"mirrord/layer/tests/apps/issue1776",
"mirrord/layer/tests/apps/issue1776portnot53",
"mirrord/layer/tests/apps/issue1899",
"mirrord/layer/tests/apps/issue2001",
"mirrord/layer/tests/apps/issue2438",
"mirrord/layer/tests/apps/issue3248",
"mirrord/layer/tests/apps/rebind0",
"sample/rust",
"medschool",
"tests",
"tests/rust-e2e-fileops",
"tests/rust-unix-socket-client",
"tests/rust-bypassed-unix-socket",
"tests/issue1317",
"tests/rust-websockets",
"tests/rust-sqs-printer",
"mirrord/intproxy",
#"mirrord/agent/env",
#"mirrord/agent/iptables",
#"mirrord/layer/tests/apps/fileops",
#"mirrord/layer/tests/apps/outgoing",
#"mirrord/layer/tests/apps/listen_ports",
#"mirrord/layer/tests/apps/dns_resolve",
#"mirrord/layer/tests/apps/recv_from",
#"mirrord/layer/tests/apps/issue1776",
#"mirrord/layer/tests/apps/issue1776portnot53",
#"mirrord/layer/tests/apps/issue1899",
#"mirrord/layer/tests/apps/issue2001",
#"mirrord/layer/tests/apps/issue2438",
#"mirrord/layer/tests/apps/issue3248",
#"mirrord/layer/tests/apps/rebind0",
#"sample/rust",
#"medschool",
#"tests",
#"tests/rust-e2e-fileops",
#"tests/rust-unix-socket-client",
#"tests/rust-bypassed-unix-socket",
#"tests/issue1317",
#"tests/rust-websockets",
#"tests/rust-sqs-printer",
]
resolver = "2"

Expand Down Expand Up @@ -63,7 +63,7 @@ actix-codec = "0.5"
bincode = { version = "2", features = ["serde"] }
bytes = "1"

tokio = { version = "1" }
tokio = { version = "1", features = ["fs", "net", "io-util"] }
tokio-stream = { version = "0.1", features = ["sync"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand Down
1 change: 1 addition & 0 deletions changelog.d/.531.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
intproxy compiles on windows
7 changes: 6 additions & 1 deletion mirrord/agent/env/src/checked_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ use std::{
fmt,
marker::PhantomData,
net::{AddrParseError, IpAddr, SocketAddr},
os::unix::ffi::OsStrExt,
str::{FromStr, Utf8Error},
};

#[cfg(not(windows))]
use std::os::unix::ffi::OsStrExt;

use base64::{engine::general_purpose, Engine};
#[cfg(feature = "k8s-openapi")]
use k8s_openapi::api::core::v1::EnvVar;
Expand Down Expand Up @@ -89,7 +91,10 @@ impl<V: EnvValue> CheckedEnv<V> {
pub fn try_from_env(self) -> Result<Option<V>, V::FromReprError> {
match std::env::var_os(self.name) {
Some(repr) => {
#[cfg(not(windows))]
let value = V::from_repr(repr.as_bytes())?;
#[cfg(windows)]
let value = V::from_repr(repr.as_encoded_bytes())?;
Ok(Some(value))
}
None => Ok(None),
Expand Down
18 changes: 14 additions & 4 deletions mirrord/config/src/config/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ use std::{
env::VarError,
ffi::{OsStr, OsString},
ops::Not,
os::unix::ffi::OsStrExt,
};

#[cfg(not(windows))]
use std::os::unix::ffi::OsStrExt;


/// Context for generating and verifying a [`MirrordConfig`](super::MirrordConfig).
///
/// See:
Expand Down Expand Up @@ -94,17 +97,24 @@ impl ConfigContext {
///
/// This is the only way we should read environment when generating or verifying configuration.
pub fn get_env(&self, name: &str) -> Result<String, VarError> {
#[cfg(not(windows))]
let name = OsStr::from_bytes(name.as_bytes());

#[cfg(windows)]
let name = OsStr::new(name);

let os_value = match self.env_override.get(name) {
Some(value) => Ok(value.clone()),
None if self.strict_env => Err(VarError::NotPresent),
None => std::env::var_os(name).ok_or(VarError::NotPresent),
}?;

std::str::from_utf8(os_value.as_bytes())
.map(ToString::to_string)
.map_err(|_| VarError::NotUnicode(os_value))
#[cfg(not(windows))]
let s = std::str::from_utf8(os_value.as_bytes()).map(ToString::to_string);
#[cfg(windows)]
let s = os_value.clone().into_string();

s.map_err(|_| VarError::NotUnicode(os_value))
}

/// Returns the mark previously set with [`ConfigContext::empty_target_final`].
Expand Down
4 changes: 3 additions & 1 deletion mirrord/intproxy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ hyper = { workspace = true, features = ["client", "http1", "http2"] }
hyper-util.workspace = true
http-body-util.workspace = true
bytes.workspace = true
rand.workspace = true
tokio-rustls.workspace = true
rustls.workspace = true
tokio-retry.workspace = true

[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
rand.workspace = true

[dev-dependencies]
rcgen.workspace = true
rstest.workspace = true
62 changes: 54 additions & 8 deletions mirrord/intproxy/src/proxies/outgoing/net_protocol_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,43 @@
//! [`OutgoingProxy`](super::OutgoingProxy).
use std::{
env, io,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
path::PathBuf,
io, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
};
#[cfg(not(windows))]
use std::{
env, path::PathBuf,
};


use bytes::BytesMut;
use mirrord_intproxy_protocol::NetProtocol;
use mirrord_protocol::{
outgoing::{
tcp::LayerTcpOutgoing, udp::LayerUdpOutgoing, LayerClose, LayerConnect, LayerWrite,
SocketAddress, UnixAddr,
SocketAddress,

},
ClientMessage, ConnectionId,
};
#[cfg(not(windows))]
use mirrord_protocol::outgoing::UnixAddr;
#[cfg(not(windows))]
use rand::distr::{Alphanumeric, SampleString};
use tokio::{
fs,
use ::tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{TcpListener, TcpStream, UdpSocket, UnixListener, UnixStream},
net::{TcpListener, TcpStream, UdpSocket},
};
#[cfg(not(windows))]
use ::tokio::fs;
#[cfg(windows)]
mod tokio {
pub mod net {
pub struct UnixStream{}
pub struct UnixListener{}
}
}
use tokio::{
net::{UnixListener, UnixStream},
};

/// Trait for [`NetProtocol`] that handles differences in [`mirrord_protocol::outgoing`] between
Expand Down Expand Up @@ -94,6 +112,7 @@ impl NetProtocolExt for NetProtocol {
Self::Stream => PreparedSocket::TcpListener(TcpListener::bind(bind_at).await?),
}
}
#[cfg(not(windows))]
SocketAddress::Unix(..) => match self {
Self::Stream => {
let path = PreparedSocket::generate_uds_path().await?;
Expand All @@ -104,6 +123,10 @@ impl NetProtocolExt for NetProtocol {
panic!("layer requested outgoing datagrams over unix sockets");
}
},
#[cfg(windows)]
_ => {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "unsupported SocketAddress"));
},
};

Ok(socket)
Expand All @@ -115,13 +138,16 @@ pub enum PreparedSocket {
/// There is no real listening/accepting here, see [`NetProtocol::Datagrams`] for more info.
UdpSocket(UdpSocket),
TcpListener(TcpListener),
#[allow(dead_code)]
UnixListener(UnixListener),
}

impl PreparedSocket {
/// For unix listeners, relative to the temp dir.
#[cfg(not(windows))]
const UNIX_STREAMS_DIRNAME: &'static str = "mirrord-unix-sockets";

#[cfg(not(windows))]
async fn generate_uds_path() -> io::Result<PathBuf> {
let tmp_dir = env::temp_dir().join(Self::UNIX_STREAMS_DIRNAME);
if !tmp_dir.exists() {
Expand All @@ -137,11 +163,16 @@ impl PreparedSocket {
let address = match self {
Self::TcpListener(listener) => listener.local_addr()?.into(),
Self::UdpSocket(socket) => socket.local_addr()?.into(),
#[cfg(not(windows))]
Self::UnixListener(listener) => {
let addr = listener.local_addr()?;
let pathname = addr.as_pathname().unwrap().to_path_buf();
SocketAddress::Unix(UnixAddr::Pathname(pathname))
}
#[cfg(windows)]
Self::UnixListener(_) => {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "Unsupported UnixListener").into());
}
};

Ok(address)
Expand All @@ -156,10 +187,15 @@ impl PreparedSocket {
(InnerConnectedSocket::TcpStream(stream), true)
}
Self::UdpSocket(socket) => (InnerConnectedSocket::UdpSocket(socket), false),
#[cfg(not(windows))]
Self::UnixListener(listener) => {
let (stream, _) = listener.accept().await?;
(InnerConnectedSocket::UnixStream(stream), true)
}
#[cfg(windows)]
Self::UnixListener(_) => {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "unsupported UnixListener"));
}
};

Ok(ConnectedSocket {
Expand All @@ -173,6 +209,7 @@ impl PreparedSocket {
enum InnerConnectedSocket {
UdpSocket(UdpSocket),
TcpStream(TcpStream),
#[allow(dead_code)]
UnixStream(UnixStream),
}

Expand Down Expand Up @@ -201,7 +238,10 @@ impl ConnectedSocket {
Ok(())
}
InnerConnectedSocket::TcpStream(stream) => stream.write_all(bytes).await,
#[cfg(not(windows))]
InnerConnectedSocket::UnixStream(stream) => stream.write_all(bytes).await,
#[cfg(windows)]
_ => Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "unsupported InnerConnectedSocket")),
}
}

Expand All @@ -226,12 +266,15 @@ impl ConnectedSocket {
self.buffer.clear();
Ok(bytes)
}
#[cfg(not(windows))]
InnerConnectedSocket::UnixStream(stream) => {
stream.read_buf(&mut self.buffer).await?;
let bytes = self.buffer.to_vec();
self.buffer.clear();
Ok(bytes)
}
#[cfg(windows)]
_ => Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "unsupported InnerConnectedSocket")),
}
}

Expand All @@ -243,8 +286,11 @@ impl ConnectedSocket {
pub async fn shutdown(&mut self) -> io::Result<()> {
match &mut self.inner {
InnerConnectedSocket::TcpStream(stream) => stream.shutdown().await,
InnerConnectedSocket::UnixStream(stream) => stream.shutdown().await,
#[cfg(not(windows))]
InnerConnectedSocket::UnixStream(stream) => stream.shutdown().await,
InnerConnectedSocket::UdpSocket(..) => Ok(()),
#[cfg(windows)]
_ => Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "unsupported InnerConnectedSocket")),
}
}
}
39 changes: 35 additions & 4 deletions mirrord/protocol/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ use std::io;
#[cfg(target_os = "linux")]
use std::os::unix::fs::DirEntryExt;
use std::{
fs::Metadata, io::SeekFrom, os::unix::prelude::MetadataExt, path::PathBuf, sync::LazyLock,
fs::Metadata, io::SeekFrom, path::PathBuf, sync::LazyLock,
};

#[cfg(not(windows))]
use std::os::unix::prelude::MetadataExt;
#[cfg(windows)]
use std::os::windows::fs::MetadataExt;

use bincode::{Decode, Encode};
#[cfg(target_os = "linux")]
use nix::sys::statfs::Statfs;
Expand Down Expand Up @@ -64,18 +69,20 @@ pub struct MetadataInternal {
/// file size, st_size
pub size: u64,
/// time is in nano seconds, can be converted to seconds by dividing by 1e9
/// access time, st_atime_ns
/// access time, st_atime_ns or FILETIME (windows)
pub access_time: i64,
/// modification time, st_mtime_ns
/// modification time, st_mtime_ns (unix) or FILETIME (windows)
pub modification_time: i64,
/// creation time, st_ctime_ns
/// creation time, st_ctime_ns (unix) or FILETIME (windows)
pub creation_time: i64,
/// block size, st_blksize
pub block_size: u64,
/// number of blocks, st_blocks
pub blocks: u64,
}


#[cfg(not(windows))]
impl From<Metadata> for MetadataInternal {
fn from(metadata: Metadata) -> Self {
Self {
Expand All @@ -96,6 +103,30 @@ impl From<Metadata> for MetadataInternal {
}
}


#[cfg(windows)]
impl From<Metadata> for MetadataInternal {
fn from(metadata: Metadata) -> Self {
Self {
device_id: metadata.volume_serial_number().unwrap() as u64,
// On Windows, true inode is not exposed directly from std
// You could return 0 or use Windows APIs like `GetFileInformationByHandle`
inode: metadata.file_index().unwrap(),
mode: metadata.file_attributes(),
hard_links: metadata.number_of_links().unwrap() as u64,
user_id: 0,
group_id: 0,
rdevice_id: 0,
size: metadata.file_size(),
access_time: metadata.last_access_time() as i64,
modification_time: metadata.change_time().or(Some(0)).unwrap() as i64,
creation_time: metadata.creation_time() as i64,
block_size: 0,
blocks: 0,
}
}
}

#[derive(Encode, Decode, Debug, PartialEq, Clone, Copy, Eq, Default)]
pub struct FsMetadataInternal {
/// f_type
Expand Down
2 changes: 2 additions & 0 deletions mirrord/protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
#![feature(io_error_more)]
#![warn(clippy::indexing_slicing)]
#![deny(unused_crate_dependencies)]
#![feature(windows_change_time)]
#![feature(windows_by_handle)]

pub mod batched_body;
pub mod codec;
Expand Down
Loading