various project wide changes to support win32-msvc target.

* Remove sha1 ASM acceleration (who really cares). We could specialize that feature but it's marginal.
* Create net-defaults feature so we can move p2p-unix out of the default feature set.
    * I didn't figure out conditional enabling of p2p-unix though yet. See the Cargo.toml.
      Maybe instead of using a feature, we just enable it for all unix platforms.
    * Move UnixListener behind p2p-unix.
* darkwallet: for win32 use bundled rusqlite (used by tor-dirmgr).
* sdk: add wasm feature to avoid declaring ABI methods with no corresponding impl linked, which causes linker errors for release builds on windows.
* Move unix specific imports and function calls in src/ behind relevant config targets.
* TCP sockets on Windows call set_reuse_address().
* src/util/path.rs relevant home_dir() impls.
This commit is contained in:
darkfi
2025-01-16 16:52:32 +01:00
parent 1e8a11f855
commit 119cd41abe
14 changed files with 264 additions and 63 deletions

View File

@@ -68,7 +68,7 @@ futures-rustls = {version = "0.26.0", default-features = false, features = ["log
# Pluggable Transports
socket2 = {version = "0.5.7", features = ["all"], optional = true}
arti-client = {version = "0.23.0", default-features = false, features = ["async-std", "compression", "error_detail", "rustls", "accel-sha1-asm", "onion-service-client", "onion-service-service"], optional = true}
arti-client = {version = "0.23.0", default-features = false, features = ["async-std", "compression", "error_detail", "rustls", "onion-service-client", "onion-service-service"], optional = true}
tor-error = {version = "0.23.0", optional = true}
tor-rtcompat = {version = "0.23.0", features = ["async-std", "rustls"], optional = true}
tor-hscrypto = {version = "0.23.0", optional = true}
@@ -201,7 +201,7 @@ p2p-tor = [
"tor-cell",
]
net = [
net-defaults = [
"async-trait",
"ed25519-compact",
"futures",
@@ -227,11 +227,15 @@ net = [
#"p2p-nym",
]
p2p-unix = []
net = ["net-defaults"]
rpc = [
"async-trait",
"httparse",
"net",
"net-defaults",
]
system = [
@@ -278,6 +282,14 @@ zk = [
zkas = [
"darkfi-serial",
]
# Could not get this to work. Complains manifest-key is ignored.
#[target.'cfg(target_family = "unix")'.features]
#net = ["net-defaults", "p2p-unix"]
#
#[target.'cfg(target_family = "windows")'.features]
#net = ["net-defaults"]
# -----END LIBRARY FEATURES-----
[patch.crates-io]

View File

@@ -3054,7 +3054,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniquad"
version = "0.4.7"
source = "git+https://github.com/not-fl3/miniquad#3a5b56399ec446a35bf4a0e855dac969f920d3d4"
source = "git+https://github.com/not-fl3/miniquad#0d4043157531b1972e58d96bcc4d4827d853d036"
dependencies = [
"libc",
"ndk-sys",
@@ -4439,16 +4439,6 @@ dependencies = [
"cfg-if",
"cpufeatures",
"digest",
"sha1-asm",
]
[[package]]
name = "sha1-asm"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "286acebaf8b67c1130aedffad26f594eff0c1292389158135327d2e23aed582b"
dependencies = [
"cc",
]
[[package]]

View File

@@ -80,6 +80,10 @@ rusqlite = {version = "0.32.1", features = ["bundled"]}
tor-dirmgr = {version="0.23.0", features=["static"]}
#android-fileopen = {path = "./android-fileopen/"}
[target.'cfg(target_os = "windows")'.dependencies]
# Used by tor-dirmgr
rusqlite = {version = "0.32", features = ["bundled"]}
[package.metadata.android.activity_attributes]
"android:exported" = "true"
"android:windowSoftInputMode" = "adjustResize"

View File

@@ -0,0 +1,141 @@
# Windows Build Guide (MSVC)
Skip the first step if you're already using Windows.
## Prepare the VM
You will need qemu and the remote-viewer tool.
Provision a disk:
```
qemu-img create -f raw winblows-raw.disk 100G
```
Download the Windows ISO from their website. Use this script to launch QEMU.
```
#!/bin/bash
ISO=Win10_22H2_EnglishInternational_x64v1.iso
args=(
--cdrom $ISO --boot order=d
-drive file=winblows-disk.raw,format=raw
-m 30G -accel kvm -cpu qemu64
# We forward 22 to 10022 for SSH
#-net nic -net user,hostname=windowsvm
-net nic -net user,hostname=windowsvm,hostfwd=tcp::10146-:22
# This fixes the fucked up mouse
#-device qemu-xhci -device usb-mouse -device usb-tablet
-machine vmport=off
# Auto-resize display
# -vga qxl
# We use virtio since it allows us the full res size at least
-vga virtio -spice port=30001,disable-ticketing=on
-device virtio-serial -chardev spicevmc,id=vdagent,debug=0,name=vdagent
-device virtserialport,chardev=vdagent,name=com.redhat.spice.0
)
qemu-system-x86_64 "${args[@]}"
```
There will be no output. Use remote-viewer to attach the display:
```
remote-viewer spice://localhost:30001
```
Now install Windows. Then power off Windows. Download the [virtio-win ISO].
Modify the `ISO=...` line of the script above and relaunch the VM.
Navigate to the CD drive in the file explorer and install the virtio x64 driver.
In your browser go to "spice windows guest" and scroll down the webpage.
Download and install "Windows SPICE Guest Tools".
Relaunch the Windows VM. Adjust your display resolution and fullscreen the VM.
### (Optional) Enable SSH
This will enable you to work on Windows from within your host.
Open Settings -> Apps -> Optional features -> + Add a feature. Search
for "OpenSSH Server" and install it.
Open Services -> OpenSSH SSH Server. Make "Startup type" Automatic.
You can now ssh into your windows and use cmd.exe. In the script above,
we forward port 22 to 10146. You can put this in `~/.ssh/config`.
```
Host winblows
Hostname localhost
User a
Port 10146
```
You can also make an `/etc/fstab` entry with:
```
sshfs#winblows: /mnt/winblows fuse noauto,defaults 0 0
```
Then `mount /mnt/winblows && cd /mnt/winblows/.ssh/` and copy your SSH pubkey
to `authorized_keys`.
Open "This PC", View -> Hidden files, open `C:\ProgramData\ssh\sshd_config`
to disable password login and just use pubkey auth.
Also disable the administrator auth keys setting in there too (bottom 2 lines).
Then restart SSH.
## Setting Up the Dev Environment
Install rustup, which will also install Visual Studio. Next, next, finish.
After visual studio, it will then proceed with the rustup install.
Select 2 and enter nightly.
```
1) Proceed with standard installation (default - just press enter)
2) Customize installation
3) Cancel installation
>2
Default host triple? [x86_64-pc-windows-msvc]
(leave this unchanged)
Default toolchain? (stable/beta/nightly/none)
nightly
Profile (which tools and data to install)? (minimal/default/complete) [default]
(leave this unchanged)
```
Then proceed with the installation (option 1).
## Building the DarkFi App
Go to the [codeberg repo] and select "⋯", then Download ZIP. Unzip the folder
in an accessible place.
Open cmd and navigate to the folder. Now run `cargo build`.
```
C:\Users\a> cd ../../darkfi/bin/darkwallet/
C:\darkfi\bin\darkwallet> cargo build
```
## (Optional) Mesa GL
This is buggy af software renderer.
* Setup OpenGL using [this guide](https://thomas.inf3.ch/2019-06-12-opengl-kvm-mesa3d/index.html).
* Download [mesa3d-xxx-release-msvc.7z](https://github.com/pal1000/mesa-dist-win/releases)
and install the default options.
[virtio-win ISO]: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso

View File

@@ -33,6 +33,7 @@ darkfi-contract-test-harness = {path = "../test-harness"}
# so the wasm32-unknown-unknown target is enabled.
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2.8", features = ["custom"] }
darkfi-sdk = { path = "../../sdk", features = ["wasm"] }
[features]
default = []

View File

@@ -29,6 +29,7 @@ smol = "2.0.2"
# so the wasm32-unknown-unknown target is enabled.
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2.8", features = ["custom"] }
darkfi-sdk = { path = "../../sdk", features = ["wasm"] }
[features]
default = []

View File

@@ -35,6 +35,7 @@ darkfi-contract-test-harness = {path = "../test-harness"}
# so the wasm32-unknown-unknown target is enabled.
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2.8", features = ["custom"] }
darkfi-sdk = { path = "../../sdk", features = ["wasm"] }
[features]
default = []

View File

@@ -24,11 +24,7 @@ use std::sync::{
use futures::{stream::FuturesUnordered, TryFutureExt};
use futures_rustls::rustls::crypto::{ring, CryptoProvider};
use log::{debug, error, info, warn};
use smol::{
fs::{self, unix::PermissionsExt},
lock::RwLock as AsyncRwLock,
stream::StreamExt,
};
use smol::{fs, lock::RwLock as AsyncRwLock, stream::StreamExt};
use url::Url;
use super::{
@@ -49,6 +45,9 @@ use crate::{
Result,
};
#[cfg(target_family = "unix")]
use smol::fs::unix::PermissionsExt;
/// Atomic pointer to the p2p interface
pub type P2pPtr = Arc<P2p>;
@@ -92,6 +91,8 @@ impl P2p {
if let Some(ref datastore) = settings.p2p_datastore {
let datastore = expand_path(datastore)?;
fs::create_dir_all(&datastore).await?;
// Windows only has readonly so don't worry about it
#[cfg(target_family = "unix")]
fs::set_permissions(&datastore, PermissionsExt::from_mode(0o700)).await?;
}

View File

@@ -16,16 +16,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use std::{
io::{self, ErrorKind},
time::Duration,
};
use std::{io, time::Duration};
use async_trait::async_trait;
use log::error;
use smol::io::{AsyncRead, AsyncWrite};
use url::Url;
#[cfg(feature = "p2p-unix")]
use std::io::ErrorKind;
/// TLS upgrade mechanism
pub(crate) mod tls;
@@ -44,6 +44,7 @@ pub(crate) mod tor;
pub(crate) mod nym;
/// Unix socket transport
#[cfg(feature = "p2p-unix")]
pub(crate) mod unix;
/// Dialer variants
@@ -72,6 +73,7 @@ pub enum DialerVariant {
NymTls(nym::NymDialer),
/// Unix socket
#[cfg(feature = "p2p-unix")]
Unix(unix::UnixDialer),
/// SOCKS5 proxy
@@ -92,6 +94,7 @@ pub enum ListenerVariant {
Tor(tor::TorListener),
/// Unix socket
#[cfg(feature = "p2p-unix")]
Unix(unix::UnixListener),
}
@@ -111,6 +114,7 @@ macro_rules! enforce_hostport {
};
}
#[cfg(feature = "p2p-unix")]
macro_rules! enforce_abspath {
($endpoint:ident) => {
if $endpoint.host_str().is_some() || $endpoint.port().is_some() {
@@ -179,6 +183,7 @@ impl Dialer {
Ok(Self { endpoint, variant })
}
#[cfg(feature = "p2p-unix")]
"unix" => {
// Build a Unix socket dialer
enforce_abspath!(endpoint);
@@ -252,6 +257,7 @@ impl Dialer {
todo!();
}
#[cfg(feature = "p2p-unix")]
DialerVariant::Unix(dialer) => {
let path = match self.endpoint.to_file_path() {
Ok(v) => v,
@@ -312,6 +318,7 @@ impl Listener {
Ok(Self { endpoint, variant })
}
#[cfg(feature = "p2p-unix")]
"unix" => {
enforce_abspath!(endpoint);
let variant = unix::UnixListener::new().await?;
@@ -351,6 +358,7 @@ impl Listener {
Ok(Box::new(l))
}
#[cfg(feature = "p2p-unix")]
ListenerVariant::Unix(listener) => {
let path = match self.endpoint.to_file_path() {
Ok(v) => v,
@@ -384,6 +392,7 @@ impl PtStream for arti_client::DataStream {}
#[cfg(feature = "p2p-tor")]
impl PtStream for futures_rustls::TlsStream<arti_client::DataStream> {}
#[cfg(feature = "p2p-unix")]
impl PtStream for smol::net::unix::UnixStream {}
/// Wrapper trait for async listeners

View File

@@ -34,6 +34,23 @@ use url::Url;
use super::{PtListener, PtStream};
trait SocketExt {
fn enable_reuse_port(&self) -> io::Result<()>;
}
impl SocketExt for Socket {
fn enable_reuse_port(&self) -> io::Result<()> {
#[cfg(target_family = "unix")]
self.set_reuse_port(true)?;
// On Windows SO_REUSEPORT means the same thing as SO_REUSEADDR
#[cfg(target_family = "windows")]
self.set_reuse_address(true)?;
Ok(())
}
}
/// TCP Dialer implementation
#[derive(Debug, Clone)]
pub struct TcpDialer {
@@ -63,7 +80,7 @@ impl TcpDialer {
socket.set_nodelay(true)?;
let keepalive = TcpKeepalive::new().with_time(Duration::from_secs(20));
socket.set_tcp_keepalive(&keepalive)?;
socket.set_reuse_port(true)?;
socket.enable_reuse_port()?;
Ok(socket)
}
@@ -147,7 +164,7 @@ impl TcpListener {
socket.set_nodelay(true)?;
let keepalive = TcpKeepalive::new().with_time(Duration::from_secs(20));
socket.set_tcp_keepalive(&keepalive)?;
socket.set_reuse_port(true)?;
socket.enable_reuse_port()?;
Ok(socket)
}

View File

@@ -14,6 +14,7 @@ doctest = false
[features]
default = []
async = ["darkfi-serial/async"]
wasm = []
[dependencies]
# Error handling

View File

@@ -75,6 +75,7 @@ mod test;
pub mod util;
pub use util::Poseidon;
#[cfg(feature = "wasm")]
pub mod wasmdb;
// Bit size for Fp (and Fq)

View File

@@ -52,5 +52,6 @@ pub use tx::ContractCall;
pub mod util;
#[macro_use]
#[cfg(feature = "wasm")]
/// WASM API functions
pub mod wasm;

View File

@@ -18,59 +18,80 @@
use std::{
env,
ffi::{CStr, OsString},
fs, mem,
os::unix::prelude::OsStringExt,
ffi::OsString,
fs,
path::{Path, PathBuf},
ptr,
};
use crate::{Error, Result};
/// Returns the path to the user's home directory.
/// Use `$HOME`, fallbacks to `libc::getpwuid_r`, otherwise `None`.
pub fn home_dir() -> Option<PathBuf> {
env::var_os("HOME")
.and_then(|h| if h.is_empty() { None } else { Some(h) })
.or_else(|| unsafe { home_fallback() })
.map(PathBuf::from)
}
/// Get the home directory from the passwd entry of the current user using
/// `getpwuid_r(3)`. If it manages, returns an `OsString`, otherwise returns `None`.
unsafe fn home_fallback() -> Option<OsString> {
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
n if n < 0 => 512_usize,
n => n as usize,
#[cfg(target_family = "unix")]
mod home_dir_impl {
use std::{
env,
ffi::{CStr, OsString},
mem,
os::unix::prelude::OsStringExt,
path::PathBuf,
ptr,
};
let mut buf = Vec::with_capacity(amt);
let mut passwd: libc::passwd = mem::zeroed();
let mut result = ptr::null_mut();
/// Returns the path to the user's home directory.
/// Use `$HOME`, fallbacks to `libc::getpwuid_r`, otherwise `None`.
pub fn home_dir() -> Option<PathBuf> {
env::var_os("HOME")
.and_then(|h| if h.is_empty() { None } else { Some(h) })
.or_else(|| unsafe { home_fallback() })
.map(PathBuf::from)
}
let r = libc::getpwuid_r(
libc::getuid(),
&mut passwd,
buf.as_mut_ptr(),
buf.capacity(),
&mut result,
);
/// Get the home directory from the passwd entry of the current user using
/// `getpwuid_r(3)`. If it manages, returns an `OsString`, otherwise returns `None`.
unsafe fn home_fallback() -> Option<OsString> {
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
n if n < 0 => 512_usize,
n => n as usize,
};
match r {
0 if !result.is_null() => {
let ptr = passwd.pw_dir as *const _;
let bytes = CStr::from_ptr(ptr).to_bytes();
if bytes.is_empty() {
return None
let mut buf = Vec::with_capacity(amt);
let mut passwd: libc::passwd = mem::zeroed();
let mut result = ptr::null_mut();
let r = libc::getpwuid_r(
libc::getuid(),
&mut passwd,
buf.as_mut_ptr(),
buf.capacity(),
&mut result,
);
match r {
0 if !result.is_null() => {
let ptr = passwd.pw_dir as *const _;
let bytes = CStr::from_ptr(ptr).to_bytes();
if bytes.is_empty() {
return None
}
Some(OsStringExt::from_vec(bytes.to_vec()))
}
Some(OsStringExt::from_vec(bytes.to_vec()))
_ => None,
}
_ => None,
}
}
#[cfg(target_family = "windows")]
mod home_dir_impl {
use std::{env, path::PathBuf};
pub fn home_dir() -> Option<PathBuf> {
env::var_os("APPDATA").map(PathBuf::from)
}
}
pub use home_dir_impl::home_dir;
/// Returns `$XDG_CONFIG_HOME`, `$HOME/.config`, or `None`.
pub fn config_dir() -> Option<PathBuf> {
env::var_os("XDG_CONFIG_HOME")