2020-04-01 04:34:32 +08:00
|
|
|
//! async TCP interface
|
|
|
|
//!
|
|
|
|
//! TODO: implement futures AsyncRead/AsyncWrite/Stream/Sink interfaces
|
|
|
|
|
2020-03-31 07:16:58 +08:00
|
|
|
use core::{
|
|
|
|
future::Future,
|
|
|
|
pin::Pin,
|
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
2020-04-02 05:34:53 +08:00
|
|
|
use alloc::vec::Vec;
|
2020-03-31 07:16:58 +08:00
|
|
|
use smoltcp::{
|
2020-04-17 02:28:40 +08:00
|
|
|
Error, Result,
|
2020-03-31 07:16:58 +08:00
|
|
|
socket::{
|
2020-04-01 04:34:32 +08:00
|
|
|
SocketHandle, SocketRef,
|
2020-04-17 02:28:40 +08:00
|
|
|
TcpSocketBuffer, TcpSocket, TcpState,
|
2020-03-31 07:16:58 +08:00
|
|
|
},
|
2020-04-17 02:43:36 +08:00
|
|
|
time::Duration,
|
2020-03-31 07:16:58 +08:00
|
|
|
};
|
2020-04-02 04:55:25 +08:00
|
|
|
use crate::task;
|
2020-03-31 07:16:58 +08:00
|
|
|
use super::Sockets;
|
|
|
|
|
2020-04-01 04:34:32 +08:00
|
|
|
/// References a smoltcp TcpSocket
|
2020-03-31 07:16:58 +08:00
|
|
|
pub struct TcpStream {
|
|
|
|
handle: SocketHandle,
|
|
|
|
}
|
|
|
|
|
2020-04-02 05:34:53 +08:00
|
|
|
/// Wait while letting `$f()` poll a stream's socket
|
2020-04-01 04:34:32 +08:00
|
|
|
macro_rules! poll_stream {
|
|
|
|
($stream: expr, $output: ty, $f: expr) => (async {
|
|
|
|
struct Adhoc<'a> {
|
|
|
|
stream: &'a TcpStream,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Future for Adhoc<'a> {
|
|
|
|
type Output = $output;
|
|
|
|
|
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
let result = self.stream.with_socket($f);
|
|
|
|
if !result.is_ready() {
|
|
|
|
Sockets::register_waker(cx.waker().clone());
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Adhoc { stream: $stream }.await
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-03-31 07:16:58 +08:00
|
|
|
impl TcpStream {
|
2020-04-02 05:34:53 +08:00
|
|
|
/// Allocates sockets and its buffers, registers it in the
|
|
|
|
/// SocketSet.
|
|
|
|
///
|
|
|
|
/// Not `pub` as the result can not yet be used. Use `listen()` or
|
|
|
|
/// `connect()` to obtain a valid TcpStream.
|
2020-03-31 07:16:58 +08:00
|
|
|
fn new(rx_bufsize: usize, tx_bufsize: usize) -> Self {
|
2020-04-02 05:21:27 +08:00
|
|
|
fn uninit_vec<T>(size: usize) -> Vec<T> {
|
|
|
|
let mut result = Vec::with_capacity(size);
|
|
|
|
unsafe {
|
|
|
|
result.set_len(size);
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
let rx_buffer = TcpSocketBuffer::new(uninit_vec(rx_bufsize));
|
|
|
|
let tx_buffer = TcpSocketBuffer::new(uninit_vec(tx_bufsize));
|
2020-03-31 07:16:58 +08:00
|
|
|
let socket = TcpSocket::new(rx_buffer, tx_buffer);
|
|
|
|
let handle = Sockets::instance().sockets.borrow_mut()
|
|
|
|
.add(socket);
|
|
|
|
TcpStream { handle }
|
|
|
|
}
|
|
|
|
|
2020-04-01 04:34:32 +08:00
|
|
|
/// Operate on the referenced TCP socket
|
2020-03-31 07:16:58 +08:00
|
|
|
fn with_socket<F, R>(&self, f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(SocketRef<TcpSocket>) -> R,
|
|
|
|
{
|
|
|
|
let mut sockets = Sockets::instance().sockets.borrow_mut();
|
|
|
|
let socket_ref = sockets.get::<TcpSocket>(self.handle);
|
|
|
|
f(socket_ref)
|
|
|
|
}
|
|
|
|
|
2020-04-01 04:34:32 +08:00
|
|
|
/// Listen for the next incoming connection on a TCP
|
|
|
|
/// port. Succeeds on connection attempt.
|
2020-04-02 04:55:25 +08:00
|
|
|
///
|
|
|
|
/// Calling this serially in a loop will cause slow/botched
|
|
|
|
/// connection attempts stall any more new connections. Use
|
|
|
|
/// `listen()` with a backlog instead.
|
2020-04-17 02:28:40 +08:00
|
|
|
pub async fn accept(port: u16, rx_bufsize: usize, tx_bufsize: usize) -> Result<Self> {
|
2020-03-31 07:16:58 +08:00
|
|
|
let stream = Self::new(rx_bufsize, tx_bufsize);
|
2020-04-02 05:34:53 +08:00
|
|
|
// Set socket to listen
|
2020-04-17 02:28:40 +08:00
|
|
|
stream.with_socket(|mut s| s.listen(port))?;
|
2020-04-02 05:34:53 +08:00
|
|
|
// Wait for a connection
|
2020-04-02 05:01:48 +08:00
|
|
|
poll_stream!(&stream, (), |socket| {
|
2020-04-17 02:28:40 +08:00
|
|
|
if socket.state() != TcpState::Listen {
|
2020-04-02 05:01:48 +08:00
|
|
|
Poll::Ready(())
|
|
|
|
} else {
|
|
|
|
Poll::Pending
|
|
|
|
}
|
|
|
|
}).await;
|
2020-04-17 02:28:40 +08:00
|
|
|
|
|
|
|
Ok(stream)
|
2020-03-31 07:16:58 +08:00
|
|
|
}
|
|
|
|
|
2020-04-01 04:34:32 +08:00
|
|
|
/// Probe the receive buffer
|
|
|
|
///
|
|
|
|
/// Instead of handing you the data on the heap all at once,
|
|
|
|
/// smoltcp's read interface is wrapped so that your callback can
|
|
|
|
/// just return `Poll::Pending` if there is not enough data
|
|
|
|
/// yet. Likewise, return the amount of bytes consumed from the
|
|
|
|
/// buffer in the `Poll::Ready` result.
|
2020-04-17 02:28:40 +08:00
|
|
|
pub async fn recv<F, R>(&self, f: F) -> Result<R>
|
2020-04-01 04:34:32 +08:00
|
|
|
where
|
|
|
|
F: Fn(&[u8]) -> Poll<(usize, R)>,
|
|
|
|
{
|
|
|
|
struct Recv<'a, F: FnOnce(&[u8]) -> Poll<(usize, R)>, R> {
|
|
|
|
stream: &'a TcpStream,
|
|
|
|
f: F,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, F: Fn(&[u8]) -> Poll<(usize, R)>, R> Future for Recv<'a, F, R> {
|
2020-04-17 02:28:40 +08:00
|
|
|
type Output = Result<R>;
|
2020-04-01 04:34:32 +08:00
|
|
|
|
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
let result = self.stream.with_socket(|mut socket| {
|
2020-04-17 02:28:40 +08:00
|
|
|
if socket_is_handhshaking(&socket) {
|
|
|
|
return Ok(Poll::Pending);
|
|
|
|
}
|
|
|
|
|
2020-04-15 09:16:25 +08:00
|
|
|
socket.recv(|buf| {
|
|
|
|
if buf.len() > 0 {
|
|
|
|
match (self.f)(buf) {
|
|
|
|
Poll::Ready((amount, result)) =>
|
|
|
|
(amount, Poll::Ready(Ok(result))),
|
|
|
|
Poll::Pending =>
|
|
|
|
// 0 bytes consumed
|
|
|
|
(0, Poll::Pending),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
(0, Poll::Pending)
|
|
|
|
}
|
2020-04-01 04:34:32 +08:00
|
|
|
})
|
|
|
|
});
|
|
|
|
match result {
|
2020-04-17 02:28:40 +08:00
|
|
|
Ok(Poll::Pending) => {
|
|
|
|
Sockets::register_waker(cx.waker().clone());
|
|
|
|
Poll::Pending
|
|
|
|
}
|
2020-04-01 04:34:32 +08:00
|
|
|
Ok(result) => {
|
|
|
|
result
|
|
|
|
}
|
|
|
|
Err(e) =>
|
|
|
|
Poll::Ready(Err(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Recv {
|
|
|
|
stream: self,
|
|
|
|
f,
|
|
|
|
}.await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Wait until there is any space in the socket's send queue
|
2020-04-17 02:28:40 +08:00
|
|
|
async fn wait_can_send(&self) -> Result<()> {
|
|
|
|
poll_stream!(self, Result<()>, |socket| {
|
|
|
|
if socket_is_handhshaking(&socket) {
|
|
|
|
Poll::Pending
|
2020-04-01 04:34:32 +08:00
|
|
|
} else if socket.can_send() {
|
|
|
|
Poll::Ready(Ok(()))
|
2020-04-17 02:28:40 +08:00
|
|
|
} else if ! socket.may_send() {
|
|
|
|
Poll::Ready(Err(Error::Truncated))
|
2020-04-01 04:34:32 +08:00
|
|
|
} else {
|
|
|
|
Poll::Pending
|
|
|
|
}
|
|
|
|
}).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Yields to wait for more buffer space
|
2020-04-17 02:28:40 +08:00
|
|
|
pub async fn send<I: IntoIterator<Item = u8>>(&self, data: I) -> Result<()> {
|
2020-04-01 04:34:32 +08:00
|
|
|
let mut data = data.into_iter();
|
|
|
|
let mut done = false;
|
|
|
|
while !done {
|
|
|
|
self.wait_can_send().await?;
|
|
|
|
|
|
|
|
self.with_socket(|mut socket| {
|
|
|
|
socket.send(|buf| {
|
|
|
|
for i in 0..buf.len() {
|
|
|
|
if let Some(byte) = data.next() {
|
|
|
|
buf[i] = byte;
|
|
|
|
} else {
|
|
|
|
done = true;
|
|
|
|
return (i, ())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(buf.len(), ())
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-06-18 07:56:49 +08:00
|
|
|
/// Yields to wait for more buffer space
|
|
|
|
pub async fn send_slice(&self, mut data: &'_ [u8]) -> Result<()> {
|
|
|
|
while data.len() > 0 {
|
|
|
|
self.wait_can_send().await?;
|
|
|
|
|
|
|
|
data = self.with_socket(|mut socket| {
|
|
|
|
socket.send(|buf| {
|
|
|
|
let len = buf.len().min(data.len());
|
|
|
|
buf[..len].copy_from_slice(&data[..len]);
|
|
|
|
data = &data[len..];
|
|
|
|
(len, data)
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-04-01 04:34:32 +08:00
|
|
|
/// Wait for all queued data to be sent and ACKed
|
|
|
|
///
|
|
|
|
/// **Warning:** this may not work as immediately as expected! The
|
|
|
|
/// other side may wait until it sends packets to you for
|
|
|
|
/// piggybacking the ACKs.
|
2020-04-17 02:28:40 +08:00
|
|
|
pub async fn flush(&self) -> Result<()> {
|
|
|
|
poll_stream!(self, Result<()>, |socket| {
|
|
|
|
if socket_is_handhshaking(&socket) {
|
2020-04-01 04:34:32 +08:00
|
|
|
Poll::Pending
|
2020-04-17 02:28:40 +08:00
|
|
|
} else if socket.may_send() && socket.send_queue() > 0 {
|
|
|
|
Poll::Pending
|
|
|
|
} else if socket.may_send() {
|
|
|
|
Poll::Ready(Ok(()))
|
2020-04-01 04:34:32 +08:00
|
|
|
} else {
|
2020-04-17 02:28:40 +08:00
|
|
|
Poll::Ready(Err(Error::Truncated))
|
2020-04-01 04:34:32 +08:00
|
|
|
}
|
|
|
|
}).await
|
2020-03-31 07:16:58 +08:00
|
|
|
}
|
2020-04-17 02:43:36 +08:00
|
|
|
|
|
|
|
/// Close the transmit half of the connection
|
|
|
|
pub async fn close(&self) {
|
|
|
|
self.with_socket(|mut socket| socket.close());
|
|
|
|
|
|
|
|
// Yield for one iface.poll() to send the packet
|
|
|
|
task::r#yield().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Destroy the socket, sending the RST
|
|
|
|
pub async fn abort(self) {
|
|
|
|
self.with_socket(|mut socket| socket.abort());
|
|
|
|
|
|
|
|
// Yield for one iface.poll() to send the packet
|
|
|
|
task::r#yield().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn keep_alive(&self) -> Option<Duration> {
|
|
|
|
self.with_socket(|socket| socket.keep_alive())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_keep_alive(&mut self, interval: Option<Duration>) {
|
|
|
|
self.with_socket(|mut socket| socket.set_keep_alive(interval));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn timeout(&self) -> Option<Duration> {
|
|
|
|
self.with_socket(|socket| socket.timeout())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_timeout(&mut self, duration: Option<Duration>) {
|
|
|
|
self.with_socket(|mut socket| socket.set_timeout(duration));
|
|
|
|
}
|
2020-03-31 07:16:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for TcpStream {
|
2020-04-02 05:34:53 +08:00
|
|
|
/// Free item in the socket set, which leads to deallocation of
|
|
|
|
/// the rx/tx buffers associated with this socket.
|
2020-03-31 07:16:58 +08:00
|
|
|
fn drop(&mut self) {
|
|
|
|
Sockets::instance().sockets.borrow_mut()
|
|
|
|
.remove(self.handle);
|
|
|
|
}
|
|
|
|
}
|
2020-04-17 02:28:40 +08:00
|
|
|
|
|
|
|
fn socket_is_handhshaking(socket: &SocketRef<TcpSocket>) -> bool {
|
|
|
|
match socket.state() {
|
|
|
|
TcpState::SynSent | TcpState::SynReceived =>
|
|
|
|
true,
|
|
|
|
_ =>
|
|
|
|
false,
|
|
|
|
}
|
|
|
|
}
|