2021-04-27 02:02:02 -04:00
|
|
|
use crate::*;
|
|
|
|
|
2021-07-24 01:53:00 -04:00
|
|
|
async fn handle_outgoing_connection(stream: tokio::net::TcpStream, client_addr: &mut Context<'_>, max_stanza_size_bytes: usize) -> Result<()> {
|
|
|
|
info!("{} connected", client_addr.log_from());
|
2021-04-27 02:02:02 -04:00
|
|
|
|
|
|
|
let in_filter = StanzaFilter::new(max_stanza_size_bytes);
|
|
|
|
|
|
|
|
let (in_rd, mut in_wr) = tokio::io::split(stream);
|
|
|
|
|
|
|
|
// we naively read 1 byte at a time, which buffering significantly speeds up
|
|
|
|
//let in_rd = tokio::io::BufReader::with_capacity(IN_BUFFER_SIZE, in_rd);
|
|
|
|
|
|
|
|
// now read to figure out client vs server
|
2022-01-19 01:14:39 -05:00
|
|
|
let (stream_open, is_c2s, in_rd, mut in_filter) = stream_preamble(StanzaReader(in_rd), client_addr, in_filter).await?;
|
2021-07-24 01:53:00 -04:00
|
|
|
client_addr.set_c2s_stream_open(is_c2s, &stream_open);
|
2021-04-27 02:02:02 -04:00
|
|
|
// pull raw reader back out of StanzaReader
|
|
|
|
let mut in_rd = in_rd.0;
|
|
|
|
|
2021-07-24 01:53:00 -04:00
|
|
|
// we require a valid to= here or we fail
|
|
|
|
let to = std::str::from_utf8(stream_open.extract_between(b" to='", b"'").or_else(|_| stream_open.extract_between(b" to=\"", b"\""))?)?;
|
2021-04-27 02:02:02 -04:00
|
|
|
|
2022-01-19 01:14:39 -05:00
|
|
|
let (mut out_wr, mut out_rd, stream_open) = srv_connect(to, is_c2s, &stream_open, &mut in_filter, client_addr).await?;
|
2021-04-27 02:02:02 -04:00
|
|
|
// send server response to client
|
|
|
|
in_wr.write_all(&stream_open).await?;
|
|
|
|
in_wr.flush().await?;
|
|
|
|
drop(stream_open);
|
|
|
|
|
|
|
|
let mut out_buf = [0u8; OUT_BUFFER_SIZE];
|
|
|
|
|
|
|
|
loop {
|
|
|
|
tokio::select! {
|
|
|
|
Ok(buf) = out_rd.next(&mut in_filter) => {
|
|
|
|
match buf {
|
|
|
|
None => break,
|
|
|
|
Some(buf) => {
|
2021-07-24 01:53:00 -04:00
|
|
|
trace!("{} '{}'", client_addr.log_to(), to_str(buf));
|
2021-04-27 02:02:02 -04:00
|
|
|
in_wr.write_all(buf).await?;
|
|
|
|
in_wr.flush().await?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// we could filter outgoing from-client stanzas by size here too by doing same as above
|
|
|
|
// but instead, we'll just send whatever the client sends as it sends it...
|
|
|
|
Ok(n) = in_rd.read(&mut out_buf) => {
|
|
|
|
if n == 0 {
|
|
|
|
break;
|
|
|
|
}
|
2021-07-24 01:53:00 -04:00
|
|
|
trace!("{} '{}'", client_addr.log_from(), to_str(&out_buf[0..n]));
|
2021-04-27 02:02:02 -04:00
|
|
|
out_wr.write_all(&out_buf[0..n]).await?;
|
|
|
|
out_wr.flush().await?;
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-24 01:53:00 -04:00
|
|
|
info!("{} disconnected", client_addr.log_from());
|
2021-04-27 02:02:02 -04:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn spawn_outgoing_listener(local_addr: SocketAddr, max_stanza_size_bytes: usize) -> JoinHandle<Result<()>> {
|
|
|
|
tokio::spawn(async move {
|
|
|
|
let listener = TcpListener::bind(&local_addr).await.die("cannot listen on port/interface");
|
|
|
|
loop {
|
|
|
|
let (stream, client_addr) = listener.accept().await?;
|
|
|
|
tokio::spawn(async move {
|
2021-07-24 01:53:00 -04:00
|
|
|
let mut client_addr = Context::new("unk-out", client_addr);
|
|
|
|
if let Err(e) = handle_outgoing_connection(stream, &mut client_addr, max_stanza_size_bytes).await {
|
|
|
|
error!("{} {}", client_addr.log_from(), e);
|
2021-04-27 02:02:02 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
#[allow(unreachable_code)]
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|