├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ └── bug_report.md ├── dependabot.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── audit.yml │ ├── ci.yml │ └── cd.yml ├── clippy.toml ├── CODE_OF_CONDUCT.md ├── systemd ├── rtltcp.socket └── rtltcp.service ├── .cargo └── audit.toml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-MIT ├── CONTRIBUTING.md ├── README.md ├── src └── main.rs ├── LICENSE-APACHE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .cargo-ok 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | disallowed-methods = [ 2 | # Setting environment variables can cause issues with non-rust code 3 | "std::env::set_var" 4 | ] 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project adheres to the Rust Code of Conduct, which [can be found online](https://www.rust-lang.org/conduct.html). 4 | -------------------------------------------------------------------------------- /systemd/rtltcp.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=RTL TCP Socket 3 | PartOf=rtltcp.service 4 | 5 | [Socket] 6 | ListenStream=[::]:1234 7 | 8 | [Install] 9 | WantedBy=sockets.target 10 | -------------------------------------------------------------------------------- /systemd/rtltcp.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=RTL TCP Service 3 | After=network.target 4 | Requires=rtltcp.socket 5 | 6 | [Service] 7 | Type=notify 8 | ExecStart=/usr/local/bin/rtltcp 9 | TimeoutStopSec=5 10 | -------------------------------------------------------------------------------- /.cargo/audit.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | ignore = [ 3 | # chrono: Potential segfault in localtime_r invocations 4 | # rtltcp avoids setting any environment variables to avoid this issue 5 | "RUSTSEC-2020-0159", 6 | ] 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | # Look for `Cargo.toml` and `Cargo.lock` in the root directory 5 | directory: "/" 6 | # Check for updates every Monday 7 | schedule: 8 | interval: weekly 9 | open-pull-requests-limit: 10 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Motivations 11 | 12 | 15 | 16 | ## Solution 17 | 18 | 19 | 20 | ## Alternatives 21 | 22 | 23 | 24 | ## Additional context 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | 3 | on: 4 | schedule: 5 | # Runs at 00:00 UTC everyday 6 | - cron: '0 0 * * *' 7 | push: 8 | paths: 9 | - '**/Cargo.toml' 10 | - '**/Cargo.lock' 11 | pull_request: 12 | 13 | jobs: 14 | audit: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v2 19 | # Ensure that the latest version of Cargo is installed 20 | - name: Install Rust 21 | uses: actions-rs/toolchain@v1 22 | with: 23 | toolchain: stable 24 | profile: minimal 25 | override: true 26 | - uses: Swatinem/rust-cache@v1 27 | - uses: actions-rs/audit-check@v1 28 | with: 29 | token: ${{ secrets.GITHUB_TOKEN }} 30 | 31 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rtltcp" 3 | description = "A rust implementation of rtl-tcp with better buffering and support for systemd socket activation." 4 | version = "0.1.1" 5 | authors = ["Niclas Hoyer "] 6 | edition = "2021" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/niclashoyer/rtltcp" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [features] 13 | default = ["daemon_systemd"] 14 | daemon_systemd = ["listenfd", "systemd"] 15 | 16 | [dependencies] 17 | "rtlsdr_mt" = "2.1" 18 | "tracing" = "0.1" 19 | "tracing-subscriber" = "0.3" 20 | "ctrlc" = "3.2" 21 | "clap" = { version = "4.5", features = ["derive"] } 22 | "listenfd" = { version = "1.0", optional = true } 23 | "systemd" = { version = "0.10", "optional" = true } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Bug description 11 | 12 | 13 | 14 | - Would you like to work on a fix? [y/n] 15 | 16 | ## To Reproduce 17 | 18 | Steps to reproduce the behavior: 19 | 20 | 1. ... 21 | 2. ... 22 | 3. ... 23 | 4. ... 24 | 25 | 26 | 27 | ## Expected behavior 28 | 29 | 30 | 31 | ## Screenshots 32 | 33 | 34 | 35 | ## Environment 36 | 37 | 38 | 39 | - OS: [e.g. Ubuntu 20.04] 40 | - rtltcp version: [e.g. 0.1.0] 41 | 42 | ## Additional context 43 | 44 | 45 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Niclas Hoyer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | First off, thank you for considering contributing to rtltcp. 4 | 5 | If your contribution is not straightforward, please first discuss the change you 6 | wish to make by creating a new issue before making the change. 7 | 8 | ## Reporting issues 9 | 10 | Before reporting an issue on the 11 | [issue tracker](https://github.com/niclashoyer/rtltcp/issues), 12 | please check that it has not already been reported by searching for some related 13 | keywords. 14 | 15 | ## Pull requests 16 | 17 | Try to do one pull request per change. 18 | 19 | ### Updating the changelog 20 | 21 | Update the changes you have made in 22 | [CHANGELOG](https://github.com/niclashoyer/rtltcp/blob/main/CHANGELOG.md) 23 | file under the **Unreleased** section. 24 | 25 | Add the changes of your pull request to one of the following subsections, 26 | depending on the types of changes defined by 27 | [Keep a changelog](https://keepachangelog.com/en/1.0.0/): 28 | 29 | - `Added` for new features. 30 | - `Changed` for changes in existing functionality. 31 | - `Deprecated` for soon-to-be removed features. 32 | - `Removed` for now removed features. 33 | - `Fixed` for any bug fixes. 34 | - `Security` in case of vulnerabilities. 35 | 36 | If the required subsection does not exist yet under **Unreleased**, create it! 37 | 38 | ## Developing 39 | 40 | ### Set up 41 | 42 | This is no different than other Rust projects. 43 | 44 | ```shell 45 | git clone https://github.com/niclashoyer/rtltcp 46 | cd rtltcp 47 | cargo test 48 | ``` 49 | 50 | ### Useful Commands 51 | 52 | - Build and run release version: 53 | 54 | ```shell 55 | cargo build --release && cargo run --release 56 | ``` 57 | 58 | - Run Clippy: 59 | 60 | ```shell 61 | cargo clippy --all-targets --all-features --workspace 62 | ``` 63 | 64 | - Run all tests: 65 | 66 | ```shell 67 | cargo test --all-features --workspace 68 | ``` 69 | 70 | - Check to see if there are code formatting issues 71 | 72 | ```shell 73 | cargo fmt --all -- --check 74 | ``` 75 | 76 | - Format the code in the project 77 | 78 | ```shell 79 | cargo fmt --all 80 | ``` 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rtltcp 2 | 3 | [![Rust GitHub Template](https://img.shields.io/badge/Rust%20GitHub-Template-blue)](https://rust-github.github.io/) 4 | [![Crates.io](https://img.shields.io/crates/v/rtltcp.svg)](https://crates.io/crates/rtltcp) 5 | [![CI](https://github.com/niclashoyer/rtltcp/workflows/CI/badge.svg)](https://github.com/niclashoyer/rtltcp/actions) 6 | [![Coverage Status](https://coveralls.io/repos/github/niclashoyer/rtltcp/badge.svg?branch=main)](https://coveralls.io/github/niclashoyer/rtltcp?branch=main) 7 | 8 | A rust implementation of [rtl-tcp](https://github.com/pinkavaj/rtl-sdr/blob/master/src/rtl_tcp.c) 9 | with better buffering and support for systemd [socket activation](http://0pointer.de/blog/projects/socket-activation.html). 10 | 11 | ## Installation 12 | 13 | ### Download the latest binary release 14 | 15 | Download the [latest release](https://github.com/niclashoyer/rtltcp/releases) of rtltcp and place it in `/usr/local/bin`: 16 | 17 | ```bash 18 | # ARMv7 (e.g. Raspberry Pi) 19 | wget https://github.com/niclashoyer/rtltcp/releases/download/0.1.0/rtltcp-raspbian-armv7 -O /usr/local/bin/rtltcp 20 | chmod +x /usr/local/bin/rtltcp 21 | ``` 22 | 23 | ### Cargo 24 | 25 | If you want to build the code using your own rust toolchain, you can use `cargo` to do this for you. 26 | 27 | * Install the rust toolchain in order to have cargo installed by following 28 | [this](https://www.rust-lang.org/tools/install) guide. 29 | * run `cargo install rtltcp` 30 | 31 | ### Using Systemd Socket Activation 32 | 33 | By using systemd socket activation it is possible to start rtltcp just if there is a connection. This keeps the rtl-sdr stick cool while not in use without any effort on the server side. 34 | 35 | To use socket activation, place a file `rtltcp.service` and a file `rtltcp.socket` in `/etc/systemd/system/`. 36 | 37 | `rtltcp.service`: 38 | 39 | ```ini 40 | [Unit] 41 | Description=RTL TCP Service 42 | After=network.target 43 | Requires=rtltcp.socket 44 | 45 | [Service] 46 | Type=notify 47 | User=pi 48 | ExecStart=/usr/local/bin/rtltcp 49 | TimeoutStopSec=5 50 | ``` 51 | 52 | `rtltcp.socket`: 53 | ```ini 54 | [Unit] 55 | Description=RTL TCP Socket 56 | PartOf=rtltcp.service 57 | 58 | [Socket] 59 | ListenStream=[::]:1234 60 | 61 | [Install] 62 | WantedBy=sockets.target 63 | ``` 64 | 65 | Install rtltcp either by using `cargo install` or download the latest release (see above). 66 | Now enable and start the socket: 67 | 68 | ```bash 69 | systemctl enable rtltcp.socket 70 | systemctl start rtltcp.socket 71 | ``` 72 | 73 | Systemd should now be listening on port 1234 and start/stop rtltcp automatically. 74 | 75 | ## License 76 | 77 | Licensed under either of 78 | 79 | * Apache License, Version 2.0 80 | ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 81 | * MIT license 82 | ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 83 | 84 | at your option. 85 | 86 | ## Contribution 87 | 88 | Unless you explicitly state otherwise, any contribution intentionally submitted 89 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 90 | dual licensed as above, without any additional terms or conditions. 91 | 92 | See [CONTRIBUTING.md](CONTRIBUTING.md). 93 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI # Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | 11 | test: 12 | name: Test Suite 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v2 17 | - name: Install Rust toolchain 18 | uses: actions-rs/toolchain@v1 19 | with: 20 | toolchain: stable 21 | profile: minimal 22 | override: true 23 | - name: install dependencies 24 | shell: bash 25 | run: | 26 | sudo apt update 27 | sudo apt-get install -y librtlsdr-dev libsystemd-dev 28 | - uses: Swatinem/rust-cache@v1 29 | - uses: actions-rs/cargo@v1 30 | with: 31 | command: test 32 | args: --all-features --workspace 33 | 34 | rustfmt: 35 | name: Rustfmt 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: Checkout repository 39 | uses: actions/checkout@v2 40 | - name: Install Rust toolchain 41 | uses: actions-rs/toolchain@v1 42 | with: 43 | toolchain: stable 44 | profile: minimal 45 | override: true 46 | components: rustfmt 47 | - uses: Swatinem/rust-cache@v1 48 | - name: Check formatting 49 | uses: actions-rs/cargo@v1 50 | with: 51 | command: fmt 52 | args: --all -- --check 53 | 54 | clippy: 55 | name: Clippy 56 | runs-on: ubuntu-latest 57 | steps: 58 | - name: Checkout repository 59 | uses: actions/checkout@v2 60 | - name: Install Rust toolchain 61 | uses: actions-rs/toolchain@v1 62 | with: 63 | toolchain: stable 64 | profile: minimal 65 | override: true 66 | components: clippy 67 | - name: install dependencies 68 | shell: bash 69 | run: | 70 | sudo apt update 71 | sudo apt-get install -y librtlsdr-dev libsystemd-dev 72 | - uses: Swatinem/rust-cache@v1 73 | - name: Clippy check 74 | uses: actions-rs/cargo@v1 75 | with: 76 | command: clippy 77 | args: --all-targets --all-features --workspace -- -D warnings 78 | 79 | docs: 80 | name: Docs 81 | runs-on: ubuntu-latest 82 | steps: 83 | - name: Checkout repository 84 | uses: actions/checkout@v2 85 | - name: Install Rust toolchain 86 | uses: actions-rs/toolchain@v1 87 | with: 88 | toolchain: stable 89 | profile: minimal 90 | override: true 91 | - uses: Swatinem/rust-cache@v1 92 | - name: Check documentation 93 | env: 94 | RUSTDOCFLAGS: -D warnings 95 | uses: actions-rs/cargo@v1 96 | with: 97 | command: doc 98 | args: --no-deps --document-private-items --all-features --workspace --examples 99 | 100 | publish-dry-run: 101 | name: Publish dry run 102 | runs-on: ubuntu-latest 103 | steps: 104 | - name: Checkout repository 105 | uses: actions/checkout@v2 106 | - name: Install Rust toolchain 107 | uses: actions-rs/toolchain@v1 108 | with: 109 | toolchain: stable 110 | profile: minimal 111 | override: true 112 | - name: install dependencies 113 | shell: bash 114 | run: | 115 | sudo apt update 116 | sudo apt-get install -y librtlsdr-dev libsystemd-dev 117 | - uses: Swatinem/rust-cache@v1 118 | - uses: actions-rs/cargo@v1 119 | with: 120 | command: publish 121 | args: --dry-run 122 | 123 | coverage: 124 | name: Code coverage 125 | runs-on: ubuntu-latest 126 | steps: 127 | - name: Checkout repository 128 | uses: actions/checkout@v2 129 | - name: Install Rust toolchain 130 | uses: actions-rs/toolchain@v1 131 | with: 132 | toolchain: stable 133 | profile: minimal 134 | override: true 135 | - name: install dependencies 136 | shell: bash 137 | run: | 138 | sudo apt update 139 | sudo apt-get install -y librtlsdr-dev libsystemd-dev 140 | - uses: Swatinem/rust-cache@v1 141 | - name: Run cargo-tarpaulin 142 | uses: actions-rs/tarpaulin@v0.1 143 | with: 144 | args: '--all-features --workspace --ignore-tests --out Lcov' 145 | - name: Upload to Coveralls 146 | # upload only if push 147 | if: ${{ github.event_name == 'push' }} 148 | uses: coverallsapp/github-action@master 149 | with: 150 | github-token: ${{ secrets.GITHUB_TOKEN }} 151 | path-to-lcov: './lcov.info' 152 | 153 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: CD # Continuous Deployment 2 | 3 | on: 4 | push: 5 | tags: 6 | - '[0-9]+.[0-9]+.[0-9]+' 7 | 8 | jobs: 9 | 10 | publish: 11 | name: Publishing for ${{ matrix.job.os }} 12 | runs-on: ${{ matrix.job.os }} 13 | strategy: 14 | matrix: 15 | rust: [stable] 16 | job: 17 | - os: ubuntu-latest 18 | os-name: linux 19 | target: x86_64-unknown-linux-gnu 20 | architecture: x86_64 21 | binary-postfix: "" 22 | use-cross: false 23 | - os: ubuntu-latest 24 | os-name: linux 25 | target: aarch64-unknown-linux-gnu 26 | architecture: arm64 27 | binary-postfix: "" 28 | use-cross: true 29 | - os: ubuntu-latest 30 | os-name: linux 31 | target: i686-unknown-linux-gnu 32 | architecture: i686 33 | binary-postfix: "" 34 | use-cross: true 35 | - os: ubuntu-latest 36 | os-name: linux 37 | target: armv7-unknown-linux-gnueabihf 38 | architecture: armv7 39 | binary-postfix: "" 40 | use-cross: true 41 | 42 | steps: 43 | - name: Checkout repository 44 | uses: actions/checkout@v2 45 | - name: Install Rust toolchain 46 | uses: actions-rs/toolchain@v1 47 | with: 48 | toolchain: ${{ matrix.rust }} 49 | profile: minimal 50 | override: true 51 | - name: install dependencies 52 | shell: bash 53 | run: | 54 | sudo apt update 55 | sudo apt-get install -y librtlsdr-dev libsystemd-dev 56 | - uses: Swatinem/rust-cache@v1 57 | - name: Cargo build 58 | uses: actions-rs/cargo@v1 59 | with: 60 | command: build 61 | use-cross: ${{ matrix.job.use-cross }} 62 | toolchain: ${{ matrix.rust }} 63 | args: --release --target ${{ matrix.job.target }} 64 | 65 | - name: install strip command 66 | shell: bash 67 | run: | 68 | if [[ ${{ matrix.job.target }} == aarch64-unknown-linux-gnu ]]; then 69 | sudo apt update 70 | sudo apt-get install -y binutils-aarch64-linux-gnu 71 | elif [[ ${{ matrix.job.target }} == armv7-unknown-linux-gnueabihf ]]; then 72 | sudo apt update 73 | sudo apt-get install -y binutils-arm-linux-gnueabihf 74 | fi 75 | - name: Packaging final binary 76 | shell: bash 77 | run: | 78 | cd target/${{ matrix.job.target }}/release 79 | 80 | ####### reduce binary size by removing debug symbols ####### 81 | BINARY_NAME=rtltcp${{ matrix.job.binary-postfix }} 82 | if [[ ${{ matrix.job.target }} == aarch64-unknown-linux-gnu ]]; then 83 | GCC_PREFIX="aarch64-linux-gnu-" 84 | elif [[ ${{ matrix.job.target }} == armv7-unknown-linux-gnueabihf ]]; then 85 | GCC_PREFIX="arm-linux-gnueabihf-" 86 | else 87 | GCC_PREFIX="" 88 | fi 89 | "$GCC_PREFIX"strip $BINARY_NAME 90 | 91 | ########## create tar.gz ########## 92 | RELEASE_NAME=rtltcp-${GITHUB_REF/refs\/tags\//}-${{ matrix.job.os-name }}-${{ matrix.job.architecture }} 93 | tar czvf $RELEASE_NAME.tar.gz $BINARY_NAME 94 | 95 | ########## create sha256 ########## 96 | if [[ ${{ runner.os }} == 'Windows' ]]; then 97 | certutil -hashfile $RELEASE_NAME.tar.gz sha256 | grep -E [A-Fa-f0-9]{64} > $RELEASE_NAME.sha256 98 | else 99 | shasum -a 256 $RELEASE_NAME.tar.gz > $RELEASE_NAME.sha256 100 | fi 101 | - name: Releasing assets 102 | uses: softprops/action-gh-release@v1 103 | with: 104 | files: | 105 | target/${{ matrix.job.target }}/release/rtltcp-*.tar.gz 106 | target/${{ matrix.job.target }}/release/rtltcp-*.sha256 107 | env: 108 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 109 | 110 | publish-cargo: 111 | name: Publishing to Cargo 112 | runs-on: ubuntu-latest 113 | steps: 114 | - name: Checkout repository 115 | uses: actions/checkout@v2 116 | - uses: actions-rs/toolchain@v1 117 | with: 118 | toolchain: stable 119 | profile: minimal 120 | override: true 121 | - name: install dependencies 122 | shell: bash 123 | run: | 124 | sudo apt update 125 | sudo apt-get install -y librtlsdr-dev libsystemd-dev 126 | - uses: Swatinem/rust-cache@v1 127 | - uses: actions-rs/cargo@v1 128 | with: 129 | command: publish 130 | args: --token ${{ secrets.CARGO_API_KEY }} 131 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | use std::io::prelude::*; 3 | use std::io::BufWriter; 4 | use std::net::TcpListener; 5 | use std::sync::atomic::{AtomicBool, Ordering}; 6 | use std::sync::mpsc::sync_channel; 7 | use std::sync::{Arc, Mutex}; 8 | 9 | use clap::Parser; 10 | #[cfg(feature = "systemd")] 11 | use listenfd::ListenFd; 12 | use tracing::{debug, info}; 13 | 14 | #[derive(Parser, Debug)] 15 | #[clap( 16 | author, 17 | version, 18 | about = "an I/Q spectrum server for RTL2832 based DVB-T receivers", 19 | long_about = None 20 | )] 21 | struct Args { 22 | /// listen address 23 | #[clap(short, long, default_value = "[::]")] 24 | address: String, 25 | 26 | /// listen port 27 | #[clap(short, long, default_value_t = 1234)] 28 | port: u16, 29 | 30 | /// device index 31 | #[clap(short, long, default_value_t = 0)] 32 | device_index: u32, 33 | 34 | /// number of decoding buffers 35 | #[clap(short, long, default_value_t = 15)] 36 | buffers: u32, 37 | 38 | /// tcp sending buffer size (in bytes) 39 | #[clap(short, long, default_value_t = 512000)] 40 | tcp_buffers: usize, 41 | } 42 | 43 | fn main() -> Result<(), Box> { 44 | tracing_subscriber::fmt::init(); 45 | 46 | let args = Args::parse(); 47 | 48 | let listener; 49 | #[cfg(feature = "systemd")] 50 | { 51 | let mut listenfd = ListenFd::from_env(); 52 | listener = if let Some(listener) = listenfd 53 | .take_tcp_listener(0) 54 | .map_err(|_| "Could not get file descriptor from input")? 55 | { 56 | listener 57 | } else { 58 | TcpListener::bind(format!("{}:{}", args.address, args.port))? 59 | }; 60 | systemd::daemon::notify(false, [(systemd::daemon::STATE_READY, "1")].iter())?; 61 | } 62 | #[cfg(not(feature = "systemd"))] 63 | { 64 | listener = TcpListener::bind(format!("{}:{}", args, address, args.port))?; 65 | } 66 | 67 | let (sender, receiver) = sync_channel(0); 68 | let sender_ctrlc = sender.clone(); 69 | let should_exit = Arc::new(AtomicBool::new(false)); 70 | ctrlc::set_handler(move || { 71 | match sender_ctrlc.try_send(()) { 72 | Ok(_) => {} 73 | Err(_) => { 74 | // cancel thread not waiting yet, we can exit immediately 75 | std::process::exit(0); 76 | } 77 | } 78 | })?; 79 | 80 | info!("waiting for connection…"); 81 | let (stream, _addr) = listener.accept()?; 82 | let (ctl, mut reader) = 83 | rtlsdr_mt::open(args.device_index).map_err(|_| "Could not open RTL SDR device")?; 84 | let ctl = Arc::new(Mutex::new(ctl)); 85 | 86 | let thread_ctl = std::thread::spawn({ 87 | let ctl = ctl.clone(); 88 | let should_exit = should_exit.clone(); 89 | let mut stream = stream.try_clone()?; 90 | move || { 91 | let mut buf = [0; 5]; 92 | loop { 93 | stream.read_exact(&mut buf).unwrap(); 94 | if should_exit.load(Ordering::SeqCst) { 95 | break; 96 | } 97 | match buf[0] { 98 | 0x01 => { 99 | let freq = u32::from_be_bytes((&buf[1..5]).try_into().unwrap()); 100 | info!("setting center freq to {}", freq); 101 | ctl.lock().unwrap().set_center_freq(freq).unwrap(); 102 | } 103 | 0x02 => { 104 | let sample_rate = u32::from_be_bytes((&buf[1..5]).try_into().unwrap()); 105 | info!("setting sample rate to {}", sample_rate); 106 | ctl.lock().unwrap().set_sample_rate(sample_rate).unwrap(); 107 | } 108 | 0x03 => { 109 | let gain_mode = i32::from_be_bytes((&buf[1..5]).try_into().unwrap()); 110 | if gain_mode > 0 { 111 | info!("manual tuner gain requested"); 112 | info!("setting automatic gain control to on"); 113 | ctl.lock().unwrap().enable_agc().unwrap(); 114 | } else { 115 | info!("manual tuner gain requested, disabling agc"); 116 | info!("setting automatic gain control to off"); 117 | ctl.lock().unwrap().disable_agc().unwrap(); 118 | } 119 | } 120 | 0x04 => { 121 | let gain = i32::from_be_bytes((&buf[1..5]).try_into().unwrap()); 122 | info!("setting manual gain to {}", gain); 123 | ctl.lock().unwrap().set_tuner_gain(gain).unwrap(); 124 | } 125 | 0x05 => { 126 | let ppm = i32::from_be_bytes((&buf[1..5]).try_into().unwrap()); 127 | info!("setting ppm to {}", ppm); 128 | ctl.lock().unwrap().set_ppm(ppm).unwrap(); 129 | } 130 | 0x08 => { 131 | let agc = u32::from_be_bytes((&buf[1..5]).try_into().unwrap()) == 1u32; 132 | if agc { 133 | info!("setting automatic gain control to on"); 134 | ctl.lock().unwrap().enable_agc().unwrap(); 135 | } else { 136 | info!("setting automatic gain control to off"); 137 | ctl.lock().unwrap().disable_agc().unwrap(); 138 | } 139 | } 140 | _ => { 141 | debug!("recv unsupported command {:?}", buf); 142 | } 143 | } 144 | } 145 | } 146 | }); 147 | 148 | let thread_cancel = std::thread::spawn({ 149 | move || { 150 | receiver.recv().unwrap(); 151 | info!("stopping read from device"); 152 | ctl.lock().unwrap().cancel_async_read(); 153 | should_exit.store(true, Ordering::SeqCst); 154 | } 155 | }); 156 | 157 | let mut buf_write_stream = BufWriter::with_capacity(args.tcp_buffers, stream); 158 | let mut magic_packet = vec![]; 159 | magic_packet.extend_from_slice(b"RTL0"); 160 | magic_packet.extend_from_slice(&5u32.to_be_bytes()); // FIXME 161 | magic_packet.extend_from_slice(&[0x00, 0x00, 0x00, 0x1d]); // FIXME 162 | buf_write_stream.write_all(&magic_packet)?; 163 | reader 164 | .read_async(args.buffers, 0, |bytes| { 165 | buf_write_stream.write_all(bytes).unwrap_or_else(|_err| { 166 | sender.try_send(()).expect("can't exit normally"); 167 | }); 168 | }) 169 | .unwrap(); 170 | 171 | thread_cancel.join().unwrap(); 172 | thread_ctl.join().unwrap(); 173 | 174 | Ok(()) 175 | } 176 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "anstream" 7 | version = "0.6.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 10 | dependencies = [ 11 | "anstyle", 12 | "anstyle-parse", 13 | "anstyle-query", 14 | "anstyle-wincon", 15 | "colorchoice", 16 | "is_terminal_polyfill", 17 | "utf8parse", 18 | ] 19 | 20 | [[package]] 21 | name = "anstyle" 22 | version = "1.0.10" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 25 | 26 | [[package]] 27 | name = "anstyle-parse" 28 | version = "0.2.6" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 31 | dependencies = [ 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle-query" 37 | version = "1.1.2" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 40 | dependencies = [ 41 | "windows-sys", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-wincon" 46 | version = "3.0.6" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 49 | dependencies = [ 50 | "anstyle", 51 | "windows-sys", 52 | ] 53 | 54 | [[package]] 55 | name = "bitflags" 56 | version = "2.7.0" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" 59 | 60 | [[package]] 61 | name = "build-env" 62 | version = "0.3.1" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "1522ac6ee801a11bf9ef3f80403f4ede6eb41291fac3dde3de09989679305f25" 65 | 66 | [[package]] 67 | name = "cfg-if" 68 | version = "1.0.0" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 71 | 72 | [[package]] 73 | name = "cfg_aliases" 74 | version = "0.2.1" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 77 | 78 | [[package]] 79 | name = "clap" 80 | version = "4.5.26" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" 83 | dependencies = [ 84 | "clap_builder", 85 | "clap_derive", 86 | ] 87 | 88 | [[package]] 89 | name = "clap_builder" 90 | version = "4.5.26" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" 93 | dependencies = [ 94 | "anstream", 95 | "anstyle", 96 | "clap_lex", 97 | "strsim", 98 | ] 99 | 100 | [[package]] 101 | name = "clap_derive" 102 | version = "4.5.24" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" 105 | dependencies = [ 106 | "heck", 107 | "proc-macro2", 108 | "quote", 109 | "syn", 110 | ] 111 | 112 | [[package]] 113 | name = "clap_lex" 114 | version = "0.7.4" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 117 | 118 | [[package]] 119 | name = "colorchoice" 120 | version = "1.0.3" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 123 | 124 | [[package]] 125 | name = "cstr-argument" 126 | version = "0.1.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "b6bd9c8e659a473bce955ae5c35b116af38af11a7acb0b480e01f3ed348aeb40" 129 | dependencies = [ 130 | "cfg-if", 131 | "memchr", 132 | ] 133 | 134 | [[package]] 135 | name = "ctrlc" 136 | version = "3.4.5" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" 139 | dependencies = [ 140 | "nix", 141 | "windows-sys", 142 | ] 143 | 144 | [[package]] 145 | name = "erased-serde" 146 | version = "0.4.5" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" 149 | dependencies = [ 150 | "serde", 151 | "typeid", 152 | ] 153 | 154 | [[package]] 155 | name = "foreign-types" 156 | version = "0.5.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" 159 | dependencies = [ 160 | "foreign-types-macros", 161 | "foreign-types-shared", 162 | ] 163 | 164 | [[package]] 165 | name = "foreign-types-macros" 166 | version = "0.2.3" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" 169 | dependencies = [ 170 | "proc-macro2", 171 | "quote", 172 | "syn", 173 | ] 174 | 175 | [[package]] 176 | name = "foreign-types-shared" 177 | version = "0.3.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" 180 | 181 | [[package]] 182 | name = "heck" 183 | version = "0.5.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 186 | 187 | [[package]] 188 | name = "is_terminal_polyfill" 189 | version = "1.70.1" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 192 | 193 | [[package]] 194 | name = "itoa" 195 | version = "1.0.14" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 198 | 199 | [[package]] 200 | name = "lazy_static" 201 | version = "1.5.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 204 | 205 | [[package]] 206 | name = "libc" 207 | version = "0.2.169" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 210 | 211 | [[package]] 212 | name = "libsystemd-sys" 213 | version = "0.9.3" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "ed080163caa59cc29b34bce2209b737149a4bac148cd9a8b04e4c12822798119" 216 | dependencies = [ 217 | "build-env", 218 | "libc", 219 | "pkg-config", 220 | ] 221 | 222 | [[package]] 223 | name = "listenfd" 224 | version = "1.0.1" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "e0500463acd96259d219abb05dc57e5a076ef04b2db9a2112846929b5f174c96" 227 | dependencies = [ 228 | "libc", 229 | "uuid", 230 | "winapi", 231 | ] 232 | 233 | [[package]] 234 | name = "log" 235 | version = "0.4.24" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "3d6ea2a48c204030ee31a7d7fc72c93294c92fe87ecb1789881c9543516e1a0d" 238 | dependencies = [ 239 | "value-bag", 240 | ] 241 | 242 | [[package]] 243 | name = "memchr" 244 | version = "2.7.4" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 247 | 248 | [[package]] 249 | name = "nix" 250 | version = "0.29.0" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" 253 | dependencies = [ 254 | "bitflags", 255 | "cfg-if", 256 | "cfg_aliases", 257 | "libc", 258 | ] 259 | 260 | [[package]] 261 | name = "nu-ansi-term" 262 | version = "0.46.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 265 | dependencies = [ 266 | "overload", 267 | "winapi", 268 | ] 269 | 270 | [[package]] 271 | name = "once_cell" 272 | version = "1.20.2" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 275 | 276 | [[package]] 277 | name = "overload" 278 | version = "0.1.1" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 281 | 282 | [[package]] 283 | name = "pin-project-lite" 284 | version = "0.2.16" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 287 | 288 | [[package]] 289 | name = "pkg-config" 290 | version = "0.3.31" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 293 | 294 | [[package]] 295 | name = "proc-macro2" 296 | version = "1.0.93" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 299 | dependencies = [ 300 | "unicode-ident", 301 | ] 302 | 303 | [[package]] 304 | name = "quote" 305 | version = "1.0.38" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 308 | dependencies = [ 309 | "proc-macro2", 310 | ] 311 | 312 | [[package]] 313 | name = "rtlsdr_mt" 314 | version = "2.2.0" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "7ead428bf7bc845190da3cbb5db2d54465b53e9ac4fc4ddf1d84269c11415e5a" 317 | dependencies = [ 318 | "libc", 319 | "rtlsdr_sys", 320 | ] 321 | 322 | [[package]] 323 | name = "rtlsdr_sys" 324 | version = "1.1.2" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "5b10767c93eb67d309e4e7530d5eb1e3ce2427fd48544e6488b03fb4ec255a67" 327 | dependencies = [ 328 | "libc", 329 | "pkg-config", 330 | ] 331 | 332 | [[package]] 333 | name = "rtltcp" 334 | version = "0.1.1" 335 | dependencies = [ 336 | "clap", 337 | "ctrlc", 338 | "listenfd", 339 | "rtlsdr_mt", 340 | "systemd", 341 | "tracing", 342 | "tracing-subscriber", 343 | ] 344 | 345 | [[package]] 346 | name = "ryu" 347 | version = "1.0.18" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 350 | 351 | [[package]] 352 | name = "serde" 353 | version = "1.0.217" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 356 | dependencies = [ 357 | "serde_derive", 358 | ] 359 | 360 | [[package]] 361 | name = "serde_derive" 362 | version = "1.0.217" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 365 | dependencies = [ 366 | "proc-macro2", 367 | "quote", 368 | "syn", 369 | ] 370 | 371 | [[package]] 372 | name = "serde_fmt" 373 | version = "1.0.3" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4" 376 | dependencies = [ 377 | "serde", 378 | ] 379 | 380 | [[package]] 381 | name = "sharded-slab" 382 | version = "0.1.7" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 385 | dependencies = [ 386 | "lazy_static", 387 | ] 388 | 389 | [[package]] 390 | name = "smallvec" 391 | version = "1.13.2" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 394 | 395 | [[package]] 396 | name = "strsim" 397 | version = "0.11.1" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 400 | 401 | [[package]] 402 | name = "sval" 403 | version = "2.13.2" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "f6dc0f9830c49db20e73273ffae9b5240f63c42e515af1da1fceefb69fceafd8" 406 | 407 | [[package]] 408 | name = "sval_buffer" 409 | version = "2.13.2" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "429922f7ad43c0ef8fd7309e14d750e38899e32eb7e8da656ea169dd28ee212f" 412 | dependencies = [ 413 | "sval", 414 | "sval_ref", 415 | ] 416 | 417 | [[package]] 418 | name = "sval_dynamic" 419 | version = "2.13.2" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "68f16ff5d839396c11a30019b659b0976348f3803db0626f736764c473b50ff4" 422 | dependencies = [ 423 | "sval", 424 | ] 425 | 426 | [[package]] 427 | name = "sval_fmt" 428 | version = "2.13.2" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "c01c27a80b6151b0557f9ccbe89c11db571dc5f68113690c1e028d7e974bae94" 431 | dependencies = [ 432 | "itoa", 433 | "ryu", 434 | "sval", 435 | ] 436 | 437 | [[package]] 438 | name = "sval_json" 439 | version = "2.13.2" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "0deef63c70da622b2a8069d8600cf4b05396459e665862e7bdb290fd6cf3f155" 442 | dependencies = [ 443 | "itoa", 444 | "ryu", 445 | "sval", 446 | ] 447 | 448 | [[package]] 449 | name = "sval_nested" 450 | version = "2.13.2" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "a39ce5976ae1feb814c35d290cf7cf8cd4f045782fe1548d6bc32e21f6156e9f" 453 | dependencies = [ 454 | "sval", 455 | "sval_buffer", 456 | "sval_ref", 457 | ] 458 | 459 | [[package]] 460 | name = "sval_ref" 461 | version = "2.13.2" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "bb7c6ee3751795a728bc9316a092023529ffea1783499afbc5c66f5fabebb1fa" 464 | dependencies = [ 465 | "sval", 466 | ] 467 | 468 | [[package]] 469 | name = "sval_serde" 470 | version = "2.13.2" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "2a5572d0321b68109a343634e3a5d576bf131b82180c6c442dee06349dfc652a" 473 | dependencies = [ 474 | "serde", 475 | "sval", 476 | "sval_nested", 477 | ] 478 | 479 | [[package]] 480 | name = "syn" 481 | version = "2.0.96" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 484 | dependencies = [ 485 | "proc-macro2", 486 | "quote", 487 | "unicode-ident", 488 | ] 489 | 490 | [[package]] 491 | name = "systemd" 492 | version = "0.10.0" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "afec0101d9ae8ab26aedf0840109df689938ea7e538aa03df4369f1854f11562" 495 | dependencies = [ 496 | "cstr-argument", 497 | "foreign-types", 498 | "libc", 499 | "libsystemd-sys", 500 | "log", 501 | "memchr", 502 | "utf8-cstr", 503 | ] 504 | 505 | [[package]] 506 | name = "thread_local" 507 | version = "1.1.8" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 510 | dependencies = [ 511 | "cfg-if", 512 | "once_cell", 513 | ] 514 | 515 | [[package]] 516 | name = "tracing" 517 | version = "0.1.41" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 520 | dependencies = [ 521 | "pin-project-lite", 522 | "tracing-attributes", 523 | "tracing-core", 524 | ] 525 | 526 | [[package]] 527 | name = "tracing-attributes" 528 | version = "0.1.28" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 531 | dependencies = [ 532 | "proc-macro2", 533 | "quote", 534 | "syn", 535 | ] 536 | 537 | [[package]] 538 | name = "tracing-core" 539 | version = "0.1.33" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 542 | dependencies = [ 543 | "once_cell", 544 | "valuable", 545 | ] 546 | 547 | [[package]] 548 | name = "tracing-log" 549 | version = "0.2.0" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 552 | dependencies = [ 553 | "log", 554 | "once_cell", 555 | "tracing-core", 556 | ] 557 | 558 | [[package]] 559 | name = "tracing-subscriber" 560 | version = "0.3.19" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 563 | dependencies = [ 564 | "nu-ansi-term", 565 | "sharded-slab", 566 | "smallvec", 567 | "thread_local", 568 | "tracing-core", 569 | "tracing-log", 570 | ] 571 | 572 | [[package]] 573 | name = "typeid" 574 | version = "1.0.2" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" 577 | 578 | [[package]] 579 | name = "unicode-ident" 580 | version = "1.0.14" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 583 | 584 | [[package]] 585 | name = "utf8-cstr" 586 | version = "0.1.6" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "55bcbb425141152b10d5693095950b51c3745d019363fc2929ffd8f61449b628" 589 | 590 | [[package]] 591 | name = "utf8parse" 592 | version = "0.2.2" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 595 | 596 | [[package]] 597 | name = "uuid" 598 | version = "1.11.1" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" 601 | 602 | [[package]] 603 | name = "valuable" 604 | version = "0.1.0" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 607 | 608 | [[package]] 609 | name = "value-bag" 610 | version = "1.10.0" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" 613 | dependencies = [ 614 | "value-bag-serde1", 615 | "value-bag-sval2", 616 | ] 617 | 618 | [[package]] 619 | name = "value-bag-serde1" 620 | version = "1.10.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b" 623 | dependencies = [ 624 | "erased-serde", 625 | "serde", 626 | "serde_fmt", 627 | ] 628 | 629 | [[package]] 630 | name = "value-bag-sval2" 631 | version = "1.10.0" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a" 634 | dependencies = [ 635 | "sval", 636 | "sval_buffer", 637 | "sval_dynamic", 638 | "sval_fmt", 639 | "sval_json", 640 | "sval_ref", 641 | "sval_serde", 642 | ] 643 | 644 | [[package]] 645 | name = "winapi" 646 | version = "0.3.9" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 649 | dependencies = [ 650 | "winapi-i686-pc-windows-gnu", 651 | "winapi-x86_64-pc-windows-gnu", 652 | ] 653 | 654 | [[package]] 655 | name = "winapi-i686-pc-windows-gnu" 656 | version = "0.4.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 659 | 660 | [[package]] 661 | name = "winapi-x86_64-pc-windows-gnu" 662 | version = "0.4.0" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 665 | 666 | [[package]] 667 | name = "windows-sys" 668 | version = "0.59.0" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 671 | dependencies = [ 672 | "windows-targets", 673 | ] 674 | 675 | [[package]] 676 | name = "windows-targets" 677 | version = "0.52.6" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 680 | dependencies = [ 681 | "windows_aarch64_gnullvm", 682 | "windows_aarch64_msvc", 683 | "windows_i686_gnu", 684 | "windows_i686_gnullvm", 685 | "windows_i686_msvc", 686 | "windows_x86_64_gnu", 687 | "windows_x86_64_gnullvm", 688 | "windows_x86_64_msvc", 689 | ] 690 | 691 | [[package]] 692 | name = "windows_aarch64_gnullvm" 693 | version = "0.52.6" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 696 | 697 | [[package]] 698 | name = "windows_aarch64_msvc" 699 | version = "0.52.6" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 702 | 703 | [[package]] 704 | name = "windows_i686_gnu" 705 | version = "0.52.6" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 708 | 709 | [[package]] 710 | name = "windows_i686_gnullvm" 711 | version = "0.52.6" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 714 | 715 | [[package]] 716 | name = "windows_i686_msvc" 717 | version = "0.52.6" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 720 | 721 | [[package]] 722 | name = "windows_x86_64_gnu" 723 | version = "0.52.6" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 726 | 727 | [[package]] 728 | name = "windows_x86_64_gnullvm" 729 | version = "0.52.6" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 732 | 733 | [[package]] 734 | name = "windows_x86_64_msvc" 735 | version = "0.52.6" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 738 | --------------------------------------------------------------------------------