1#![cfg_attr(docsrs, feature(doc_cfg))]
3
4use std::{
5 borrow::Cow,
6 net::{SocketAddr, ToSocketAddrs},
7 time::Instant,
8};
9
10use quiche::{Config, ConnectionId, RecvInfo, SendInfo};
11
12#[derive(Debug, PartialEq, Eq, thiserror::Error)]
14pub enum Error {
15 #[error(transparent)]
17 Quiche(#[from] quiche::Error),
18
19 #[error("Retry this operation later.")]
24 Retry,
25
26 #[error("Resource is busy.")]
28 Busy,
29
30 #[error("Resource is not found.")]
32 NotFound,
33
34 #[error("Failed to validate client address.")]
35 ValidateAddress,
36
37 #[error("Maximumn currently opened streams.")]
38 MaxStreams,
39}
40
41impl From<Error> for std::io::Error {
42 fn from(value: Error) -> Self {
43 match value {
44 Error::Quiche(error) => std::io::Error::other(error),
45 Error::Retry | Error::Busy => {
46 std::io::Error::new(std::io::ErrorKind::WouldBlock, value)
47 }
48
49 Error::NotFound => std::io::Error::new(std::io::ErrorKind::NotFound, value),
50 _ => std::io::Error::other(value),
51 }
52 }
53}
54
55pub type Result<T> = std::result::Result<T, Error>;
57
58pub trait WouldBlock<T> {
60 type Error;
61
62 fn would_block(self) -> std::task::Poll<std::result::Result<T, Self::Error>>;
63}
64
65impl<T> WouldBlock<T> for Result<T> {
66 type Error = Error;
67
68 fn would_block(self) -> std::task::Poll<Result<T>> {
69 match self {
70 Err(Error::Busy) | Err(Error::Retry) => std::task::Poll::Pending,
71 _ => std::task::Poll::Ready(self),
72 }
73 }
74}
75
76impl<T> WouldBlock<T> for std::io::Result<T> {
77 type Error = std::io::Error;
78
79 fn would_block(self) -> std::task::Poll<std::result::Result<T, Self::Error>> {
80 match self {
81 Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => std::task::Poll::Pending,
82 _ => std::task::Poll::Ready(self),
83 }
84 }
85}
86
87#[inline]
89pub fn random_conn_id() -> ConnectionId<'static> {
90 let mut buf = vec![0; 20];
91 boring::rand::rand_bytes(&mut buf).unwrap();
92
93 ConnectionId::from_vec(buf)
94}
95
96#[inline]
98pub fn is_local(stream_id: u64, is_server: bool) -> bool {
99 (stream_id & 0x1) == (is_server as u64)
100}
101
102#[inline]
104pub fn is_bidi(stream_id: u64) -> bool {
105 (stream_id & 0x2) == 0
106}
107
108#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
110pub enum EventKind {
111 Send,
113 Recv,
115 Connected,
117 Accept,
119 Closed,
121 StreamOpenBidi,
123 StreamOpenUni,
125 StreamAccept,
127 StreamSend,
129 StreamRecv,
131 ReadLock,
133}
134
135#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
137pub struct Token(pub u32);
138
139#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
141pub struct Event {
142 pub token: Token,
144 pub kind: EventKind,
146 pub is_server: bool,
148 pub is_error: bool,
150 pub stream_id: u64,
152}
153
154#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
156pub enum StreamKind {
157 Uni,
158 Bidi,
159}
160
161impl From<u64> for StreamKind {
162 fn from(value: u64) -> Self {
163 if is_bidi(value) {
164 StreamKind::Bidi
165 } else {
166 StreamKind::Uni
167 }
168 }
169}
170
171pub trait QuicPoll: Send + Sync {
173 type Error;
174 fn poll(&self, events: &mut Vec<Event>) -> std::result::Result<Option<Instant>, Self::Error>;
177
178 fn register(&self, wrapped: quiche::Connection) -> std::result::Result<Token, Self::Error>;
182
183 fn deregister(&self, token: Token) -> std::result::Result<quiche::Connection, Self::Error>;
185
186 fn len(&self) -> usize;
188
189 fn close(
198 &self,
199 token: Token,
200 app: bool,
201 err: u64,
202 reason: Cow<'static, [u8]>,
203 ) -> std::result::Result<(), Self::Error>;
204
205 fn stream_open(
207 &self,
208 token: Token,
209 kind: StreamKind,
210 non_blocking: bool,
211 ) -> std::result::Result<Option<u64>, Self::Error>;
212
213 fn stream_shutdown(
217 &self,
218 token: Token,
219 stream_id: u64,
220 err: u64,
221 ) -> std::result::Result<(), Self::Error>;
222
223 fn stream_send(
227 &self,
228 token: Token,
229 stream_id: u64,
230 buf: &[u8],
231 fin: bool,
232 ) -> std::result::Result<usize, Self::Error>;
233
234 fn stream_recv(
238 &self,
239 token: Token,
240 stream_id: u64,
241 buf: &mut [u8],
242 ) -> std::result::Result<(usize, bool), Self::Error>;
243}
244
245#[cfg(feature = "client")]
247#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
248pub trait QuicClient: QuicPoll {
249 fn connect(
251 &self,
252 server_name: Option<&str>,
253 local: SocketAddr,
254 peer: SocketAddr,
255 config: &mut Config,
256 ) -> std::result::Result<Token, Self::Error>;
257}
258
259pub trait QuicTransport {
261 type Error;
262
263 fn recv(&self, buf: &mut [u8], info: RecvInfo) -> std::result::Result<usize, Self::Error>;
265
266 fn send(
268 &self,
269 token: Token,
270 buf: &mut [u8],
271 ) -> std::result::Result<(usize, SendInfo), Self::Error>;
272}
273
274#[cfg(feature = "server")]
276#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
277pub trait QuicServerTransport: QuicTransport {
278 fn recv_with_acceptor(
280 &self,
281 acceptor: &mut Acceptor,
282 buf: &mut [u8],
283 recv_size: usize,
284 recv_info: RecvInfo,
285 unparker: Option<&crossbeam_utils::sync::Unparker>,
286 ) -> std::result::Result<(usize, SendInfo), Self::Error>;
287}
288
289pub trait QuicBind: QuicPoll + Sized {
291 #[cfg(feature = "server")]
293 #[cfg_attr(docsrs, doc(cfg(feature = "server")))]
294 fn bind<S>(laddrs: S, acceptor: Option<Acceptor>) -> std::result::Result<Self, Self::Error>
295 where
296 S: ToSocketAddrs;
297
298 #[cfg(not(feature = "server"))]
300 #[cfg_attr(docsrs, doc(cfg(not(feature = "server"))))]
301 fn bind<S>(laddrs: S) -> std::result::Result<Self, Self::Error>
302 where
303 S: ToSocketAddrs;
304
305 fn local_addrs(&self) -> impl Iterator<Item = &SocketAddr>;
307}
308
309#[cfg(feature = "server")]
310#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
311mod acceptor;
312#[cfg(feature = "server")]
313pub use acceptor::*;
314
315pub use quiche;