Skip to main content

buffer_core/shm/
reader.rs

1use std::fs::{self, OpenOptions};
2
3use core_types::{ErrorCode, ErrorDomain, RtError};
4
5use super::config::validate_cfg;
6use super::header::{HEADER_SIZE, read_header};
7use super::segment_io::{init_segment_files, io_to_err, map_ro, segment_path, slot_for};
8use super::{SharedMemoryBufferRef, SharedMemoryLease, SharedMemoryReader, ShmTransportConfig};
9
10impl SharedMemoryReader {
11    pub fn new(cfg: ShmTransportConfig) -> Result<Self, RtError> {
12        validate_cfg(&cfg)?;
13        fs::create_dir_all(&cfg.directory)
14            .map_err(|err| io_to_err("create shm directory failed", err))?;
15        init_segment_files(&cfg)?;
16        Ok(Self { cfg })
17    }
18
19    pub fn loan(&self, reference: SharedMemoryBufferRef) -> Result<SharedMemoryLease, RtError> {
20        if reference.len > self.cfg.segment_payload_bytes {
21            return Err(RtError::new(
22                ErrorCode::InvalidState,
23                ErrorDomain::Core,
24                false,
25                "invalid shared memory reference length",
26            ));
27        }
28
29        let slot = slot_for(reference.buffer_id, self.cfg.segment_count);
30        let segment_path = segment_path(&self.cfg, slot);
31        let file = OpenOptions::new()
32            .read(true)
33            .open(&segment_path)
34            .map_err(|err| io_to_err("open shm segment for read failed", err))?;
35        let mmap = map_ro(&file)?;
36
37        let (buf_id, len) = read_header(&mmap)?;
38        if buf_id != reference.buffer_id {
39            return Err(RtError::new(
40                ErrorCode::InvalidState,
41                ErrorDomain::Core,
42                false,
43                format!(
44                    "stale shm slot content: expected buffer_id={} actual={}",
45                    reference.buffer_id, buf_id
46                ),
47            ));
48        }
49
50        if len != reference.len {
51            return Err(RtError::new(
52                ErrorCode::InvalidState,
53                ErrorDomain::Core,
54                false,
55                format!(
56                    "shm payload length mismatch: expected={} actual={}",
57                    reference.len, len
58                ),
59            ));
60        }
61
62        let start = HEADER_SIZE + reference.offset;
63        let end = start + reference.len;
64        if end > HEADER_SIZE + self.cfg.segment_payload_bytes {
65            return Err(RtError::new(
66                ErrorCode::InvalidState,
67                ErrorDomain::Core,
68                false,
69                "shm reference range out of bounds",
70            ));
71        }
72
73        Ok(SharedMemoryLease {
74            mmap,
75            offset: start,
76            len: reference.len,
77        })
78    }
79}