mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Add drop to AdapterStream
This commit is contained in:
@@ -11,8 +11,7 @@
|
|||||||
//! - Optional PCAP packet capture
|
//! - Optional PCAP packet capture
|
||||||
//! - Implements `AsyncRead` and `AsyncWrite` for Tokio compatibility
|
//! - Implements `AsyncRead` and `AsyncWrite` for Tokio compatibility
|
||||||
//!
|
//!
|
||||||
//! # Limitations
|
//! # Limitations (unecessary for CDTunnel)
|
||||||
//! - Only supports one connection at a time
|
|
||||||
//! - No proper sequence number tracking
|
//! - No proper sequence number tracking
|
||||||
//! - No retransmission or congestion control
|
//! - No retransmission or congestion control
|
||||||
//! - Requires 100% reliable underlying transport
|
//! - Requires 100% reliable underlying transport
|
||||||
@@ -22,8 +21,8 @@
|
|||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! use std::net::{IpAddr, Ipv4Addr};
|
//! use std::net::{IpAddr, Ipv4Addr};
|
||||||
//! use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
//! use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
//! use your_crate::tcp::Adapter;
|
//! use idevice::tcp::{adapter::Adapter, stream::AdapterStream};
|
||||||
//! use your_crate::ReadWrite; // Assuming you have a ReadWrite trait
|
//! use idevice::ReadWrite;
|
||||||
//!
|
//!
|
||||||
//! #[tokio::main]
|
//! #[tokio::main]
|
||||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
@@ -39,19 +38,19 @@
|
|||||||
//! adapter.pcap("capture.pcap").await?;
|
//! adapter.pcap("capture.pcap").await?;
|
||||||
//!
|
//!
|
||||||
//! // Connect to remote server
|
//! // Connect to remote server
|
||||||
//! adapter.connect(80).await?;
|
//! let stream = AdapterStream::new(&mut adapter, 80).await?;
|
||||||
//!
|
//!
|
||||||
//! // Send HTTP request
|
//! // Send HTTP request
|
||||||
//! adapter.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n").await?;
|
//! stream.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n").await?;
|
||||||
//! adapter.flush().await?;
|
//! stream.flush().await?;
|
||||||
//!
|
//!
|
||||||
//! // Read response
|
//! // Read response
|
||||||
//! let mut buf = vec![0; 1024];
|
//! let mut buf = vec![0; 1024];
|
||||||
//! let n = adapter.read(&mut buf).await?;
|
//! let n = stream.read(&mut buf).await?;
|
||||||
//! println!("Received: {}", String::from_utf8_lossy(&buf[..n]));
|
//! println!("Received: {}", String::from_utf8_lossy(&buf[..n]));
|
||||||
//!
|
//!
|
||||||
//! // Close connection
|
//! // Close connection
|
||||||
//! adapter.close().await?;
|
//! stream.close().await?;
|
||||||
//!
|
//!
|
||||||
//! Ok(())
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
@@ -59,7 +58,7 @@
|
|||||||
//!
|
//!
|
||||||
//! # Warning
|
//! # Warning
|
||||||
//! This implementation makes significant simplifications and should not be used
|
//! This implementation makes significant simplifications and should not be used
|
||||||
//! in production environments or with unreliable network transports.
|
//! with unreliable network transports.
|
||||||
|
|
||||||
use std::{collections::HashMap, io::ErrorKind, net::IpAddr, path::Path, sync::Arc};
|
use std::{collections::HashMap, io::ErrorKind, net::IpAddr, path::Path, sync::Arc};
|
||||||
|
|
||||||
@@ -106,11 +105,8 @@ impl ConnectionState {
|
|||||||
///
|
///
|
||||||
/// This is an extremely naive, limited, and dangerous TCP stack implementation.
|
/// This is an extremely naive, limited, and dangerous TCP stack implementation.
|
||||||
/// Key limitations:
|
/// Key limitations:
|
||||||
/// - Only one connection can be active at a time
|
|
||||||
/// - ACKs aren't properly tracked and are silently ignored
|
/// - ACKs aren't properly tracked and are silently ignored
|
||||||
/// - Should only be used when the underlying transport is 100% reliable
|
/// - Should only be used when the underlying transport is 100% reliable
|
||||||
///
|
|
||||||
/// The adapter implements `AsyncRead` and `AsyncWrite` for convenient IO operations.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Adapter {
|
pub struct Adapter {
|
||||||
/// The underlying transport connection
|
/// The underlying transport connection
|
||||||
@@ -120,9 +116,10 @@ pub struct Adapter {
|
|||||||
/// The remote peer's IP address
|
/// The remote peer's IP address
|
||||||
peer_ip: IpAddr,
|
peer_ip: IpAddr,
|
||||||
|
|
||||||
|
/// The states of the connections
|
||||||
states: HashMap<u16, ConnectionState>, // host port by state
|
states: HashMap<u16, ConnectionState>, // host port by state
|
||||||
|
dropped: Vec<u16>,
|
||||||
|
|
||||||
// Logging
|
|
||||||
/// Optional PCAP file for packet logging
|
/// Optional PCAP file for packet logging
|
||||||
pcap: Option<Arc<Mutex<tokio::fs::File>>>,
|
pcap: Option<Arc<Mutex<tokio::fs::File>>>,
|
||||||
}
|
}
|
||||||
@@ -136,13 +133,14 @@ impl Adapter {
|
|||||||
/// * `peer_ip` - The remote IP address to connect to
|
/// * `peer_ip` - The remote IP address to connect to
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// A new unconnected `Adapter` instance
|
/// A new `Adapter` instance
|
||||||
pub fn new(peer: Box<dyn ReadWrite>, host_ip: IpAddr, peer_ip: IpAddr) -> Self {
|
pub fn new(peer: Box<dyn ReadWrite>, host_ip: IpAddr, peer_ip: IpAddr) -> Self {
|
||||||
Self {
|
Self {
|
||||||
peer,
|
peer,
|
||||||
host_ip,
|
host_ip,
|
||||||
peer_ip,
|
peer_ip,
|
||||||
states: HashMap::new(),
|
states: HashMap::new(),
|
||||||
|
dropped: Vec::new(),
|
||||||
pcap: None,
|
pcap: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,7 +151,7 @@ impl Adapter {
|
|||||||
/// * `port` - The remote port number to connect to
|
/// * `port` - The remote port number to connect to
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// * `Ok(())` if connection was successful
|
/// * `Ok(u16)` the chosen host port if successful
|
||||||
/// * `Err(std::io::Error)` if connection failed
|
/// * `Err(std::io::Error)` if connection failed
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
@@ -362,6 +360,10 @@ impl Adapter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn connection_drop(&mut self, host_port: u16) {
|
||||||
|
self.dropped.push(host_port);
|
||||||
|
}
|
||||||
|
|
||||||
/// Flushes the packets
|
/// Flushes the packets
|
||||||
pub(crate) async fn write_buffer_flush(&mut self) -> Result<(), std::io::Error> {
|
pub(crate) async fn write_buffer_flush(&mut self) -> Result<(), std::io::Error> {
|
||||||
for (_, state) in self.states.clone() {
|
for (_, state) in self.states.clone() {
|
||||||
@@ -377,6 +379,18 @@ impl Adapter {
|
|||||||
state.write_buffer.clear();
|
state.write_buffer.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since we have extra clocks and we haven't been cancelled by the runtime, let's reap the
|
||||||
|
// dropped connections
|
||||||
|
for d in self.dropped.clone() {
|
||||||
|
if let Some(state) = self.states.remove(&d) {
|
||||||
|
self.close(state.host_port).await.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We can't clear until it's all done, since we can get cancelled by the runtime at any
|
||||||
|
// point.
|
||||||
|
self.dropped.clear();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Jackson Coxson
|
//! A stream for the adapter
|
||||||
|
|
||||||
use std::{future::Future, task::Poll};
|
use std::{future::Future, task::Poll};
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ pub struct AdapterStream<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AdapterStream<'a> {
|
impl<'a> AdapterStream<'a> {
|
||||||
|
/// Connect to the specified port
|
||||||
pub async fn connect(adapter: &'a mut Adapter, port: u16) -> Result<Self, std::io::Error> {
|
pub async fn connect(adapter: &'a mut Adapter, port: u16) -> Result<Self, std::io::Error> {
|
||||||
let host_port = adapter.connect(port).await?;
|
let host_port = adapter.connect(port).await?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@@ -26,6 +27,7 @@ impl<'a> AdapterStream<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gracefully closes the stream
|
||||||
pub async fn close(&mut self) -> Result<(), std::io::Error> {
|
pub async fn close(&mut self) -> Result<(), std::io::Error> {
|
||||||
self.adapter.close(self.host_port).await
|
self.adapter.close(self.host_port).await
|
||||||
}
|
}
|
||||||
@@ -156,3 +158,9 @@ impl AsyncWrite for AdapterStream<'_> {
|
|||||||
future.poll(cx)
|
future.poll(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for AdapterStream<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.adapter.connection_drop(self.host_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user