Skip to content

Commit 111c8d0

Browse files
authored
Merge pull request #282 from AsakuraMizu/quic
2 parents f616fdc + ee92ffd commit 111c8d0

File tree

29 files changed

+5333
-82
lines changed

29 files changed

+5333
-82
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ members = [
1313
"compio-tls",
1414
"compio-log",
1515
"compio-process",
16+
"compio-quic",
1617
]
1718
resolver = "2"
1819

@@ -36,7 +37,9 @@ compio-dispatcher = { path = "./compio-dispatcher", version = "0.3.0" }
3637
compio-log = { path = "./compio-log", version = "0.1.0" }
3738
compio-tls = { path = "./compio-tls", version = "0.2.0", default-features = false }
3839
compio-process = { path = "./compio-process", version = "0.1.0" }
40+
compio-quic = { path = "./compio-quic", version = "0.1.0" }
3941

42+
bytes = "1.7.1"
4043
flume = "0.11.0"
4144
cfg-if = "1.0.0"
4245
criterion = "0.5.1"
@@ -49,10 +52,13 @@ nix = "0.29.0"
4952
once_cell = "1.18.0"
5053
os_pipe = "1.1.4"
5154
paste = "1.0.14"
55+
rand = "0.8.5"
56+
rustls = { version = "0.23.1", default-features = false }
5257
slab = "0.4.9"
5358
socket2 = "0.5.6"
5459
tempfile = "3.8.1"
5560
tokio = "1.33.0"
61+
tracing-subscriber = "0.3.18"
5662
widestring = "1.0.2"
5763
windows-sys = "0.52.0"
5864

compio-buf/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
1717
[dependencies]
1818
bumpalo = { version = "3.14.0", optional = true }
1919
arrayvec = { version = "0.7.4", optional = true }
20-
bytes = { version = "1.5.0", optional = true }
20+
bytes = { workspace = true, optional = true }
2121

2222
[target.'cfg(unix)'.dependencies]
2323
libc = { workspace = true }

compio-driver/src/iocp/op.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -781,12 +781,11 @@ static WSA_RECVMSG: OnceLock<LPFN_WSARECVMSG> = OnceLock::new();
781781

782782
/// Receive data and source address with ancillary data into vectored buffer.
783783
pub struct RecvMsg<T: IoVectoredBufMut, C: IoBufMut, S> {
784+
msg: WSAMSG,
784785
addr: SOCKADDR_STORAGE,
785-
addr_len: socklen_t,
786786
fd: SharedFd<S>,
787787
buffer: T,
788788
control: C,
789-
control_len: u32,
790789
_p: PhantomPinned,
791790
}
792791

@@ -802,12 +801,11 @@ impl<T: IoVectoredBufMut, C: IoBufMut, S> RecvMsg<T, C, S> {
802801
"misaligned control message buffer"
803802
);
804803
Self {
804+
msg: unsafe { std::mem::zeroed() },
805805
addr: unsafe { std::mem::zeroed() },
806-
addr_len: std::mem::size_of::<SOCKADDR_STORAGE>() as _,
807806
fd,
808807
buffer,
809808
control,
810-
control_len: 0,
811809
_p: PhantomPinned,
812810
}
813811
}
@@ -820,8 +818,8 @@ impl<T: IoVectoredBufMut, C: IoBufMut, S> IntoInner for RecvMsg<T, C, S> {
820818
(
821819
(self.buffer, self.control),
822820
self.addr,
823-
self.addr_len,
824-
self.control_len as _,
821+
self.msg.namelen,
822+
self.msg.Control.len as _,
825823
)
826824
}
827825
}
@@ -835,26 +833,23 @@ impl<T: IoVectoredBufMut, C: IoBufMut, S: AsRawFd> OpCode for RecvMsg<T, C, S> {
835833
})?;
836834

837835
let this = self.get_unchecked_mut();
836+
838837
let mut slices = this.buffer.io_slices_mut();
839-
let mut msg = WSAMSG {
840-
name: &mut this.addr as *mut _ as _,
841-
namelen: this.addr_len,
842-
lpBuffers: slices.as_mut_ptr() as _,
843-
dwBufferCount: slices.len() as _,
844-
Control: std::mem::transmute::<IoSliceMut, WSABUF>(this.control.as_io_slice_mut()),
845-
dwFlags: 0,
846-
};
847-
this.control_len = 0;
838+
this.msg.name = &mut this.addr as *mut _ as _;
839+
this.msg.namelen = std::mem::size_of::<SOCKADDR_STORAGE>() as _;
840+
this.msg.lpBuffers = slices.as_mut_ptr() as _;
841+
this.msg.dwBufferCount = slices.len() as _;
842+
this.msg.Control =
843+
std::mem::transmute::<IoSliceMut, WSABUF>(this.control.as_io_slice_mut());
848844

849845
let mut received = 0;
850846
let res = recvmsg_fn(
851847
this.fd.as_raw_fd() as _,
852-
&mut msg,
848+
&mut this.msg,
853849
&mut received,
854850
optr,
855851
None,
856852
);
857-
this.control_len = msg.Control.len;
858853
winsock_result(res, received)
859854
}
860855

compio-log/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ repository = { workspace = true }
1313
tracing = { version = "0.1", default-features = false }
1414

1515
[dev-dependencies]
16-
tracing-subscriber = "0.3"
16+
tracing-subscriber = { workspace = true }
1717

1818
[features]
1919
enable_log = []

compio-net/src/socket.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use std::{future::Future, io, mem::ManuallyDrop};
1+
use std::{
2+
future::Future,
3+
io,
4+
mem::{ManuallyDrop, MaybeUninit},
5+
};
26

37
use compio_buf::{BufResult, IntoInner, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut};
48
#[cfg(unix)]
@@ -325,7 +329,51 @@ impl Socket {
325329
}
326330

327331
#[cfg(unix)]
328-
pub fn set_socket_option<T>(&self, level: i32, name: i32, value: &T) -> io::Result<()> {
332+
pub unsafe fn get_socket_option<T: Copy>(&self, level: i32, name: i32) -> io::Result<T> {
333+
let mut value: MaybeUninit<T> = MaybeUninit::uninit();
334+
let mut len = size_of::<T>() as libc::socklen_t;
335+
syscall!(libc::getsockopt(
336+
self.socket.as_raw_fd(),
337+
level,
338+
name,
339+
value.as_mut_ptr() as _,
340+
&mut len
341+
))
342+
.map(|_| {
343+
debug_assert_eq!(len as usize, size_of::<T>());
344+
// SAFETY: The value is initialized by `getsockopt`.
345+
value.assume_init()
346+
})
347+
}
348+
349+
#[cfg(windows)]
350+
pub unsafe fn get_socket_option<T: Copy>(&self, level: i32, name: i32) -> io::Result<T> {
351+
let mut value: MaybeUninit<T> = MaybeUninit::uninit();
352+
let mut len = size_of::<T>() as i32;
353+
syscall!(
354+
SOCKET,
355+
windows_sys::Win32::Networking::WinSock::getsockopt(
356+
self.socket.as_raw_fd() as _,
357+
level,
358+
name,
359+
value.as_mut_ptr() as _,
360+
&mut len
361+
)
362+
)
363+
.map(|_| {
364+
debug_assert_eq!(len as usize, size_of::<T>());
365+
// SAFETY: The value is initialized by `getsockopt`.
366+
value.assume_init()
367+
})
368+
}
369+
370+
#[cfg(unix)]
371+
pub unsafe fn set_socket_option<T: Copy>(
372+
&self,
373+
level: i32,
374+
name: i32,
375+
value: &T,
376+
) -> io::Result<()> {
329377
syscall!(libc::setsockopt(
330378
self.socket.as_raw_fd(),
331379
level,
@@ -337,7 +385,12 @@ impl Socket {
337385
}
338386

339387
#[cfg(windows)]
340-
pub fn set_socket_option<T>(&self, level: i32, name: i32, value: &T) -> io::Result<()> {
388+
pub unsafe fn set_socket_option<T: Copy>(
389+
&self,
390+
level: i32,
391+
name: i32,
392+
value: &T,
393+
) -> io::Result<()> {
341394
syscall!(
342395
SOCKET,
343396
windows_sys::Win32::Networking::WinSock::setsockopt(

compio-net/src/udp.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,26 @@ impl UdpSocket {
316316
.await
317317
}
318318

319+
/// Gets a socket option.
320+
///
321+
/// # Safety
322+
///
323+
/// The caller must ensure `T` is the correct type for `level` and `name`.
324+
pub unsafe fn get_socket_option<T: Copy>(&self, level: i32, name: i32) -> io::Result<T> {
325+
self.inner.get_socket_option(level, name)
326+
}
327+
319328
/// Sets a socket option.
320-
pub fn set_socket_option<T>(&self, level: i32, name: i32, value: &T) -> io::Result<()> {
329+
///
330+
/// # Safety
331+
///
332+
/// The caller must ensure `T` is the correct type for `level` and `name`.
333+
pub unsafe fn set_socket_option<T: Copy>(
334+
&self,
335+
level: i32,
336+
name: i32,
337+
value: &T,
338+
) -> io::Result<()> {
321339
self.inner.set_socket_option(level, name, value)
322340
}
323341
}

compio-net/tests/udp.rs

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use compio_net::{CMsgBuilder, CMsgIter, UdpSocket};
1+
use compio_net::UdpSocket;
22

33
#[compio_macros::test]
44
async fn connect() {
@@ -64,57 +64,3 @@ async fn send_to() {
6464
active_addr
6565
);
6666
}
67-
68-
#[compio_macros::test]
69-
async fn send_msg_with_ipv6_ecn() {
70-
#[cfg(unix)]
71-
use libc::{IPPROTO_IPV6, IPV6_RECVTCLASS, IPV6_TCLASS};
72-
#[cfg(windows)]
73-
use windows_sys::Win32::Networking::WinSock::{
74-
IPPROTO_IPV6, IPV6_ECN, IPV6_RECVTCLASS, IPV6_TCLASS,
75-
};
76-
77-
const MSG: &str = "foo bar baz";
78-
79-
let passive = UdpSocket::bind("[::1]:0").await.unwrap();
80-
let passive_addr = passive.local_addr().unwrap();
81-
82-
passive
83-
.set_socket_option(IPPROTO_IPV6, IPV6_RECVTCLASS, &1)
84-
.unwrap();
85-
86-
let active = UdpSocket::bind("[::1]:0").await.unwrap();
87-
let active_addr = active.local_addr().unwrap();
88-
89-
let mut control = vec![0u8; 32];
90-
let mut builder = CMsgBuilder::new(&mut control);
91-
92-
const ECN_BITS: i32 = 0b10;
93-
94-
#[cfg(unix)]
95-
builder
96-
.try_push(IPPROTO_IPV6, IPV6_TCLASS, ECN_BITS)
97-
.unwrap();
98-
#[cfg(windows)]
99-
builder.try_push(IPPROTO_IPV6, IPV6_ECN, ECN_BITS).unwrap();
100-
101-
let len = builder.finish();
102-
control.truncate(len);
103-
104-
active.send_msg(MSG, control, passive_addr).await.unwrap();
105-
106-
let ((_, _, addr), (buffer, control)) = passive
107-
.recv_msg(Vec::with_capacity(20), Vec::with_capacity(32))
108-
.await
109-
.unwrap();
110-
assert_eq!(addr, active_addr);
111-
assert_eq!(buffer, MSG.as_bytes());
112-
unsafe {
113-
let mut iter = CMsgIter::new(&control);
114-
let cmsg = iter.next().unwrap();
115-
assert_eq!(cmsg.level(), IPPROTO_IPV6);
116-
assert_eq!(cmsg.ty(), IPV6_TCLASS);
117-
assert_eq!(cmsg.data::<i32>(), &ECN_BITS);
118-
assert!(iter.next().is_none());
119-
}
120-
}

compio-quic/Cargo.toml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
[package]
2+
name = "compio-quic"
3+
version = "0.1.0"
4+
description = "QUIC for compio"
5+
categories = ["asynchronous", "network-programming"]
6+
keywords = ["async", "net", "quic"]
7+
edition = { workspace = true }
8+
authors = { workspace = true }
9+
readme = { workspace = true }
10+
license = { workspace = true }
11+
repository = { workspace = true }
12+
13+
[package.metadata.docs.rs]
14+
all-features = true
15+
rustdoc-args = ["--cfg", "docsrs"]
16+
17+
[dependencies]
18+
# Workspace dependencies
19+
compio-io = { workspace = true }
20+
compio-buf = { workspace = true }
21+
compio-log = { workspace = true }
22+
compio-net = { workspace = true }
23+
compio-runtime = { workspace = true, features = ["time"] }
24+
25+
quinn-proto = "0.11.3"
26+
rustls = { workspace = true }
27+
rustls-platform-verifier = { version = "0.3.3", optional = true }
28+
rustls-native-certs = { version = "0.7.1", optional = true }
29+
webpki-roots = { version = "0.26.3", optional = true }
30+
h3 = { version = "0.0.6", optional = true }
31+
32+
# Utils
33+
bytes = { workspace = true }
34+
flume = { workspace = true }
35+
futures-util = { workspace = true }
36+
rustc-hash = "2.0.0"
37+
thiserror = "1.0.63"
38+
39+
# Windows specific dependencies
40+
[target.'cfg(windows)'.dependencies]
41+
windows-sys = { workspace = true, features = ["Win32_Networking_WinSock"] }
42+
43+
[target.'cfg(unix)'.dependencies]
44+
libc = { workspace = true }
45+
46+
[dev-dependencies]
47+
compio-buf = { workspace = true, features = ["bytes"] }
48+
compio-dispatcher = { workspace = true }
49+
compio-driver = { workspace = true }
50+
compio-fs = { workspace = true }
51+
compio-macros = { workspace = true }
52+
compio-runtime = { workspace = true, features = ["criterion"] }
53+
54+
criterion = { workspace = true, features = ["async_tokio"] }
55+
http = "1.1.0"
56+
quinn = "0.11.3"
57+
rand = { workspace = true }
58+
rcgen = "0.13.1"
59+
socket2 = { workspace = true, features = ["all"] }
60+
tokio = { workspace = true, features = ["rt", "macros"] }
61+
tracing-subscriber = { workspace = true, features = ["env-filter"] }
62+
63+
[features]
64+
default = []
65+
io-compat = ["futures-util/io"]
66+
platform-verifier = ["dep:rustls-platform-verifier"]
67+
native-certs = ["dep:rustls-native-certs"]
68+
webpki-roots = ["dep:webpki-roots"]
69+
h3 = ["dep:h3"]
70+
# FIXME: see https://github.com/quinn-rs/quinn/pull/1962
71+
72+
[[example]]
73+
name = "http3-client"
74+
required-features = ["h3"]
75+
76+
[[example]]
77+
name = "http3-server"
78+
required-features = ["h3"]
79+
80+
[[bench]]
81+
name = "quic"
82+
harness = false

0 commit comments

Comments
 (0)