Skip to main content

jsonrpc_fdpass/
lib.rs

1//! # JSON-RPC 2.0 with Unix File Descriptor Passing
2//!
3//! This crate provides an implementation of JSON-RPC 2.0 with file descriptor passing over Unix
4//! domain sockets. It enables reliable inter-process communication (IPC) with the ability to
5//! pass file descriptors alongside JSON-RPC messages.
6//!
7//! ## Features
8//!
9//! - **JSON-RPC 2.0 compliance**: Full support for requests, responses, and notifications
10//! - **File descriptor passing**: Pass file descriptors using Unix socket ancillary data
11//! - **Streaming JSON parsing**: Self-delimiting JSON messages without newline requirements
12//! - **Async support**: Built on tokio for high-performance async I/O
13//! - **Type-safe**: Rust's type system ensures correct message handling
14//!
15//! ## Quick Start
16//!
17//! ### Server Example
18//!
19//! ```rust,no_run
20//! use jsonrpc_fdpass::{Server, Result};
21//! use std::fs::File;
22//! use serde_json::Value;
23//!
24//! #[tokio::main]
25//! async fn main() -> Result<()> {
26//!     let mut server = Server::new();
27//!     
28//!     server.register_method("read_file", |_method, _params, fds| {
29//!         if let Some(fd) = fds.into_iter().next() {
30//!             let mut file = File::from(fd);
31//!             let mut contents = String::new();
32//!             use std::io::Read;
33//!             file.read_to_string(&mut contents).unwrap();
34//!             Ok((Some(Value::String(contents)), Vec::new()))
35//!         } else {
36//!             Err(jsonrpc_fdpass::Error::InvalidMessage("No FD provided".into()))
37//!         }
38//!     });
39//!     
40//!     server.listen("/tmp/test.sock").await
41//! }
42//! ```
43//!
44//! ### Client Example
45//!
46//! ```rust,no_run
47//! use jsonrpc_fdpass::{
48//!     JsonRpcRequest, JsonRpcMessage, MessageWithFds, UnixSocketTransport, Result
49//! };
50//! use std::fs::File;
51//! use std::os::unix::io::OwnedFd;
52//! use serde_json::json;
53//! use tokio::net::UnixStream;
54//!
55//! #[tokio::main]
56//! async fn main() -> Result<()> {
57//!     let stream = UnixStream::connect("/tmp/test.sock").await?;
58//!     let transport = UnixSocketTransport::new(stream);
59//!     let (mut sender, mut receiver) = transport.split();
60//!     
61//!     let file = File::open("example.txt").unwrap();
62//!     let fd: OwnedFd = file.into();
63//!     
64//!     let request = JsonRpcRequest::new(
65//!         "read_file".to_string(),
66//!         Some(json!({"filename": "example.txt"})),
67//!         json!(1),
68//!     );
69//!     let message = MessageWithFds::new(JsonRpcMessage::Request(request), vec![fd]);
70//!     sender.send(message).await?;
71//!     
72//!     let response = receiver.receive().await?;
73//!     println!("Response: {:?}", response.message);
74//!     
75//!     Ok(())
76//! }
77//! ```
78//!
79//! ## Protocol Details
80//!
81//! This implementation is a minimal extension to JSON-RPC 2.0 that adds file descriptor
82//! passing over Unix domain sockets:
83//!
84//! - Uses Unix domain sockets (SOCK_STREAM)
85//! - Standard JSON-RPC 2.0 message format with no additional framing requirements
86//! - JSON objects are self-delimiting; no newline or length-prefix framing is required
87//! - File descriptors are passed as ancillary data via sendmsg(2)/recvmsg(2)
88//! - Each sendmsg() call contains exactly one complete JSON-RPC message
89//!
90//! ### File Descriptor Count Field
91//!
92//! When file descriptors are attached to a message, the `fds` field at the top level
93//! of the JSON object specifies how many FDs are attached:
94//!
95//! ```json
96//! {
97//!   "jsonrpc": "2.0",
98//!   "method": "read_file",
99//!   "params": {"filename": "example.txt"},
100//!   "id": 1,
101//!   "fds": 1
102//! }
103//! ```
104//!
105//! File descriptors are passed positionally—the application layer defines the semantic
106//! mapping between FD positions and parameters.
107
108#![forbid(unsafe_code)]
109#![deny(missing_docs)]
110
111/// Error types for JSON-RPC operations.
112pub mod error;
113/// JSON-RPC message types and serialization.
114pub mod message;
115/// JSON-RPC 2.0 server implementation with file descriptor passing.
116pub mod server;
117/// Low-level Unix socket transport with ancillary data support.
118pub mod transport;
119
120pub use error::{Error, Result};
121pub use jsonrpsee::types::error::{
122    CALL_EXECUTION_FAILED_CODE, ErrorCode, ErrorObject as JsonRpcError, INTERNAL_ERROR_CODE,
123    INTERNAL_ERROR_MSG, INVALID_PARAMS_CODE, INVALID_PARAMS_MSG, INVALID_REQUEST_CODE,
124    INVALID_REQUEST_MSG, METHOD_NOT_FOUND_CODE, METHOD_NOT_FOUND_MSG, PARSE_ERROR_CODE,
125    PARSE_ERROR_MSG,
126};
127pub use message::{
128    FILE_DESCRIPTOR_ERROR_CODE, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest,
129    JsonRpcResponse, MessageWithFds, file_descriptor_error,
130};
131pub use server::Server;
132pub use transport::{DEFAULT_MAX_FDS_PER_SENDMSG, Receiver, Sender, UnixSocketTransport};