Skip to content

Commit 35659ab

Browse files
committed
pldm-file: Add --zeroes and --offset to host example
The pldm-file-host example can now serve a synthetic 4GB file of zeroes, and also supports a --file argument. --offset can be used to create output with the offset included every 64 bytes, for debug purposes. Signed-off-by: Matt Johnston <[email protected]>
1 parent 77da3b1 commit 35659ab

File tree

3 files changed

+148
-23
lines changed

3 files changed

+148
-23
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pldm-file/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ num-traits = { workspace = true }
1818
pldm = { workspace = true }
1919

2020
[dev-dependencies]
21+
argh = { workspace = true }
2122
anyhow = "1.0"
2223
chrono = { workspace = true, features = ["clock"] }
2324
mctp-linux = { workspace = true }

pldm-file/examples/host.rs

Lines changed: 146 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,163 @@ use std::io::{Read, Seek, SeekFrom};
1212
use std::os::unix::fs::MetadataExt;
1313
use std::time::{Duration, Instant};
1414

15+
use argh;
16+
17+
/// PLDM file host
18+
#[derive(argh::FromArgs)]
19+
struct Args {
20+
/// file to serve
21+
#[argh(
22+
option,
23+
short = 'f',
24+
default = r#""pldm-file-host.bin".to_string()"#
25+
)]
26+
file: String,
27+
28+
/// serve zeroes
29+
#[argh(switch)]
30+
zeroes: bool,
31+
32+
/// serve a file containing the offset at intervals
33+
#[argh(switch)]
34+
offset: bool,
35+
}
36+
1537
struct Host {
16-
file: RefCell<File>,
17-
stamp: RefCell<(Instant, usize)>,
38+
file_size: u32,
39+
speed: Speed,
40+
mode: Mode,
41+
}
42+
43+
enum Mode {
44+
File {
45+
file: RefCell<File>,
46+
filename: String,
47+
},
48+
Offset,
49+
Zeroes,
50+
}
51+
52+
impl Mode {
53+
fn filename(&self) -> String {
54+
match self {
55+
Self::File { filename, .. } => filename.clone(),
56+
Self::Offset => "offset".to_string(),
57+
Self::Zeroes => "zeroes".to_string(),
58+
}
59+
}
1860
}
1961

20-
const FILENAME: &str = "pldm-file-host.bin";
2162
// Arbitrary, 0 is reserved.
2263
const PDR_HANDLE: u32 = 1;
2364

2465
impl Host {
25-
fn new() -> Result<Self> {
66+
fn new(args: &Args) -> Result<Self> {
67+
let speed = Speed::new();
68+
69+
let mut file_size = u32::MAX;
70+
let mode = if args.zeroes {
71+
info!("Serving zeroes");
72+
Mode::Zeroes
73+
} else if args.offset {
74+
info!("Serving offset");
75+
Mode::Offset
76+
} else {
77+
let file = File::open(&args.file).with_context(|| {
78+
format!("cannot open input file {}", args.file)
79+
})?;
80+
file_size = file
81+
.metadata()
82+
.context("Metadata failed")?
83+
.size()
84+
.try_into()
85+
.context("File size > u32")?;
86+
info!("Serving {}, {} bytes", args.file, file_size);
87+
Mode::File {
88+
file: RefCell::new(file),
89+
filename: args.file.clone(),
90+
}
91+
};
92+
2693
Ok(Self {
27-
file: RefCell::new(File::open(FILENAME).with_context(|| {
28-
format!("cannot open input file {FILENAME}")
29-
})?),
30-
stamp: RefCell::new((Instant::now(), 0)),
94+
mode,
95+
file_size,
96+
speed,
3197
})
3298
}
3399
}
34100

35101
impl pldm_file::host::Host for Host {
36102
fn read(&self, buf: &mut [u8], offset: usize) -> std::io::Result<usize> {
103+
self.speed.update(offset);
104+
105+
match &self.mode {
106+
Mode::File { file, .. } => {
107+
let mut file = file.borrow_mut();
108+
file.seek(SeekFrom::Start(offset as u64))?;
109+
read_whole(&mut file, buf)
110+
}
111+
Mode::Zeroes => {
112+
buf.fill(0);
113+
Ok(buf.len())
114+
}
115+
Mode::Offset => {
116+
let mut o = offset;
117+
for b in buf.chunks_mut(64) {
118+
if let Some(b) = b.get_mut(..4) {
119+
b.copy_from_slice(&o.to_be_bytes())
120+
}
121+
o += b.len();
122+
}
123+
Ok(buf.len())
124+
}
125+
}
126+
}
127+
}
128+
129+
/// Reads into buf until EOF or error.
130+
///
131+
/// A returned `length < buf.len()` means EOF. `buf` should not be empty.
132+
fn read_whole(f: &mut File, buf: &mut [u8]) -> std::io::Result<usize> {
133+
let total = buf.len();
134+
let mut rest = buf;
135+
while !rest.is_empty() {
136+
match f.read(rest) {
137+
// EOF
138+
Ok(0) => return Ok(total - rest.len()),
139+
Ok(l) => rest = &mut rest[l..],
140+
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
141+
Err(e) => return Err(e),
142+
}
143+
}
144+
// Full output
145+
return Ok(total);
146+
}
147+
148+
struct Speed {
149+
stamp: RefCell<(Instant, usize)>,
150+
}
151+
152+
impl Speed {
153+
fn new() -> Self {
154+
Self {
155+
stamp: RefCell::new((Instant::now(), 0)),
156+
}
157+
}
158+
159+
fn update(&self, offset: usize) {
37160
let mut stamp = self.stamp.borrow_mut();
38161
let now = Instant::now();
162+
if offset == 0 {
163+
stamp.0 = now;
164+
}
165+
39166
let del = now - stamp.0;
40167
if del > Duration::from_secs(2) {
41168
let rate = (offset - stamp.1) / del.as_millis() as usize;
42169
info!("{rate} kB/s, offset {offset}");
43170
*stamp = (now, offset);
44171
}
45-
let mut file = self.file.borrow_mut();
46-
file.seek(SeekFrom::Start(offset as u64))?;
47-
file.read(buf)
48172
}
49173
}
50174

@@ -57,7 +181,10 @@ fn main() -> Result<()> {
57181
let mut listener = MctpLinuxAsyncListener::new(mctp::MCTP_TYPE_PLDM, None)?;
58182
let mut pldm_ctrl = pldm::control::responder::Responder::<2>::new();
59183
let mut pldm_file = FileResponder::new();
60-
let mut host = Host::new().context("unable to create file host")?;
184+
185+
let args: Args = argh::from_env();
186+
187+
let mut host = Host::new(&args).context("unable to create file host")?;
61188

62189
FileResponder::register(&mut pldm_ctrl)?;
63190

@@ -180,15 +307,6 @@ fn handle_get_pdr(
180307
return Ok(plat_codes::INVALID_RECORD_CHANGE_NUMBER);
181308
}
182309

183-
let file_max_size = host
184-
.file
185-
.borrow()
186-
.metadata()
187-
.context("Metadata failed")?
188-
.size()
189-
.try_into()
190-
.context("File size > u32")?;
191-
192310
let pdr_resp = GetPDRResp::new_single(
193311
PDR_HANDLE,
194312
PdrRecord::FileDescriptor(FileDescriptorPdr {
@@ -204,10 +322,15 @@ fn handle_get_pdr(
204322
oem_file_classification: 0,
205323
capabilities: file_capabilities::EX_READ_OPEN,
206324
file_version: 0xFFFFFFFF,
207-
file_max_size,
325+
file_max_size: host.file_size,
208326
// TODO
209327
file_max_desc_count: 1,
210-
file_name: FILENAME.try_into().expect("Filename too long"),
328+
file_name: host
329+
.mode
330+
.filename()
331+
.as_str()
332+
.try_into()
333+
.expect("Filename too long"),
211334
oem_file_classification_name: Default::default(),
212335
}),
213336
)?;

0 commit comments

Comments
 (0)