Skip to content

Commit ff1dd24

Browse files
committed
proxy/handler: rework args handling a little bit
1 parent 72adf51 commit ff1dd24

File tree

5 files changed

+99
-105
lines changed

5 files changed

+99
-105
lines changed

src/core/config.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@ impl CustomConfig {
426426
}
427427
}
428428

429+
pub fn default_config_file() -> PathBuf {
430+
PathBuf::from(env!("CONFIG_DIR")).join("pushpin.conf")
431+
}
432+
429433
pub fn get_config_file(
430434
work_dir: &Path,
431435
arg_config: Option<PathBuf>,
@@ -446,10 +450,7 @@ pub fn get_config_file(
446450
.join("pushpin.conf"),
447451
);
448452
// default
449-
config_files.push(PathBuf::from(format!(
450-
"{}/pushpin.conf",
451-
env!("CONFIG_DIR")
452-
)));
453+
config_files.push(default_config_file());
453454
}
454455
}
455456

src/handler/cliargs.rs

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
use crate::core::config::get_config_file;
17+
use crate::core::config::default_config_file;
1818
use crate::core::version;
1919
use clap::{arg, Parser};
20-
use std::env;
2120
use std::ffi::CString;
2221
use std::path::PathBuf;
2322

@@ -57,17 +56,18 @@ pub struct CliArgs {
5756
impl CliArgs {
5857
/// Verifies the command line arguments.
5958
pub fn verify(mut self) -> Self {
60-
let work_dir = env::current_dir().unwrap_or_default();
61-
let config_path: Option<PathBuf> = self.config_file.as_ref().map(PathBuf::from);
62-
63-
// Resolve the config file path using get_config_file
64-
self.config_file = match get_config_file(&work_dir, config_path) {
65-
Ok(path) => Some(path.to_string_lossy().to_string()),
66-
Err(e) => {
67-
eprintln!("error: failed to find configuration file: {}", e);
68-
std::process::exit(1);
69-
}
70-
};
59+
let config_file = self
60+
.config_file
61+
.map(PathBuf::from)
62+
.unwrap_or_else(default_config_file);
63+
64+
// FIXME: don't put back as a string after resolving
65+
self.config_file = Some(
66+
config_file
67+
.to_str()
68+
.expect("path sourced from string should convert")
69+
.to_string(),
70+
);
7171

7272
if self.verbose {
7373
self.log_level = 3;
@@ -81,12 +81,7 @@ impl CliArgs {
8181
.config_file
8282
.as_ref()
8383
.map_or_else(
84-
|| {
85-
let work_dir = std::env::current_dir().unwrap_or_default();
86-
let default_config = get_config_file(&work_dir, None)
87-
.unwrap_or_else(|_| "examples/config/pushpin.conf".into());
88-
CString::new(default_config.to_string_lossy().to_string()).unwrap()
89-
},
84+
|| CString::new("").unwrap(),
9085
|s| CString::new(s.as_str()).unwrap(),
9186
)
9287
.into_raw();
@@ -120,13 +115,15 @@ impl CliArgs {
120115
}
121116

122117
pub mod ffi {
118+
use std::ffi::{c_char, c_int, c_uint};
119+
123120
#[repr(C)]
124121
pub struct HandlerCliArgs {
125-
pub config_file: *mut libc::c_char,
126-
pub log_file: *mut libc::c_char,
127-
pub log_level: libc::c_uint,
128-
pub ipc_prefix: *mut libc::c_char,
129-
pub port_offset: libc::c_int,
122+
pub config_file: *mut c_char,
123+
pub log_file: *mut c_char,
124+
pub log_level: c_uint,
125+
pub ipc_prefix: *mut c_char,
126+
pub port_offset: c_int,
130127
}
131128
}
132129

@@ -174,8 +171,6 @@ mod tests {
174171
port_offset: Some(8080),
175172
};
176173

177-
let args_ffi = args.to_ffi();
178-
179174
// Test verify() method
180175
let verified_args = args.verify();
181176
assert_eq!(verified_args.config_file, Some(config_test_file.clone()));
@@ -185,6 +180,8 @@ mod tests {
185180
assert_eq!(verified_args.ipc_prefix, Some("ipc".to_string()));
186181
assert_eq!(verified_args.port_offset, Some(8080));
187182

183+
let args_ffi = verified_args.to_ffi();
184+
188185
// Test conversion to C++-compatible struct
189186
unsafe {
190187
assert_eq!(
@@ -224,14 +221,9 @@ mod tests {
224221
port_offset: None,
225222
};
226223

227-
let empty_args_ffi = empty_args.to_ffi();
228-
229224
// Test verify() with empty args
230225
let verified_empty_args = empty_args.verify();
231-
let default_config_file = get_config_file(&env::current_dir().unwrap(), None)
232-
.unwrap()
233-
.to_string_lossy()
234-
.to_string();
226+
let default_config_file = default_config_file().to_str().unwrap().to_string();
235227
assert_eq!(
236228
verified_empty_args.config_file,
237229
Some(default_config_file.clone())
@@ -242,6 +234,8 @@ mod tests {
242234
assert_eq!(verified_empty_args.ipc_prefix, None);
243235
assert_eq!(verified_empty_args.port_offset, None);
244236

237+
let empty_args_ffi = verified_empty_args.to_ffi();
238+
245239
// Test conversion to C++-compatible struct
246240
unsafe {
247241
assert_eq!(

src/handler/handlerapp.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ class HandlerApp::Private
104104
QCoreApplication::setApplicationVersion(Config::get().version);
105105

106106
HandlerArgsData args(argsFfi);
107-
Settings settings(args.configFile);
108-
if (!args.ipcPrefix.isEmpty()) settings.setIpcPrefix(args.ipcPrefix);
109-
if (args.portOffset != -1) settings.setPortOffset(args.portOffset);
110107

111108
// Set the log level
112109
if(args.logLevel != -1)
@@ -131,11 +128,15 @@ class HandlerApp::Private
131128
QFile file(args.configFile);
132129
if(!file.open(QIODevice::ReadOnly))
133130
{
134-
log_error("failed to open %s", qPrintable(args.configFile));
131+
log_error("failed to open config file: %s", qPrintable(args.configFile));
135132
return 1;
136133
}
137134
}
138135

136+
Settings settings(args.configFile);
137+
if (!args.ipcPrefix.isEmpty()) settings.setIpcPrefix(args.ipcPrefix);
138+
if (args.portOffset != -1) settings.setPortOffset(args.portOffset);
139+
139140
QStringList services = settings.value("runner/services").toStringList();
140141

141142
QStringList connmgr_in_stream_specs = settings.value("proxy/connmgr_in_stream_specs").toStringList();

src/proxy/cliargs.rs

Lines changed: 58 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
* limitations under the License.
1515
*/
1616

17-
use crate::core::config::get_config_file;
17+
use crate::core::config::default_config_file;
1818
use crate::core::version;
1919
use clap::{arg, Parser};
20-
use std::env;
21-
use std::ffi::CString;
20+
use std::ffi::{c_char, CString};
2221
use std::path::PathBuf;
22+
use std::slice;
2323

2424
// Struct to hold the command line arguments
2525
#[derive(Parser, Debug)]
@@ -57,17 +57,18 @@ pub struct CliArgs {
5757
impl CliArgs {
5858
/// Verifies the command line arguments.
5959
pub fn verify(mut self) -> Self {
60-
let work_dir = env::current_dir().unwrap_or_default();
61-
let config_path: Option<PathBuf> = self.config_file.as_ref().map(PathBuf::from);
62-
63-
// Resolve the config file path using get_config_file
64-
self.config_file = match get_config_file(&work_dir, config_path) {
65-
Ok(path) => Some(path.to_string_lossy().to_string()),
66-
Err(e) => {
67-
eprintln!("error: failed to find configuration file: {}", e);
68-
std::process::exit(1);
69-
}
70-
};
60+
let config_file = self
61+
.config_file
62+
.map(PathBuf::from)
63+
.unwrap_or_else(default_config_file);
64+
65+
// FIXME: don't put back as a string after resolving
66+
self.config_file = Some(
67+
config_file
68+
.to_str()
69+
.expect("path sourced from string should convert")
70+
.to_string(),
71+
);
7172

7273
if self.verbose {
7374
self.log_level = 3;
@@ -81,12 +82,7 @@ impl CliArgs {
8182
.config_file
8283
.as_ref()
8384
.map_or_else(
84-
|| {
85-
let work_dir = std::env::current_dir().unwrap_or_default();
86-
let default_config = get_config_file(&work_dir, None)
87-
.unwrap_or_else(|_| "examples/config/pushpin.conf".into());
88-
CString::new(default_config.to_string_lossy().to_string()).unwrap()
89-
},
85+
|| CString::new("").unwrap(),
9086
|s| CString::new(s.as_str()).unwrap(),
9187
)
9288
.into_raw();
@@ -109,47 +105,47 @@ impl CliArgs {
109105
)
110106
.into_raw();
111107

112-
let (routes, routes_count) = if !self.route.is_empty() {
113-
// Allocate array of string pointers
114-
let routes_array = unsafe {
115-
libc::malloc(self.route.len() * std::mem::size_of::<*mut libc::c_char>())
116-
as *mut *mut libc::c_char
117-
};
118-
119-
// Convert each route to CString and store pointer in array
120-
for (i, item) in self.route.iter().enumerate() {
121-
let c_string = CString::new(item.to_string()).unwrap().into_raw();
122-
unsafe {
123-
*routes_array.add(i) = c_string;
124-
}
125-
}
126-
127-
(routes_array, self.route.len() as libc::c_uint)
128-
} else {
129-
let routes_array = unsafe { libc::malloc(0) as *mut *mut libc::c_char };
130-
(routes_array, 0)
131-
};
108+
let mut routes: Vec<*mut c_char> = Vec::new();
109+
110+
// Convert each route to CString and store pointer in array
111+
for item in &self.route {
112+
let item = item.as_bytes();
113+
114+
// ensure no trailing nul byte
115+
let end = item.iter().position(|b| *b == 0).unwrap_or(item.len());
116+
let item = &item[..end];
117+
118+
let c_string = CString::new(item).unwrap().into_raw();
119+
routes.push(c_string);
120+
}
121+
122+
let routes = routes.into_boxed_slice();
123+
124+
let routes_count = routes.len();
125+
let routes: *mut [*mut c_char] = Box::into_raw(routes);
132126

133127
ffi::ProxyCliArgs {
134128
config_file,
135129
log_file,
136130
log_level: self.log_level,
137131
ipc_prefix,
138-
routes,
132+
routes: routes as *mut *mut c_char,
139133
routes_count,
140134
}
141135
}
142136
}
143137

144138
pub mod ffi {
139+
use std::ffi::{c_char, c_uint};
140+
145141
#[repr(C)]
146142
pub struct ProxyCliArgs {
147-
pub config_file: *mut libc::c_char,
148-
pub log_file: *mut libc::c_char,
149-
pub log_level: libc::c_uint,
150-
pub ipc_prefix: *mut libc::c_char,
151-
pub routes: *mut *mut libc::c_char,
152-
pub routes_count: libc::c_uint,
143+
pub config_file: *mut c_char,
144+
pub log_file: *mut c_char,
145+
pub log_level: c_uint,
146+
pub ipc_prefix: *mut c_char,
147+
pub routes: *mut *mut c_char,
148+
pub routes_count: libc::size_t,
153149
}
154150
}
155151

@@ -177,15 +173,18 @@ pub unsafe extern "C" fn destroy_proxy_cli_args(ffi_args: ffi::ProxyCliArgs) {
177173
let _ = CString::from_raw(ffi_args.ipc_prefix);
178174
}
179175
if !ffi_args.routes.is_null() {
176+
// SAFETY: the raw parts were originally derived from a boxed slice
177+
let routes = unsafe {
178+
Box::from_raw(slice::from_raw_parts_mut(
179+
ffi_args.routes,
180+
ffi_args.routes_count,
181+
))
182+
};
183+
180184
// Free each individual route string
181-
for i in 0..ffi_args.routes_count {
182-
let route_ptr = *ffi_args.routes.add(i as usize);
183-
if !route_ptr.is_null() {
184-
let _ = CString::from_raw(route_ptr);
185-
}
185+
for item in routes.iter() {
186+
let _ = CString::from_raw(*item);
186187
}
187-
188-
libc::free(ffi_args.routes as *mut libc::c_void);
189188
}
190189
}
191190

@@ -209,8 +208,6 @@ mod tests {
209208
route: vec!["route1".to_string(), "route2".to_string()],
210209
};
211210

212-
let args_ffi = args.to_ffi();
213-
214211
// Test verify() method
215212
let verified_args = args.verify();
216213
assert_eq!(verified_args.config_file, Some(config_test_file.clone()));
@@ -223,6 +220,8 @@ mod tests {
223220
vec!["route1".to_string(), "route2".to_string()]
224221
);
225222

223+
let args_ffi = verified_args.to_ffi();
224+
226225
// Test conversion to C++-compatible struct
227226
unsafe {
228227
assert_eq!(
@@ -277,14 +276,9 @@ mod tests {
277276
route: Vec::new(),
278277
};
279278

280-
let empty_args_ffi = empty_args.to_ffi();
281-
282279
// Test verify() with empty args
283280
let verified_empty_args = empty_args.verify();
284-
let default_config_file = get_config_file(&env::current_dir().unwrap(), None)
285-
.unwrap()
286-
.to_string_lossy()
287-
.to_string();
281+
let default_config_file = default_config_file().to_str().unwrap().to_string();
288282
assert_eq!(
289283
verified_empty_args.config_file,
290284
Some(default_config_file.clone())
@@ -295,6 +289,8 @@ mod tests {
295289
assert_eq!(verified_empty_args.ipc_prefix, None);
296290
assert!(verified_empty_args.route.is_empty());
297291

292+
let empty_args_ffi = verified_empty_args.to_ffi();
293+
298294
// Test conversion to C++-compatible struct
299295
unsafe {
300296
assert_eq!(

0 commit comments

Comments
 (0)