Skip to content
Closed
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
13 changes: 13 additions & 0 deletions .github/target.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Wind CI Build Target Configuration

[[target]]
os = "ubuntu-latest"
target = "x86_64-unknown-linux-gnu"
release-name = "x86_64-linux"
skip-test = false

[[target]]
os = "macos-latest"
target = "aarch64-apple-darwin"
release-name = "aarch64-darwin"
skip-test = false
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
uses: rust-proxy/workflows/.github/workflows/rust-build.yml@main
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reusable workflow is referenced by a moving ref (@main). For reproducible CI and to avoid unexpected breakages, pin this to an immutable tag or commit SHA (and update deliberately when needed).

Suggested change
uses: rust-proxy/workflows/.github/workflows/rust-build.yml@main
uses: rust-proxy/workflows/.github/workflows/rust-build.yml@0123456789abcdef0123456789abcdef01234567

Copilot uses AI. Check for mistakes.
with:
packages: "wind"
run-tests: true
only-clippy-tests-on-pr: true
10 changes: 5 additions & 5 deletions crates/wind-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "wind-core"
version.workspace = true
repository.workspace = true
edition.workspace = true
description.workspace = true
version = "0.1.1"
repository = "https://github.com/proxy-rs/wind"
edition = "2024"
description = "Wind core networking abstractions"
license = "MIT OR Apache-2.0"

[features]
Expand All @@ -15,7 +15,7 @@ pin-project = "1"
tokio = { version = "1", default-features = false, features = ["io-util", "macros", "time", "net"] }
tokio-util = { version = "0.7", features = ["rt"] }

quinn = { version = "0.11", default-features = false, optional = true }
quinn = { workspace = true, default-features = false, optional = true }
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quinn = { workspace = true, ... } won’t resolve unless the root Cargo.toml defines quinn under [workspace.dependencies]. Since the workspace manifest currently only has [workspace.package], this change will cause a dependency resolution error; add the workspace dependency or pin a version in this crate.

Suggested change
quinn = { workspace = true, default-features = false, optional = true }
quinn = { version = "0.11", default-features = false, optional = true }

Copilot uses AI. Check for mistakes.
quinn-udp = "0.5"

socket2 = "0.6"
Expand Down
49 changes: 23 additions & 26 deletions crates/wind-core/src/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@ use std::{

use bytes::Bytes;
use futures::future::poll_fn;
#[cfg(feature = "quic")]
pub use quinn::UdpPoller;
pub use quinn_udp::{EcnCodepoint, RecvMeta as QuinnRecvMeta, Transmit, UdpSocketState};
// Re-export quinn-udp's RecvMeta directly
// pub use quinn_udp::RecvMeta;
use tokio::io::Interest;

use crate::types::TargetAddr;

#[cfg(not(feature = "quic"))]
pub trait UdpPoller: Send + Sync + Debug + 'static {
fn poll_writable(self: Pin<&mut Self>, cx: &mut Context) -> Poll<std::io::Result<()>>;
}
Expand All @@ -31,25 +28,25 @@ pub trait UdpPoller: Send + Sync + Debug + 'static {
#[derive(Debug, Clone)]
pub struct RecvMeta {
/// The source address of the datagram(s) contained in the buffer
pub addr: SocketAddr,
pub addr: SocketAddr,
/// The number of bytes the associated buffer has
pub len: usize,
pub len: usize,
/// The size of a single datagram in the associated buffer
///
/// When GRO (Generic Receive Offload) is used this indicates the size of a
/// single datagram inside the buffer. If the buffer is larger, that is if
/// [`len`] is greater then this value, then the individual datagrams
/// contained have their boundaries at `stride` increments from the start.
/// The last datagram could be smaller than `stride`.
pub stride: usize,
pub stride: usize,
/// The Explicit Congestion Notification bits for the datagram(s) in the
/// buffer
pub ecn: Option<EcnCodepoint>,
pub ecn: Option<EcnCodepoint>,
/// The destination IP address which was encoded in this datagram
///
/// Populated on platforms: Windows, Linux, Android (API level > 25),
/// FreeBSD, OpenBSD, NetBSD, macOS, and iOS.
pub dst_ip: Option<IpAddr>,
pub dst_ip: Option<IpAddr>,
/// The destination address that this packet is intended for
/// This is our custom field for better packet routing
pub destination: Option<TargetAddr>,
Expand All @@ -59,11 +56,11 @@ impl Default for RecvMeta {
/// Constructs a value with arbitrary fields, intended to be overwritten
fn default() -> Self {
Self {
addr: SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
len: 0,
stride: 0,
ecn: None,
dst_ip: None,
addr: SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
len: 0,
stride: 0,
ecn: None,
dst_ip: None,
destination: None,
}
}
Expand All @@ -72,20 +69,20 @@ impl Default for RecvMeta {
impl From<QuinnRecvMeta> for RecvMeta {
fn from(meta: QuinnRecvMeta) -> Self {
Self {
addr: meta.addr,
len: meta.len,
stride: meta.stride,
ecn: meta.ecn,
dst_ip: meta.dst_ip,
addr: meta.addr,
len: meta.len,
stride: meta.stride,
ecn: meta.ecn,
dst_ip: meta.dst_ip,
destination: None,
}
}
}

#[derive(Debug, Clone)]
pub struct UdpPacket {
pub source: Option<TargetAddr>,
pub target: TargetAddr,
pub source: Option<TargetAddr>,
pub target: TargetAddr,
pub payload: Bytes,
}

Expand Down Expand Up @@ -130,11 +127,11 @@ pub trait AbstractUdpSocket: Send + Sync {
/// Sends data on the socket to the given address.
fn poll_send(&self, _cx: &mut Context<'_>, buf: &[u8], target: SocketAddr) -> Poll<IoResult<usize>> {
let transmit = Transmit {
destination: target,
contents: buf,
ecn: None,
destination: target,
contents: buf,
ecn: None,
segment_size: None,
src_ip: None,
src_ip: None,
};
match self.try_send(&transmit) {
Ok(_) => Poll::Ready(Ok(buf.len())),
Expand All @@ -150,14 +147,14 @@ pub trait AbstractUdpSocket: Send + Sync {

#[derive(Debug)]
pub struct TokioUdpSocket {
io: tokio::net::UdpSocket,
io: tokio::net::UdpSocket,
inner: UdpSocketState,
}
impl TokioUdpSocket {
pub fn new(sock: std::net::UdpSocket) -> std::io::Result<Self> {
Ok(Self {
inner: UdpSocketState::new((&sock).into())?,
io: tokio::net::UdpSocket::from_std(sock)?,
io: tokio::net::UdpSocket::from_std(sock)?,
})
}
}
Expand Down
10 changes: 5 additions & 5 deletions crates/wind-socks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[package]
name = "wind-socks"
version.workspace = true
repository.workspace = true
edition.workspace = true
description.workspace = true
version = "0.1.1"
repository = "https://github.com/proxy-rs/wind"
edition = "2024"
description = "Wind SOCKS5 implementation"
license = "MIT OR Apache-2.0"

[dependencies]
wind-core = { version = "0.1.1", path = "../wind-core"}
wind-core = { path = "../wind-core"}
# Async
tokio = { version = "1", default-features = false, features = ["net"] }
tokio-util = { version = "0.7", features = ["codec"] }
Expand Down
12 changes: 6 additions & 6 deletions crates/wind-tuic/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "wind-tuic"
version.workspace = true
repository.workspace = true
edition.workspace = true
description.workspace = true
version = "0.1.1"
repository = "https://github.com/proxy-rs/wind"
edition = "2024"
description = "Wind TUIC protocol implementation"
license = "MIT OR Apache-2.0"

[features]
Expand All @@ -22,13 +22,13 @@ ring = [
]

[dependencies]
wind-core = { version = "0.1.1", path = "../wind-core", features = ["quic"]}
wind-core = { path = "../wind-core", features = ["quic"]}


# Async
tokio = { version = "1", default-features = false, features = ["net"] }
tokio-util = { version = "0.7", features = ["codec"] }
quinn = { version = "0.11", default-features = false, features = ["runtime-tokio"]}
quinn = { workspace = true, default-features = false, features = ["runtime-tokio", "qlog"] }
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

workspace = true for quinn requires a [workspace.dependencies] quinn = ... entry in the root Cargo.toml. The current root manifest has no workspace dependencies section, so this will not resolve and will break builds; either add the workspace dependency or specify a concrete version here.

Suggested change
quinn = { workspace = true, default-features = false, features = ["runtime-tokio", "qlog"] }
quinn = { version = "0.11", default-features = false, features = ["runtime-tokio", "qlog"] }

Copilot uses AI. Check for mistakes.
crossfire = { version = "2", features = ["tokio"] }

tokio-stream = "0.1"
Expand Down
22 changes: 11 additions & 11 deletions crates/wind-tuic/src/inbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ impl Default for TuicInboundOpts {
/// TUIC inbound server
pub struct TuicInbound {
pub ctx: Arc<AppContext>,
opts: TuicInboundOpts,
cancel: CancellationToken,
opts: TuicInboundOpts,
cancel: CancellationToken,
}

impl TuicInbound {
Expand Down Expand Up @@ -243,16 +243,16 @@ impl AbstractInbound for TuicInbound {

/// Represents an authenticated connection
struct InboundCtx {
conn: quinn::Connection,
uuid: Arc<RwLock<Option<Uuid>>>,
users: HashMap<Uuid, String>,
conn: quinn::Connection,
uuid: Arc<RwLock<Option<Uuid>>>,
users: HashMap<Uuid, String>,
udp_sessions: Arc<RwLock<HashMap<u16, UdpSession>>>,
}

/// UDP session tracking
#[allow(dead_code)]
struct UdpSession {
assoc_id: u16,
assoc_id: u16,
// Track packet fragments if needed
fragments: Cache<u16, Vec<u8>>,
}
Expand Down Expand Up @@ -323,7 +323,7 @@ async fn handle_connection<C: InboundCallback>(
}
Ok(recv) => recv,
};

let conn = connection.clone();
if let Err(e) = handle_uni_stream(conn, recv, callback).await {
error!("Uni stream error: {:?}", e);
Expand All @@ -338,7 +338,7 @@ async fn handle_connection<C: InboundCallback>(
}
Ok(streams) => streams,
};

let conn = connection.clone();
if let Err(e) = handle_bi_stream(conn, send, recv, callback).await {
error!("Bi stream error: {:?}", e);
Expand All @@ -353,7 +353,7 @@ async fn handle_connection<C: InboundCallback>(
}
Ok(datagram) => datagram,
};

let conn = connection.clone();
if let Err(e) = handle_datagram(conn, datagram, callback).await {
error!("Datagram error: {:?}", e);
Expand Down Expand Up @@ -390,7 +390,7 @@ async fn handle_uni_stream<C: InboundCallback>(
// Decode address
let addr = crate::proto::decode_address(&mut buf, "uni stream packet")?;
let payload = buf.split_to(size as usize).freeze();

// Convert address to TargetAddr using helper function
let target_addr = crate::proto::address_to_target(addr)?;
handle_udp_packet(&ctx, assoc_id, target_addr, payload, callback).await?;
Expand Down Expand Up @@ -491,7 +491,7 @@ async fn handle_datagram<C: InboundCallback>(
if let Command::Packet { assoc_id, size, .. } = cmd {
let addr = crate::proto::decode_address(&mut buf, "datagram packet")?;
let payload = buf.split_to(size as usize).freeze();

// Convert address to TargetAddr using helper function
let target_addr = crate::proto::address_to_target(addr)?;
handle_udp_packet(&connection, assoc_id, target_addr, payload, callback).await?;
Expand Down
1 change: 1 addition & 0 deletions crates/wind-tuic/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(error_generic_member_access)]

pub mod proto;
pub mod simple_udp;
mod task;
pub mod tls;

Expand Down
Loading
Loading