use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
use crate::net::{NetworkAddress, NetworkTarget};
use crate::{Protocol, SessionConnector};
mod codec;
mod message;
mod sink;
mod stream;
pub use codec::PayloadCodec;
use message::PayloadMessage;
use sink::PayloadSink;
use stream::PayloadStream;
pub type TcpPayload = Payload<OwnedReadHalf, OwnedWriteHalf>;
pub struct Payload<R: AsyncRead, W: AsyncWrite> {
stream: PayloadStream<R>,
sink: PayloadSink<W>,
}
impl<R: AsyncRead, W: AsyncWrite> Payload<R, W> {
pub fn new(id: u64, src: R, dst: W, parent_mss: usize) -> Self {
Self {
stream: PayloadStream::new(id, src, parent_mss),
sink: PayloadSink::new(id, dst),
}
}
}
impl<R: AsyncRead, W: AsyncWrite> Protocol for Payload<R, W> {
type Message = PayloadMessage;
type Codec = PayloadCodec;
type StreamHalf = PayloadStream<R>;
type SinkHalf = PayloadSink<W>;
fn into_split(self) -> (Self::StreamHalf, Self::SinkHalf) {
(self.stream, self.sink)
}
fn codec() -> Self::Codec {
PayloadCodec::new()
}
}
#[derive(Clone)]
pub struct TcpPayloadFactory {
parent_mss: usize,
}
impl TcpPayloadFactory {
pub fn new(parent_mss: usize) -> Self {
Self { parent_mss }
}
}
impl SessionConnector for TcpPayloadFactory {
type Item = TcpPayload;
fn connect(
&self,
id: u64,
target: NetworkTarget,
) -> impl Future<Output = (u64, std::io::Result<Self::Item>)> + Send + 'static {
let mss = self.parent_mss;
async move {
let result = match target.addr() {
NetworkAddress::IpAddr(ip) => TcpStream::connect((ip, target.port())).await,
NetworkAddress::Name(name) => TcpStream::connect((name, target.port())).await,
};
let result = result.map(|tcp_stream| {
let (src, dst) = tcp_stream.into_split();
Payload::new(id, src, dst, mss)
});
(id, result)
}
}
}
#[cfg(test)]
pub mod tests {
use tokio_test::assert_ok;
use crate::FrameSize;
use crate::proto::payload::Payload;
use crate::proto::payload::codec::PayloadCodec;
use crate::test::{TestNetwork, TestPayload};
#[tokio::test]
async fn valid_io_flow() {
const SESSION_ID: u64 = 5;
for (c_io, s_io, len) in TestPayload::iter() {
let (c_r, c_w) = tokio::io::split(c_io);
let client = Payload::new(SESSION_ID, c_r, c_w, PayloadCodec::mtu());
let (s_r, s_w) = tokio::io::split(s_io);
let server = Payload::new(SESSION_ID, s_r, s_w, PayloadCodec::mtu());
let network = TestNetwork::new(client, server);
let (c_to_s_result, s_to_c_result) = network.run().await;
assert_ok!(c_to_s_result);
assert_ok!(s_to_c_result);
assert!(c_to_s_result.unwrap() >= len);
assert!(s_to_c_result.unwrap() >= len);
}
}
}