1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
//! # Safer-Ring: Safe `io_uring` for Rust
//!
//! A comprehensive, safe Rust wrapper around `io_uring` that provides zero-cost abstractions
//! while preventing common memory safety issues. The library uses Rust's type system,
//! lifetime management, and pinning to ensure that buffers remain valid during asynchronous
//! I/O operations, eliminating use-after-free bugs and data races.
//!
//! ## Key Features
//!
//! ### Safety Guarantees
//! - **Memory Safety**: Compile-time guarantees that buffers outlive their operations
//! - **Type Safety**: State machines prevent operations in invalid states
//! - **Lifetime Safety**: Automatic enforcement of buffer and operation lifetimes
//! - **Thread Safety**: Safe sharing of resources across async tasks
//!
//! ### Performance Optimizations
//! - **Zero-Cost Abstractions**: No runtime overhead compared to raw `io_uring`
//! - **Batch Operations**: Submit multiple operations efficiently with dependency support
//! - **Buffer Pooling**: Efficient buffer reuse to minimize allocations
//! - **Advanced Features**: Support for buffer selection, multi-shot operations, and more
//!
//! ### Developer Experience
//! - **Async/Await**: Seamless integration with Rust's async ecosystem
//! - **Comprehensive Logging**: Structured logging and performance metrics
//! - **Flexible Configuration**: Optimized presets for different use cases
//! - **Graceful Degradation**: Automatic fallback for older kernel versions
//!
//! ## Quick Start
//!
//! ### Recommended: Ownership Transfer API
//!
//! ```rust,no_run
//! use safer_ring::{Ring, OwnedBuffer};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create a new ring with 32 entries
//! let mut ring = Ring::new(32)?;
//!
//! // Create a buffer - ownership will be transferred during I/O
//! let buffer = OwnedBuffer::new(1024);
//!
//! // Safe read with ownership transfer ("hot potato" pattern)
//! let (bytes_read, buffer) = ring.read_owned(0, buffer).await?;
//! println!("Read {} bytes", bytes_read);
//!
//! // Buffer is safely returned and can be reused
//! let (bytes_written, _buffer) = ring.write_owned(1, buffer).await?;
//! println!("Wrote {} bytes", bytes_written);
//!
//! # Ok(())
//! # }
//! ```
//!
//! ## A Note on the `PinnedBuffer` API (Educational / Not Recommended)
//!
//! You may see a [`PinnedBuffer`] type and methods like [`read()`](Ring::read) or [`write()`](Ring::write) in the codebase.
//!
//! **This API is considered educational and is not suitable for practical use.** It suffers from
//! fundamental lifetime constraints in Rust that make it impossible to use in loops or for
//! concurrent operations on the same [`Ring`] instance. It exists to demonstrate the complexities
//! that the [`OwnedBuffer`] model successfully solves. For all applications, please use the
//! [`OwnedBuffer`] API.
//!
//! The example below is provided for completeness but is not a recommended pattern:
//!
//! ```rust,ignore
//! use safer_ring::{Ring, PinnedBuffer};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut ring = Ring::new(32)?;
//! let mut buffer = PinnedBuffer::with_capacity(1024);
//!
//! // This pattern works for a single, one-shot operation but fails in loops.
//! let (bytes_read, buffer) = ring.read(0, buffer.as_mut_slice())?.await?;
//! println!("Read {} bytes", bytes_read);
//!
//! # Ok(())
//! # }
//! ```
//!
//! ### High-Performance Batch Operations
//!
//! For high-throughput applications, submit multiple operations in a single batch:
//!
//! ```rust,ignore
//! use safer_ring::{Ring, Batch, Operation, PinnedBuffer, BatchConfig};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Note: Batch operations currently require careful lifetime management
//! // See examples/async_demo.rs for working patterns
//! let mut ring = Ring::new(128)?;
//! let mut batch = Batch::new();
//!
//! // Prepare multiple buffers
//! let mut read_buffer = PinnedBuffer::with_capacity(4096);
//! let mut write_buffer = PinnedBuffer::from_slice(b"Hello, world!");
//!
//! // Add operations to the batch
//! batch.add_operation(Operation::read().fd(0).buffer(read_buffer.as_mut_slice()))?;
//! batch.add_operation(Operation::write().fd(1).buffer(write_buffer.as_mut_slice()))?;
//!
//! // Submit all operations at once
//! let results = ring.submit_batch(batch)?.await?;
//! println!("Batch completed: {} operations", results.results.len());
//!
//! # Ok(())
//! # }
//! ```
//!
//! > **Note**: Batch operations are fully implemented but have some API ergonomics
//! > limitations. See `examples/async_demo.rs` for working usage patterns.
//!
//! ### Network Server Example
//!
//! ```rust,ignore
//! use safer_ring::{Ring, PinnedBuffer, BufferPool};
//! use std::os::unix::io::RawFd;
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let ring = Ring::new(256)?;
//! let buffer_pool = BufferPool::new(100, 4096);
//! let listening_fd: RawFd = 3; // Assume we have a listening socket
//!
//! loop {
//! // Accept a new connection
//! let client_fd = ring.accept(listening_fd)?.await?;
//!
//! // Get a buffer from the pool
//! let buffer = buffer_pool.get().unwrap();
//!
//! // Read data from the client
//! let (bytes_read, buffer) = ring.recv(client_fd, buffer.as_mut_slice())?.await?;
//!
//! // Echo the data back
//! let (bytes_written, _buffer) = ring.send(client_fd, buffer.as_mut_slice())?.await?;
//!
//! println!("Echoed {} bytes", bytes_written);
//! // Buffer is automatically returned to pool when dropped
//! }
//! # }
//! ```
//!
//! ## Configuration and Optimization
//!
//! Safer-ring provides pre-configured setups for different use cases:
//!
//! ```rust,no_run
//! use safer_ring::{Ring, SaferRingConfig};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Low-latency configuration for real-time applications
//! let config = SaferRingConfig::low_latency();
//! let ring = Ring::with_config(config)?;
//!
//! // High-throughput configuration for batch processing
//! let config = SaferRingConfig::high_throughput();
//! let ring = Ring::with_config(config)?;
//!
//! // Auto-detect optimal configuration for current system
//! let config = SaferRingConfig::auto_detect()?;
//! let ring = Ring::with_config(config)?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! ## Advanced Features
//!
//! ### Buffer Selection and Provided Buffers
//!
//! ```rust,no_run
//! use safer_ring::{Ring, BufferGroup, AdvancedConfig};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create a buffer group for kernel buffer selection
//! let mut buffer_group = BufferGroup::new(1, 64, 4096)?;
//!
//! // Configure ring with advanced features
//! let mut config = AdvancedConfig::default();
//! config.buffer_selection = true;
//! config.provided_buffers = true;
//!
//! let ring = Ring::with_advanced_config(config)?;
//! // Use buffer selection for zero-copy reads
//! # Ok(())
//! # }
//! ```
//!
//! ### Comprehensive Logging and Metrics
//!
//! ```rust,ignore
//! use safer_ring::{Ring, SaferRingConfig, LogLevel};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Enable detailed logging and metrics
//! let mut config = SaferRingConfig::development();
//! config.logging.enabled = true;
//! config.logging.level = LogLevel::Debug;
//! config.logging.metrics = true;
//!
//! let mut ring = Ring::with_config(config)?;
//!
//! // Operations are automatically logged with timing information
//! let mut buffer = safer_ring::PinnedBuffer::with_capacity(1024);
//! let (bytes_read, _) = ring.read(0, buffer.as_mut_slice())?.await?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! ## Platform Support
//!
//! - **Linux**: Full `io_uring` support with all advanced features
//! - **Other platforms**: Graceful degradation with stub implementations for testing
//!
//! ## Minimum Kernel Requirements
//!
//! - **Basic functionality**: Linux 5.1+
//! - **Advanced features**: Linux 5.19+ (buffer selection, multi-shot operations)
//! - **Optimal performance**: Linux 6.0+ (cooperative task running, defer taskrun)
//!
//! The library automatically detects available features and gracefully degrades
//! functionality on older kernels while maintaining API compatibility.
//!
//! ## Security Considerations
//!
//! ### File Descriptor Responsibility
//!
//! **⚠️ CRITICAL SECURITY NOTICE**: This library accepts raw file descriptors (`RawFd`)
//! from user code and does **NOT** perform any validation, permission checks, or access
//! control. The application is **entirely responsible** for ensuring file descriptor security.
//!
//! ### Security Responsibilities
//!
//! **The calling application must ensure that all file descriptors:**
//! - Are valid and owned by the current process
//! - Have appropriate permissions for the intended operation (read/write/accept)
//! - Are not subject to race conditions from concurrent access
//! - Point to intended resources (files, sockets, devices)
//! - Have been properly authenticated and authorized
//! - Are not being used maliciously by untrusted code
//!
//! ### Potential Security Risks
//!
//! **Using invalid, unauthorized, or malicious file descriptors can result in:**
//! - Reading from or writing to unintended files, sockets, or devices
//! - Information disclosure or data corruption
//! - Privilege escalation or unauthorized system access
//! - Buffer overflow attacks or memory corruption (from network data)
//! - Denial of service or system instability
//!
//! ### Security Best Practices
//!
//! **Always implement these security controls at the application level:**
//! - Validate file descriptors at security boundaries
//! - Use proper access control and permission checks
//! - Implement input validation for all received data
//! - Consider using sandboxing or privilege isolation
//! - Apply principle of least privilege for file access
//! - Use secure network protocols and authentication
//! - Monitor and log suspicious file descriptor usage
//!
//! ### Data Validation
//!
//! **For network operations, the application must:**
//! - Validate all received data before processing
//! - Implement proper input sanitization and bounds checking
//! - Use secure parsing for untrusted input data
//! - Consider data confidentiality and integrity requirements
//! - Protect against injection attacks and protocol exploitation
//!
//! This library provides **memory safety** and **async safety** but does **NOT** provide
//! **security boundaries** or **access control**. Security must be implemented at the
//! application layer.
// Core modules - fundamental building blocks for safe io_uring operations
// Backend abstraction for io_uring and epoll
// Buffer ownership management for safety
// Runtime detection and fallback system
// Cancellation safety and orphaned operation tracking
// Advanced features - performance optimizations and convenience APIs
// Advanced io_uring features (buffer selection, multi-shot, etc.)
// AsyncRead/AsyncWrite compatibility adapters
// Configuration options for different use cases
// async/await integration
// Comprehensive logging and debugging support
// Performance profiling and optimization utilities
// Buffer pooling for reduced allocations
// FD/buffer registration for kernel optimization
// Re-exports for convenience - commonly used types at crate root
pub use ;
pub use PinnedBuffer;
pub use ; // Async compatibility
pub use ;
pub use ;
pub use ;
pub use ;
pub use ; // Core ownership types
pub use ;
pub use ;
pub use ;
pub use ; // Runtime system
pub use ; // Cancellation safety
// Type aliases for common patterns - reduces verbosity in user code
/// Future type for read operations that can be awaited.
pub type ReadFuture<'ring, 'buf> = ReadFuture;
/// Future type for write operations that can be awaited.
pub type WriteFuture<'ring, 'buf> = WriteFuture;
/// Future type for accept operations that can be awaited.
pub type AcceptFuture<'ring> = AcceptFuture;
/// Future type for send operations that can be awaited.
pub type SendFuture<'ring, 'buf> = SendFuture;
/// Future type for receive operations that can be awaited.
pub type RecvFuture<'ring, 'buf> = RecvFuture;
/// Future type for batch operations that can be awaited.
pub type BatchFuture<'ring> = BatchFuture;
/// Standalone future type for batch operations that doesn't hold Ring references.
pub type StandaloneBatchFuture = StandaloneBatchFuture;