mirror of
https://github.com/aramperes/onetun.git
synced 2025-09-09 05:58:31 -04:00
Graceful shutdown. Docs.
This commit is contained in:
parent
8243945970
commit
006a1b0b4e
4 changed files with 40 additions and 2 deletions
29
src/main.rs
29
src/main.rs
|
@ -298,11 +298,20 @@ async fn virtual_tcp_interface(
|
||||||
let _server_handle = socket_set.add(server_socket?);
|
let _server_handle = socket_set.add(server_socket?);
|
||||||
let client_handle = socket_set.add(client_socket?);
|
let client_handle = socket_set.add(client_socket?);
|
||||||
|
|
||||||
|
let mut graceful_shutdown = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let loop_start = smoltcp::time::Instant::now();
|
let loop_start = smoltcp::time::Instant::now();
|
||||||
|
let forceful_shutdown = abort.load(Ordering::Relaxed);
|
||||||
|
|
||||||
if abort.load(Ordering::Relaxed) {
|
if forceful_shutdown {
|
||||||
break;
|
// Un-graceful shutdown: sends a RST packet.
|
||||||
|
trace!(
|
||||||
|
"[{}] Forcefully shutting down virtual interface",
|
||||||
|
virtual_port
|
||||||
|
);
|
||||||
|
let mut client_socket = socket_set.get::<TcpSocket>(client_handle);
|
||||||
|
client_socket.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
match virtual_interface.poll(&mut socket_set, loop_start) {
|
match virtual_interface.poll(&mut socket_set, loop_start) {
|
||||||
|
@ -347,10 +356,26 @@ async fn virtual_tcp_interface(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !graceful_shutdown && !forceful_shutdown && !client_socket.is_active() {
|
||||||
|
// Graceful shutdown
|
||||||
|
client_socket.close();
|
||||||
|
trace!(
|
||||||
|
"[{}] Gracefully shutting down virtual interface",
|
||||||
|
virtual_port
|
||||||
|
);
|
||||||
|
// We don't break the loop right away so that the FIN segment can be sent in the next poll.
|
||||||
|
graceful_shutdown = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if graceful_shutdown || forceful_shutdown {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::time::sleep(Duration::from_millis(1)).await;
|
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||||
}
|
}
|
||||||
trace!("[{}] Virtual interface task terminated", virtual_port);
|
trace!("[{}] Virtual interface task terminated", virtual_port);
|
||||||
|
abort.store(true, Ordering::Relaxed);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ const MIN_PORT: u16 = 32768;
|
||||||
const MAX_PORT: u16 = 60999;
|
const MAX_PORT: u16 = 60999;
|
||||||
const PORT_RANGE: Range<u16> = MIN_PORT..MAX_PORT;
|
const PORT_RANGE: Range<u16> = MIN_PORT..MAX_PORT;
|
||||||
|
|
||||||
|
/// A pool of virtual ports available.
|
||||||
|
/// This structure is thread-safe and lock-free; you can use it safely in an `Arc`.
|
||||||
pub struct PortPool {
|
pub struct PortPool {
|
||||||
/// Remaining ports
|
/// Remaining ports
|
||||||
inner: lockfree::queue::Queue<u16>,
|
inner: lockfree::queue::Queue<u16>,
|
||||||
|
@ -20,6 +22,7 @@ impl Default for PortPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PortPool {
|
impl PortPool {
|
||||||
|
/// Initializes a new pool of virtual ports.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let inner = lockfree::queue::Queue::default();
|
let inner = lockfree::queue::Queue::default();
|
||||||
PORT_RANGE.for_each(|p| inner.push(p) as ());
|
PORT_RANGE.for_each(|p| inner.push(p) as ());
|
||||||
|
@ -29,6 +32,7 @@ impl PortPool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Requests a free port from the pool. An error is returned if none is available (exhaused max capacity).
|
||||||
pub fn next(&self) -> anyhow::Result<u16> {
|
pub fn next(&self) -> anyhow::Result<u16> {
|
||||||
let port = self
|
let port = self
|
||||||
.inner
|
.inner
|
||||||
|
@ -41,11 +45,13 @@ impl PortPool {
|
||||||
Ok(port)
|
Ok(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Releases a port back into the pool.
|
||||||
pub fn release(&self, port: u16) {
|
pub fn release(&self, port: u16) {
|
||||||
self.inner.push(port);
|
self.inner.push(port);
|
||||||
self.taken.remove(&port);
|
self.taken.remove(&port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the given port is in use by a virtual interface.
|
||||||
pub fn is_in_use(&self, port: u16) -> bool {
|
pub fn is_in_use(&self, port: u16) -> bool {
|
||||||
self.taken.contains(&port)
|
self.taken.contains(&port)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,13 @@ use smoltcp::phy::{Device, DeviceCapabilities, Medium};
|
||||||
use smoltcp::time::Instant;
|
use smoltcp::time::Instant;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// A virtual device that processes IP packets. IP packets received from the WireGuard endpoint
|
||||||
|
/// are made available to this device using a broadcast channel receiver. IP packets sent from this device
|
||||||
|
/// are asynchronously sent out to the WireGuard tunnel.
|
||||||
pub struct VirtualIpDevice {
|
pub struct VirtualIpDevice {
|
||||||
/// Tunnel to send IP packets to.
|
/// Tunnel to send IP packets to.
|
||||||
wg: Arc<WireGuardTunnel>,
|
wg: Arc<WireGuardTunnel>,
|
||||||
|
/// Broadcast channel receiver for received IP packets.
|
||||||
ip_broadcast_rx: tokio::sync::broadcast::Receiver<Vec<u8>>,
|
ip_broadcast_rx: tokio::sync::broadcast::Receiver<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ use crate::MAX_PACKET;
|
||||||
/// The capacity of the broadcast channel for received IP packets.
|
/// The capacity of the broadcast channel for received IP packets.
|
||||||
const BROADCAST_CAPACITY: usize = 1_000;
|
const BROADCAST_CAPACITY: usize = 1_000;
|
||||||
|
|
||||||
|
/// A WireGuard tunnel. Encapsulates and decapsulates IP packets
|
||||||
|
/// to be sent to and received from a remote UDP endpoint.
|
||||||
|
/// This tunnel supports at most 1 peer IP at a time, but supports simultaneous ports.
|
||||||
pub struct WireGuardTunnel {
|
pub struct WireGuardTunnel {
|
||||||
source_peer_ip: IpAddr,
|
source_peer_ip: IpAddr,
|
||||||
/// `boringtun` peer/tunnel implementation, used for crypto & WG protocol.
|
/// `boringtun` peer/tunnel implementation, used for crypto & WG protocol.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue