use std::time::Duration;
use crate::network_helpers::Error;
use stratum_core::{
codec_sv2::{
Decoded, Decrypted, EncodableFrame, Handshake, HandshakeMessage, NoiseDecoder,
NoiseEncoder, Transport, TransportDecryptState, TransportEncryptState,
state::{ExpectsHandshakeMessage, InitiatorSent},
},
noise_sv2::{AeadError, INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE, Initiator, Responder},
};
use tokio::net::{
TcpStream,
tcp::{OwnedReadHalf, OwnedWriteHalf},
};
use stratum_core::{codec_sv2::SerializedFrame, noise_sv2::ELLSWIFT_ENCODING_SIZE};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tracing::debug;
pub struct NoiseTcpStream {
reader: NoiseTcpReadHalf,
writer: NoiseTcpWriteHalf,
}
pub struct NoiseTcpReadHalf {
reader: OwnedReadHalf,
decoder: NoiseDecoder,
state: Option<TransportDecryptState>,
current_frame_buf: Vec<u8>,
bytes_read: usize,
}
pub struct NoiseTcpWriteHalf {
writer: OwnedWriteHalf,
encoder: NoiseEncoder,
state: TransportEncryptState,
}
impl NoiseTcpStream {
pub async fn connect(
stream: TcpStream,
initiator: Box<Initiator>,
timeout: Duration,
) -> Result<Self, Error> {
let (mut reader, mut writer) = stream.into_split();
let mut decoder = NoiseDecoder::new();
let mut encoder = NoiseEncoder::new();
let handshake = Handshake::initiator(initiator);
let (first_msg, handshake) = handshake.step_0()?;
send_handshake_frame(&mut writer, first_msg, &mut encoder).await?;
debug!("First handshake message sent");
let second_msg =
receive_handshake_frame::<InitiatorSent>(&mut reader, &mut decoder, timeout).await?;
debug!("Second handshake message received");
let payload: [u8; INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE] = second_msg
.payload()
.try_into()
.map_err(|_| Error::HandshakeRemoteInvalidMessage)?;
Ok(Self::from_transport(
reader,
writer,
decoder,
encoder,
handshake.step_2(payload)?,
))
}
pub async fn accept(
stream: TcpStream,
responder: Box<Responder>,
timeout: Duration,
) -> Result<Self, Error> {
let (mut reader, mut writer) = stream.into_split();
let mut decoder = NoiseDecoder::new();
let mut encoder = NoiseEncoder::new();
let handshake = Handshake::responder(responder);
let first_msg =
receive_handshake_frame::<Responder>(&mut reader, &mut decoder, timeout).await?;
debug!("First handshake message received");
let payload: [u8; ELLSWIFT_ENCODING_SIZE] = first_msg
.payload()
.try_into()
.map_err(|_| Error::HandshakeRemoteInvalidMessage)?;
let (second_msg, transport) = handshake.step_1(payload)?;
send_handshake_frame(&mut writer, second_msg, &mut encoder).await?;
debug!("Second handshake message sent");
Ok(Self::from_transport(
reader, writer, decoder, encoder, transport,
))
}
fn from_transport(
reader: OwnedReadHalf,
writer: OwnedWriteHalf,
decoder: NoiseDecoder,
encoder: NoiseEncoder,
transport: Transport,
) -> Self {
let (encrypt_state, decrypt_state) = transport.split();
Self {
reader: NoiseTcpReadHalf {
reader,
decoder,
state: Some(decrypt_state),
current_frame_buf: vec![],
bytes_read: 0,
},
writer: NoiseTcpWriteHalf {
writer,
encoder,
state: encrypt_state,
},
}
}
pub fn into_split(self) -> (NoiseTcpReadHalf, NoiseTcpWriteHalf) {
(self.reader, self.writer)
}
}
impl NoiseTcpWriteHalf {
pub async fn write_frame<F: EncodableFrame>(&mut self, frame: F) -> Result<(), Error> {
let buf = self.encoder.encode_transport(frame, &mut self.state)?;
self.writer
.write_all(buf.as_ref())
.await
.map_err(|_| Error::SocketClosed)?;
Ok(())
}
pub fn try_write_frame<F: EncodableFrame>(&mut self, frame: F) -> Result<bool, Error> {
let buf = self.encoder.encode_transport(frame, &mut self.state)?;
match self.writer.try_write(buf.as_ref()) {
Ok(n) if n == buf.len() => Ok(true),
Ok(_) => Err(Error::SocketClosed),
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(false),
Err(_) => Err(Error::SocketClosed),
}
}
pub async fn shutdown(&mut self) -> Result<(), Error> {
self.writer
.shutdown()
.await
.map_err(|_| Error::SocketClosed)
}
}
impl NoiseTcpReadHalf {
pub async fn read_frame(&mut self) -> Result<SerializedFrame, Error> {
loop {
let expected = self.decoder.writable_len();
if self.current_frame_buf.len() != expected {
self.current_frame_buf.resize(expected, 0);
self.bytes_read = 0;
}
while self.bytes_read < expected {
let n = self
.reader
.read(&mut self.current_frame_buf[self.bytes_read..])
.await
.map_err(|_| Error::SocketClosed)?;
if n == 0 {
return Err(Error::SocketClosed);
}
self.bytes_read += n;
}
self.decoder
.writable()
.copy_from_slice(&self.current_frame_buf[..]);
self.bytes_read = 0;
match self.next_frame()? {
Some(frame) => return Ok(frame),
None => tokio::task::yield_now().await,
}
}
}
pub fn try_read_frame(&mut self) -> Result<Option<SerializedFrame>, Error> {
let expected = self.decoder.writable_len();
if self.current_frame_buf.len() != expected {
self.current_frame_buf.resize(expected, 0);
self.bytes_read = 0;
}
if expected > 0 {
match self
.reader
.try_read(&mut self.current_frame_buf[self.bytes_read..])
{
Ok(0) => return Err(Error::SocketClosed),
Ok(n) => self.bytes_read += n,
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => return Ok(None),
Err(_) => return Err(Error::SocketClosed),
}
if self.bytes_read < expected {
return Ok(None);
}
}
self.decoder
.writable()
.copy_from_slice(&self.current_frame_buf[..]);
self.bytes_read = 0;
self.next_frame()
}
fn next_frame(&mut self) -> Result<Option<SerializedFrame>, Error> {
let state = self
.state
.take()
.ok_or(stratum_core::codec_sv2::Error::AeadError(AeadError))?;
match self.decoder.next_transport_frame(state)? {
Decrypted::Frame(frame, state) => {
self.state = Some(state);
Ok(Some(frame))
}
Decrypted::Incomplete(_, state) => {
self.state = Some(state);
Ok(None)
}
}
}
}
async fn send_handshake_frame(
writer: &mut OwnedWriteHalf,
frame: HandshakeMessage,
encoder: &mut NoiseEncoder,
) -> Result<(), Error> {
let buffer = encoder.encode_handshake(frame);
writer
.write_all(buffer.as_ref())
.await
.map_err(|_| Error::SocketClosed)?;
Ok(())
}
async fn receive_handshake_frame<R: ExpectsHandshakeMessage>(
reader: &mut OwnedReadHalf,
decoder: &mut NoiseDecoder,
timeout: Duration,
) -> Result<HandshakeMessage, Error> {
loop {
let mut buffer = vec![0u8; decoder.writable_len()];
tokio::time::timeout(timeout, reader.read_exact(&mut buffer))
.await
.map_err(|_| Error::HandshakeTimeout)?
.map_err(|_| Error::SocketClosed)?;
decoder.writable().copy_from_slice(&buffer);
match decoder.next_handshake_frame::<R>() {
Ok(Decoded::Frame(frame)) => return Ok(frame),
Ok(Decoded::Incomplete(_)) => {
debug!("Waiting for more bytes during handshake");
}
Err(e) => return Err(Error::CodecError(e)),
}
}
}