mirror of
https://github.com/MercuryWorkshop/epoxy-tls.git
synced 2025-05-12 14:00:01 -04:00
threadpercore
This commit is contained in:
parent
400f9c6761
commit
dfb14f5f97
3 changed files with 138 additions and 45 deletions
|
@ -70,6 +70,17 @@ pub enum RuntimeFlavor {
|
||||||
/// Alternate multi-threaded tokio runtime.
|
/// Alternate multi-threaded tokio runtime.
|
||||||
#[cfg(tokio_unstable)]
|
#[cfg(tokio_unstable)]
|
||||||
MultiThreadAlt,
|
MultiThreadAlt,
|
||||||
|
/// Thread-per-core tokio runtimes.
|
||||||
|
ThreadPerCore,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RuntimeFlavor {
|
||||||
|
pub fn is_thread_per_core(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::ThreadPerCore => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BindAddr = (SocketType, String);
|
pub type BindAddr = (SocketType, String);
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
io::{BufReader, Cursor},
|
io::{BufReader, Cursor}, net::SocketAddr, os::fd::AsFd, path::PathBuf, pin::Pin, str::FromStr, sync::Arc
|
||||||
os::fd::AsFd,
|
|
||||||
path::PathBuf,
|
|
||||||
pin::Pin,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
@ -11,7 +7,7 @@ use rustls_pemfile::{certs, private_key};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::{remove_file, try_exists, File},
|
fs::{remove_file, try_exists, File},
|
||||||
io::{AsyncBufRead, AsyncRead, AsyncWrite, ReadHalf, WriteHalf},
|
io::{AsyncBufRead, AsyncRead, AsyncWrite, ReadHalf, WriteHalf},
|
||||||
net::{tcp, unix, TcpListener, TcpStream, UnixListener, UnixStream},
|
net::{tcp, unix, TcpListener, TcpSocket, TcpStream, UnixListener, UnixStream},
|
||||||
};
|
};
|
||||||
use tokio_rustls::{rustls, server::TlsStream, TlsAcceptor};
|
use tokio_rustls::{rustls, server::TlsStream, TlsAcceptor};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -286,9 +282,20 @@ pub enum ServerListener {
|
||||||
|
|
||||||
impl ServerListener {
|
impl ServerListener {
|
||||||
async fn bind_tcp(bind: &BindAddr) -> anyhow::Result<TcpListener> {
|
async fn bind_tcp(bind: &BindAddr) -> anyhow::Result<TcpListener> {
|
||||||
TcpListener::bind(&bind.1)
|
if CONFIG.server.runtime.is_thread_per_core() {
|
||||||
.await
|
let listener = TcpSocket::new_v4()?;
|
||||||
.with_context(|| format!("failed to bind to tcp address `{}`", bind.1))
|
listener
|
||||||
|
.set_reuseport(true)
|
||||||
|
.context("failed to set SO_REUSEPORT")?;
|
||||||
|
listener
|
||||||
|
.bind(SocketAddr::from_str(&bind.1)?)
|
||||||
|
.with_context(|| format!("failed to bind to tcp address `{}`", bind.1))?;
|
||||||
|
Ok(listener.listen(64)?)
|
||||||
|
} else {
|
||||||
|
TcpListener::bind(&bind.1)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to bind to tcp address `{}`", bind.1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn bind_unix(bind: &BindAddr) -> anyhow::Result<UnixListener> {
|
async fn bind_unix(bind: &BindAddr) -> anyhow::Result<UnixListener> {
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
#![deny(clippy::todo)]
|
#![deny(clippy::todo)]
|
||||||
#![allow(unexpected_cfgs)]
|
#![allow(unexpected_cfgs)]
|
||||||
|
|
||||||
use std::{collections::HashMap, fs::read_to_string, net::IpAddr};
|
use std::{collections::HashMap, fs::read_to_string, future::Future, net::IpAddr, pin::Pin};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use config::{validate_config_cache, Cli, Config, RuntimeFlavor, StatsEndpoint};
|
use config::{validate_config_cache, BindAddr, Cli, Config, RuntimeFlavor, StatsEndpoint};
|
||||||
|
use futures_util::{future::select_all, FutureExt, TryFutureExt};
|
||||||
use handle::{handle_wisp, handle_wsproxy, wisp::wispnet::handle_wispnet};
|
use handle::{handle_wisp, handle_wsproxy, wisp::wispnet::handle_wispnet};
|
||||||
use hickory_resolver::{
|
use hickory_resolver::{
|
||||||
config::{NameServerConfigGroup, ResolverConfig, ResolverOpts},
|
config::{NameServerConfigGroup, ResolverConfig, ResolverOpts},
|
||||||
|
@ -15,13 +16,13 @@ use hickory_resolver::{
|
||||||
};
|
};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use listener::ServerListener;
|
use listener::ServerListener;
|
||||||
use log::{error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use route::{route_stats, ServerRouteResult};
|
use route::{route_stats, ServerRouteResult};
|
||||||
use stats::generate_stats;
|
use stats::generate_stats;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
runtime,
|
runtime,
|
||||||
signal::unix::{signal, SignalKind},
|
signal::unix::{signal, SignalKind},
|
||||||
sync::Mutex,
|
sync::{oneshot, Mutex},
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use wisp_mux::packet::ConnectPacket;
|
use wisp_mux::packet::ConnectPacket;
|
||||||
|
@ -134,6 +135,9 @@ fn main() -> Result<()> {
|
||||||
RuntimeFlavor::MultiThread => runtime::Builder::new_multi_thread(),
|
RuntimeFlavor::MultiThread => runtime::Builder::new_multi_thread(),
|
||||||
#[cfg(tokio_unstable)]
|
#[cfg(tokio_unstable)]
|
||||||
RuntimeFlavor::MultiThreadAlt => runtime::Builder::new_multi_thread_alt(),
|
RuntimeFlavor::MultiThreadAlt => runtime::Builder::new_multi_thread_alt(),
|
||||||
|
|
||||||
|
// threadpercore has completely different runtime setup
|
||||||
|
RuntimeFlavor::ThreadPerCore => return threadpercore_main(),
|
||||||
};
|
};
|
||||||
|
|
||||||
builder.enable_all();
|
builder.enable_all();
|
||||||
|
@ -146,7 +150,7 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
async fn async_main() -> Result<()> {
|
async fn async_init() {
|
||||||
#[cfg(feature = "tokio-console")]
|
#[cfg(feature = "tokio-console")]
|
||||||
console_subscriber::init();
|
console_subscriber::init();
|
||||||
|
|
||||||
|
@ -160,20 +164,68 @@ async fn async_main() -> Result<()> {
|
||||||
trace!("CLI: {:#?}", &*CLI);
|
trace!("CLI: {:#?}", &*CLI);
|
||||||
trace!("CONFIG: {:#?}", &*CONFIG);
|
trace!("CONFIG: {:#?}", &*CONFIG);
|
||||||
trace!("RESOLVER: {:?}", &*RESOLVER);
|
trace!("RESOLVER: {:?}", &*RESOLVER);
|
||||||
|
}
|
||||||
|
|
||||||
tokio::spawn(async {
|
#[doc(hidden)]
|
||||||
let mut sig = signal(SignalKind::user_defined1()).unwrap();
|
fn threadpercore_main() -> Result<()> {
|
||||||
while sig.recv().await.is_some() {
|
let rt = runtime::Builder::new_current_thread()
|
||||||
match generate_stats().await {
|
.enable_all()
|
||||||
Ok(stats) => info!("Stats:\n{}", stats),
|
.build()?;
|
||||||
Err(err) => error!("error while creating stats {:?}", err),
|
|
||||||
}
|
rt.block_on(async_init());
|
||||||
|
|
||||||
|
let cores = std::thread::available_parallelism()?.get();
|
||||||
|
|
||||||
|
let mut threads = Vec::with_capacity(cores);
|
||||||
|
|
||||||
|
for _ in 1..cores {
|
||||||
|
threads.push(Box::pin(threadpercore_init_thread(listen_wisp()).map_err(|x| anyhow!(x)).map(|x| x?)) as Pin<Box<dyn Future<Output = Result<()>>>>);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.block_on(async move {
|
||||||
|
tokio::spawn(listen_stats_cli());
|
||||||
|
|
||||||
|
if let Some(bind_addr) = CONFIG
|
||||||
|
.server
|
||||||
|
.stats_endpoint
|
||||||
|
.as_ref()
|
||||||
|
.and_then(StatsEndpoint::get_bindaddr)
|
||||||
|
{
|
||||||
|
tokio::spawn(listen_stats(bind_addr));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
let mut listener = ServerListener::new(&CONFIG.server.bind)
|
let wisp = Box::pin(tokio::spawn(listen_wisp()).map_err(|x| anyhow!(x)).map(|x| x?)) as Pin<Box<dyn Future<Output = Result<()>>>>;
|
||||||
.await
|
|
||||||
.with_context(|| format!("failed to bind to address {}", CONFIG.server.bind.1))?;
|
select_all(threads.into_iter().chain(std::iter::once(wisp))).await.0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn threadpercore_init_thread<T: Send + 'static>(
|
||||||
|
func: impl Future<Output = Result<T>> + Sync + Send + 'static,
|
||||||
|
) -> oneshot::Receiver<Result<T>> {
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let ret = (|| {
|
||||||
|
let rt = runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
debug!("created threadpercore thread");
|
||||||
|
|
||||||
|
rt.block_on(func)
|
||||||
|
})();
|
||||||
|
|
||||||
|
let _ = tx.send(ret.context("thread per core thread failed"));
|
||||||
|
});
|
||||||
|
rx
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
async fn async_main() -> Result<()> {
|
||||||
|
async_init().await;
|
||||||
|
|
||||||
|
tokio::spawn(listen_stats_cli());
|
||||||
|
|
||||||
if let Some(bind_addr) = CONFIG
|
if let Some(bind_addr) = CONFIG
|
||||||
.server
|
.server
|
||||||
|
@ -181,27 +233,50 @@ async fn async_main() -> Result<()> {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(StatsEndpoint::get_bindaddr)
|
.and_then(StatsEndpoint::get_bindaddr)
|
||||||
{
|
{
|
||||||
info!("stats server listening on {:?}", bind_addr);
|
tokio::spawn(listen_stats(bind_addr));
|
||||||
let mut stats_listener = ServerListener::new(&bind_addr).await.with_context(|| {
|
|
||||||
format!("failed to bind to address {} for stats server", bind_addr.1)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
loop {
|
|
||||||
match stats_listener.accept().await {
|
|
||||||
Ok((stream, _)) => {
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = Box::pin(route_stats(stream)).await {
|
|
||||||
error!("error while routing stats client: {:?}", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(e) => error!("error while accepting stats client: {:?}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listen_wisp().await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
async fn listen_stats_cli() {
|
||||||
|
let mut sig = signal(SignalKind::user_defined1()).unwrap();
|
||||||
|
while sig.recv().await.is_some() {
|
||||||
|
match generate_stats().await {
|
||||||
|
Ok(stats) => info!("Stats:\n{}", stats),
|
||||||
|
Err(err) => error!("error while creating stats {:?}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
async fn listen_stats(bind_addr: BindAddr) -> Result<()> {
|
||||||
|
info!("stats server listening on {:?}", bind_addr);
|
||||||
|
let mut stats_listener = ServerListener::new(&bind_addr)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to bind to address {} for stats server", bind_addr.1))?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match stats_listener.accept().await {
|
||||||
|
Ok((stream, _)) => {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = Box::pin(route_stats(stream)).await {
|
||||||
|
error!("error while routing stats client: {:?}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => error!("error while accepting stats client: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
async fn listen_wisp() -> Result<()> {
|
||||||
|
let mut listener = ServerListener::new(&CONFIG.server.bind)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to bind to address {}", CONFIG.server.bind.1))?;
|
||||||
|
|
||||||
let stats_endpoint = CONFIG
|
let stats_endpoint = CONFIG
|
||||||
.server
|
.server
|
||||||
.stats_endpoint
|
.stats_endpoint
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue