mtorrent_core/utp/
handle.rs1use super::connection::Connection;
2use super::protocol::{Header, TypeVer, dbg_header_extensions};
3use super::udp;
4use bytes::Bytes;
5use futures_util::{FutureExt, Stream, StreamExt};
6use local_async_utils::prelude::*;
7use log::log_enabled;
8use mtorrent_utils::split_stream::SplitStream;
9use std::hash::RandomState;
10use std::io;
11use std::net::SocketAddr;
12use std::ops::Deref;
13use std::pin::Pin;
14use std::rc::Rc;
15use std::task::{Context, Poll, ready};
16use tokio::io::{AsyncRead, AsyncWrite};
17use tokio::sync::mpsc;
18use tokio::task;
19
20#[derive(Debug, Clone)]
23pub struct InboundConnectData(Header);
24
25pub struct InboundListener(local_bounded::Receiver<(SocketAddr, Bytes)>);
28
29impl InboundListener {
30 pub(super) fn new(receiver: local_bounded::Receiver<(SocketAddr, Bytes)>) -> Self {
31 Self(receiver)
32 }
33}
34
35impl Stream for InboundListener {
36 type Item = (SocketAddr, InboundConnectData);
37
38 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
39 let Self(receiver) = self.get_mut();
40 loop {
41 let inbound = ready!(receiver.poll_next_unpin(cx));
42 let Some((source, mut packet)) = inbound else {
43 return Poll::Ready(None);
44 };
45 if let Ok(header) = Header::decode_from(&mut packet) {
46 if log_enabled!(log::Level::Trace) {
47 log::trace!(
48 "InboundListener got {:?} from {source}",
49 dbg_header_extensions(&header, &packet)
50 );
51 }
52 if let TypeVer::Syn = header.type_ver {
53 return Poll::Ready(Some((source, InboundConnectData(header))));
54 }
55 }
56 }
57 }
58}
59
60#[derive(Clone)]
62pub struct EndpointHandle {
63 cmds: mpsc::Sender<udp::Command>,
64 hasher_state: Rc<RandomState>,
65}
66
67impl EndpointHandle {
68 const PIPE_CAPACITY: usize = crate::pwp::MAX_BLOCK_SIZE;
69 const INGRESS_QUEUE: usize = 64;
70
71 pub(super) fn new(cmds: mpsc::Sender<udp::Command>) -> Self {
72 Self {
73 cmds,
74 hasher_state: Rc::new(RandomState::new()),
75 }
76 }
77
78 pub async fn add_outbound_connection(&self, remote_addr: SocketAddr) -> io::Result<DataStream> {
84 let (left, right) = local_pipe::duplex_pipe(Self::PIPE_CAPACITY);
85 let (egress_sender, egress_receiver) = local_bounded::channel(1);
86 let (ingress_sender, ingress_receiver) = local_bounded::channel(Self::INGRESS_QUEUE);
87 let handle = udp::ConnectionHandle::new(egress_receiver, ingress_sender);
88 self.cmds
89 .send(udp::Command::AddConnection((remote_addr, handle)))
90 .await
91 .map_err(|_| io::Error::from(io::ErrorKind::BrokenPipe))?;
92
93 let connection = Connection::outbound(
94 remote_addr,
95 right,
96 ingress_receiver,
97 egress_sender,
98 self.hasher_state.deref(),
99 )
100 .await?;
101 log::debug!("Outbound connection to {remote_addr} established");
102
103 let (notifier, receiver) = local_condvar::condvar();
104 task::spawn_local(connection.run(receiver).inspect(move |result| match result {
105 Ok(()) => {
106 log::debug!("Outbound connection to {remote_addr} closed");
107 }
108 Err(e) => {
109 log::error!("Outbound connection to {remote_addr} exited with error: {e}");
110 }
111 }));
112 Ok(DataStream {
113 pipe: left,
114 _canceller: notifier,
115 })
116 }
117
118 pub async fn add_inbound_connection(
124 &self,
125 remote_addr: SocketAddr,
126 data: InboundConnectData,
127 ) -> io::Result<DataStream> {
128 let InboundConnectData(syn) = data;
129 let (left, right) = local_pipe::duplex_pipe(Self::PIPE_CAPACITY);
130 let (egress_sender, egress_receiver) = local_bounded::channel(1);
131 let (ingress_sender, ingress_receiver) = local_bounded::channel(Self::INGRESS_QUEUE);
132 let handle = udp::ConnectionHandle::new(egress_receiver, ingress_sender);
133 self.cmds
134 .send(udp::Command::AddConnection((remote_addr, handle)))
135 .await
136 .map_err(|_| io::Error::from(io::ErrorKind::BrokenPipe))?;
137
138 let connection =
139 Connection::inbound(remote_addr, right, ingress_receiver, egress_sender, syn).await?;
140 log::debug!("Inbound connection from {remote_addr} established");
141
142 let (notifier, receiver) = local_condvar::condvar();
143 task::spawn_local(connection.run(receiver).inspect(move |result| match result {
144 Ok(()) => {
145 log::debug!("Inbound connection from {remote_addr} closed");
146 }
147 Err(e) => {
148 log::error!("Inbound connection from {remote_addr} exited with error: {e}");
149 }
150 }));
151 Ok(DataStream {
152 pipe: left,
153 _canceller: notifier,
154 })
155 }
156
157 pub async fn reset_connections(&self) {
159 let _ = self.cmds.send(udp::Command::ResetConnections).await;
160 }
161}
162
163#[derive(Debug)]
166pub struct DataStream {
167 pipe: local_pipe::DuplexEnd,
168 _canceller: local_condvar::Sender,
169}
170
171impl AsyncRead for DataStream {
172 fn poll_read(
173 self: Pin<&mut Self>,
174 cx: &mut Context<'_>,
175 buf: &mut tokio::io::ReadBuf<'_>,
176 ) -> Poll<io::Result<()>> {
177 Pin::new(&mut self.get_mut().pipe).poll_read(cx, buf)
178 }
179}
180
181impl AsyncWrite for DataStream {
182 fn poll_write(
183 self: Pin<&mut Self>,
184 cx: &mut Context<'_>,
185 buf: &[u8],
186 ) -> Poll<io::Result<usize>> {
187 Pin::new(&mut self.get_mut().pipe).poll_write(cx, buf)
188 }
189
190 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
191 Pin::new(&mut self.get_mut().pipe).poll_flush(cx)
192 }
193
194 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
195 Pin::new(&mut self.get_mut().pipe).poll_shutdown(cx)
196 }
197
198 fn poll_write_vectored(
199 self: Pin<&mut Self>,
200 cx: &mut Context<'_>,
201 bufs: &[io::IoSlice<'_>],
202 ) -> Poll<io::Result<usize>> {
203 Pin::new(&mut self.get_mut().pipe).poll_write_vectored(cx, bufs)
204 }
205
206 fn is_write_vectored(&self) -> bool {
207 self.pipe.is_write_vectored()
208 }
209}
210
211impl SplitStream for DataStream {
212 type Ingress<'i> = <local_pipe::DuplexEnd as SplitStream>::Ingress<'i>;
213
214 type Egress<'e> = <local_pipe::DuplexEnd as SplitStream>::Egress<'e>;
215
216 fn split(&mut self) -> (Self::Ingress<'_>, Self::Egress<'_>) {
217 self.pipe.split()
218 }
219}