Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion e2e-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ impl TestConfigBuilder {
self
}

/// Set the gRPC service address.
pub fn grpc_service_address(mut self, address: &str) -> Self {
self.grpc_service_address = address.to_string();
self
}

/// Set the node alias, or `None` to omit it entirely.
pub fn alias(mut self, alias: Option<&str>) -> Self {
self.alias = alias.map(str::to_string);
Expand Down Expand Up @@ -596,7 +602,7 @@ pub fn start_expect_failure(
}
/// Allocate distinct ports outside the default Linux/macOS ephemeral ranges.
/// Allocate each port only once per test process, so stopped servers can restart.
fn reserve_port() -> TcpListener {
pub fn reserve_port() -> TcpListener {
static NEXT_PORT: AtomicU32 = AtomicU32::new(10_000);
loop {
let port = NEXT_PORT.fetch_add(1, Ordering::Relaxed);
Expand Down
14 changes: 13 additions & 1 deletion e2e-tests/tests/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
// licenses.

use e2e_tests::{
start_expect_failure, ChainSource, LdkServerHandle, TestBitcoind, TestConfigBuilder,
reserve_port, start_expect_failure, ChainSource, LdkServerHandle, TestBitcoind,
TestConfigBuilder,
};
use ldk_server_grpc::api::GetNodeInfoRequest;

Expand Down Expand Up @@ -98,6 +99,17 @@ async fn test_config_with_tls_hosts() {
assert!(info.current_best_block.is_some());
}

#[test]
fn test_config_fail_grpc_address_in_use() {
let bitcoind = TestBitcoind::new();
let blocker = reserve_port();
let address = blocker.local_addr().unwrap().to_string();
let stderr = start_expect_failure(&bitcoind, |params| {
TestConfigBuilder::new(params).grpc_service_address(&address).build()
});
assert!(stderr.contains("Failed to bind gRPC service address"), "Unexpected stderr: {stderr}");
}

#[test]
fn test_config_fail_log_file_matches_storage_dir() {
let bitcoind = TestBitcoind::new();
Expand Down
69 changes: 36 additions & 33 deletions ldk-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use log::{debug, error, info, warn};
use prost::Message;
use tokio::net::TcpListener;
use tokio::select;
use tokio::signal::unix::SignalKind;
use tokio::signal::unix::{Signal, SignalKind};
use tokio::sync::broadcast;

use crate::api::node_to_proto_custom_tlv;
Expand Down Expand Up @@ -322,6 +322,30 @@ fn main() {
let (event_sender, _) = broadcast::channel::<EventEnvelope>(1024);
let (shutdown_tx, shutdown_rx) = tokio::sync::watch::channel(false);

// Set up everything that can fail locally before the node starts, so that a failure never
// leaves a running node behind, and handle signals from the start.
let server_config =
match get_or_generate_tls_config(config_file.tls_config, storage_dir.to_str().unwrap()) {
Ok(config) => config,
Err(e) => {
error!("Failed to set up TLS: {e}");
std::process::exit(-1);
},
};
let tls_acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config));

let grpc_listener = match runtime.block_on(TcpListener::bind(config_file.grpc_service_addr)) {
Ok(listener) => listener,
Err(e) => {
error!("Failed to bind gRPC service address {}: {e}", config_file.grpc_service_addr);
std::process::exit(-1);
},
};

let mut sighup_stream = register_signal(&runtime, SignalKind::hangup());
let mut sigterm_stream = register_signal(&runtime, SignalKind::terminate());
let mut sigint_stream = register_signal(&runtime, SignalKind::interrupt());

info!("Starting ldk-server version {FULL_VERSION}");
match node.start() {
Ok(()) => {},
Expand All @@ -343,22 +367,6 @@ fn main() {
}

runtime.block_on(async {
// Register SIGHUP handler for log rotation
let mut sighup_stream = match tokio::signal::unix::signal(SignalKind::hangup()) {
Ok(stream) => stream,
Err(e) => {
error!("Failed to register SIGHUP handler: {e}");
std::process::exit(-1);
}
};

let mut sigterm_stream = match tokio::signal::unix::signal(SignalKind::terminate()) {
Ok(stream) => stream,
Err(e) => {
error!("Failed to register for SIGTERM stream: {e}");
std::process::exit(-1);
}
};
let event_node = Arc::clone(&node);
let mut ready_channel_ids: HashSet<ChannelId> = event_node
.list_channels()
Expand Down Expand Up @@ -398,21 +406,6 @@ fn main() {
None
};

let grpc_listener = TcpListener::bind(config_file.grpc_service_addr)
.await
.expect("Failed to bind listening port");

let server_config = match get_or_generate_tls_config(
config_file.tls_config,
storage_dir.to_str().unwrap(),
) {
Ok(config) => config,
Err(e) => {
error!("Failed to set up TLS: {e}");
std::process::exit(-1);
}
};
let tls_acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config));
info!("gRPC service listening on {}", config_file.grpc_service_addr);

systemd::notify_ready();
Expand Down Expand Up @@ -753,7 +746,7 @@ fn main() {
Err(e) => error!("Failed to accept connection: {}", e),
}
}
_ = tokio::signal::ctrl_c() => {
_ = sigint_stream.recv() => {
info!("Received CTRL-C, shutting down..");
let _ = shutdown_tx.send(true);
break;
Expand All @@ -779,6 +772,16 @@ fn main() {
log::logger().flush();
}

fn register_signal(runtime: &tokio::runtime::Runtime, kind: SignalKind) -> Signal {
match runtime.block_on(async { tokio::signal::unix::signal(kind) }) {
Ok(signal) => signal,
Err(e) => {
error!("Failed to register signal handler for {kind:?}: {e}");
std::process::exit(-1);
},
}
}

fn ensure_no_unsupported_storage_migration(
network_dir: &Path, ldk_node_storage: &LdkNodeStorageConfig,
) -> Result<(), String> {
Expand Down
Loading