interprocess Rust library

repository·main·Indexed 20 days ago

https://github.com/kotauskas/interprocess

A Rust inter-process communication (IPC) toolkit providing a uniform interface across Windows and Unix-like systems. It offers high-performance alternatives to TCP localhost sockets via local sockets, unnamed pipes, FIFO files (Unix), and named pipes (Windows). The library supports asynchronous I/O via the Tokio runtime and provides platform-specific extensions through the os module.

Tokens
10.4K
Snippets
26
Records
43
Agent score
70%

What's inside interprocess

  1. Mitigating LLM contamination via feature gates

    main
    To minimize the risk of LLM contamination from third-party dependencies that form part of the public API, certain dependencies are gated behind off-by-default features. This allows users to opt-in to specific functionality while maintaining a cleaner dependency profile by default.
  2. Understand platform support and compatibility

    main

    Interprocess supports Windows and generic Unix-like systems. Platform-specific extensions are exposed via #[cfg] gates. If you attempt to use a feature on a platform that does not support it, you will encounter a compile error rather than a runtime error.

    Support Levels

    • Explicit support (Windows, Linux, macOS): Guaranteed to compile and pass all tests in CI.
    • Explicit support with incomplete CI (FreeBSD, Android): Expected to compile and pass tests; CI runs Clippy and Rustdoc via cross-compilation.
    • Explicit support without CI (OpenBSD, NetBSD): Expected to compile and pass tests; verified via manual testing.
    • Support by association (Dragonfly BSD, Redox, Fuchsia, iOS, tvOS, watchOS): Expected to compile and pass tests based on identical behavior to higher-tier platforms.
    • Assumed support (Other #[cfg(unix)] systems): Expected to work, but bugs are considered low priority.
  3. Choose an Interprocess communication primitive

    main

    Interprocess provides several IPC (Inter-Process Communication) interfaces depending on your requirements.

    • Local sockets: The flagship feature. Use these instead of localhost TCP sockets for better performance and easier authentication/identification. If you are unsure where to start, begin with the local_socket module.
    • Unnamed pipes: Use these when the standard pipes provided by std::process are insufficient.
    • FIFO files (Unix only): Primarily useful for communicating with programs that specifically require FIFO files (often used in shell scripting).
    • Named pipes (Windows only): The Windows counterpart to Unix domain sockets, used to implement local sockets.
  4. Use Asynchronous I/O with Tokio

    main

    Interprocess supports asynchronous I/O via the Tokio runtime.

    • Local sockets and Windows named pipes are provided directly by Interprocess for async use.
    • Unix domain sockets are available via Tokio's own implementation.

    Note: Support for the smol runtime is not currently being actively worked on.

  5. Verify LLM-free status for compliance

    main

    If your project or organization has restrictions prohibiting the use of LLM-generated dependencies, interprocess can be safely added to your allowlist. The author guarantees that LLMs have not been used in the development of this software and that LLM-generated code is not present in the source tree.

    Note on Transitive Dependencies: While an effort is made to avoid dependencies containing LLM-generated code, the author cannot guarantee a total lack of such software in the entire transitive dependency tree. If you discover LLM usage in upstream dependencies, you are encouraged to report it on the project's issue tracker.

  6. Understand PipeStream flushing and limbo behavior

    main

    The PipeStream implementation includes specialized handling for data integrity during connection termination and flushing efficiency.

    Connection Termination (Thunking)

    To prevent unexpected errors during shutdown, ERROR_PIPE_NOT_CONNECTED and std::io::ErrorKind::BrokenPipe are translated into:

    • Ok(0) (EOF) for bytestreams.
    • RecvResult::EndOfStream for message streams.

    The Limbo Thread Pool

    To ensure the peer receives all sent data before the handle is closed, PipeStream uses a thread pool called limbo.

    • When a stream is dropped, if it contains unsent data (hasn't been flushed since the last send), the handle is sent to the limbo pool.
    • The limbo pool ensures handles are flushed before being closed, preventing the peer from receiving a BrokenPipe or EOF prematurely.
    • Limbo Elision: If a stream has not performed any sends since its last explicit flush, it will bypass the limbo pool to avoid unnecessary overhead. You can force limbo behavior using .mark_dirty().

    Flushing Optimization

    • Consecutive .flush() calls on a stream that hasn't sent new data since the last flush are elided (treated as a no-op) to improve performance.
  7. How local socket name types affect implementation dispatch

    main

    In interprocess, the way you define a local socket name determines which underlying OS implementation (e.g., Unix Domain Sockets vs. Windows Named Pipes) is used. This is achieved through type-level markers that implement the PathNameType or NamespacedNameType traits.

    To use these, you do not implement the traits yourself (they are sealed). Instead, you pass these tag types as generic arguments to the following conversion methods:

    1. For filesystem paths: Use ToFsName::to_fs_name() with a type implementing PathNameType.
    2. For namespaced strings: Use ToNsName::to_ns_name() with a type implementing NamespacedNameType.

    Choosing the correct name type ensures your code correctly maps inputs to the intended local socket implementation for the target platform.

  8. Use GenericNamespaced for platform-agnostic namespaced strings

    main

    The GenericNamespaced tag type provides a consistent mapping from arbitrary OS strings to local socket names across different platforms.

    Platform Behavior

    • Windows: Resolves to named pipe names by prepending \.\pipe\ (addressing local named pipes only).
    • Linux: Resolves to the abstract namespace with no transformations (maximum length of 107 bytes).
    • Other Unices: Resolves to filesystem paths by prepending /tmp/.

    To use this, pass GenericNamespaced to ToNsName::to_ns_name().

  9. Use platform-specific IPC primitives via the os module

    main

    The interprocess crate provides platform-specific implementations for various interprocess communication (IPC) primitives through the os module. Depending on your target platform, you will use either interprocess::os::unix or interprocess::os::windows.

    • Unix-like systems (Linux, macOS, FreeBSD): Access primitives via interprocess::os::unix.
    • Windows: Access primitives via interprocess::os::windows.

    If you are viewing documentation on Docs.rs, you can switch between these platform views using the 'Platform' menu in the header bar to see the specific APIs available for each OS.

  10. Handle Windows-specific named pipe connection behavior

    main

    When using local sockets on Windows (which are implemented via named pipes), it is critical to call .accept() (or iterate via .incoming()) periodically.

    If a client connects and then immediately disconnects before the server calls accept, the named pipe instance enters a 'dead-on-arrival' state. This state will prevent new clients from connecting until the existing connection is cleared by a call to accept.

  11. Communicate pipe handles to child processes

    main

    Since unnamed pipes are only accessible via their handles, you can pass the numeric handle/file descriptor to a child process to establish communication.

    1. In the parent process: Use AsRawHandle (Windows) or AsRawFd (Unix) to get the numeric value of the Sender or Recver.
    2. Transfer: Pass this value to the child process via a command-line argument or an environment variable.
    3. In the child process: Reconstruct the I/O object using FromRawHandle or FromRawFd from the standard library.

    Note: interprocess does not manage the transfer mechanism itself; it only provides the handles.

  12. Configure the `tokio` feature gate

    main

    To use the asynchronous variants of IPC primitives provided by Interprocess, you must enable the tokio feature in your Cargo.toml.

    By default, this feature is off.

    [dependencies]
    interprocess = { version = "2.4.3", features = ["tokio"] }