mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-09-30 14:20:52 +00:00

Before this commit, anything that touched RawSocket or TapInterface worked partly by accident and partly because of a horrible crutch that resulted in massive latencies as well as inevitable packet loss every time an ARP request had to be issued. Also, there was no way to use poll() other than by continuously calling it in a busy loop. After this commit, poll() indicates when the earliest timer expires, and so the caller can sleep until that moment (or until packets arrive). Note that there is a subtle problem remaining: every time poll() is called, every socket with a pending outbound packet whose IP address doesn't correspond to a MAC address will send a new ARP request, resulting in potentially a whole lot of such requests. ARP rate limiting is a separate topic though.
96 lines
3.4 KiB
Rust
96 lines
3.4 KiB
Rust
#[macro_use]
|
|
extern crate log;
|
|
extern crate env_logger;
|
|
extern crate getopts;
|
|
extern crate smoltcp;
|
|
|
|
mod utils;
|
|
|
|
use std::str::{self, FromStr};
|
|
use std::time::Instant;
|
|
use std::os::unix::io::AsRawFd;
|
|
use smoltcp::phy::wait as phy_wait;
|
|
use smoltcp::wire::{EthernetAddress, IpAddress};
|
|
use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
|
|
use smoltcp::socket::{AsSocket, SocketSet};
|
|
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
|
|
|
|
fn main() {
|
|
utils::setup_logging("");
|
|
|
|
let (mut opts, mut free) = utils::create_options();
|
|
utils::add_tap_options(&mut opts, &mut free);
|
|
utils::add_middleware_options(&mut opts, &mut free);
|
|
free.push("ADDRESS");
|
|
free.push("PORT");
|
|
|
|
let mut matches = utils::parse_options(&opts, free);
|
|
let device = utils::parse_tap_options(&mut matches);
|
|
let fd = device.as_raw_fd();
|
|
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
|
|
let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
|
|
let port = u16::from_str(&matches.free[1]).expect("invalid port format");
|
|
|
|
let startup_time = Instant::now();
|
|
|
|
let arp_cache = SliceArpCache::new(vec![Default::default(); 8]);
|
|
|
|
let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 64]);
|
|
let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 128]);
|
|
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
|
|
|
|
let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
|
let protocol_addr = IpAddress::v4(192, 168, 69, 2);
|
|
let mut iface = EthernetInterface::new(
|
|
Box::new(device), Box::new(arp_cache) as Box<ArpCache>,
|
|
hardware_addr, [protocol_addr]);
|
|
|
|
let mut sockets = SocketSet::new(vec![]);
|
|
let tcp_handle = sockets.add(tcp_socket);
|
|
|
|
{
|
|
let socket: &mut TcpSocket = sockets.get_mut(tcp_handle).as_socket();
|
|
socket.connect((address, port), (protocol_addr, 49500)).unwrap();
|
|
}
|
|
|
|
let mut tcp_active = false;
|
|
loop {
|
|
{
|
|
let socket: &mut TcpSocket = sockets.get_mut(tcp_handle).as_socket();
|
|
if socket.is_active() && !tcp_active {
|
|
debug!("connected");
|
|
} else if !socket.is_active() && tcp_active {
|
|
debug!("disconnected");
|
|
break
|
|
}
|
|
tcp_active = socket.is_active();
|
|
|
|
if socket.may_recv() {
|
|
let data = {
|
|
let mut data = socket.recv(128).unwrap().to_owned();
|
|
if data.len() > 0 {
|
|
debug!("recv data: {:?}",
|
|
str::from_utf8(data.as_ref()).unwrap_or("(invalid utf8)"));
|
|
data = data.split(|&b| b == b'\n').collect::<Vec<_>>().concat();
|
|
data.reverse();
|
|
data.extend(b"\n");
|
|
}
|
|
data
|
|
};
|
|
if socket.can_send() && data.len() > 0 {
|
|
debug!("send data: {:?}",
|
|
str::from_utf8(data.as_ref()).unwrap_or("(invalid utf8)"));
|
|
socket.send_slice(&data[..]).unwrap();
|
|
}
|
|
} else if socket.may_send() {
|
|
debug!("close");
|
|
socket.close();
|
|
}
|
|
}
|
|
|
|
let timestamp = utils::millis_since(startup_time);
|
|
let poll_at = iface.poll(&mut sockets, timestamp).expect("poll error");
|
|
phy_wait(fd, poll_at).expect("wait error");
|
|
}
|
|
}
|