Skip to content

Commit

Permalink
Support building on Windows (#341)
Browse files Browse the repository at this point in the history
  • Loading branch information
iyangsj authored Jul 22, 2024
1 parent 548c94e commit 952767b
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 13 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ jobs:
. "$HOME/.cargo/env"
cargo build --all -F ffi --verbose && cargo test
build_windows:
name: Build for Windows
runs-on: windows-2022
env:
TARGET: "x86_64-pc-windows-msvc"
steps:
- uses: actions/checkout@v4
with:
submodules: 'recursive'
- name: Install rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: ${{ env.TARGET }}
- name: Install dependencies
uses: crazy-max/ghaction-chocolatey@v3
with:
args: install nasm
- name: Build TQUIC library and tools
run: cargo build --all -F ffi --verbose && cargo test

build_ios:
name: Build for iOS
runs-on: macos-latest
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ hex = "0.4"
priority-queue = "1.3.2"
sfv = { version = "0.9" }

[target."cfg(windows)".dependencies]
winapi = { version = "0.3", features = ["wincrypt", "ws2def", "ws2ipdef", "ws2tcpip"] }

[dev-dependencies]
env_logger = "0.10.0"
mio = { version = "0.8", features = ["net", "os-poll"] }
Expand Down
1 change: 0 additions & 1 deletion cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ cpp_compat = true
documentation = true

# A list of headers to #include (with quotes)
sys_includes = ["sys/socket.h", "sys/types.h"]
includes = ["openssl/ssl.h", "tquic_def.h"]

[export]
Expand Down
4 changes: 2 additions & 2 deletions include/tquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "openssl/ssl.h"
#include "tquic_def.h"

Expand Down Expand Up @@ -1105,6 +1103,7 @@ void quic_conn_set_keylog(struct quic_conn_t *conn, void (*cb)(const uint8_t *da

/**
* Set keylog file.
* Note: The API is not applicable for Windows.
*/
void quic_conn_set_keylog_fd(struct quic_conn_t *conn, int fd);

Expand All @@ -1122,6 +1121,7 @@ void quic_conn_set_qlog(struct quic_conn_t *conn,

/**
* Set qlog file.
* Note: The API is not applicable for Windows.
*/
void quic_conn_set_qlog_fd(struct quic_conn_t *conn, int fd, const char *title, const char *desc);

Expand Down
14 changes: 14 additions & 0 deletions include/tquic_def.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
#ifndef _TQUIC_DEF_H_
#define _TQUIC_DEF_H_

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#include <winsock2.h>
#include <ws2tcpip.h>
typedef SSIZE_T ssize_t;
struct iovec {
void *iov_base; // starting address
size_t iov_len; // number of bytes to transfer
};
#else
#include <sys/socket.h>
#include <sys/types.h>
#endif


/**
* An enum representing the available verbosity level filters of the logger.
*/
Expand Down
26 changes: 25 additions & 1 deletion src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,29 @@ fn new_boringssl_cmake_config() -> cmake::Config {
boringssl_cmake
}

/// Return the build sub-dir for boringssl.
fn get_boringssl_build_sub_dir() -> &'static str {
if !cfg!(target_env = "msvc") {
return "";
}

// Note: MSVC outputs static libs in a sub-directory.
let debug = std::env::var("DEBUG").expect("DEBUG not set");
let opt_level = std::env::var("OPT_LEVEL").expect("OPT_LEVEL not set");

match &opt_level[..] {
"1" | "2" | "3" => {
if &debug[..] == "true" {
"RelWithDebInfo"
} else {
"Release"
}
}
"s" | "z" => "MinSizeRel",
_ => "Debug",
}
}

fn main() {
if let Ok(boringssl_lib_dir) = std::env::var("BORINGSSL_LIB_DIR") {
// Build with static boringssl lib.
Expand All @@ -121,7 +144,8 @@ fn main() {
cfg.build_target("ssl").build();
cfg.build_target("crypto").build().display().to_string()
};
let build_dir = format!("{boringssl_dir}/build/");
let sub_dir = get_boringssl_build_sub_dir();
let build_dir = format!("{boringssl_dir}/build/{sub_dir}");
println!("cargo:rustc-link-search=native={build_dir}");
}

Expand Down
122 changes: 114 additions & 8 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use std::net::Ipv6Addr;
use std::net::SocketAddr;
use std::net::SocketAddrV4;
use std::net::SocketAddrV6;
use std::os::fd::FromRawFd;
use std::ptr;
use std::rc::Rc;
use std::slice;
Expand All @@ -31,23 +30,80 @@ use std::sync::atomic;
use std::sync::Arc;
use std::time::Instant;

#[cfg(unix)]
use std::os::fd::FromRawFd;

use bytes::Bytes;
use libc::c_char;
use libc::c_int;
use libc::c_void;
use libc::in6_addr;
use libc::in_addr;
use libc::iovec;
use libc::sa_family_t;
use libc::size_t;
use libc::sockaddr;
use libc::ssize_t;

#[cfg(not(windows))]
use libc::in_addr;
#[cfg(windows)]
use winapi::shared::inaddr::IN_ADDR as in_addr;

#[cfg(not(windows))]
use libc::in6_addr;
#[cfg(windows)]
use winapi::shared::in6addr::IN6_ADDR as in6_addr;

#[cfg(not(windows))]
use libc::sa_family_t;
#[cfg(windows)]
use winapi::shared::ws2def::ADDRESS_FAMILY as sa_family_t;

#[cfg(not(windows))]
use libc::sockaddr_in;
#[cfg(windows)]
use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in;

#[cfg(not(windows))]
use libc::sockaddr_in6;
#[cfg(windows)]
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;

#[cfg(not(windows))]
use libc::sockaddr_storage;
#[cfg(windows)]
use winapi::shared::ws2def::SOCKADDR_STORAGE_LH as sockaddr_storage;

#[cfg(windows)]
use libc::c_int as socklen_t;
#[cfg(not(windows))]
use libc::socklen_t;
use libc::ssize_t;

#[cfg(not(windows))]
use libc::AF_INET;
#[cfg(windows)]
use winapi::shared::ws2def::AF_INET;

#[cfg(not(windows))]
use libc::AF_INET6;
#[cfg(windows)]
use winapi::shared::ws2def::AF_INET6;

#[cfg(windows)]
use winapi::shared::in6addr::in6_addr_u;
#[cfg(windows)]
use winapi::shared::inaddr::in_addr_S_un;
#[cfg(windows)]
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH_u;

#[cfg(not(windows))]
use libc::iovec;

/// cbindgen:ignore
#[cfg(windows)]
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct iovec {
iov_base: *mut c_void, // starting address
iov_len: size_t, // number of bytes to transfer
}

use crate::codec::Decoder;
use crate::connection::ConnectionStats;
Expand Down Expand Up @@ -1243,7 +1299,9 @@ pub extern "C" fn quic_conn_set_keylog(
}

/// Set keylog file.
/// Note: The API is not applicable for Windows.
#[no_mangle]
#[cfg(unix)]
pub extern "C" fn quic_conn_set_keylog_fd(conn: &mut Connection, fd: c_int) {
let file = unsafe { std::fs::File::from_raw_fd(fd) };
let writer = std::io::BufWriter::new(file);
Expand Down Expand Up @@ -1275,7 +1333,9 @@ pub extern "C" fn quic_conn_set_qlog(
}

/// Set qlog file.
/// Note: The API is not applicable for Windows.
#[no_mangle]
#[cfg(unix)]
pub extern "C" fn quic_conn_set_qlog_fd(
conn: &mut Connection,
fd: c_int,
Expand Down Expand Up @@ -1733,16 +1793,34 @@ fn sock_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
AF_INET => {
assert!(addr_len as usize == std::mem::size_of::<sockaddr_in>());
let in4 = unsafe { *(addr as *const _ as *const sockaddr_in) };

#[cfg(not(windows))]
let addr = Ipv4Addr::from(u32::from_be(in4.sin_addr.s_addr));
#[cfg(windows)]
let addr = {
let ip = unsafe { in4.sin_addr.S_un.S_un_b() };
Ipv4Addr::from([ip.s_b1, ip.s_b2, ip.s_b3, ip.s_b4])
};

let port = u16::from_be(in4.sin_port);
SocketAddrV4::new(addr, port).into()
}
AF_INET6 => {
assert!(addr_len as usize == std::mem::size_of::<sockaddr_in6>());
let in6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };

#[cfg(not(windows))]
let addr = Ipv6Addr::from(in6.sin6_addr.s6_addr);
#[cfg(windows)]
let addr = Ipv6Addr::from(*unsafe { in6.sin6_addr.u.Byte() });

let port = u16::from_be(in6.sin6_port);

#[cfg(not(windows))]
let scope_id = in6.sin6_scope_id;
#[cfg(windows)]
let scope_id = unsafe { *in6.u.sin6_scope_id() };

SocketAddrV6::new(addr, port, in6.sin6_flowinfo, scope_id).into()
}
_ => unimplemented!("unsupported address type"),
Expand All @@ -1756,9 +1834,17 @@ fn sock_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
SocketAddr::V4(addr) => unsafe {
let sa_len = std::mem::size_of::<sockaddr_in>();
let out_in = out as *mut _ as *mut sockaddr_in;
let sin_addr = in_addr {
s_addr: u32::from_ne_bytes(addr.ip().octets()),
let s_addr = u32::from_ne_bytes(addr.ip().octets());

#[cfg(not(windows))]
let sin_addr = in_addr { s_addr };
#[cfg(windows)]
let sin_addr = {
let mut s_un = std::mem::zeroed::<in_addr_S_un>();
*s_un.S_addr_mut() = s_addr;
in_addr { S_un: s_un }
};

*out_in = sockaddr_in {
sin_family: AF_INET as sa_family_t,
sin_addr,
Expand All @@ -1773,17 +1859,37 @@ fn sock_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
SocketAddr::V6(addr) => unsafe {
let sa_len = std::mem::size_of::<sockaddr_in6>();
let out_in6 = out as *mut _ as *mut sockaddr_in6;

#[cfg(not(windows))]
let sin6_addr = in6_addr {
s6_addr: addr.ip().octets(),
};
#[cfg(windows)]
let sin6_addr = {
let mut u = std::mem::zeroed::<in6_addr_u>();
*u.Byte_mut() = addr.ip().octets();
in6_addr { u }
};

#[cfg(windows)]
let u = {
let mut u = std::mem::zeroed::<SOCKADDR_IN6_LH_u>();
*u.sin6_scope_id_mut() = addr.scope_id();
u
};

*out_in6 = sockaddr_in6 {
sin6_family: AF_INET6 as sa_family_t,
sin6_addr,
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
sin6_len: sa_len as u8,
sin6_port: sin_port,
sin6_flowinfo: addr.flowinfo(),

#[cfg(not(windows))]
sin6_scope_id: addr.scope_id(),
#[cfg(windows)]
u,
};
sa_len as socklen_t
},
Expand Down
Loading

0 comments on commit 952767b

Please sign in to comment.