use std::future::Future; use std::io::ErrorKind; use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; use futures_util::stream; use tokio::net::{TcpListener, TcpStream}; use tokio::sync::Mutex as AsyncMutex; use crate::async_stream::AsyncStream; use crate::bytes::Bytes; use crate::endpoint::Endpoint; use crate::resource::{Pull, read_limit}; #[derive(Clone, Debug)] pub struct Listener(Arc>); impl Listener { pub fn close(&self) -> Result<(), String> { self.0.close() } } #[derive(Debug)] struct SocketState { endpoint: Endpoint, reader: AsyncMutex<()>, writer: AsyncMutex<()>, timeout_millis: AtomicU64, } #[derive(Clone, Debug)] pub struct Socket(Arc); impl Socket { fn new(stream: TcpStream) -> Self { Self(Arc::new(SocketState { endpoint: Endpoint::new(stream), reader: AsyncMutex::new(()), writer: AsyncMutex::new(()), timeout_millis: AtomicU64::new(0), })) } pub fn close(&self) -> Result<(), String> { self.0.endpoint.close() } async fn operation( &self, operation: impl Future>, ) -> Result { let operation = self.0.endpoint.while_open(operation); match self.0.timeout_millis.load(Ordering::Relaxed) { 0 => operation.await, millis => timed(Duration::from_millis(millis), operation).await, } } } pub async fn connect(host: &str, port: i64) -> Result { connect_stream(host, port).await.map(Socket::new) } pub(crate) async fn connect_stream(host: &str, port: i64) -> Result { let addresses = addresses(host, port).await?; let stream = TcpStream::connect(addresses.as_slice()) .await .map_err(|error| error.to_string())?; prepare_stream(stream) } pub async fn connect_timeout(address: &str, port: i64, millis: i64) -> Result { connect_stream_timeout(address, port, millis) .await .map(Socket::new) } pub(crate) async fn connect_stream_timeout( address: &str, port: i64, millis: i64, ) -> Result { let address = address .parse::() .map_err(|_| "timed connect requires a numeric IP address")?; let address = SocketAddr::new(address, port_number(port)?); timed(timeout_duration(millis)?, async { let stream = TcpStream::connect(address) .await .map_err(|error| error.to_string())?; prepare_stream(stream) }) .await } pub async fn listen(host: &str, port: i64) -> Result { let addresses = addresses(host, port).await?; let listener = TcpListener::bind(addresses.as_slice()) .await .map_err(|error| error.to_string())?; Ok(Listener(Arc::new(Endpoint::new(listener)))) } pub async fn accept(listener: &Listener) -> Result { accept_stream(listener).await.map(Socket::new) } async fn accept_stream(listener: &Listener) -> Result { let socket = listener.0.get()?; listener .0 .while_open(async { let (stream, _) = socket.accept().await.map_err(|error| error.to_string())?; prepare_stream(stream) }) .await } pub fn port(listener: &Listener) -> Result { listener .0 .get()? .local_addr() .map(|address| i64::from(address.port())) .map_err(|error| error.to_string()) } fn prepare_stream(stream: TcpStream) -> Result { stream .set_nodelay(true) .map_err(|error| error.to_string())?; Ok(stream) } pub fn timeout(socket: &Socket, millis: i64) -> Result<(), String> { let duration = timeout_duration(millis)?; socket.0.endpoint.get()?; socket .0 .timeout_millis .store(duration.as_millis() as u64, Ordering::Relaxed); Ok(()) } pub async fn read(socket: &Socket, limit: i64) -> Result, String> { let limit = read_limit(limit)?; let stream = socket.0.endpoint.get()?; socket .operation(async { let _reader = socket.0.reader.lock().await; // 等待读锁和可读事件后再分配缓冲区,避免等待者各占一份内存。 stream.readable().await.map_err(|error| error.to_string())?; let mut bytes = Vec::new(); bytes .try_reserve_exact(limit) .map_err(|error| error.to_string())?; bytes.resize(limit, 0); loop { match stream.try_read(&mut bytes) { Ok(length) => { bytes.truncate(length); return Ok((length != 0).then(|| Bytes::new(bytes))); } Err(error) if error.kind() == ErrorKind::WouldBlock => { stream.readable().await.map_err(|error| error.to_string())?; } Err(error) => return Err(error.to_string()), } } }) .await } // 部分写入中断时先关闭连接,再释放写锁,阻止下一次写入接在残缺内容后。 struct WriteProgress<'a> { socket: &'a Socket, partial: bool, } impl Drop for WriteProgress<'_> { fn drop(&mut self) { if self.partial { let _ = self.socket.close(); } } } pub async fn write(socket: &Socket, bytes: &Bytes) -> Result<(), String> { let stream = socket.0.endpoint.get()?; socket .operation(async { let _writer = socket.0.writer.lock().await; let mut progress = WriteProgress { socket, partial: false, }; let mut offset = 0; while offset < bytes.values().len() { stream.writable().await.map_err(|error| error.to_string())?; match stream.try_write(&bytes.values()[offset..]) { Ok(0) => return Err("socket write returned zero bytes".into()), Ok(length) => { offset += length; progress.partial = offset < bytes.values().len(); } Err(error) if error.kind() == ErrorKind::WouldBlock => {} Err(error) => return Err(error.to_string()), } } Ok(()) }) .await } pub fn connections(listener: Listener) -> AsyncStream> { incoming(listener, false).map(|connection| connection.map(Socket::new)) } pub(crate) fn incoming( listener: Listener, end_on_close: bool, ) -> AsyncStream> { AsyncStream::new(stream::unfold(listener, move |listener| async move { let result = tokio::select! { biased; _ = listener.closed(), if end_on_close => return None, result = accept_stream(&listener) => result, }; let event = match result { Ok(socket) => Pull::Item(Ok(socket)), Err(error) => Pull::Last(Err(error)), }; Some((event, listener)) })) } impl Listener { pub(crate) async fn closed(&self) { self.0.closed().await; } } pub fn chunks(socket: Socket, limit: i64) -> Result>, String> { read_limit(limit)?; socket.0.endpoint.get()?; Ok(AsyncStream::new(stream::unfold( socket, move |socket| async move { let event = match read(&socket, limit).await { Ok(Some(bytes)) => Pull::Item(Ok(bytes)), Ok(None) => return None, Err(error) => Pull::Last(Err(error)), }; Some((event, socket)) }, ))) } async fn addresses(host: &str, port: i64) -> Result, String> { let port = port_number(port)?; if let Ok(address) = host.parse::() { return Ok(vec![SocketAddr::new(address, port)]); } let host = host.to_owned(); // DNS 复用有界 blocking 通道及其结构化清理。 crate::task::blocking(move || { (host.as_str(), port) .to_socket_addrs() .map(Iterator::collect) .map_err(|error| error.to_string()) }) .await } fn port_number(port: i64) -> Result { u16::try_from(port).map_err(|_| "port must be between 0 and 65535".into()) } fn timeout_duration(millis: i64) -> Result { let millis = u64::try_from(millis) .ok() .filter(|millis| *millis > 0) .ok_or("timeout must be a positive Int")?; Ok(Duration::from_millis(millis)) } async fn timed( duration: Duration, operation: impl Future>, ) -> Result { tokio::time::timeout(duration, operation) .await .map_err(|_| "network operation timed out".to_owned())? }