Skip to content

Commit 8163753

Browse files
authored
Sans io updated (#39)
* first step for sans-io * fix rstest * working raw sockets * add fast macos feature * add macos-fast feature * linux fix * version bump * add min for macos * last stash --------- Co-authored-by: Frank Lee <>
1 parent ebbcb27 commit 8163753

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1109
-148
lines changed

.github/workflows/bluefin.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ jobs:
2828
run: cargo build --verbose
2929
- name: Run tests
3030
run: cargo test --verbose
31+
- name: Build w/ macos-fast
32+
if: runner.os == 'macOS'
33+
run: cargo build --verbose --features macos-fast
34+
- name: Run test w/ macos-fast
35+
if: runner.os == 'macOS'
36+
run: cargo test --verbose --features macos-fast
3137

3238
coverage:
3339
runs-on: ubuntu-latest

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Generated by Cargo
22
# will have compiled files and executables
3-
/target/
3+
**/target/
44

55
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
66
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html

Cargo.toml

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
[package]
2-
name = "bluefin"
1+
[workspace]
2+
members = ["bluefin", "bluefin-io", "bluefin-proto"]
3+
resolver = "2"
4+
5+
[workspace.package]
36
version = "0.1.6"
47
edition = "2021"
58
description = "An experimental, secure, P2P, transport-layer protocol."
@@ -8,33 +11,17 @@ repository = "https://github.com/franklee26/bluefin"
811

912
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1013

11-
[dependencies]
14+
[workspace.dependencies]
1215
local-ip-address = "0.6.3"
13-
rand = "0.8.5"
14-
rstest = "0.23.0"
16+
rand = "0.9.0-beta.1"
17+
rstest = "0.26.1"
1518
thiserror = "2.0.9"
1619
tokio = { version = "1.42.0", features = ["full", "tracing"] }
17-
console-subscriber = "0.4.1"
20+
console-subscriber = "0.5.0"
1821
libc = "0.2.164"
19-
socket2 = "0.5.8"
20-
21-
[dev-dependencies]
22-
local-ip-address = "0.6.3"
23-
rstest = "0.23.0"
24-
25-
[lib]
26-
name = "bluefin"
27-
28-
[[bin]]
29-
name = "client"
30-
path = "src/bin/client.rs"
31-
32-
[[bin]]
33-
name = "server"
34-
path = "src/bin/server.rs"
22+
socket2 = { version = "0.6.1", features = ["all"] }
3523

36-
[lints.rust]
37-
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage,coverage_nightly)', 'cfg(kani)'] }
24+
[workspace.lints.rust]
3825

3926
[profile.release]
4027
opt-level = 3

bluefin-io/Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "bluefin-io"
3+
version.workspace = true
4+
edition.workspace = true
5+
description.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
9+
[dependencies]
10+
libc = { workspace = true }
11+
socket2 = { workspace = true }
12+
thiserror = "2.0.9"
13+
tokio = { workspace = true, features = ["full", "tracing"] }
14+
rand = "0.9.0-beta.1"
15+
16+
[dev-dependencies]
17+
local-ip-address = "0.6.3"
18+
rstest = { workspace = true }
19+
20+
[build-dependencies]
21+
cfg_aliases = "0.2.1"
22+
23+
[lints]
24+
workspace = true
25+
26+
[features]
27+
macos-fast = []

bluefin-io/build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use cfg_aliases::cfg_aliases;
2+
3+
fn main() {
4+
cfg_aliases! {
5+
macos: { target_os = "macos" },
6+
linux: { target_os = "linux" },
7+
macos_fast: { all(target_os = "macos", feature = "macos-fast") },
8+
}
9+
}

bluefin-io/src/error.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::io::ErrorKind;
2+
use thiserror::Error;
3+
4+
pub type BluefinIoResult<T> = Result<T, BluefinIoError>;
5+
6+
#[derive(Error, Debug, PartialEq)]
7+
pub enum BluefinIoError {
8+
#[error("std::io::Error: `{0}`")]
9+
StdIoError(String),
10+
11+
#[error("`{0}`")]
12+
InsufficientBufferSize(String),
13+
14+
#[error("`{0}`")]
15+
Unsupported(String),
16+
}
17+
18+
impl From<std::io::Error> for BluefinIoError {
19+
fn from(error: std::io::Error) -> Self {
20+
BluefinIoError::StdIoError(error.to_string())
21+
}
22+
}
23+
24+
impl From<ErrorKind> for BluefinIoError {
25+
fn from(error: ErrorKind) -> Self {
26+
BluefinIoError::StdIoError(error.to_string())
27+
}
28+
}

bluefin-io/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod error;
2+
pub mod socket;

bluefin-io/src/socket/cmsghdr.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use crate::error::{BluefinIoError, BluefinIoResult};
2+
use libc::c_int;
3+
4+
// This is a wrapper on the following structure:
5+
// see: https://man7.org/linux/man-pages/man3/cmsg.3.html
6+
// struct cmsghdr {
7+
// size_t cmsg_len; /* Data byte count, including header
8+
// (type is socklen_t in POSIX) */
9+
// int cmsg_level; /* Originating protocol */
10+
// int cmsg_type; /* Protocol-specific type */
11+
// /* followed by
12+
// unsigned char cmsg_data[]; */
13+
// };
14+
pub(crate) struct CmsghdrBufferHandler<'a> {
15+
// This is a ref to the msghdr struct which holds this cmsghdr buffer. We need to keep this
16+
// reference because the CMSG_NXTHDR() requires the msghdr as an input parameter.
17+
src_msghdr: &'a libc::msghdr,
18+
// Mutable reference to the first cmsghdr in the ancillary data buffer. This value
19+
// must be derived from the CMSG_FIRSTHDR() macro defined in cmsg (3).
20+
// According to the man pages, this pointer can be null if there is not enough space allocated.
21+
// We will need to use the size + total_bytes fields below to safely unwrap this value.
22+
// The `append` call is responsible for advancing the pointer to the next free address if
23+
// more data was successfully appended.
24+
cmsghdr_ptr: Option<&'a mut libc::cmsghdr>,
25+
// The amount of bytes we have written to the ancillary buffer. This must not exceed
26+
// the `total_bytes` value below.
27+
size: usize,
28+
// Total bytes allocated to the ancillary data buffer.
29+
total_bytes: usize,
30+
}
31+
32+
impl<'a> CmsghdrBufferHandler<'a> {
33+
pub(crate) fn new(msghdr: &'a libc::msghdr) -> Self {
34+
let cmsghdr_ptr = unsafe { libc::CMSG_FIRSTHDR(msghdr).as_mut() };
35+
Self {
36+
src_msghdr: msghdr,
37+
cmsghdr_ptr,
38+
size: 0,
39+
total_bytes: msghdr.msg_controllen as _,
40+
}
41+
}
42+
43+
pub(crate) fn append<T>(
44+
&mut self,
45+
cmsg_level: c_int,
46+
cmsg_type: c_int,
47+
cmsg_data: T,
48+
) -> BluefinIoResult<()> {
49+
// Need to use CMSG_SPACE macro to determine how much space cmsg_data would occupy
50+
let val_size: usize = unsafe { libc::CMSG_SPACE(size_of_val(&cmsg_data) as _) } as _;
51+
if self.size + val_size > self.total_bytes {
52+
return Err(BluefinIoError::InsufficientBufferSize(
53+
"Could not add value to ancillary data as data exceeds available free space"
54+
.to_string(),
55+
));
56+
}
57+
58+
// Since there is enough space, we can get unwrap safely and get the mutable ref.
59+
let cmsghdr = self.cmsghdr_ptr.take().unwrap();
60+
61+
// Set the level, type and len.
62+
cmsghdr.cmsg_level = cmsg_level;
63+
cmsghdr.cmsg_type = cmsg_type;
64+
// size_of_val() is insufficient here. As stated in cmsg(3), we need to consider alignment.
65+
cmsghdr.cmsg_len = unsafe { libc::CMSG_LEN(size_of_val(&cmsg_data) as _) as _ };
66+
67+
// Now finally write the data
68+
// First use CMSG_DATA() to get a pointer to the data portion of cmsghdr.
69+
let cmsghdr_data_ptr = unsafe { libc::CMSG_DATA(cmsghdr) };
70+
// Now, write the data.
71+
unsafe {
72+
// Need to cast this to the correct pointer type
73+
std::ptr::write(cmsghdr_data_ptr as *mut T, cmsg_data);
74+
};
75+
76+
// Account for the space we used
77+
self.size += val_size;
78+
79+
// Finally, we must advance self.cmsghdr_ptr. As directed in the man pages we will use
80+
// CMSG_NXTHDR().
81+
let next_cmsghdr = unsafe { libc::CMSG_NXTHDR(self.src_msghdr, cmsghdr).as_mut() };
82+
self.cmsghdr_ptr = next_cmsghdr;
83+
Ok(())
84+
}
85+
}

bluefin-io/src/socket/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use crate::error::{BluefinIoError, BluefinIoResult};
2+
use libc::{c_int, setsockopt};
3+
4+
mod cmsghdr;
5+
pub mod udp_socket;
6+
7+
pub(crate) fn set_sock_opt<T>(
8+
fd: c_int,
9+
level: c_int,
10+
name: c_int,
11+
value: T,
12+
) -> BluefinIoResult<()> {
13+
unsafe {
14+
match setsockopt(
15+
fd,
16+
level,
17+
name,
18+
&value as *const _ as _,
19+
size_of_val(&value) as _,
20+
) {
21+
0 => Ok(()),
22+
_ => Err(BluefinIoError::StdIoError(
23+
std::io::Error::last_os_error().to_string(),
24+
)),
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)