Skip to content

Commit 8bdff7a

Browse files
committed
Implement forward_datagrams_in_buffer with split_first_chunk
1 parent 87936ac commit 8bdff7a

File tree

2 files changed

+21
-19
lines changed

2 files changed

+21
-19
lines changed

src/forward_traffic.rs

+20-19
Original file line numberDiff line numberDiff line change
@@ -100,37 +100,38 @@ async fn maybe_timeout<F: Future>(
100100

101101
/// Forward all complete datagrams in `buffer` to `udp_out`.
102102
/// Returns the number of processed bytes.
103-
async fn forward_datagrams_in_buffer(udp_out: &UdpSocket, buffer: &[u8]) -> io::Result<usize> {
104-
let mut header_start = 0;
103+
async fn forward_datagrams_in_buffer(udp_out: &UdpSocket, mut buffer: &[u8]) -> io::Result<usize> {
104+
let original_buffer_len = buffer.len();
105105
loop {
106-
let header_end = header_start + HEADER_LEN;
107-
// "parse" the header
108-
let header = match buffer.get(header_start..header_end) {
109-
Some(header) => <[u8; HEADER_LEN]>::try_from(header).unwrap(),
110-
// Buffer does not contain entire header for next datagram
111-
None => break Ok(header_start),
112-
};
113-
let datagram_len = usize::from(u16::from_be_bytes(header));
114-
let datagram_start = header_end;
115-
let datagram_end = datagram_start + datagram_len;
116-
117-
let datagram_data = match buffer.get(datagram_start..datagram_end) {
118-
Some(datagram_data) => datagram_data,
106+
let (datagram_data, tail) = match split_first_datagram(buffer) {
107+
Some(data_tuple) => data_tuple,
119108
// The buffer does not contain the entire datagram
120-
None => break Ok(header_start),
109+
None => break Ok(original_buffer_len - buffer.len()),
121110
};
122111

123112
let udp_write_len = udp_out.send(datagram_data).await?;
124113
assert_eq!(
125-
udp_write_len, datagram_len,
114+
udp_write_len,
115+
datagram_data.len(),
126116
"Did not send entire UDP datagram"
127117
);
128-
log::trace!("Forwarded {} byte TCP->UDP", datagram_len);
118+
log::trace!("Forwarded {} byte TCP->UDP", datagram_data.len());
129119

130-
header_start = datagram_end;
120+
buffer = tail;
131121
}
132122
}
133123

124+
/// Parses the header at the beginning of the `buffer` and if it contains a full
125+
/// `udp-to-tcp` datagram it splits the buffer and returns the datagram data and
126+
/// buffer tail as two separate slices: `(datagram_data, tail)`
127+
fn split_first_datagram(buffer: &[u8]) -> Option<(&[u8], &[u8])> {
128+
let (header, tail) = buffer.split_first_chunk::<HEADER_LEN>()?;
129+
let datagram_len = usize::from(u16::from_be_bytes(*header));
130+
let datagram_data = tail.get(..datagram_len)?;
131+
let tail = tail.get(datagram_len..)?;
132+
Some((datagram_data, tail))
133+
}
134+
134135
/// Reads datagrams from `udp_in` and writes them (with the 16 bit header containing the length)
135136
/// to `tcp_out` indefinitely, or until an IO error happens on either socket.
136137
async fn process_udp2tcp(

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
8181
#![forbid(unsafe_code)]
8282
#![deny(clippy::all)]
83+
#![feature(slice_first_last_chunk)]
8384

8485
pub mod tcp2udp;
8586
pub mod udp2tcp;

0 commit comments

Comments
 (0)