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
34 changes: 34 additions & 0 deletions src/core/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,40 @@ pub enum NetListenConfig {
Unix(UnixListenConfig),
}

impl NetListenConfig {
/// Parse config file prometheus_port format.
pub fn from_prometheus_port_str(s: &str) -> Result<Self, String> {
if let Some(path) = s.strip_prefix("ipc://") {
if path.is_empty() {
return Err(format!("invalid listen address '{s}'; ipc path is empty"));
}

Ok(Self::Unix(UnixListenConfig {
path: path.into(),
mode: None,
user: None,
group: None,
params: HashMap::new(),
}))
Comment thread
jkarneges marked this conversation as resolved.
} else {
let addr = if let Ok(addr) = s.parse::<std::net::SocketAddr>() {
addr
} else if let Ok(port) = s.parse::<u16>() {
std::net::SocketAddr::from(([0, 0, 0, 0], port))
} else {
return Err(format!(
"invalid listen address '{s}'; expected ipc://PATH, IP:PORT, or PORT"
));
};

Ok(Self::Tcp(TcpListenConfig {
addr,
params: HashMap::new(),
}))
}
}
}

impl FromStr for NetListenConfig {
type Err = String;

Expand Down
41 changes: 20 additions & 21 deletions src/core/prometheus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,31 +281,13 @@ async fn handle_connection<S: AsyncRead + AsyncWrite>(

pub mod ffi {
use super::*;
use crate::core::config::NetListenConfig;
use libc::c_char;
use std::ffi::{CStr, CString};

/// Opaque handle to a `prometheus::Registry`, for use across the FFI boundary.
pub enum PrometheusRegistry {}

fn parse_listen_addr(addr: &str) -> Result<NetListener, String> {
if let Some(path) = addr.strip_prefix("ipc://") {
let l = mio::net::UnixListener::bind(path)
.map_err(|e| format!("failed to bind {path}: {e}"))?;
Ok(NetListener::Unix(l))
} else if let Ok(socket_addr) = addr.parse::<std::net::SocketAddr>() {
let l = mio::net::TcpListener::bind(socket_addr)
.map_err(|e| format!("failed to bind {socket_addr}: {e}"))?;
Ok(NetListener::Tcp(l))
} else if let Ok(port) = addr.parse::<u16>() {
let socket_addr = std::net::SocketAddr::from(([0, 0, 0, 0], port));
let l = mio::net::TcpListener::bind(socket_addr)
.map_err(|e| format!("failed to bind {socket_addr}: {e}"))?;
Ok(NetListener::Tcp(l))
} else {
Err(format!("invalid listen address: {addr}"))
}
}

/// Create and start a prometheus HTTP server listening on `addr`. The provided `registry` is
/// cloned internally so the server is independent of the registry's lifetime. Returns an opaque
/// handle; call `prometheus_server_destroy` when done. On failure, returns null and writes a
Expand All @@ -322,10 +304,27 @@ pub mod ffi {
registry: *const PrometheusRegistry,
error: *mut *const c_char,
) -> *mut PrometheusServer {
let addr = CStr::from_ptr(addr).to_str().expect("invalid addr string");
let addr = match CStr::from_ptr(addr).to_str() {
Ok(addr) => addr,
Err(e) => {
*error = CString::new(format!("invalid listen address: {e}"))
.unwrap_or_default()
.into_raw();
return std::ptr::null_mut();
}
};

let registry = &*(registry as *const prometheus::Registry);

let listener = match parse_listen_addr(addr) {
let config = match NetListenConfig::from_prometheus_port_str(addr) {
Ok(c) => c,
Err(e) => {
*error = CString::new(e).unwrap_or_default().into_raw();
return std::ptr::null_mut();
}
};

let listener = match NetListener::bind_config(&config) {
Ok(l) => l,
Err(e) => {
*error = CString::new(e).unwrap_or_default().into_raw();
Expand Down
Loading