diff --git a/.vscode/launch.json b/.vscode/launch.json index d6f0d78..7f5506b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,16 +7,16 @@ { "type": "lldb", "request": "launch", - "name": "Debug unit tests in library 'doip'", + "name": "Debug unit tests in library 'simple_doip'", "cargo": { "args": [ "test", "--no-run", "--lib", - "--package=doip" + "--package=simple_doip" ], "filter": { - "name": "doip", + "name": "simple_doip", "kind": "lib" } }, @@ -31,7 +31,7 @@ "args": [ "build", "--example=simple_client", - "--package=doip" + "--package=simple_doip" ], "filter": { "name": "simple_client", @@ -50,7 +50,7 @@ "test", "--no-run", "--example=simple_client", - "--package=doip" + "--package=simple_doip" ], "filter": { "name": "simple_client", @@ -68,7 +68,7 @@ "args": [ "build", "--example=echo_server", - "--package=doip" + "--package=simple_doip" ], "filter": { "name": "echo_server", @@ -87,7 +87,7 @@ "test", "--no-run", "--example=echo_server", - "--package=doip" + "--package=simple_doip" ], "filter": { "name": "echo_server", @@ -106,7 +106,7 @@ "test", "--no-run", "--test=integration_test", - "--package=doip" + "--package=simple_doip" ], "filter": { "name": "integration_test", diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 1a8b3b9..1587f28 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -566,8 +566,8 @@ returning `true` breaks it. Either delete the field or make the loop honor it. ### 7.6 Other rough edges -These are documented in `README.md` under **Status** and are repeated here only -as a pointer: no TLS; no unsolicited UDP vehicle announcement at power-on +The README's **Scope and limitations** section names these for an integrator +choosing the crate; the mechanics are here. No TLS; no unsolicited UDP vehicle announcement at power-on (identification requests over UDP *are* answered, but only by `Server::run_udp_responder` on a socket the caller binds and drives — `run_server` binds TCP alone — and only the broadcast `0x0001` form, since `Payload::decode` diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..57fee90 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,110 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/) (treating +`0.x` breaking changes as minor bumps, per the Cargo/SemVer convention for +pre-1.0 crates). + +This file was reconstructed from the commit and pull-request history when the +crate was prepared for publication, so entries before that point describe what +changed rather than what was announced at the time. + +## [Unreleased] + +### Added + +- `LICENSE-MIT` and `LICENSE-APACHE`. The manifest had declared + `MIT OR Apache-2.0` without carrying either text. +- `CHANGELOG.md`, `CONTRIBUTING.md`, `SECURITY.md`. +- `release-plz.toml`. Versioning, the changelog, tags, GitHub releases + and the crates.io publish are handled by release-plz through the + org-wide reusable workflow, matching `uds_protocol` and + `automotive_wire_codec`. There is no release workflow in this repo. + +### Changed + +- docs.rs now builds with all features, so the `client`, `server` and `codec` + API appears in the published documentation. `default = []`, so the default + build documents only the `no_std` core. +- `release-plz.toml` and `rust-toolchain.toml` are no longer packaged into + the published crate. + +## [0.5.2] — 2026-09-03 + +### Fixed + +- A failed connection reported `Error::SocketNotBound` instead of the + underlying connect error, so the reason a connection failed was discarded + and no log level revealed it. + +## [0.5.1] — 2026-08-25 + +### Fixed + +- A response already buffered by the client was dropped when the connection + closed, instead of being delivered to the caller waiting for it. + +## [0.5.0] — 2026-08-25 + +### Changed + +- **Breaking:** the diagnostic-message response timeout is configurable on + `ClientOptions`, and the client now waits `A_DoIP_Diagnostic_Message` for an + acknowledgement rather than the 50 ms figure ISO 13400-2 places on a DoIP + *entity*. The old value timed out on any peer that took longer than 50 ms to + acknowledge. + +## [0.4.0] — 2026-08-19 + +### Changed + +- **Breaking:** `ServerConnectionHandler::diagnostic_message` takes + `&mut dyn ResponseWriter` and returns `Result<(), Error>`. It previously + returned a single `OwnedMessage`, so a handler could emit either the + `DiagnosticMessageAck` or the functional response but not both — which is + what DoIP prescribes, and what a UDS tester waits for. + +### Added + +- `ResponseWriter`, so a handler can emit an acknowledgement, any number of + "response pending" messages, and a final answer, awaiting work between them. +- `Server::run_server_with_listener`, for injecting a bound `TcpListener`. +- `Server::run_udp_responder`, answering vehicle-identification requests over + UDP. + +## [0.3.1] — 2026-08-12 + +### Changed + +- A routing-activation denial is returned to the caller as an error instead of + only being logged. + +## [0.3.0] — 2026-07-30 + +### Changed + +- `MessageError` is built on the `automotive-wire-codec` error fragments, which + makes that crate's error taxonomy part of this crate's public API. + +## [0.2.0] — 2026-07-30 + +### Changed + +- **Breaking:** the protocol core is `no_std` and zero-copy. Messages borrow + from the receive buffer instead of allocating, `alloc` gates the owned + mirrors, and `std` and the async layers became opt-in Cargo features + (`default = []`). + +## [0.1.0] + +Initial implementation: DoIP message types, framing, and an async client and +server over tokio. + + + +[Unreleased]: https://github.com/luminartech/simple_doip/compare/v0.5.1...HEAD +[0.5.1]: https://github.com/luminartech/simple_doip/compare/v0.1.0...v0.5.1 +[0.1.0]: https://github.com/luminartech/simple_doip/releases/tag/v0.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bf2e4bb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,87 @@ +# Contributing + +Pull requests are welcome, as are bug reports and questions in the issue +tracker. + +[`ARCHITECTURE.md`](ARCHITECTURE.md) is the place to start for anything beyond +a small fix. It covers the feature-gated layering, the sans-io framing/decode +seam, the error taxonomy, and — in its last section — the invariants to +preserve when changing the crate. + +## Building and testing + +The minimum supported Rust version is **1.88**. `default = []`, so a bare +`cargo test` exercises only the `no_std` core: + +```sh +cargo test --all-features # everything +cargo test --features client,server # the async layers +cargo test --no-default-features # the no_std core alone +``` + +The `no_std` core must keep building for a bare-metal target: + +```sh +rustup target add thumbv7em-none-eabihf +cargo check --no-default-features --target thumbv7em-none-eabihf +``` + +CI additionally checks each feature individually, `cargo fmt`, and +`cargo clippy --all-features -- -D warnings -Dclippy::pedantic`, and builds the +documentation with `RUSTDOCFLAGS=-D warnings`. Running the three commands above +plus `cargo fmt` and clippy locally will catch almost everything before it gets +there. + +## Wire-format changes + +`tests/golden_vectors.rs` decodes and re-encodes byte sequences held as `.hex` +files in `tests/golden/`. A change that alters the bytes on the wire should +either fail one of those vectors or add a new one — a round-trip test written +against the crate's own output passes whenever `encode` and `decode` share the +same misreading. + +## Commits and pull requests + +Commit subjects follow [Conventional Commits](https://www.conventionalcommits.org/) +(`feat:`, `fix:`, `docs:`, `build:`, `chore:`, with a `!` for a breaking +change), because the changelog is organized around them. Say what changed and +why in the body. + +**The pull request title is the one that counts.** The repository merges by +squash with `squash_merge_commit_title: PR_TITLE`, so the PR title — not the +subjects of the commits on the branch — becomes the commit subject on `main`, +and that is what the changelog and the next version number are computed from. +A branch whose commits are immaculate still lands as whatever the PR title +says. CI lints the title for you. + +## Releases + +[release-plz](https://release-plz.dev) owns versioning, the changelog, tags, +GitHub releases, and the crates.io publish. There is no release workflow in +this repository and no version to bump by hand: a push to `main` maintains an +open release PR, and merging that PR publishes. `release-plz.toml` holds the +configuration, shared byte-for-byte with `uds_protocol` and +`automotive_wire_codec`. + +The version comes out of the squashed subjects since the last release: + +| Subject | Effect while `0.x` | +|---|---| +| `feat:` | minor | +| `fix:`, `perf:`, `refactor:`, `revert:`, `docs:` | patch | +| `chore:`, `ci:`, `build:`, `test:`, `style:` | nothing on their own | +| any of the above with `!`, or a `BREAKING CHANGE:` footer | minor | + +Pre-1.0 a breaking change is a minor bump, so `!` is what lifts a `fix:` out +of a patch. Reach for it whenever a caller has to change something to keep +working — including changes the compiler will not flag. A function that +starts emitting different bytes breaks a caller as surely as a renamed +argument does, and `cargo-semver-checks` inspects the API surface, so it will +not catch that one for you. + +## Licensing + +Contributions are dual-licensed under +[MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at the user's option, +matching the crate itself. By opening a pull request you agree that your +contribution may be distributed under those terms. diff --git a/Cargo.lock b/Cargo.lock index d48cd9d..fb7441a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,7 +31,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", "futures-sink", @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" @@ -135,38 +135,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.5", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-channel", "futures-core", @@ -176,7 +176,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -289,12 +288,6 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "proc-macro2" version = "1.0.106" @@ -389,7 +382,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -403,6 +396,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "thiserror" version = "2.0.18" @@ -420,7 +424,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -457,7 +461,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d3d0363..5d47b84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,21 @@ repository = "https://github.com/luminartech/simple_doip" readme = "README.md" keywords = ["doip", "iso13400", "automotive", "diagnostics", "no-std"] categories = ["network-programming", "embedded", "no-std"] -exclude = ["docs/", ".github/", ".vscode/"] +exclude = [ + "docs/", + ".github/", + ".vscode/", + # Repo-local tooling, not part of the library a consumer receives. + "release-plz.toml", + "rust-toolchain.toml", +] + +# `default = []`, so docs.rs would otherwise build the no_std core alone and +# publish a reference with no `client`, `server`, `codec`, `alloc` or `std` +# API in it -- most of what the README points a reader at. Every feature is +# additive, so all of them can be on at once. +[package.metadata.docs.rs] +all-features = true [dependencies] automotive-wire-codec = "0.3" diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 850bd79..11fa10c 100644 --- a/README.md +++ b/README.md @@ -8,53 +8,29 @@ the feature-gated layering, the sans-io framing/decode seam, the error taxonomy, the relationship to `automotive-wire-codec`, and the known issues and deferred refactors a new maintainer should read before changing anything. -## Status - -The protocol core (framing, message encode/decode, golden-vector-tested -against the on-wire format) is solid and exercised by the test suite. The -async `client` and `server` layers work for the common case but have known -gaps a new integrator should know about before relying on them: - -- **No TLS.** Connections are established in the clear on `TCP_PORT` - (`13400`); `TCP_TLS_PORT` (`3496`) is defined per ISO 13400-2 but nothing in - this crate uses it. -- **No unsolicited UDP vehicle announcement.** The server never sends the UDP - vehicle-announcement broadcast on startup, so a tester learns of an entity - only by asking. Vehicle identification requests over UDP *are* answered, but - only by `Server::run_udp_responder`, on a `UdpSocket` the caller bound and - drives: `run_server` binds TCP alone, so an entity that starts through it - and nothing else is invisible to a discovery probe. `run_udp_responder` - answers the broadcast request form (`0x0001`) only; the directed - with-EID (`0x0002`) and with-VIN (`0x0003`) forms are declined, because - `Payload::decode` discards the EID/VIN bytes and the responder cannot tell - whether it is the addressee. -- **The server accepts one TCP connection at a time.** The accept loop in - `Server::run_server_with_listener` (which `Server::run_server` delegates to) - awaits each client's connection handling to completion before calling - `accept()` again, so a second client cannot connect while the first is still - being served — and one tester that connects and then stalls wedges that - entity until it disconnects. -- **Entity status requests and vehicle identification requests over TCP are - silently dropped.** `Server::handle_client_message` logs a warning and sends - no reply for either, so a tester that asks gets silence rather than an error - or a negative response. Identification requests are answered on the UDP path - only. -- **A `DiagnosticMessage` arriving while the client is waiting for an ACK is - silently discarded.** After `Client::send_diagnostic_message`, the inner - client is in its `AwaitAck` state; a `DiagnosticMessage` that arrives before - the acknowledgement is neither buffered nor forwarded to the update channel - (only a generic `trace!` of the received message marks its passing) — it is - simply dropped. This requires the peer to acknowledge - before it responds. A peer that responds first (or that coalesces both into - one burst the client reads out of order) will appear to never answer, and the - subsequent `receive_diagnostic_response` will time out. -- **`ClientConnectionInfo::logical_address` is always `0x0000`.** The server - does not yet track per-connection logical addresses, so this field is a - placeholder rather than the client's real address. -- The handler passed to `Server::new` is not validated. - -None of this blocks bare-metal or single-client use; it matters if you need -concurrent clients, unsolicited announcement, or TLS today. +## Scope and limitations + +The protocol core — framing, message encode/decode — is golden-vector tested +against the on-wire format. The async `client` and `server` cover the common +case, within these bounds: + +- **No TLS.** Connections are in the clear on `TCP_PORT` (`13400`); + `TCP_TLS_PORT` (`3496`) is defined by ISO 13400-2 and unused here. +- **The server serves one TCP connection at a time.** A second client cannot + connect while the first is being served. +- **No unsolicited UDP vehicle announcement.** A tester learns of an entity only + by asking, and identification is answered on the UDP path only, by + `Server::run_udp_responder` on a socket the caller binds and drives. +- **The client requires the peer to acknowledge before it responds.** A + `DiagnosticMessage` that arrives while the client is waiting for the + acknowledgement is dropped, so a peer that answers first appears never to + answer at all. +- **`ClientConnectionInfo::logical_address` is not yet tracked per connection.** + +[`ARCHITECTURE.md`](ARCHITECTURE.md) §7 has the mechanics behind each of these, +and the deferred work around them. + +None of this constrains bare-metal or single-client use. ## Quickstart @@ -156,6 +132,13 @@ semver: a breaking change in that crate is a breaking change here too. The minimum supported Rust version is **1.88**, bound by let-chain syntax used in this crate. +## Contributing + +Pull requests, bug reports and questions are welcome — see +[`CONTRIBUTING.md`](CONTRIBUTING.md). Security reports go through GitHub's +private vulnerability reporting; see [`SECURITY.md`](SECURITY.md). + ## License -Licensed under either of MIT or Apache-2.0 at your option. +Licensed under either of [MIT](LICENSE-MIT) or +[Apache-2.0](LICENSE-APACHE) at your option. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..2f5d9ae --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,35 @@ +# Security policy + +## Reporting a vulnerability + +Report security issues through GitHub's private vulnerability reporting: open +the [Security tab](https://github.com/luminartech/simple_doip/security) and +choose **Report a vulnerability**. That opens a private advisory visible only +to the maintainers. + +Please do not open a public issue for a security report. + +A report is most useful with the crate version, the feature set enabled, and a +byte sequence or test case that reproduces the behavior. + +## Supported versions + +This crate is pre-1.0. Fixes land on the latest published version; there are no +maintained release branches. + +## Scope + +`simple_doip` implements the ISO 13400-2 transport. Two properties of that +protocol matter when assessing a report, because they are the specification's +design rather than defects in this crate: + +- **DoIP carries no transport security.** Connections on `TCP_PORT` (`13400`) + are in the clear. `TCP_TLS_PORT` (`3496`) is defined by ISO 13400-2, and + nothing in this crate uses it. +- **Routing activation is not authentication.** It is an addressing handshake. + Any access control over a diagnostic session belongs to the layers above + this one. + +What is in scope: anything that makes the crate misbehave on attacker-supplied +bytes — a panic, an out-of-bounds read, an unbounded allocation, a decode that +accepts a frame it should reject, or a hang reachable from the wire. diff --git a/release-plz.toml b/release-plz.toml new file mode 100644 index 0000000..3cd7368 --- /dev/null +++ b/release-plz.toml @@ -0,0 +1,35 @@ +# release-plz owns versioning, the changelog, tags, GitHub releases, and the +# crates.io publish. The jobs that run it live in the org-wide reusable +# workflow (`use-release-plz: true` in `.github/workflows/main.yml`), so there +# is no release workflow in this repository. +# +# The values below are byte-identical to `uds_protocol` and +# `automotive_wire_codec`. Keep them that way: the point of the shared config +# is that a reader of one protocol repo already knows the others. +# +# How a version gets decided: the repo squash-merges with +# `squash_merge_commit_title: PR_TITLE`, so the PR *title* is the commit +# subject on `main`, and these parsers read those subjects. `fix:` and `feat:` +# move the version; `chore`/`ci`/`build`/`test`/`style` are invisible to it. +# A breaking change needs an explicit `!` (`fix(messages)!: ...`) or a +# `BREAKING CHANGE:` footer -- see CONTRIBUTING.md. +[workspace] +changelog_update = true +git_release_enable = true + +[changelog] +commit_parsers = [ + { message = "^feat", group = "Added" }, + { message = "^fix", group = "Fixed" }, + { message = "^perf", group = "Performance" }, + { message = "^docs?", group = "Documentation" }, + { message = "^refactor", group = "Changed" }, + { message = "^revert", group = "Reverted" }, + { message = "^style", skip = true }, + { message = "^test", skip = true }, + { message = "^chore\\(release\\)", skip = true }, + { message = "^chore", skip = true }, + { message = "^ci", skip = true }, + { message = "^build", skip = true }, + { message = ".*", group = "Other" }, +]