diff --git a/.github/workflows/latest-dependencies.yaml b/.github/workflows/latest-dependencies.yaml index 22ef11b2..7dde495b 100644 --- a/.github/workflows/latest-dependencies.yaml +++ b/.github/workflows/latest-dependencies.yaml @@ -106,14 +106,18 @@ jobs: cargo update --verbose - name: Build with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature build --locked - name: Run tests (bins/lib/tests/examples) with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature test --locked @@ -126,17 +130,23 @@ jobs: # certain features only for some doctests, so we run them without # `cargo-hack`. - name: Run doctests with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo test --locked --all-features --doc - - name: Build package with all features enabled - # We allow dirty state here because it is only expected after update. - run: >- - cargo package - --locked --all-features - --allow-dirty + # FIXME: Re-enable this step after switching to open62541-sys v0.6.x. + #- name: Build package with all features enabled + #- name: Build package with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + #if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} + # We allow dirty state here because it is only expected after update. + #run: >- + # cargo package + # --locked --all-features + # --allow-dirty diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d6c07e50..b876d92e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -128,14 +128,18 @@ jobs: shared-key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.target }}-${{ matrix.runner_os }} - name: Build with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature build --locked - name: Run tests (bins/lib/tests/examples) with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature test --locked @@ -148,15 +152,20 @@ jobs: # certain features only for some doctests, so we run them without # `cargo-hack`. - name: Run doctests with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo test --locked --all-features --doc - - name: Build package with all features enabled - run: >- - cargo package - --locked --all-features + # FIXME: Re-enable this step after switching to open62541-sys v0.6.x. + #- name: Build package with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + #if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} + #run: >- + # cargo package + # --locked --all-features diff --git a/CHANGELOG.md b/CHANGELOG.md index 428265d1..25852589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,19 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Add method `ua::VariableAttributes::with_array_dimensions()`. - Add method `Server::add_data_type_node()` and type `DataTypeNode`. +- Add method `ua::CertificateVerification::memory_store()` and `ua::TrustListDataType`. + +### Changed + +- Breaking: Upgrade to open62541 version + [1.5.0](https://github.com/open62541/open62541/releases/tag/v1.5.0). +- Breaking: Remove method `ua::CertificateVerification::custom()` and trait + `CustomCertificateVerification`. +- Breaking: Remove `Unknown` variant from `ua::DataTypeDefinition`. +- Breaking: Return `Result` from `DataTypeExt::from_inner()`. +- Breaking: Replace `ua::String::is_invalid()` with `ua::String::is_null()`. +- Breaking: Replace `ua::ByteString::is_invalid()` with `ua::ByteString::is_null()`. +- Breaking: Remove `into_expanded_node_id()` from `ua::NodeId`. Use `Into::into()` instead. - Add `ua::DataTypeDescription`, `ua::EnumDescription`, `ua::StructureDescription`, `ua::StructureField`, `ua::StructureType`. - Add missing accessor methods to `ua::StructureDefinition`. @@ -22,14 +35,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Add method `new()` to `ua::ExpandedNodeId`. - Add `From`/`Into` conversion from `ua::NodeId` to `ua::ExpandedNodeId`. -### Changed - -- Breaking: Remove `Unknown` variant from `ua::DataTypeDefinition`. -- Breaking: Return `Result` from `DataTypeExt::from_inner()`. -- Breaking: Replace `ua::String::is_invalid()` with `ua::String::is_null()`. -- Breaking: Replace `ua::ByteString::is_invalid()` with `ua::ByteString::is_null()`. -- Breaking: Remove `into_expanded_node_id()` from `ua::NodeId`. Use `Into::into()` instead. - ### Fixed - Fix linker errors for build target `x86_64-linux-unknown-gnu` by updating `open62541-sys` to diff --git a/Cargo.lock b/Cargo.lock index 19cda02b..ebe3edb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,36 +2,15 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -43,78 +22,65 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" @@ -124,15 +90,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bcder" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627747a6774aab38beb35990d88309481378558875a41da1a4b2e373c906ef0" +checksum = "1f7c42c9913f68cf9390a225e81ad56a5c515347287eb98baa710090ca1de86d" dependencies = [ "bytes", "smallvec", @@ -160,27 +126,27 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.4.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytes" -version = "1.9.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.57" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "shlex", @@ -197,27 +163,26 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.52.0", + "windows-link", ] [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -226,18 +191,18 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "const-oid" @@ -253,9 +218,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "zeroize", @@ -263,25 +228,47 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", - "serde", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn", + "unicode-xid", ] [[package]] name = "either" -version = "1.9.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "env_filter" -version = "0.1.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", "regex", @@ -289,14 +276,14 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.1" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] @@ -308,9 +295,9 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -323,9 +310,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -333,15 +320,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -350,15 +337,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -367,21 +354,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -391,50 +378,37 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - [[package]] name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "hermit-abi" -version = "0.3.9" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hex" @@ -442,22 +416,17 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -471,6 +440,12 @@ dependencies = [ "cc", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.13.0" @@ -491,15 +466,39 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jiff" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -507,41 +506,40 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-link", ] [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.20" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "minimal-lexical" @@ -549,15 +547,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - [[package]] name = "nom" version = "7.1.3" @@ -584,35 +573,23 @@ dependencies = [ ] [[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "once_cell" -version = "1.20.2" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open62541" version = "0.10.1" dependencies = [ "anyhow", + "derive_more", "env_logger", "futures", "futures-channel", @@ -635,9 +612,8 @@ dependencies = [ [[package]] name = "open62541-sys" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c391efd372284037bf63d0d43249ff118cc25e94ec07d1a8a9508844c1cc2b6a" +version = "0.6.0" +source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#ffda3c08c1b7eaa7cfa5a5c24b3ea5db58c3c29e" dependencies = [ "bindgen", "cc", @@ -647,9 +623,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -657,44 +633,53 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.0", + "windows-link", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ "base64", - "serde", + "serde_core", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "portable-atomic" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +dependencies = [ + "portable-atomic", +] [[package]] name = "powerfmt" @@ -704,15 +689,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" -version = "0.2.16" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", @@ -720,18 +708,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -749,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -759,7 +747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -768,32 +756,32 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -803,9 +791,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -814,41 +802,44 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "ring" -version = "0.17.12" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9b823fa29b721a59671b41d6b06e66b29e0628e207e8b1c3ceeda701ec928d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", ] [[package]] -name = "rustc-demangle" -version = "0.1.23" +name = "rustc-hash" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] -name = "rustc-hash" -version = "2.1.0" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] [[package]] -name = "ryu" -version = "1.0.16" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "scopeguard" @@ -856,20 +847,35 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" -version = "1.0.196" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -878,13 +884,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] @@ -904,18 +912,15 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "spki" @@ -929,9 +934,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -940,18 +945,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -960,30 +965,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.38" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb041120f25f8fbe8fd2dbe4671c7c2ed74d83be2e7a77529bf7e0790ae3f472" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.3" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.20" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -991,21 +996,19 @@ dependencies = [ [[package]] name = "tokio" -version = "1.38.2" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68722da18b0fc4a05fdc1120b302b82051265792a1e1b399086e9b204b10ad3d" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", - "num_cpus", "pin-project-lite", "tokio-macros", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", @@ -1014,9 +1017,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -1026,17 +1035,19 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ - "serde", + "js-sys", + "serde_core", + "wasm-bindgen", ] [[package]] @@ -1047,50 +1058,37 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1098,172 +1096,172 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-targets 0.52.0", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ - "windows-targets 0.48.5", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "windows-interface" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ - "windows-targets 0.52.0", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.52.0" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows-link", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_aarch64_gnullvm" +name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] [[package]] -name = "windows_i686_gnu" -version = "0.48.5" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "windows_i686_gnu" -version = "0.52.0" +name = "windows_aarch64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_i686_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_msvc" -version = "0.52.0" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +name = "windows_i686_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "x509-certificate" @@ -1284,22 +1282,48 @@ dependencies = [ "zeroize", ] +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 3e1a60b9..87d4f0b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,14 @@ categories = ["network-programming", "embedded", "api-bindings"] include = ["src/", "README.md", "CHANGELOG.md", "LICENSES/MPL-2.0.txt"] [dependencies] +derive_more = { version = "2.0.1", features = ["debug"] } futures-channel = "0.3.30" futures-core = { version = "0.3.30", default-features = false } log = "0.4.20" -open62541-sys = "0.5.4" +# FIXME: Revert before merge. +# FIXME: After depending on open62541-sys v0.6.x re-enable the final packaging step +# in .github/workflows/test.yaml and .github/workflows/latest-dependencies.yaml. +open62541-sys = { git = "https://github.com/HMIProject/open62541-sys.git", branch = "open62541-1.5" } parking_lot = "0.12.4" paste = "1.0.14" serde = { version = "1.0.194", optional = true } diff --git a/src/async_subscription.rs b/src/async_subscription.rs index 499a310d..c78deaea 100644 --- a/src/async_subscription.rs +++ b/src/async_subscription.rs @@ -268,11 +268,10 @@ async fn create_subscription( _client: *mut UA_Client, userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_CreateSubscriptionResponse, ) { log::debug!("Subscriptions_create() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); @@ -334,11 +333,10 @@ fn delete_subscriptions(client: &ua::Client, request: &ua::DeleteSubscriptionsRe _client: *mut UA_Client, _userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_DeleteSubscriptionsResponse, ) { log::debug!("Subscriptions_delete() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); diff --git a/src/client.rs b/src/client.rs index e9233412..d58b9382 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,8 +1,7 @@ use std::{ffi::CString, ptr, time::Duration}; use open62541_sys::{ - UA_CertificateVerification_AcceptAll, UA_Client_connect, UA_Client_getEndpoints, - UA_ClientConfig, + UA_CertificateGroup_AcceptAll, UA_Client_connect, UA_Client_getEndpoints, UA_ClientConfig, }; use crate::{DataType as _, Error, Result, ua}; @@ -195,7 +194,7 @@ impl ClientBuilder { pub fn accept_all(mut self) -> Self { let config = self.config_mut(); unsafe { - UA_CertificateVerification_AcceptAll(&raw mut config.certificateVerification); + UA_CertificateGroup_AcceptAll(&raw mut config.certificateVerification); } self } diff --git a/src/lib.rs b/src/lib.rs index fb88ee90..cde88f14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,10 +253,7 @@ pub use self::{ ServerBuilder, ServerRunner, VariableNode, }, service::{ServiceRequest, ServiceResponse}, - traits::{ - Attribute, Attributes, CustomCertificateVerification, DataTypeExt, FilterOperand, - MonitoringFilter, - }, + traits::{Attribute, Attributes, DataTypeExt, FilterOperand, MonitoringFilter}, userdata::{Userdata, UserdataSentinel}, value::{ScalarValue, ValueType, VariantValue}, }; diff --git a/src/monitored_item/create_monitored_items.rs b/src/monitored_item/create_monitored_items.rs index b744cb1f..228cb318 100644 --- a/src/monitored_item/create_monitored_items.rs +++ b/src/monitored_item/create_monitored_items.rs @@ -290,11 +290,10 @@ unsafe extern "C" fn response_callback_c( _client: *mut UA_Client, userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_CreateMonitoredItemsResponse, ) { log::debug!("MonitoredItems_createDataChanges() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); diff --git a/src/monitored_item/delete_monitored_items.rs b/src/monitored_item/delete_monitored_items.rs index 442f9456..6b75285e 100644 --- a/src/monitored_item/delete_monitored_items.rs +++ b/src/monitored_item/delete_monitored_items.rs @@ -56,11 +56,10 @@ unsafe extern "C" fn callback_execute_response_c( _client: *mut UA_Client, userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_DeleteMonitoredItemsResponse, ) { log::debug!("MonitoredItems_delete_async() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); @@ -114,11 +113,10 @@ unsafe extern "C" fn callback_log_response_c( _client: *mut UA_Client, _userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_DeleteMonitoredItemsResponse, ) { log::debug!("MonitoredItems_delete_async() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); diff --git a/src/server.rs b/src/server.rs index 2b4556af..d5a0a46f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -7,23 +7,23 @@ mod node_types; use std::{ any::Any, ffi::{CString, c_void}, - ptr, + mem, ptr, sync::Arc, time::Instant, }; +use derive_more::Debug; use open62541_sys::{ - __UA_Server_addNode, UA_CertificateVerification_AcceptAll, UA_NodeId, - UA_STATUSCODE_BADNOTFOUND, UA_Server, UA_Server_addDataSourceVariableNode, - UA_Server_addDataTypeNode, UA_Server_addMethodNodeEx, UA_Server_addNamespace, - UA_Server_addReference, UA_Server_browse, UA_Server_browseNext, UA_Server_browseRecursive, - UA_Server_browseSimplifiedBrowsePath, UA_Server_createEvent, UA_Server_deleteNode, + UA_CertificateGroup_AcceptAll, UA_GlobalNodeLifecycle, UA_NodeId, UA_STATUSCODE_BADNOTFOUND, + UA_Server, UA_Server_addCallbackValueSourceVariableNode, UA_Server_addDataTypeNode, + UA_Server_addMethodNodeEx, UA_Server_addNamespace, UA_Server_addNode_begin, + UA_Server_addNode_finish, UA_Server_addReference, UA_Server_browse, UA_Server_browseNext, + UA_Server_browseRecursive, UA_Server_browseSimplifiedBrowsePath, UA_Server_deleteNode, UA_Server_deleteReference, UA_Server_getConfig, UA_Server_getNamespaceByIndex, UA_Server_getNamespaceByName, UA_Server_getStatistics, UA_Server_read, UA_Server_readObjectProperty, UA_Server_run_iterate, UA_Server_run_shutdown, UA_Server_run_startup, UA_Server_runUntilInterrupt, UA_Server_translateBrowsePathToNodeIds, - UA_Server_triggerEvent, UA_Server_writeDataValue, UA_Server_writeObjectProperty, - UA_Server_writeValue, UA_ServerConfig, + UA_Server_writeDataValue, UA_Server_writeObjectProperty, UA_Server_writeValue, UA_ServerConfig, }; use parking_lot::{Condvar, Mutex, MutexGuard}; @@ -68,6 +68,9 @@ pub use self::{ pub struct ServerBuilder { config: ua::ServerConfig, + /// Heap-allocated set of callbacks in `config.nodeLifecycle`. + global_node_lifecycle: Box, + /// [`AccessControl`] instances may hold additional data that must be kept alive until server is /// shut down. The sentinel value cleans this up when it is dropped. access_control_sentinel: Option>, @@ -77,6 +80,7 @@ impl ServerBuilder { fn new(config: ua::ServerConfig) -> Self { Self { config, + global_node_lifecycle: Box::default(), access_control_sentinel: None, } } @@ -195,8 +199,8 @@ impl ServerBuilder { pub fn accept_all(mut self) -> Self { let config = self.config_mut(); unsafe { - UA_CertificateVerification_AcceptAll(&raw mut config.secureChannelPKI); - UA_CertificateVerification_AcceptAll(&raw mut config.sessionPKI); + UA_CertificateGroup_AcceptAll(&raw mut config.secureChannelPKI); + UA_CertificateGroup_AcceptAll(&raw mut config.sessionPKI); } self } @@ -226,7 +230,7 @@ impl ServerBuilder { /// Builds OPC UA server. #[must_use] - pub fn build(mut self) -> (Server, ServerRunner) { + pub fn build(self) -> (Server, ServerRunner) { unsafe extern "C" fn destructor_c( _server: *mut UA_Server, _session_id: *const UA_NodeId, @@ -261,22 +265,25 @@ impl ServerBuilder { } } - let config = self.config_mut(); - - // PANIC: We never set lifecycle hooks elsewhere in config. - debug_assert!(config.nodeLifecycle.destructor.is_none()); - config.nodeLifecycle.destructor = Some(destructor_c); - let Self { - config, + mut config, + mut global_node_lifecycle, access_control_sentinel, } = self; + // PANIC: We never set lifecycle hooks elsewhere in config. + debug_assert!(global_node_lifecycle.destructor.is_none()); + global_node_lifecycle.destructor = Some(destructor_c); + + // SAFETY: We keep `global_node_lifecycle` alive until `clear_global_node_lifecycle()`. + unsafe { set_global_node_lifecycle(&mut config, &mut global_node_lifecycle) }; + let server = Arc::new(ua::Server::new_with_config(config)); let state = Arc::new(RunnerState::new()); let runner = ServerRunner::new( Arc::clone(&server), + global_node_lifecycle, access_control_sentinel, Arc::clone(&state), ); @@ -366,6 +373,7 @@ enum RunnerStateInner { #[derive(Debug)] struct ServerConfigGuard<'a> { + #[debug(skip)] config: &'a UA_ServerConfig, guard: RunnerStateGuard<'a>, } @@ -610,18 +618,20 @@ impl Server { let mut out_new_node_id = ua::NodeId::null(); let status_code = ua::StatusCode::new(unsafe { - __UA_Server_addNode( + UA_Server_addNode_begin( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), // Passing ownership is trivial with primitive value (`u32`). attributes.node_class().clone().into_raw(), - requested_new_node_id.as_ptr(), - parent_node_id.as_ptr(), - reference_type_id.as_ptr(), - // TODO: Verify that `__UA_Server_addNode()` takes ownership. + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&requested_new_node_id), + DataType::to_raw_copy(&parent_node_id), + DataType::to_raw_copy(&reference_type_id), + // TODO: Verify that `UA_Server_addNode_begin()` takes ownership. browse_name.clone().into_raw(), - type_definition.as_ptr(), - attributes.as_node_attributes().as_ptr(), + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&type_definition), + attributes.as_node_attributes().as_ptr().cast(), attributes.attribute_type(), context.map_or(ptr::null_mut(), NodeContext::leak), out_new_node_id.as_mut_ptr(), @@ -629,6 +639,16 @@ impl Server { }); Error::verify_good(&status_code)?; + let status_code = ua::StatusCode::new(unsafe { + UA_Server_addNode_finish( + // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + self.server.as_ptr().cast_mut(), + // TODO: Verify that `UA_Server_addNode_finish()` does not take ownership. + DataType::to_raw_copy(&out_new_node_id), + ) + }); + Error::verify_good(&status_code)?; + Ok(out_new_node_id) } @@ -657,18 +677,20 @@ impl Server { let mut out_new_node_id = ua::NodeId::null(); let status_code = ua::StatusCode::new(unsafe { - __UA_Server_addNode( + UA_Server_addNode_begin( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), // Passing ownership is trivial with primitive value (`u32`). ua::NodeClass::OBJECT.into_raw(), - requested_new_node_id.as_ptr(), - parent_node_id.as_ptr(), - reference_type_id.as_ptr(), - // TODO: Verify that `__UA_Server_addNode()` takes ownership. + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&requested_new_node_id), + DataType::to_raw_copy(&parent_node_id), + DataType::to_raw_copy(&reference_type_id), + // TODO: Verify that `UA_Server_addNode_begin()` takes ownership. browse_name.into_raw(), - type_definition.as_ptr(), - attributes.as_node_attributes().as_ptr(), + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&type_definition), + attributes.as_node_attributes().as_ptr().cast(), ua::ObjectAttributes::data_type(), ptr::null_mut(), out_new_node_id.as_mut_ptr(), @@ -676,6 +698,16 @@ impl Server { }); Error::verify_good(&status_code)?; + let status_code = ua::StatusCode::new(unsafe { + UA_Server_addNode_finish( + // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + self.server.as_ptr().cast_mut(), + // TODO: Verify that `UA_Server_addNode_finish()` does not take ownership. + DataType::to_raw_copy(&out_new_node_id), + ) + }); + Error::verify_good(&status_code)?; + Ok(out_new_node_id) } @@ -704,18 +736,20 @@ impl Server { let mut out_new_node_id = ua::NodeId::null(); let status_code = ua::StatusCode::new(unsafe { - __UA_Server_addNode( + UA_Server_addNode_begin( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), // Passing ownership is trivial with primitive value (`u32`). ua::NodeClass::VARIABLE.into_raw(), - requested_new_node_id.as_ptr(), - parent_node_id.as_ptr(), - reference_type_id.as_ptr(), - // TODO: Verify that `__UA_Server_addNode()` takes ownership. + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&requested_new_node_id), + DataType::to_raw_copy(&parent_node_id), + DataType::to_raw_copy(&reference_type_id), + // TODO: Verify that `UA_Server_addNode_begin()` takes ownership. browse_name.into_raw(), - type_definition.as_ptr(), - attributes.as_node_attributes().as_ptr(), + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&type_definition), + attributes.as_node_attributes().as_ptr().cast(), ua::VariableAttributes::data_type(), ptr::null_mut(), out_new_node_id.as_mut_ptr(), @@ -723,6 +757,16 @@ impl Server { }); Error::verify_good(&status_code)?; + let status_code = ua::StatusCode::new(unsafe { + UA_Server_addNode_finish( + // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + self.server.as_ptr().cast_mut(), + // TODO: Verify that `UA_Server_addNode_finish()` does not take ownership. + DataType::to_raw_copy(&out_new_node_id), + ) + }); + Error::verify_good(&status_code)?; + Ok(out_new_node_id) } @@ -757,20 +801,20 @@ impl Server { // SAFETY: We store `node_context` inside the node to keep `data_source` alive. let (data_source, node_context) = unsafe { data_source::wrap_data_source(data_source) }; let status_code = ua::StatusCode::new(unsafe { - UA_Server_addDataSourceVariableNode( + UA_Server_addCallbackValueSourceVariableNode( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. requested_new_node_id.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. parent_node_id.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. reference_type_id.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. browse_name.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. type_definition.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. attributes.into_raw(), data_source, node_context.leak(), @@ -1049,65 +1093,69 @@ impl Server { Error::verify_good(&status_code) } - /// Creates an event. - /// - /// This returns the [`ua::NodeId`] of the created event. - /// - /// # Errors - /// - /// This fails when the event could not be created. - pub fn create_event(&self, event_type: &ua::NodeId) -> Result { - // This out variable must be initialized without memory allocation because the call below - // overwrites it in place, without releasing any held data first. - let mut out_node_id = ua::NodeId::init(); - let status_code = ua::StatusCode::new(unsafe { - UA_Server_createEvent( - // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. - self.server.as_ptr().cast_mut(), - // SAFETY: Passing as value is okay here, as event_type is only used for the scope - // of the function and does not get modified. - DataType::to_raw_copy(event_type), - out_node_id.as_mut_ptr(), - ) - }); - Error::verify_good(&status_code)?; - Ok(out_node_id) - } - - /// Triggers an event. - /// - /// This returns the [`ua::EventId`] of the new event. - /// - /// # Errors - /// - /// This fails when the event could not be triggered. - pub fn trigger_event( - &self, - event_node_id: &ua::NodeId, - origin_id: &ua::NodeId, - delete_event_node: bool, - ) -> Result { - // This out variable must be initialized without memory allocation because the call below - // overwrites it in place, without releasing any held data first. - let mut out_event_id = ua::ByteString::init(); - let status_code = ua::StatusCode::new(unsafe { - UA_Server_triggerEvent( - // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. - self.server.as_ptr().cast_mut(), - // SAFETY: Passing as value is okay here, as the variables are only used for the - // scope of the function and do not get modified. - DataType::to_raw_copy(event_node_id), - DataType::to_raw_copy(origin_id), - out_event_id.as_mut_ptr(), - delete_event_node, - ) - }); - Error::verify_good(&status_code)?; - let Some(event_id) = ua::EventId::new(out_event_id) else { - return Err(Error::internal("trigger should return event ID")); - }; - Ok(event_id) - } + // FIXME: Fix implementation and add back. + // + // /// Creates an event. + // /// + // /// This returns the [`ua::NodeId`] of the created event. + // /// + // /// # Errors + // /// + // /// This fails when the event could not be created. + // pub fn create_event(&self, event_type: &ua::NodeId) -> Result { + // // This out variable must be initialized without memory allocation because the call below + // // overwrites it in place, without releasing any held data first. + // let mut out_node_id = ua::NodeId::init(); + // let status_code = ua::StatusCode::new(unsafe { + // UA_Server_createEvent( + // // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + // self.server.as_ptr().cast_mut(), + // // SAFETY: Passing as value is okay here, as event_type is only used for the scope + // // of the function and does not get modified. + // DataType::to_raw_copy(event_type), + // out_node_id.as_mut_ptr(), + // ) + // }); + // Error::verify_good(&status_code)?; + // Ok(out_node_id) + // } + + // FIXME: Fix implementation and add back. + // + // /// Triggers an event. + // /// + // /// This returns the [`ua::EventId`] of the new event. + // /// + // /// # Errors + // /// + // /// This fails when the event could not be triggered. + // pub fn trigger_event( + // &self, + // event_node_id: &ua::NodeId, + // origin_id: &ua::NodeId, + // delete_event_node: bool, + // ) -> Result { + // // This out variable must be initialized without memory allocation because the call below + // // overwrites it in place, without releasing any held data first. + // let mut out_event_id = ua::ByteString::init(); + // let status_code = ua::StatusCode::new(unsafe { + // UA_Server_triggerEvent( + // // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + // self.server.as_ptr().cast_mut(), + // // SAFETY: Passing as value is okay here, as the variables are only used for the + // // scope of the function and do not get modified. + // DataType::to_raw_copy(event_node_id), + // DataType::to_raw_copy(origin_id), + // out_event_id.as_mut_ptr(), + // delete_event_node, + // ) + // }); + // Error::verify_good(&status_code)?; + // let Some(event_id) = ua::EventId::new(out_event_id) else { + // return Err(Error::internal("trigger should return event ID")); + // }; + // Ok(event_id) + // } /// Browses specific node. /// @@ -1700,6 +1748,9 @@ impl Server { pub struct ServerRunner { server: Arc, + /// Heap-allocated set of callbacks in `config.nodeLifecycle`. + global_node_lifecycle: Box, + /// [`AccessControl`] instances may hold additional data that must be kept alive until server is /// shut down. The sentinel value cleans this up when it is dropped. access_control_sentinel: Option>, @@ -1711,11 +1762,13 @@ impl ServerRunner { #[must_use] fn new( server: Arc, + global_node_lifecycle: Box, access_control_sentinel: Option>, state: Arc, ) -> Self { Self { server, + global_node_lifecycle, access_control_sentinel, state, } @@ -1742,9 +1795,11 @@ impl ServerRunner { pub fn run_until_interrupt(mut self) -> Result<()> { let Self { server, + global_node_lifecycle, access_control_sentinel, state, } = &mut self; + let global_node_lifecycle = mem::take(global_node_lifecycle); let access_control_sentinel = access_control_sentinel.take(); let mut state_guard = state.lock(); @@ -1772,6 +1827,8 @@ impl ServerRunner { } } + unsafe { clear_global_node_lifecycle(server, global_node_lifecycle) }; + // Compile-time assertion to make sure that the sentinel value was still around for the call // above (including any branches that exit early with `?` or `return`): only when the server // has finished shutting down, we are allowed to drop sentinel values. @@ -1791,9 +1848,11 @@ impl ServerRunner { pub fn run_until_cancelled(mut self, mut is_cancelled: impl FnMut() -> bool) -> Result<()> { let Self { server, + global_node_lifecycle, access_control_sentinel, state, } = &mut self; + let global_node_lifecycle = mem::take(global_node_lifecycle); let access_control_sentinel = access_control_sentinel.take(); let mut state_guard = state.lock(); @@ -1868,6 +1927,8 @@ impl ServerRunner { } } + unsafe { clear_global_node_lifecycle(server, global_node_lifecycle) }; + // Compile-time assertion to make sure that the sentinel value was still around for the call // above (including any branches that exit early with `?` or `return`): only when the server // has finished shutting down, we are allowed to drop sentinel values. @@ -1900,3 +1961,47 @@ fn to_browse_result(result: &ua::BrowseResult) -> BrowseResult { Ok((references.into_vec(), result.continuation_point())) } + +/// Sets `config.nodeLifecycle` to the given value. +/// +/// # Safety +/// +/// This must be called before the server accesses `config.nodeLifecycle`. +/// +/// The boxed value `global_node_lifecycle` must be kept alive until `clear_global_node_lifecycle()` +/// has been called. +unsafe fn set_global_node_lifecycle( + config: &mut ua::ServerConfig, + global_node_lifecycle: &mut Box, +) { + let config = unsafe { config.as_mut() }; + + // PANIC: Nobody else has initialized the node lifecycle callbacks before. + debug_assert!(config.nodeLifecycle.is_null()); + + // This stores the pointer to the `Box`-allocated `global_node_lifecycle` in the config; it must + // be kept alive elsewhere (e.g., in `ServerRunner`) until the server no longer accesses it. + config.nodeLifecycle = &raw mut *global_node_lifecycle.as_mut(); +} + +/// Clears `config.nodeLifecycle`. +/// +/// # Safety +/// +/// This must be called after the server has finished accessing `config.nodeLifecycle`. +unsafe fn clear_global_node_lifecycle( + server: &ua::Server, + mut global_node_lifecycle: Box, +) { + // SAFETY: The server has finished execution and we can mutate the configuration. + let config = unsafe { &mut *UA_Server_getConfig(server.as_ptr().cast_mut()) }; + + debug_assert_eq!( + config.nodeLifecycle, + &raw mut *global_node_lifecycle.as_mut() + ); + + // Remove pointer to prevent server from making any more calls. `global_node_lifecycle` goes out + // of scope at the end of this function and gets freed. + config.nodeLifecycle = ptr::null_mut(); +} diff --git a/src/traits.rs b/src/traits.rs index f3d66483..658689c0 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -81,19 +81,6 @@ pub trait Attributes: DataType { fn as_node_attributes(&self) -> &ua::NodeAttributes; } -/// Custom certificate verification. -/// -/// This is used to implement custom callbacks in [`ua::CertificateVerification::custom()`]. -pub trait CustomCertificateVerification { - fn verify_certificate(&self, certificate: &ua::ByteString) -> ua::StatusCode; - - fn verify_application_uri( - &self, - certificate: &ua::ByteString, - application_uri: &ua::String, - ) -> ua::StatusCode; -} - /// Private-key password callback. /// /// This is used to fetch the password for a given client private key when establishing a connection diff --git a/src/ua.rs b/src/ua.rs index 335d6bcb..4449772c 100644 --- a/src/ua.rs +++ b/src/ua.rs @@ -33,6 +33,7 @@ mod session_state; mod session_statistics; mod specified_attributes; mod subscription_id; +mod trust_list_masks; mod unit_id; mod user_identity_token; @@ -68,6 +69,7 @@ pub use self::{ session_statistics::SessionStatistics, specified_attributes::SpecifiedAttributes, subscription_id::SubscriptionId, + trust_list_masks::TrustListMasks, unit_id::UnitId, user_identity_token::UserIdentityToken, }; diff --git a/src/ua/certificate_verification.rs b/src/ua/certificate_verification.rs index 0fb504c1..f88bb5d0 100644 --- a/src/ua/certificate_verification.rs +++ b/src/ua/certificate_verification.rs @@ -3,16 +3,17 @@ use std::{ ptr, }; -use open62541_sys::{ - UA_ByteString, UA_CertificateVerification, UA_CertificateVerification_AcceptAll, UA_StatusCode, - UA_String, -}; +use derive_more::Debug; +#[cfg(feature = "mbedtls")] +use open62541_sys::UA_CertificateGroup_Memorystore; +use open62541_sys::{UA_CertificateGroup, UA_CertificateGroup_AcceptAll}; -use crate::{CustomCertificateVerification, DataType, Userdata, ua}; +#[cfg(feature = "mbedtls")] +use crate::{DataType as _, ua}; -/// Wrapper for [`UA_CertificateVerification`] from [`open62541_sys`]. +/// Wrapper for [`UA_CertificateGroup`] from [`open62541_sys`]. #[derive(Debug)] -pub struct CertificateVerification(UA_CertificateVerification); +pub struct CertificateVerification(#[debug(skip)] UA_CertificateGroup); impl CertificateVerification { /// Creates certificate verification with all checks disabled. @@ -22,71 +23,36 @@ impl CertificateVerification { #[must_use] pub fn accept_all() -> Self { let mut certificate_verification = Self::init(); - // SAFETY: Certificate verification is null, but that is valid. + // SAFETY: Certificate verification is uninitialized, but that is expected. unsafe { - UA_CertificateVerification_AcceptAll(certificate_verification.as_mut_ptr()); + UA_CertificateGroup_AcceptAll(certificate_verification.as_mut_ptr()); } certificate_verification } - /// Creates certificate verification with custom callbacks. - pub fn custom(certificate_verification: impl CustomCertificateVerification + 'static) -> Self { - type Ud = Userdata>; - - unsafe extern "C" fn verify_certificate_c( - cv: *const UA_CertificateVerification, - certificate: *const UA_ByteString, - ) -> UA_StatusCode { - // SAFETY: Reference is used only for the remainder of this function. - let certificate = ua::ByteString::raw_ref(unsafe { - certificate.as_ref().expect("certificate should be set") - }); - - // SAFETY: We use the user data only when it is still alive. - let certificate_verification = unsafe { Ud::peek_at((*cv).context) }; - let status_code = certificate_verification.verify_certificate(certificate); - status_code.into_raw() - } - - unsafe extern "C" fn verify_application_uri_c( - cv: *const UA_CertificateVerification, - certificate: *const UA_ByteString, - application_uri: *const UA_String, - ) -> UA_StatusCode { - // SAFETY: References are used only for the remainder of this function. - let certificate = ua::ByteString::raw_ref(unsafe { - certificate.as_ref().expect("certificate should be set") - }); - let application_uri = ua::String::raw_ref(unsafe { - application_uri - .as_ref() - .expect("application URI should be set") - }); - - // SAFETY: We use the user data only when it is still alive. - let certificate_verification = unsafe { Ud::peek_at((*cv).context) }; - let status_code = - certificate_verification.verify_application_uri(certificate, application_uri); - status_code.into_raw() - } - - unsafe extern "C" fn clear_c(cv: *mut UA_CertificateVerification) { - // Reclaim ownership of certificate verification and drop it. - // SAFETY: We use the user data only when it is still alive. - let _unused = unsafe { Ud::consume((*cv).context) }; + #[cfg(feature = "mbedtls")] + #[must_use] + pub fn memory_store( + certificate_group_id: &ua::NodeId, + trust_list: Option<&ua::TrustListDataType>, + ) -> Self { + let mut certificate_verification = Self::init(); + // SAFETY: Certificate verification is uninitialized, but that is expected. + unsafe { + UA_CertificateGroup_Memorystore( + certificate_verification.as_mut_ptr(), + // SAFETY: Argument is only read, not modified or returned. + certificate_group_id.as_ptr().cast_mut(), + trust_list.map_or(ptr::null(), |trust_list| trust_list.as_ptr()), + // FIXME: Initialize logger. + ptr::null(), + // TODO: Allow parameters. Valid parameters are: + // - "max-trust-listsize" + // - "max-rejected-listsize" + ptr::null(), + ); } - - let inner = UA_CertificateVerification { - context: Ud::prepare(Box::new(certificate_verification)), - verifyCertificate: Some(verify_certificate_c), - verifyApplicationURI: Some(verify_application_uri_c), - getExpirationDate: None, - getSubjectName: None, - clear: Some(clear_c), - logging: ptr::null_mut(), - }; - - unsafe { Self::from_raw(inner) } + certificate_verification } /// Creates wrapper by taking ownership of value. @@ -98,7 +64,7 @@ impl CertificateVerification { /// Ownership of the value passes to `Self`. This must only be used for values that are not /// contained within other values that may be dropped. #[must_use] - pub(crate) const unsafe fn from_raw(src: UA_CertificateVerification) -> Self { + pub(crate) const unsafe fn from_raw(src: UA_CertificateGroup) -> Self { Self(src) } @@ -112,7 +78,7 @@ impl CertificateVerification { #[expect(clippy::allow_attributes, reason = "non-static condition")] #[allow(clippy::missing_const_for_fn, reason = "unsupported before Rust 1.87")] #[must_use] - pub(crate) fn into_raw(self) -> UA_CertificateVerification { + pub(crate) fn into_raw(self) -> UA_CertificateGroup { // Use `ManuallyDrop` to avoid double-free even when added code might cause panic. See // documentation of `mem::forget()` for details. let this = ManuallyDrop::new(self); @@ -125,7 +91,7 @@ impl CertificateVerification { /// This initializes the value and makes all attributes well-defined. Additional attributes may /// need to be initialized for the value to be actually useful afterwards. pub(crate) const fn init() -> Self { - let inner = MaybeUninit::::zeroed(); + let inner = MaybeUninit::::zeroed(); // SAFETY: Zero-initialized memory is a valid certificate verification. let inner = unsafe { inner.assume_init() }; // SAFETY: We pass a value without pointers to it into `Self`. @@ -140,7 +106,7 @@ impl CertificateVerification { /// The logging reference will be transferred from the old to the new certificate verification. /// /// After this, it is the responsibility of `dst` to eventually clean up the data. - pub(crate) fn move_into_raw(self, dst: &mut UA_CertificateVerification) { + pub(crate) fn move_into_raw(self, dst: &mut UA_CertificateGroup) { // Move certificate verification into target, transferring ownership. let orig = mem::replace(dst, self.into_raw()); // Take ownership of previously set certificate verification in order to drop it. @@ -161,7 +127,7 @@ impl CertificateVerification { #[must_use] #[expect(clippy::allow_attributes, reason = "non-static condition")] #[allow(clippy::missing_const_for_fn, reason = "unsupported before Rust 1.87")] - pub(crate) unsafe fn as_mut(&mut self) -> &mut UA_CertificateVerification { + pub(crate) unsafe fn as_mut(&mut self) -> &mut UA_CertificateGroup { &mut self.0 } @@ -174,7 +140,7 @@ impl CertificateVerification { #[must_use] #[expect(clippy::allow_attributes, reason = "non-static condition")] #[allow(clippy::missing_const_for_fn, reason = "unsupported before Rust 1.87")] - pub(crate) unsafe fn as_mut_ptr(&mut self) -> *mut UA_CertificateVerification { + pub(crate) unsafe fn as_mut_ptr(&mut self) -> *mut UA_CertificateGroup { &raw mut self.0 } } diff --git a/src/ua/client.rs b/src/ua/client.rs index 3f9f917e..efc88dbd 100644 --- a/src/ua/client.rs +++ b/src/ua/client.rs @@ -1,8 +1,8 @@ use std::ptr::NonNull; use open62541_sys::{ - UA_Client, UA_Client_delete, UA_Client_disconnect, UA_Client_getConfig, UA_Client_getContext, - UA_Client_getState, UA_Client_new, UA_Client_newWithConfig, + UA_Client, UA_Client_delete, UA_Client_disconnect, UA_Client_getConfig, UA_Client_getState, + UA_Client_new, UA_Client_newWithConfig, }; use crate::{ClientContext, DataType as _, Error, ua}; @@ -118,7 +118,10 @@ impl Drop for Client { // Fetch context pointer before deleting client below, but free associated memory only after // client has completely shut down. - let context = unsafe { UA_Client_getContext(self.as_mut_ptr()) }.cast::(); + let context = unsafe { UA_Client_getConfig(self.as_mut_ptr()).as_ref() } + .expect("require client config") + .clientContext + .cast::(); // `UA_Client_delete()` matches `UA_Client_new()`. This may block (!) whenever the client is // still connected, for as long as it takes to take down the connection. This can be avoided diff --git a/src/ua/data_types.rs b/src/ua/data_types.rs index 92913441..077a0919 100644 --- a/src/ua/data_types.rs +++ b/src/ua/data_types.rs @@ -80,6 +80,7 @@ mod structure_description; mod structure_field; mod structure_type; mod timestamps_to_return; +mod trust_list_data_type; mod user_name_identity_token; mod variant; mod write_request; @@ -172,6 +173,7 @@ pub use self::{ structure_field::StructureField, structure_type::StructureType, timestamps_to_return::TimestampsToReturn, + trust_list_data_type::TrustListDataType, user_name_identity_token::UserNameIdentityToken, variant::Variant, write_request::WriteRequest, diff --git a/src/ua/data_types/byte_string.rs b/src/ua/data_types/byte_string.rs index b25c96af..ac185921 100644 --- a/src/ua/data_types/byte_string.rs +++ b/src/ua/data_types/byte_string.rs @@ -113,6 +113,17 @@ impl ByteString { unsafe { self.as_bytes().unwrap_unchecked() } } + /// Converts byte string into string. + /// + /// This is lossless because the underlying types of OPC UA strings and byte strings are exactly + /// the same, only with different semantics. + #[must_use] + pub(crate) fn into_string(self) -> ua::String { + let string = self.into_raw(); + // SAFETY: We still own this string. + unsafe { ua::String::from_raw(string) } + } + #[must_use] fn array_value(&self) -> ArrayValue { // Internally, `open62541` represents strings as `Byte` array and has the same special cases diff --git a/src/ua/data_types/status_code.rs b/src/ua/data_types/status_code.rs index db8ffbc3..231a4440 100644 --- a/src/ua/data_types/status_code.rs +++ b/src/ua/data_types/status_code.rs @@ -216,7 +216,6 @@ enum_variants!( BADSERVERURIINVALID, BADSERVERNAMEMISSING, BADDISCOVERYURLMISSING, - BADSEMPAHOREFILEMISSING, BADREQUESTTYPEINVALID, BADSECURITYMODEREJECTED, BADSECURITYPOLICYREJECTED, @@ -333,6 +332,7 @@ enum_variants!( GOODDATAIGNORED, BADREQUESTNOTALLOWED, BADREQUESTNOTCOMPLETE, + BADTRANSACTIONPENDING, BADTICKETREQUIRED, BADTICKETINVALID, GOODEDITED, diff --git a/src/ua/data_types/string.rs b/src/ua/data_types/string.rs index 89e4b049..b4fd6fd5 100644 --- a/src/ua/data_types/string.rs +++ b/src/ua/data_types/string.rs @@ -1,6 +1,6 @@ use std::{ffi::CString, fmt, ptr, slice, str}; -use open62541_sys::UA_String_fromChars; +use open62541_sys::{UA_ByteString_allocBuffer, UA_String_fromChars}; use crate::{ArrayValue, DataType as _, Error, ua}; @@ -24,6 +24,24 @@ impl String { Ok(Self(str)) } + /// Creates uninitialized string of specific length. + /// + /// This should be used with caution: the uninitialized contents may contain leaked data and may + /// not be valid UTF-8. + #[must_use] + pub(crate) fn uninit(len: usize) -> Self { + let mut str = ua::ByteString::init(); + // We let `UA_ByteString_allocBuffer()` do the string allocation. + let status_code = + ua::StatusCode::new(unsafe { UA_ByteString_allocBuffer(str.as_mut_ptr(), len) }); + // PANIC: The only possible errors here are out-of-memory. + assert!( + status_code.is_good(), + "byte string should have been created" + ); + str.into_string() + } + /// Creates an invalid null string (as defined by OPC UA). #[must_use] pub fn null() -> Self { @@ -40,8 +58,9 @@ impl String { /// Gets string length. /// /// This may return [`None`] when the string itself is invalid (as defined by OPC UA). + #[expect(dead_code, reason = "unused for now")] #[must_use] - pub fn len(&self) -> Option { + pub(crate) fn len(&self) -> Option { match self.array_value() { ArrayValue::Invalid => None, ArrayValue::Empty => Some(0), @@ -84,6 +103,20 @@ impl String { } } + #[must_use] + pub(crate) fn as_mut_bytes(&mut self) -> Option<&mut [u8]> { + // Internally, `open62541` represents strings as `Byte` array and has the same special cases + // as regular arrays, i.e. empty and invalid states. + match self.array_value() { + ArrayValue::Invalid => None, + ArrayValue::Empty => Some(&mut []), + ArrayValue::Valid(data) => { + // `self.0.data` is valid, so we may use `self.0.length` now. + Some(unsafe { slice::from_raw_parts_mut(data.as_ptr(), self.0.length) }) + } + } + } + /// Returns string contents as string slice. /// /// This may return [`None`] when the string itself is invalid (as defined by OPC UA) or when it diff --git a/src/ua/data_types/trust_list_data_type.rs b/src/ua/data_types/trust_list_data_type.rs new file mode 100644 index 00000000..823c8c81 --- /dev/null +++ b/src/ua/data_types/trust_list_data_type.rs @@ -0,0 +1,59 @@ +use crate::ua; + +crate::data_type!(TrustListDataType); + +impl TrustListDataType { + #[must_use] + pub fn with_trusted_certificates(mut self, trusted_certificates: &[ua::String]) -> Self { + let array = ua::Array::from_slice(trusted_certificates); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::TRUSTEDCERTIFICATES.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::TRUSTEDCERTIFICATES.as_u32(); + } + array.move_into_raw( + &mut self.0.trustedCertificatesSize, + &mut self.0.trustedCertificates, + ); + self + } + + #[must_use] + pub fn with_trusted_crls(mut self, trusted_crls: &[ua::String]) -> Self { + let array = ua::Array::from_slice(trusted_crls); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::TRUSTEDCRLS.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::TRUSTEDCRLS.as_u32(); + } + array.move_into_raw(&mut self.0.trustedCrlsSize, &mut self.0.trustedCrls); + self + } + + #[must_use] + pub fn with_issuer_certificates(mut self, issuer_certificates: &[ua::String]) -> Self { + let array = ua::Array::from_slice(issuer_certificates); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::ISSUERCERTIFICATES.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::ISSUERCERTIFICATES.as_u32(); + } + array.move_into_raw( + &mut self.0.issuerCertificatesSize, + &mut self.0.issuerCertificates, + ); + self + } + + #[must_use] + pub fn with_issuer_crls(mut self, issuer_crls: &[ua::String]) -> Self { + let array = ua::Array::from_slice(issuer_crls); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::ISSUERCRLS.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::ISSUERCRLS.as_u32(); + } + array.move_into_raw(&mut self.0.issuerCrlsSize, &mut self.0.issuerCrls); + self + } +} diff --git a/src/ua/event_id.rs b/src/ua/event_id.rs index 0f3cc0c7..a0c6fcb5 100644 --- a/src/ua/event_id.rs +++ b/src/ua/event_id.rs @@ -10,6 +10,7 @@ impl EventId { /// This may return [`None`] when the string is invalid (as defined by OPC UA). /// /// Note: The given string should not be empty. + #[expect(dead_code, reason = "unused for now")] #[must_use] pub(crate) fn new(event_id: ua::ByteString) -> Option { // Unset event IDs are not expected. diff --git a/src/ua/logger/rust_log.rs b/src/ua/logger/rust_log.rs index 7a92e9ae..7da29108 100644 --- a/src/ua/logger/rust_log.rs +++ b/src/ua/logger/rust_log.rs @@ -1,15 +1,12 @@ use std::{ - borrow::Cow, - ffi::{CStr, c_char, c_void}, + ffi::{c_char, c_void}, ptr, }; use log::Level; -use open62541_sys::{ - UA_LogCategory, UA_LogLevel, UA_Logger, va_list_, vsnprintf_va_copy, vsnprintf_va_end, -}; +use open62541_sys::{UA_LogCategory, UA_LogLevel, UA_Logger, UA_String_vformat, va_list_}; -use crate::ua; +use crate::{DataType as _, Error, Result, ua}; // This matches the crate name. const LOG_TARGET: &str = "open62541_sys"; @@ -45,10 +42,8 @@ pub(crate) fn logger() -> ua::Logger { let msg = format_message(msg, args); let msg = match msg { - Some(ref msg) => CStr::from_bytes_with_nul(msg) - .unwrap_or(c"Invalid log message") - .to_string_lossy(), - None => Cow::Borrowed("Unknown log message"), + Ok(ref msg) => msg.as_str().unwrap_or("Invalid log message"), + Err(_) => "Unknown log message", }; let category = log_category(&category); @@ -95,72 +90,37 @@ pub(crate) fn logger() -> ua::Logger { unsafe { ua::Logger::from_raw(logger) } } -/// Initial buffer size when formatting messages. -const FORMAT_MESSAGE_DEFAULT_BUFFER_LEN: usize = 128; - -/// Maximum buffer size when formatting messages. -const FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN: usize = 65536; +/// Buffer size when formatting messages. +// This matches the limit used by default implementations `ua_log_stdout.h` and `ua_log_syslog.h`. +const FORMAT_MESSAGE_BUFFER_LEN: usize = 512; /// Formats message with `vprintf` library calls. /// -/// This returns the formatted message with a trailing NUL byte, or `None` when formatting fails. A -/// long message may be truncated (see [`FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN`] for details); its last -/// characters will be replaced with `...` to indicate this. -fn format_message(msg: *const c_char, args: va_list_) -> Option> { - // Delegate string formatting to `vsnprintf()`, the length-checked string buffer variant of the - // variadic `vprintf` family. - // - // We use the custom `vsnprintf_va_copy()` provided by `open62541_sys`. This copies the va args - // and requires an explicit call to `vsnprintf_va_end()` afterwards. - - // Allocate default buffer first. Only when the message doesn't fit, we need to allocate larger - // buffer below. - let mut msg_buffer: Vec = vec![0; FORMAT_MESSAGE_DEFAULT_BUFFER_LEN]; - loop { - let result = unsafe { - vsnprintf_va_copy( - msg_buffer.as_mut_ptr().cast::(), - msg_buffer.len(), - msg, - args, - ) - }; - let Ok(msg_len) = usize::try_from(result) else { - // Negative result is an error in the format string. Nothing we can do. - debug_assert!(result < 0); - // Free the `va_list` argument that is no consumed by `vsnprintf()`! - unsafe { vsnprintf_va_end(args) } - return None; - }; - let buffer_len = msg_len + 1; - if buffer_len > msg_buffer.len() { - // Last byte must always be the NUL terminator, even if the message - // doesn't fit into the buffer. - debug_assert_eq!(msg_buffer.last(), Some(&0)); - if msg_buffer.len() < FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN { - // Allocate larger buffer and try again. - msg_buffer.resize(FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN, 0); - continue; - } - // Message is too large to format. Truncate the message by ending it with `...`. - for char in msg_buffer.iter_mut().rev().skip(1).take(3) { +/// This returns the formatted message as string, or `Err` when formatting fails. A long message is +/// truncated (see [`FORMAT_MESSAGE_BUFFER_LEN`]); its last characters will be replaced with `...`. +fn format_message(msg: *const c_char, args: open62541_sys::va_list_) -> Result { + // With non-zero length, `UA_String_vformat()` fills the given string directly. For zero length + // strings, the result would be dynamically allocated, but this risks handling incredibly large + // amounts of memory in the log handler which we want to avoid here. + let mut msg_buffer = ua::String::uninit(FORMAT_MESSAGE_BUFFER_LEN); + + let status_code = + ua::StatusCode::new(unsafe { UA_String_vformat(msg_buffer.as_mut_ptr(), msg, args) }); + if status_code == ua::StatusCode::BADENCODINGLIMITSEXCEEDED { + // Message is too large to format. We could try again with a larger buffer, but since we do + // not know the required length (`UA_String_vformat()` doesn't return it), we would have to + // guess (e.g., doubling the length until the message fits). Simply truncate the message by + // ending it with `...` instead to ensure constant-time operation. + if let Some(msg_buffer) = msg_buffer.as_mut_bytes() { + for char in msg_buffer.iter_mut().rev().take(3) { *char = b'.'; } - } else { - // Message fits into the buffer. Make sure that `from_bytes_with_nul()` - // sees the expected single NUL terminator in the final position. - msg_buffer.truncate(buffer_len); } - break; + } else { + Error::verify_good(&status_code)?; } - // Free the `va_list` argument that is not consumed by `vsnprintf()`! - unsafe { vsnprintf_va_end(args) } - - // Last byte must always be the NUL terminator. - debug_assert_eq!(msg_buffer.last(), Some(&0)); - - Some(msg_buffer) + Ok(msg_buffer) } // These match the category names from `ua_log_stdout.c` and `ua_log_syslog.c`. diff --git a/src/ua/trust_list_masks.rs b/src/ua/trust_list_masks.rs new file mode 100644 index 00000000..adf4e65d --- /dev/null +++ b/src/ua/trust_list_masks.rs @@ -0,0 +1,67 @@ +#[expect(unreachable_pub, reason = "hidden inner enum")] +// We do not expose the inner enum. We want to use a proper `u32` for bit operations on the mask and +// we want to be clear about what is an initial (const, enum-like) value and what is a derived mask; +// specifically, the bitmask type is _not_ an enum even though declared so in `open62541-sys`. +mod inner { + crate::data_type!(TrustListMasks); + + crate::enum_variants!( + TrustListMasks, + UA_TrustListMasks, + [ + NONE, + TRUSTEDCERTIFICATES, + TRUSTEDCRLS, + ISSUERCERTIFICATES, + ISSUERCRLS, + ALL, + ], + ); +} + +/// Wrapper for trust list masks from [`open62541_sys`]. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TrustListMasks(u32); + +crate::bitmask_ops!(TrustListMasks); + +impl TrustListMasks { + pub const NONE: Self = Self(inner::TrustListMasks::NONE_U32); + pub const TRUSTEDCERTIFICATES: Self = Self(inner::TrustListMasks::TRUSTEDCERTIFICATES_U32); + pub const TRUSTEDCRLS: Self = Self(inner::TrustListMasks::TRUSTEDCRLS_U32); + pub const ISSUERCERTIFICATES: Self = Self(inner::TrustListMasks::ISSUERCERTIFICATES_U32); + pub const ISSUERCRLS: Self = Self(inner::TrustListMasks::ISSUERCRLS_U32); + pub const ALL: Self = Self(inner::TrustListMasks::ALL_U32); + + pub(crate) const fn from_u32(mask: u32) -> Self { + Self(mask) + } + + pub(crate) const fn as_u32(&self) -> u32 { + self.0 + } +} + +#[cfg(test)] +mod tests { + use crate::ua; + + #[test] + fn combine_masks() { + // We support mask combinators in `const` expressions. + const LHS: ua::TrustListMasks = ua::TrustListMasks::TRUSTEDCERTIFICATES + .or(&ua::TrustListMasks::TRUSTEDCRLS) + .or(&ua::TrustListMasks::ISSUERCERTIFICATES) + .or(&ua::TrustListMasks::ISSUERCRLS); + const RHS: ua::TrustListMasks = ua::TrustListMasks::ALL; + assert_eq!(LHS, RHS); + + // We support mask combinators with `|` shorthand notation. + let lhs = ua::TrustListMasks::TRUSTEDCERTIFICATES + | ua::TrustListMasks::TRUSTEDCRLS + | ua::TrustListMasks::ISSUERCERTIFICATES + | ua::TrustListMasks::ISSUERCRLS; + let rhs = ua::TrustListMasks::ALL; + assert_eq!(lhs, rhs); + } +}