Skip to content

Commit c2a4a79

Browse files
committed
feat: add simple UDP packet channel for easier integration
This commit introduces a simplified UDP abstraction to replace the complex AbstractUdpSocket trait from wind-core. The new implementation provides: - SimpleUdpPacket: Basic UDP packet structure (source, target, payload) - SimpleUdpChannel: Bidirectional channel for packet transmission - SimpleUdpChannelTx: Transmitter side (supports Clone) - handle_udp_simple(): New method in TuicOutbound for easy UDP handling Benefits: - Much simpler API compared to AbstractUdpSocket trait - Uses standard crossfire channels instead of custom traits - Easier integration with existing async code - Reduced complexity for UDP relay implementations The implementation maintains compatibility with existing UdpStream while providing a more ergonomic interface for UDP packet handling.
1 parent 6c7ccba commit c2a4a79

17 files changed

Lines changed: 336 additions & 197 deletions

File tree

crates/wind-core/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[package]
22
name = "wind-core"
3-
version.workspace = true
4-
repository.workspace = true
5-
edition.workspace = true
6-
description.workspace = true
3+
version = "0.1.1"
4+
repository = "https://github.com/proxy-rs/wind"
5+
edition = "2024"
6+
description = "Wind core networking abstractions"
77
license = "MIT OR Apache-2.0"
88

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

18-
quinn = { version = "0.11", default-features = false, optional = true }
18+
quinn = { workspace = true, default-features = false, optional = true }
1919
quinn-udp = "0.5"
2020

2121
socket2 = "0.6"

crates/wind-core/src/udp.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,13 @@ use std::{
1010

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

2018
use crate::types::TargetAddr;
2119

22-
#[cfg(not(feature = "quic"))]
2320
pub trait UdpPoller: Send + Sync + Debug + 'static {
2421
fn poll_writable(self: Pin<&mut Self>, cx: &mut Context) -> Poll<std::io::Result<()>>;
2522
}
@@ -31,25 +28,25 @@ pub trait UdpPoller: Send + Sync + Debug + 'static {
3128
#[derive(Debug, Clone)]
3229
pub struct RecvMeta {
3330
/// The source address of the datagram(s) contained in the buffer
34-
pub addr: SocketAddr,
31+
pub addr: SocketAddr,
3532
/// The number of bytes the associated buffer has
36-
pub len: usize,
33+
pub len: usize,
3734
/// The size of a single datagram in the associated buffer
3835
///
3936
/// When GRO (Generic Receive Offload) is used this indicates the size of a
4037
/// single datagram inside the buffer. If the buffer is larger, that is if
4138
/// [`len`] is greater then this value, then the individual datagrams
4239
/// contained have their boundaries at `stride` increments from the start.
4340
/// The last datagram could be smaller than `stride`.
44-
pub stride: usize,
41+
pub stride: usize,
4542
/// The Explicit Congestion Notification bits for the datagram(s) in the
4643
/// buffer
47-
pub ecn: Option<EcnCodepoint>,
44+
pub ecn: Option<EcnCodepoint>,
4845
/// The destination IP address which was encoded in this datagram
4946
///
5047
/// Populated on platforms: Windows, Linux, Android (API level > 25),
5148
/// FreeBSD, OpenBSD, NetBSD, macOS, and iOS.
52-
pub dst_ip: Option<IpAddr>,
49+
pub dst_ip: Option<IpAddr>,
5350
/// The destination address that this packet is intended for
5451
/// This is our custom field for better packet routing
5552
pub destination: Option<TargetAddr>,
@@ -59,11 +56,11 @@ impl Default for RecvMeta {
5956
/// Constructs a value with arbitrary fields, intended to be overwritten
6057
fn default() -> Self {
6158
Self {
62-
addr: SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
63-
len: 0,
64-
stride: 0,
65-
ecn: None,
66-
dst_ip: None,
59+
addr: SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
60+
len: 0,
61+
stride: 0,
62+
ecn: None,
63+
dst_ip: None,
6764
destination: None,
6865
}
6966
}
@@ -72,20 +69,20 @@ impl Default for RecvMeta {
7269
impl From<QuinnRecvMeta> for RecvMeta {
7370
fn from(meta: QuinnRecvMeta) -> Self {
7471
Self {
75-
addr: meta.addr,
76-
len: meta.len,
77-
stride: meta.stride,
78-
ecn: meta.ecn,
79-
dst_ip: meta.dst_ip,
72+
addr: meta.addr,
73+
len: meta.len,
74+
stride: meta.stride,
75+
ecn: meta.ecn,
76+
dst_ip: meta.dst_ip,
8077
destination: None,
8178
}
8279
}
8380
}
8481

8582
#[derive(Debug, Clone)]
8683
pub struct UdpPacket {
87-
pub source: Option<TargetAddr>,
88-
pub target: TargetAddr,
84+
pub source: Option<TargetAddr>,
85+
pub target: TargetAddr,
8986
pub payload: Bytes,
9087
}
9188

@@ -130,11 +127,11 @@ pub trait AbstractUdpSocket: Send + Sync {
130127
/// Sends data on the socket to the given address.
131128
fn poll_send(&self, _cx: &mut Context<'_>, buf: &[u8], target: SocketAddr) -> Poll<IoResult<usize>> {
132129
let transmit = Transmit {
133-
destination: target,
134-
contents: buf,
135-
ecn: None,
130+
destination: target,
131+
contents: buf,
132+
ecn: None,
136133
segment_size: None,
137-
src_ip: None,
134+
src_ip: None,
138135
};
139136
match self.try_send(&transmit) {
140137
Ok(_) => Poll::Ready(Ok(buf.len())),
@@ -150,14 +147,14 @@ pub trait AbstractUdpSocket: Send + Sync {
150147

151148
#[derive(Debug)]
152149
pub struct TokioUdpSocket {
153-
io: tokio::net::UdpSocket,
150+
io: tokio::net::UdpSocket,
154151
inner: UdpSocketState,
155152
}
156153
impl TokioUdpSocket {
157154
pub fn new(sock: std::net::UdpSocket) -> std::io::Result<Self> {
158155
Ok(Self {
159156
inner: UdpSocketState::new((&sock).into())?,
160-
io: tokio::net::UdpSocket::from_std(sock)?,
157+
io: tokio::net::UdpSocket::from_std(sock)?,
161158
})
162159
}
163160
}

crates/wind-socks/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[package]
22
name = "wind-socks"
3-
version.workspace = true
4-
repository.workspace = true
5-
edition.workspace = true
6-
description.workspace = true
3+
version = "0.1.1"
4+
repository = "https://github.com/proxy-rs/wind"
5+
edition = "2024"
6+
description = "Wind SOCKS5 implementation"
77
license = "MIT OR Apache-2.0"
88

99
[dependencies]
10-
wind-core = { version = "0.1.1", path = "../wind-core"}
10+
wind-core = { path = "../wind-core"}
1111
# Async
1212
tokio = { version = "1", default-features = false, features = ["net"] }
1313
tokio-util = { version = "0.7", features = ["codec"] }

crates/wind-tuic/Cargo.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[package]
22
name = "wind-tuic"
3-
version.workspace = true
4-
repository.workspace = true
5-
edition.workspace = true
6-
description.workspace = true
3+
version = "0.1.1"
4+
repository = "https://github.com/proxy-rs/wind"
5+
edition = "2024"
6+
description = "Wind TUIC protocol implementation"
77
license = "MIT OR Apache-2.0"
88

99
[features]
@@ -22,13 +22,13 @@ ring = [
2222
]
2323

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

2727

2828
# Async
2929
tokio = { version = "1", default-features = false, features = ["net"] }
3030
tokio-util = { version = "0.7", features = ["codec"] }
31-
quinn = { version = "0.11", default-features = false, features = ["runtime-tokio"]}
31+
quinn = { workspace = true, default-features = false, features = ["runtime-tokio", "qlog"] }
3232
crossfire = { version = "2", features = ["tokio"] }
3333

3434
tokio-stream = "0.1"

crates/wind-tuic/src/inbound.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ impl Default for TuicInboundOpts {
138138
/// TUIC inbound server
139139
pub struct TuicInbound {
140140
pub ctx: Arc<AppContext>,
141-
opts: TuicInboundOpts,
142-
cancel: CancellationToken,
141+
opts: TuicInboundOpts,
142+
cancel: CancellationToken,
143143
}
144144

145145
impl TuicInbound {
@@ -243,16 +243,16 @@ impl AbstractInbound for TuicInbound {
243243

244244
/// Represents an authenticated connection
245245
struct InboundCtx {
246-
conn: quinn::Connection,
247-
uuid: Arc<RwLock<Option<Uuid>>>,
248-
users: HashMap<Uuid, String>,
246+
conn: quinn::Connection,
247+
uuid: Arc<RwLock<Option<Uuid>>>,
248+
users: HashMap<Uuid, String>,
249249
udp_sessions: Arc<RwLock<HashMap<u16, UdpSession>>>,
250250
}
251251

252252
/// UDP session tracking
253253
#[allow(dead_code)]
254254
struct UdpSession {
255-
assoc_id: u16,
255+
assoc_id: u16,
256256
// Track packet fragments if needed
257257
fragments: Cache<u16, Vec<u8>>,
258258
}
@@ -323,7 +323,7 @@ async fn handle_connection<C: InboundCallback>(
323323
}
324324
Ok(recv) => recv,
325325
};
326-
326+
327327
let conn = connection.clone();
328328
if let Err(e) = handle_uni_stream(conn, recv, callback).await {
329329
error!("Uni stream error: {:?}", e);
@@ -338,7 +338,7 @@ async fn handle_connection<C: InboundCallback>(
338338
}
339339
Ok(streams) => streams,
340340
};
341-
341+
342342
let conn = connection.clone();
343343
if let Err(e) = handle_bi_stream(conn, send, recv, callback).await {
344344
error!("Bi stream error: {:?}", e);
@@ -353,7 +353,7 @@ async fn handle_connection<C: InboundCallback>(
353353
}
354354
Ok(datagram) => datagram,
355355
};
356-
356+
357357
let conn = connection.clone();
358358
if let Err(e) = handle_datagram(conn, datagram, callback).await {
359359
error!("Datagram error: {:?}", e);
@@ -390,7 +390,7 @@ async fn handle_uni_stream<C: InboundCallback>(
390390
// Decode address
391391
let addr = crate::proto::decode_address(&mut buf, "uni stream packet")?;
392392
let payload = buf.split_to(size as usize).freeze();
393-
393+
394394
// Convert address to TargetAddr using helper function
395395
let target_addr = crate::proto::address_to_target(addr)?;
396396
handle_udp_packet(&ctx, assoc_id, target_addr, payload, callback).await?;
@@ -491,7 +491,7 @@ async fn handle_datagram<C: InboundCallback>(
491491
if let Command::Packet { assoc_id, size, .. } = cmd {
492492
let addr = crate::proto::decode_address(&mut buf, "datagram packet")?;
493493
let payload = buf.split_to(size as usize).freeze();
494-
494+
495495
// Convert address to TargetAddr using helper function
496496
let target_addr = crate::proto::address_to_target(addr)?;
497497
handle_udp_packet(&connection, assoc_id, target_addr, payload, callback).await?;

crates/wind-tuic/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![feature(error_generic_member_access)]
22

33
pub mod proto;
4+
pub mod simple_udp;
45
mod task;
56
pub mod tls;
67

0 commit comments

Comments
 (0)