A client and server implementation of the OPC UA specification written in Rust

Overview

Introduction

This is an OPC UA server / client API implementation for Rust.

Linux
Windows

OPC UA is an industry standard for monitoring of data. It's used extensively for embedded devices, industrial control, IoT, etc. - just about anything that has data that something else wants to monitor, control or visualize.

Rust is a systems programming language and is therefore a natural choice for implementing OPC UA. This implementation supports the embedded, micro and nano profiles but may grow to support features in time.

Read the compatibility page for how the implementation conforms with the OPC UA spec.

Read the change log for changes per version as well as aspirational / upcoming work.

License

The code is licenced under MPL-2.0. Like all open source code, you use this code at your own risk.

Setup

Read the setup for instructions on building OPCUA for Rust.

Read cross compilation for hints for cross compiling OPC UA for Rust to other platforms.

Design

Read the design for more in-depth description of implementation.

Tutorial

Tutorials / user guides are still work in progress.

Further Documentation

The API documentation is generated from the latest published crates. This may be some way behind current development.

Client Client side APIs to connect to an OPC UA server.
Server Server side APIs to host an OPC UA server, address space, create new nodes, subscriptions.
Crypto Security profiles, encryption, hashing, signing / verification, certificate management.
Core Core functionality shared by client and server - Secure channel, TCP encoding, TCP messages, chunking.
Types OPC UA core types and binary encoding implementations.

Samples

If you want to get stuck in, there are a number of samples in the samples/ folder. The simple-client and the simple-server projects are minimal client and server programs respectively.

# In one bash
cd opcua/samples/simple-server
cargo run
# In another bash
cd opcua/samples/simple-client
cargo run

The full list of samples:

  1. simple-server - an OPC UA server that adds 4 variables v1, v2, v3 and v4 and updates them from a timer via push and pull mechanisms.
  2. simple-client - an OPC UA client that connects to a server and subscribes to the values of v1, v2, v3 and v4.
  3. discovery-client - an OPC UA client that connects to a discovery server and lists the servers registered on it.
  4. chess-server - an OPC UA server that connects to a chess engine as its back end and updates variables representing the state of the game.
  5. demo-server - an OPC UA server that is more complex than the simple server and can be used for compliance testing.
  6. mqtt-client - an OPC UA client that subscribes to some values and publishes them to an MQTT broker.
  7. web-client - an OPC UA client that subscribes to some values and streams them over a websocket.
  8. modbus-server - an OPC UA server that translates variables from MODBUS.
Comments
  • Switch to parking_lot and fix Clippy warnings

    Switch to parking_lot and fix Clippy warnings

    @locka99 I understand this is a massive PR which also contains backwards incompatible changes, so let me try to explain why I think this PR is really worth it...

    The main thing that this PR does, is switching from std::sync::{Mutex, RwLock} to parking_lot::{Mutex, RwLock}. This change is needed because std::sync::{Mutex, RwLock} cannot be shared between threads safely (a.k.a. it is missing the std::marker::Send trait) which is required when using it together with futures::Future:

    std::sync::RwLockWriteGuard<'_, session::session::Session>` cannot be sent between threads
    safely within `impl futures::Future`, the trait `std::marker::Send` is not implemented for 
    `std::sync::RwLockWriteGuard<'_, session::session::Session>
    

    I'm hitting this problem as I'm trying to create a full async_client without changing too much of the existing logic (so without trying to change mutexes to channels for example). So really just making the first step in having a full async client which can then be further optimized along the way, but can be used right away.

    Initially I think it makes the most sense to add it next to the existing client, but of course it would be very nice (and much easier to maintain) if they can be merged one day. Yet before I can even offer a PR with a full async_client that we can talk about, I need to be able to use all the existing mutexes in async code which is not possible without switching to parking_lot.

    Additionally I tried to fix as much Clippy warnings as I could to silence my editor a bit. These are all relatively small fixes which in no way change any of the logic! It just improves the code a tiny bit but adding small optimizations and rewriting a few loops or if else statements that should improve the efficiency or readability. But as you can see/test for yourself all the tests still pass and everything still works the same as before.

    Last little thing I did in this PR (which I can revert if you want) is changing ~1.8 to just 1.8 for all tokio dependencies. Having it locked to ~1.8 means that any other project that wants to use this crate is forced to also use this exact same version. This caused some issues for us, so for now I stripped the ~. If that is not acceptable I will add that back, but that would mean I need to maintain a fork to be able to use the client in our own project.

    I really hope I can work with you to get this PR merged. I understand that changing to parking_lot could mean that some people using this crate (these crates) will need to update some of their code when they want to use the latest version. Yet the fix is as simple as only removing a few .unwrap() calls which the compiler will also tell you. So while it does have impact, I would argue the impact is very low and the potential gain (having a full async client) could be worth the pain...

    Thanks and curious to hear your thoughts on this one!

    opened by svanharmelen 22
  • Does this library support CreateMonitoredItem of Alarm and Events

    Does this library support CreateMonitoredItem of Alarm and Events

    I tried to create a monitored item for getting alarm data of OPCU Server, no response is coming.While monitored items of data changes of particular node id is giving result. I want to know whether this library support subscribing to alarms and events or this is due to my lack of knowledge to implement with this library. I am asking this because, one C++ library i used before only supported monitoring of data changes.

    opened by ekafe 16
  • Possible performance issue / best practices

    Possible performance issue / best practices

    After familiarizing myself enough with the library to get our PoC application working, I decided to look into why - using this library as a client - it seems to be a lot slower than my previous experience with, for example gopcua, even though the code is written in Rust.

    Right now I am looking at a TCP dump ( tcp_performance.csv) and there are noticeable delays between receiving the CreateSessionResponse and sending out the ActivateSessionRequest in Session::connect_and_activate whereas the time between CreateSessionRequest and CreateSessionResponse , i.e. the time it takes for the server to respond, is barely noticable. This suggests to me that the problem lies with the client code and not on the server.

    Looking at the whole dump, it is noticeable that the delays in between a request coming in and the next request going out is always more or less 0.05 seconds. But I chose Session::connect_and_activate as an example because nothing else is happening between these two calls and there is a noticeable delay nonetheless.

    Are there any best practices to follow to get rid of this? Maybe I have to tweak some Tokio runtime parameters or somesuch to make it faster? Is anyone else experiencing the same problem by any chance?

    opened by milgner 15
  • Server connection loss is not propageted up to session

    Server connection loss is not propageted up to session

    I'm currently testing edge cases against a small python server setup. When killing the server process and restarting it, the client does not seem to be able to reconnect. That said, I'm not quite sure, whether it notices that the server has been disconnected. Is there anyway to catch this? (I tried the connection state changed and session closed callbacks, but they're not being called though).

    Log output:

    2019-01-25 10:54:40.071 - INFO - opcua_client::comms::tcp_transport - ReadState has dropped
    2019-01-25 10:54:40.071 - INFO - opcua_client::comms::tcp_transport - Read loop finished
    2019-01-25 10:54:41.581 - ERROR - opcua_client::comms::tcp_transport - Write IO error Os { code: 32, kind: BrokenPipe, message: "Broken pipe" }
    2019-01-25 10:54:41.582 - ERROR - opcua_client::comms::tcp_transport - Write loop is finished with an error ()
    2019-01-25 10:54:41.582 - INFO - opcua_client::comms::tcp_transport - WriteState has dropped
    2019-01-25 10:55:09.579 - INFO - opcua_client::session_state - Making secure channel request
    2019-01-25 10:55:09.579 - INFO - opcua_client::session_state - security_mode = None
    2019-01-25 10:55:09.579 - INFO - opcua_client::session_state - security_policy = None
    2019-01-25 10:55:19.608 - INFO - opcua_client::session_state - Timeout waiting for response from server
    2019-01-25 10:55:19.609 - INFO - opcua_client::message_queue - Request 53 has timed out and any response will be ignored
    2019-01-25 10:55:19.609 - INFO - opcua_client::session_state - Making secure channel request
    2019-01-25 10:55:19.609 - INFO - opcua_client::session_state - security_mode = None
    2019-01-25 10:55:19.609 - INFO - opcua_client::session_state - security_policy = None
    

    The making secure channel request with sec mode and policy endlessly loop after that point.

    opened by denizs 15
  • core/comms/secure_channel: Always set remote nonce

    core/comms/secure_channel: Always set remote nonce

    The set_remote_nonce_from_byte_string() performs some checks against the message security mode.

    In our tests, we use security policy = None and security mode = None, but the server sets Basic126Rsa15 for the user identity token policy meaning that we still need to use the server nonce for authentication.

    This patch removes all the checking around security policy and mode, which allows the client to connect to our OPC-UA server (Kepware) successfully.

    opened by laumann 14
  • do you have any plan to update to tokio 0.2?

    do you have any plan to update to tokio 0.2?

    Using RUST'S new syntax async & Await, the code is much cleaner.

    ctx.read_holding_registers(address, count as u16)
                .map_err(move |err| {
                    println!("Read input registers error {:?}", err);
                    OutputRegister::end_read_output_registers(&runtime_for_err);
                })
                .and_then(move |values| {
                    store_values_in_registers(values, registers.clone());
                    OutputRegister::end_read_output_registers(&runtime);
                    Ok(())
                })
    

    it's hard to read code like this.

    opened by nkbai 14
  • Use tokio version

    Use tokio version "1"

    We use tokio 1.16 internally meaning that we cannot select a compatible version when using this library as a dependency.

    I only want the version requirements to be a little more lax, not necessarily "1" but I thought this could get us started :-)

    opened by laumann 13
  • Allow the client to use the server time

    Allow the client to use the server time

    In some situations, were the server setup is managed by a 3rd party, it can be needed to “follow” the server time in the client in order to be able to setup a connection.

    This solution is pretty much inline with what is documented here, except in this solution only the time used in the client is adjusted and the host clock is left untouched.

    And just to be clear, the offset is only used for the communication and security related parts between the client and the server. For the rest the actuall time will still be used.

    I tested this against several 3rd party server and the change resulted in stable connections without any errors, reconnects or constantly renewing security channels.

    Fixes #89

    opened by svanharmelen 12
  • Trying to connect to a Basic256, SignAndEncrypt endpoint.

    Trying to connect to a Basic256, SignAndEncrypt endpoint.

    Hello,

    From samples/simple_client, I'm trying to connect to a Basic256,SignAndEncrypt endpoint with X509 token and client.connect_to_endpoint_id returns

    ERROR - opcua_client::comms::tcp_transport - Expecting a chunk, got an error message BadSecurityChecksFailed
    

    I think that certificate is OK because I use it with an other application.
    First connection without security policy/mode seems to work because it retrieves endpoint. Error arrives when it wants to connect to the endpoint and sends a secure channel request. On wireshark, viewable value in frame seems to be OK and corresponds to a frame sent with an other application.

    Do you have any idea what I could look at to try to find the problem ? Thank you very much for this library.

    opened by execuc 12
  • client: Failure to decode server response leads to broken session

    client: Failure to decode server response leads to broken session

    This takes a little explaining, so I'll start with the steps to reproduce:

    Steps to reproduce

    1. Run this docker string: $ docker run --rm -d --net host --name opcplc mcr.microsoft.com/iotedge/opc-plc:latest --pn=50000 --ph=localhost --autoaccept --sph --sn=5 --sr=10 --st=uint --fn=5 --fr=1 --ft=uint --ctb --lsn --ref --gn=5 -ut
    2. ~Apply this patch: 0001-samples-Simple-client-to-read-nodes.patch.txt on master~ EDIT: Please grab the patch attached in a comment below.
    3. cd samples/read-client
    4. RUST_OPCUA_LOG=debug cargo run

    I get the following log:

    output log
    warning: field is never read: `max_chunk_count`
      --> core/src/comms/message_writer.rs:29:5
       |
    29 |     max_chunk_count: usize,
       |     ^^^^^^^^^^^^^^^^^^^^^^
       |
       = note: `#[warn(dead_code)]` on by default
    
    warning: `opcua-core` (lib) generated 1 warning
    warning: unused imports: `Arc`, `RwLock`
      --> samples/read-client/src/main.rs:10:17
       |
    10 | use std::sync::{Arc, RwLock};
       |                 ^^^  ^^^^^^
       |
       = note: `#[warn(unused_imports)]` on by default
    
    warning: `opcua-read-client` (bin "opcua-read-client") generated 1 warning
        Finished dev [unoptimized + debuginfo] target(s) in 0.07s
         Running `/home/tj/omnioiot/opcua/target/debug/opcua-read-client`
    2022-02-28 13:58:36.480 - INFO - opcua_console_logging - Logging is enabled, use RUST_OPCUA_LOG environment variable to control filtering, logging level
    2022-02-28 13:58:36.480 - WARN - opcua_client::config - Endpoint config contains no endpoints
    2022-02-28 13:58:36.482 - INFO - opcua_client::session::session - Connect
    2022-02-28 13:58:36.482 - INFO - opcua_client::session::session - Security policy = None
    2022-02-28 13:58:36.482 - INFO - opcua_client::session::session - Security mode = None
    2022-02-28 13:58:36.482 - DEBUG - opcua_client::comms::tcp_transport - Waiting for a connect (or failure to connect)
    2022-02-28 13:58:36.483 - DEBUG - opcua_client::comms::tcp_transport - Client tokio tasks are starting for connection
    2022-02-28 13:58:36.483 - DEBUG - opcua_core::runtime - registering component client-connection-thread-ThreadId(1)
    2022-02-28 13:58:36.483 - DEBUG - opcua_client::comms::tcp_transport - Creating a connection task to connect to [::1]:50000 with url opc.tcp://localhost:50000
    2022-02-28 13:58:36.483 - DEBUG - opcua_core::runtime - registering component connection-task, 1
    2022-02-28 13:58:36.483 - DEBUG - opcua_client::comms::tcp_transport - Sending HELLO
    2022-02-28 13:58:36.483 - DEBUG - opcua_core::runtime - deregistering component connection-task, 1
    2022-02-28 13:58:36.483 - DEBUG - opcua_core::runtime - registering component finished-monitor-task, 1
    2022-02-28 13:58:36.483 - DEBUG - opcua_core::runtime - registering component read-task, 1
    2022-02-28 13:58:36.483 - DEBUG - opcua_core::runtime - registering component write-task, 1
    2022-02-28 13:58:36.483 - DEBUG - opcua_client::comms::tcp_transport - Reader got ack AcknowledgeMessage { message_header: MessageHeader { message_type: Acknowledge, message_size: 28 }, protocol_version: 0, receive_buffer_size: 65535, send_buffer_size: 65535, max_message_size: 4194304, max_chunk_count: 0 }
    2022-02-28 13:58:36.583 - DEBUG - opcua_client::comms::tcp_transport - Connected
    2022-02-28 13:58:36.583 - DEBUG - opcua_client::session::session - session:1 open_secure_channel
    2022-02-28 13:58:36.583 - INFO - opcua_client::session::session_state - Making secure channel request
    2022-02-28 13:58:36.583 - INFO - opcua_client::session::session_state - security_mode = None
    2022-02-28 13:58:36.583 - INFO - opcua_client::session::session_state - security_policy = None
    2022-02-28 13:58:36.583 - DEBUG - opcua_core::comms::secure_channel - AsymmetricSecurityHeader = AsymmetricSecurityHeader { security_policy_uri: UAString { value: Some("http://opcfoundation.org/UA/SecurityPolicy#None") }, sender_certificate: ByteString { value: None }, receiver_certificate_thumbprint: ByteString { value: None } }
    2022-02-28 13:58:36.583 - DEBUG - opcua_client::message_queue - Request 1 was processed by the server
    2022-02-28 13:58:36.584 - DEBUG - opcua_client::message_queue - Response to Request 1 has been stored
    2022-02-28 13:58:36.584 - DEBUG - opcua_client::session::session_state - Setting transport's security token
    2022-02-28 13:58:36.584 - INFO - opcua_client::session::session - Connect was successful
    2022-02-28 13:58:36.584 - DEBUG - opcua_client::session::session - session:1 get_endpoints
    2022-02-28 13:58:36.584 - DEBUG - opcua_client::message_queue - Request 2 was processed by the server
    2022-02-28 13:58:36.585 - DEBUG - opcua_client::message_queue - Response to Request 2 has been stored
    2022-02-28 13:58:36.585 - DEBUG - opcua_client::session::session - session:1 get_endpoints, success
    2022-02-28 13:58:36.586 - DEBUG - opcua_client::message_queue - Request 3 was processed by the server
    2022-02-28 13:58:36.586 - DEBUG - opcua_client::message_queue - Response to Request 3 has been stored
    2022-02-28 13:58:36.586 - ERROR - opcua_client::session::session - session:1 close_session failed ServiceFault(ServiceFault { response_header: ResponseHeader { timestamp: DateTime { date_time: 2022-02-28T13:58:36.586462900Z }, request_handle: 3, service_result: IS_ERROR | BadUnexpectedError | BadResourceUnavailable | BadCommunicationError | BadIdentityTokenInvalid | BadIdentityTokenRejected | BadNonceInvalid | BadSessionIdInvalid, service_diagnostics: DiagnosticInfo { symbolic_id: None, namespace_uri: None, locale: None, localized_text: None, additional_info: None, inner_status_code: None, inner_diagnostic_info: None }, string_table: Some([]), additional_header: ExtensionObject { node_id: NodeId { namespace: 0, identifier: Numeric(0) }, body: None } } })
    2022-02-28 13:58:36.586 - ERROR - opcua_client - Received a service fault of BadSessionIdInvalid for the request
    2022-02-28 13:58:36.586 - DEBUG - opcua_client::message_queue - Sending a quit to the message receiver
    2022-02-28 13:58:36.586 - DEBUG - opcua_client::comms::tcp_transport - Writer is about to send a CloseSecureChannelRequest which means it should close in a moment
    2022-02-28 13:58:36.586 - DEBUG - opcua_client::comms::tcp_transport - Waiting for a disconnect
    2022-02-28 13:58:36.587 - DEBUG - opcua_client::message_queue - Request 4 was processed by the server
    2022-02-28 13:58:36.587 - DEBUG - opcua_client::comms::tcp_transport - Writer is setting the connection state to finished(good)
    2022-02-28 13:58:36.587 - DEBUG - opcua_client::comms::tcp_transport - Write bytes task received a close, so closing connection after this send
    2022-02-28 13:58:36.587 - DEBUG - opcua_client::comms::tcp_transport - Writer write-task, 1 received a quit
    2022-02-28 13:58:36.587 - DEBUG - opcua_client::comms::tcp_transport - Writer loop write-task, 1 is finished
    2022-02-28 13:58:36.587 - DEBUG - opcua_core::runtime - deregistering component write-task, 1
    2022-02-28 13:58:36.587 - INFO - opcua_client::comms::tcp_transport - WriteState has dropped
    2022-02-28 13:58:36.595 - DEBUG - opcua_client::comms::tcp_transport - Connection state is finished so dropping out of connection task
    2022-02-28 13:58:36.595 - DEBUG - opcua_client::session::session_state - Session was closed with status = Good
    2022-02-28 13:58:36.595 - DEBUG - opcua_core::runtime - deregistering component connection-task, 1
    2022-02-28 13:58:36.595 - DEBUG - opcua_client::comms::tcp_transport - Client tokio tasks have stopped for connection
    2022-02-28 13:58:36.687 - DEBUG - opcua_client::comms::tcp_transport - Disconnected
    2022-02-28 13:58:36.687 - INFO - opcua_client::session::session - Session has dropped
    2022-02-28 13:58:36.687 - INFO - opcua_client::comms::tcp_transport - TcpTransport has dropped
    2022-02-28 13:58:36.687 - INFO - opcua_client::session::session_state - SessionState has dropped
    2022-02-28 13:58:36.687 - INFO - opcua_client::comms::tcp_transport - ReadState has dropped
    2022-02-28 13:58:36.688 - INFO - opcua_client::session::session - Connect
    2022-02-28 13:58:36.688 - INFO - opcua_client::session::session - Security policy = None
    2022-02-28 13:58:36.688 - INFO - opcua_client::session::session - Security mode = None
    2022-02-28 13:58:36.688 - DEBUG - opcua_client::comms::tcp_transport - Waiting for a connect (or failure to connect)
    2022-02-28 13:58:36.688 - DEBUG - opcua_client::comms::tcp_transport - Client tokio tasks are starting for connection
    2022-02-28 13:58:36.688 - DEBUG - opcua_core::runtime - registering component client-connection-thread-ThreadId(1)
    2022-02-28 13:58:36.688 - DEBUG - opcua_client::comms::tcp_transport - Creating a connection task to connect to [::1]:50000 with url opc.tcp://localhost:50000/
    2022-02-28 13:58:36.688 - DEBUG - opcua_core::runtime - registering component connection-task, 2
    2022-02-28 13:58:36.688 - DEBUG - opcua_client::comms::tcp_transport - Sending HELLO
    2022-02-28 13:58:36.688 - DEBUG - opcua_core::runtime - deregistering component connection-task, 2
    2022-02-28 13:58:36.688 - DEBUG - opcua_core::runtime - registering component finished-monitor-task, 2
    2022-02-28 13:58:36.689 - DEBUG - opcua_core::runtime - registering component read-task, 2
    2022-02-28 13:58:36.689 - DEBUG - opcua_core::runtime - registering component write-task, 2
    2022-02-28 13:58:36.689 - DEBUG - opcua_client::comms::tcp_transport - Reader got ack AcknowledgeMessage { message_header: MessageHeader { message_type: Acknowledge, message_size: 28 }, protocol_version: 0, receive_buffer_size: 65535, send_buffer_size: 65535, max_message_size: 4194304, max_chunk_count: 0 }
    2022-02-28 13:58:36.788 - DEBUG - opcua_client::comms::tcp_transport - Connected
    2022-02-28 13:58:36.788 - DEBUG - opcua_client::session::session - session:2 open_secure_channel
    2022-02-28 13:58:36.789 - INFO - opcua_client::session::session_state - Making secure channel request
    2022-02-28 13:58:36.789 - INFO - opcua_client::session::session_state - security_mode = None
    2022-02-28 13:58:36.789 - INFO - opcua_client::session::session_state - security_policy = None
    2022-02-28 13:58:36.789 - DEBUG - opcua_core::comms::secure_channel - AsymmetricSecurityHeader = AsymmetricSecurityHeader { security_policy_uri: UAString { value: Some("http://opcfoundation.org/UA/SecurityPolicy#None") }, sender_certificate: ByteString { value: None }, receiver_certificate_thumbprint: ByteString { value: None } }
    2022-02-28 13:58:36.789 - DEBUG - opcua_client::message_queue - Request 1 was processed by the server
    2022-02-28 13:58:36.789 - DEBUG - opcua_client::message_queue - Response to Request 1 has been stored
    2022-02-28 13:58:36.790 - DEBUG - opcua_client::session::session_state - Setting transport's security token
    2022-02-28 13:58:36.790 - INFO - opcua_client::session::session - Connect was successful
    2022-02-28 13:58:36.790 - DEBUG - opcua_client::session::session - session:2 CreateSessionRequest = CreateSessionRequest { request_header: RequestHeader { authentication_token: NodeId { namespace: 0, identifier: Numeric(0) }, timestamp: DateTime { date_time: 2022-02-28T13:58:36.790274400Z }, request_handle: 2, return_diagnostics: (empty), audit_entry_id: UAString { value: None }, timeout_hint: 10000, additional_header: ExtensionObject { node_id: NodeId { namespace: 0, identifier: Numeric(0) }, body: None } }, client_description: ApplicationDescription { application_uri: UAString { value: Some("urn:SimpleClient") }, product_uri: UAString { value: Some("urn:SimpleClient") }, application_name: LocalizedText { locale: UAString { value: Some("") }, text: UAString { value: Some("Simple Client") } }, application_type: Client, gateway_server_uri: UAString { value: None }, discovery_profile_uri: UAString { value: None }, discovery_urls: None }, server_uri: UAString { value: None }, endpoint_url: UAString { value: Some("opc.tcp://localhost:50000/") }, session_name: UAString { value: Some("Rust OPC UA Client") }, client_nonce: ByteString { value: Some([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) }, client_certificate: ByteString { value: Some([48, 130, 3, 171, 48, 130, 2, 147, 160, 3, 2, 1, 2, 2, 16, 93, 85, 247, 38, 30, 78, 196, 43, 190, 57, 250, 3, 76, 12, 212, 29, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 48, 102, 49, 22, 48, 20, 6, 3, 85, 4, 3, 12, 13, 83, 105, 109, 112, 108, 101, 32, 67, 108, 105, 101, 110, 116, 49, 22, 48, 20, 6, 3, 85, 4, 10, 12, 13, 83, 105, 109, 112, 108, 101, 32, 67, 108, 105, 101, 110, 116, 49, 22, 48, 20, 6, 3, 85, 4, 11, 12, 13, 83, 105, 109, 112, 108, 101, 32, 67, 108, 105, 101, 110, 116, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 73, 69, 49, 15, 48, 13, 6, 3, 85, 4, 8, 12, 6, 68, 117, 98, 108, 105, 110, 48, 30, 23, 13, 50, 49, 48, 54, 48, 56, 49, 51, 50, 56, 53, 57, 90, 23, 13, 50, 50, 48, 54, 48, 56, 49, 51, 50, 56, 53, 57, 90, 48, 102, 49, 22, 48, 20, 6, 3, 85, 4, 3, 12, 13, 83, 105, 109, 112, 108, 101, 32, 67, 108, 105, 101, 110, 116, 49, 22, 48, 20, 6, 3, 85, 4, 10, 12, 13, 83, 105, 109, 112, 108, 101, 32, 67, 108, 105, 101, 110, 116, 49, 22, 48, 20, 6, 3, 85, 4, 11, 12, 13, 83, 105, 109, 112, 108, 101, 32, 67, 108, 105, 101, 110, 116, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 73, 69, 49, 15, 48, 13, 6, 3, 85, 4, 8, 12, 6, 68, 117, 98, 108, 105, 110, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 210, 90, 66, 189, 102, 246, 193, 124, 107, 90, 185, 72, 158, 84, 63, 183, 218, 115, 87, 235, 9, 138, 178, 81, 188, 46, 178, 200, 128, 117, 112, 172, 54, 209, 137, 216, 122, 97, 204, 132, 238, 116, 203, 44, 54, 163, 250, 199, 15, 153, 121, 187, 138, 40, 140, 165, 134, 57, 120, 128, 34, 27, 207, 156, 5, 12, 231, 197, 234, 233, 44, 95, 58, 83, 5, 130, 21, 49, 146, 181, 141, 155, 71, 20, 17, 127, 5, 160, 102, 51, 246, 235, 123, 224, 16, 14, 217, 15, 51, 232, 251, 163, 215, 26, 239, 118, 202, 250, 62, 206, 63, 162, 5, 70, 35, 157, 57, 77, 176, 181, 136, 67, 16, 29, 49, 159, 91, 145, 215, 203, 87, 160, 159, 145, 50, 91, 44, 160, 190, 114, 0, 216, 70, 24, 15, 248, 233, 148, 74, 66, 48, 207, 105, 99, 101, 144, 115, 111, 197, 227, 201, 18, 169, 194, 235, 114, 74, 216, 75, 45, 212, 211, 192, 233, 139, 62, 151, 156, 136, 45, 18, 30, 197, 158, 118, 68, 178, 94, 169, 200, 70, 127, 87, 150, 176, 250, 36, 17, 225, 126, 75, 7, 132, 233, 255, 237, 124, 134, 201, 205, 236, 225, 88, 192, 53, 213, 227, 161, 121, 73, 122, 99, 180, 150, 22, 191, 84, 105, 189, 93, 13, 200, 133, 48, 251, 153, 79, 118, 18, 36, 193, 160, 234, 120, 76, 248, 153, 72, 44, 90, 136, 251, 148, 131, 41, 155, 2, 3, 1, 0, 1, 163, 85, 48, 83, 48, 11, 6, 3, 85, 29, 15, 4, 4, 3, 2, 2, 244, 48, 29, 6, 3, 85, 29, 37, 4, 22, 48, 20, 6, 8, 43, 6, 1, 5, 5, 7, 3, 1, 6, 8, 43, 6, 1, 5, 5, 7, 3, 2, 48, 37, 6, 3, 85, 29, 17, 4, 30, 48, 28, 134, 16, 117, 114, 110, 58, 83, 105, 109, 112, 108, 101, 67, 108, 105, 101, 110, 116, 130, 8, 115, 111, 102, 97, 107, 105, 110, 103, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 3, 130, 1, 1, 0, 21, 108, 215, 147, 135, 254, 230, 205, 128, 39, 20, 107, 174, 101, 87, 27, 186, 19, 80, 37, 19, 94, 189, 230, 232, 158, 86, 223, 191, 138, 219, 157, 33, 71, 246, 134, 205, 163, 242, 98, 185, 195, 5, 51, 255, 0, 98, 207, 253, 80, 231, 217, 126, 204, 230, 128, 67, 188, 106, 112, 19, 109, 47, 41, 21, 14, 205, 215, 66, 224, 68, 151, 75, 15, 217, 188, 222, 220, 93, 200, 75, 104, 159, 228, 54, 170, 202, 152, 74, 124, 49, 182, 119, 236, 82, 22, 208, 155, 137, 174, 159, 147, 133, 101, 187, 64, 220, 130, 6, 113, 133, 132, 137, 214, 194, 131, 79, 182, 24, 245, 124, 64, 220, 172, 52, 197, 58, 171, 103, 188, 159, 223, 76, 62, 147, 169, 45, 96, 130, 93, 62, 58, 166, 120, 26, 77, 251, 41, 126, 243, 175, 119, 188, 77, 88, 74, 48, 48, 171, 103, 194, 112, 145, 188, 153, 158, 245, 99, 170, 178, 80, 243, 92, 103, 254, 146, 72, 44, 181, 159, 206, 14, 227, 60, 253, 21, 5, 232, 43, 66, 52, 13, 81, 118, 213, 53, 1, 180, 77, 200, 72, 243, 37, 238, 139, 120, 206, 234, 107, 166, 191, 173, 238, 137, 91, 71, 136, 109, 209, 140, 51, 133, 54, 186, 78, 23, 240, 187, 231, 244, 220, 94, 170, 72, 251, 82, 200, 105, 37, 22, 141, 110, 64, 43, 94, 196, 153, 59, 150, 188, 195, 143, 96, 211, 97, 40]) }, requested_session_timeout: 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0, max_response_message_size: 0 }
    2022-02-28 13:58:36.790 - DEBUG - opcua_client::message_queue - Request 2 was processed by the server
    2022-02-28 13:58:36.795 - DEBUG - opcua_client::message_queue - Response to Request 2 has been stored
    2022-02-28 13:58:36.795 - DEBUG - opcua_client::session::session - session:2 Revised session timeout is 3600000
    2022-02-28 13:58:36.795 - DEBUG - opcua_client::session::session - session:2 spawn_session_activity_task(3600000)
    2022-02-28 13:58:36.795 - DEBUG - opcua_client::session::session - session:2 session timeout is 3600000, activity timer is 2700000
    2022-02-28 13:58:36.796 - DEBUG - opcua_client::session::session - session:2 Endpoint policy = Some(UserTokenPolicy { policy_id: UAString { value: Some("1") }, token_type: Anonymous, issued_token_type: UAString { value: None }, issuer_endpoint_url: UAString { value: None }, security_policy_uri: UAString { value: Some("http://opcfoundation.org/UA/SecurityPolicy#Basic256") } })
    2022-02-28 13:58:36.796 - DEBUG - opcua_client::message_queue - Request 3 was processed by the server
    2022-02-28 13:58:36.796 - DEBUG - opcua_client::message_queue - Response to Request 3 has been stored
    2022-02-28 13:58:36.796 - DEBUG - opcua_client::session::session - session:2 read() requested to read nodes [ReadValueId { node_id: NodeId { namespace: 5, identifier: String(UAString { value: Some("DataAccess_AnalogType_Array_Variant") }) }, attribute_id: 13, index_range: UAString { value: None }, data_encoding: QualifiedName { namespace_index: 0, name: UAString { value: None } } }]
    2022-02-28 13:58:36.797 - DEBUG - opcua_client::message_queue - Request 4 was processed by the server
    2022-02-28 13:58:36.798 - ERROR - opcua_types::variant - Unrecognized encoding mask
    2022-02-28 13:58:36.799 - DEBUG - opcua_core::comms::chunker - Cannot decode message ReadResponse_Encoding_DefaultBinary, err = IS_ERROR | BadUnexpectedError | BadInternalError | BadOutOfMemory | BadResourceUnavailable | BadCommunicationError | BadEncodingError | BadDecodingError
    2022-02-28 13:58:36.799 - ERROR - opcua_client::comms::tcp_transport - Reader has put connection into a finished state with status BadServiceUnsupported
    2022-02-28 13:58:36.799 - DEBUG - opcua_client::comms::tcp_transport - Sending a quit to the writer
    2022-02-28 13:58:36.799 - DEBUG - opcua_client::comms::tcp_transport - Read loop finished, connection state = Finished(IS_ERROR | BadUnexpectedError | BadInternalError | BadOutOfMemory | BadEncodingLimitsExceeded | BadUnknownResponse | BadTimeout | BadServiceUnsupported)
    2022-02-28 13:58:36.799 - DEBUG - opcua_core::runtime - deregistering component read-task, 2
    2022-02-28 13:58:36.799 - INFO - opcua_client::comms::tcp_transport - ReadState has dropped
    2022-02-28 13:58:36.799 - DEBUG - opcua_client::comms::tcp_transport - Writer write-task, 2 received a quit
    2022-02-28 13:58:36.799 - DEBUG - opcua_client::comms::tcp_transport - Writer loop write-task, 2 is finished
    2022-02-28 13:58:36.799 - DEBUG - opcua_core::runtime - deregistering component write-task, 2
    2022-02-28 13:58:36.799 - INFO - opcua_client::comms::tcp_transport - WriteState has dropped
    2022-02-28 13:58:36.800 - DEBUG - opcua_client::comms::tcp_transport - Connection state is finished so dropping out of connection task
    

    Where I see the breakdown is the line "Unrecognized encoding mask"

    2022-02-28 13:58:36.798 - ERROR - opcua_types::variant - Unrecognized encoding mask
    2022-02-28 13:58:36.799 - DEBUG - opcua_core::comms::chunker - Cannot decode message ReadResponse_Encoding_DefaultBinary, err = IS_ERROR | BadUnexpectedError | BadInternalError | BadOutOfMemory | BadResourceUnavailable | BadCommunicationError | BadEncodingError | BadDecodingError
    2022-02-28 13:58:36.799 - ERROR - opcua_client::comms::tcp_transport - Reader has put connection into a finished state with status BadServiceUnsupported
    2022-02-28 13:58:36.799 - DEBUG - opcua_client::comms::tcp_transport - Sending a quit to the writer
    

    For some reason, this shuts everything down and the read attempt eventually times out. But the session is broken in some way at this point, subsequent reads also time out.

    In the code sample there are two nodes. n1 produces this problem, but n2 does not (a value is returned). Swapping the order of the nodes, first gives a value, then it crashes.

    So far what I've figured is that from_encoding_mask() does not handle Variant. I don't know why this is, and I don't know if this is the real problem. What I would like though, is that a read that fails to decode is just returned to me as an error like everything else, so I, as the client, can decide on how to act. As it stands, the only way I can see to recover is to re-initialize the client, but that seems like overkill.

    The signature of from_encoding_mask() was changed recently (in 633b60a1252719c84c879cbb60884652e4d9a7b1) and the change from a panic to returning an error looks like the right direction, but it doesn't fully solve this issue.

    opened by laumann 11
  • Get children of the parent node for Server side

    Get children of the parent node for Server side

    Is there a way to get the children nodes for the parent node. I am trying to use String node id like "ns=2;s=/Test/Server/Folder". How server can browse this path to get all children of this node?

    I know there is a method in python library Node.get_children() , is there something similar available in rust package I can use?

    opened by jigar88 11
  • Bump tokio from 1.23.0 to 1.23.1

    Bump tokio from 1.23.0 to 1.23.1

    Bumps tokio from 1.23.0 to 1.23.1.

    Release notes

    Sourced from tokio's releases.

    Tokio v1.23.1

    This release forward ports changes from 1.18.4.

    Fixed

    • net: fix Windows named pipe server builder to maintain option when toggling pipe mode (#5336).

    #5336: tokio-rs/tokio#5336

    Commits
    • 1a997ff chore: prepare Tokio v1.23.1 release
    • a8fe333 Merge branch 'tokio-1.20.x' into tokio-1.23.x
    • ba81945 chore: prepare Tokio 1.20.3 release
    • 763bdc9 ci: run WASI tasks using latest Rust
    • 9f98535 Merge remote-tracking branch 'origin/tokio-1.18.x' into fix-named-pipes-1.20
    • 9241c3e chore: prepare Tokio v1.18.4 release
    • 699573d net: fix named pipes server configuration builder
    • See full diff in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies rust 
    opened by dependabot[bot] 0
  • Add serde(default) to ServerConfig, implemented default for TcpConfig…

    Add serde(default) to ServerConfig, implemented default for TcpConfig…

    Allows for defining partial configuration in file and take the rest from the default implementation. TcpConfig and Performance receive their own default implementation, to be partially definable in the config too.

    opened by didu14 0
  • Client Session/Tcptransport clones of session_state become out of sync if the server restarts

    Client Session/Tcptransport clones of session_state become out of sync if the server restarts

    When a client is connected to a peer, if the peer disconnects, the reconnect logic calls 'reconnect_and_activate', which calls 'reset()', which creates a new session_state, but the session.transport is not updated with the new session state, leading to inconsistencies.

    I have a patch for this here. By adding a Tcptransport::reset() that updates the session_state (and the dependent message_queue and connection_state.

    The bug can be demonstrated by commenting out session.rs:223. Running simple-client against simple-server, with line 223 commented, when restarting the server, the client will panic:

    Created a subscription with id = 1
    Data change from server:
    Item "ns=2;s=v4", Value = Double(-0.893559520249049)
    Item "ns=2;s=v1", Value = Int32(28)
    Item "ns=2;s=v2", Value = Boolean(true)
    Item "ns=2;s=v3", Value = String(UAString { value: Some("Hello World times 1") })
    Data change from server:
    Item "ns=2;s=v2", Value = Boolean(false)
    Item "ns=2;s=v4", Value = Double(0.21200710992205463)
    Item "ns=2;s=v3", Value = String(UAString { value: Some("Hello World times 2") })
    Item "ns=2;s=v1", Value = Int32(35)
    Data change from server:
    Item "ns=2;s=v2", Value = Boolean(true)
    Item "ns=2;s=v1", Value = Int32(42)
    Item "ns=2;s=v4", Value = Double(0.9950138797069145)
    Item "ns=2;s=v3", Value = String(UAString { value: Some("Hello World times 3") })
    thread 'main' panicked at 'assertion failed: self.session_state.read().id() == self.transport.session_id()', lib/src/client/session/session.rs:225:9
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    

    While this patch seems to work, it exposes a large issue. As the reconnect logic progresses, it eventually deadlocks on session.rs:1442 : SessionService::create_session::spawn_session_activity_task, which tries to access the runtime, but cannot because the TcpTransport::connect has spawned a thread that locks the runtime during the life of the connection (spawn_looping_tasks). For that reason I currently have the transport reset disabled so that the client can be restarted externally.

    If there are suggestions on how to work around this I'm happy to test.

    opened by joshuagleaton 1
  • Replace chrono with time? (CVE-2020-26235)

    Replace chrono with time? (CVE-2020-26235)

    There's a known issue with chrono which apparently leads back to the dependency on time. One fix looks to be updating chrono's dependency on time from 0.1 to 0.3 but that doesn't appear to have been done.

    An alternative suggestion is to replace chrono with time. Would it make sense to do this?

    Another discussion: https://www.reddit.com/r/rust/comments/qqu1bw/what_should_we_do_about_cve202026235_localtime_r/

    See:

    • https://nvd.nist.gov/vuln/detail/CVE-2020-26235
    • https://github.com/time-rs/time/security/advisories/GHSA-wcg3-cvx6-7396
    opened by 0x2ec 0
  • Security token id

    Security token id

    According to the specification, the secure token id is:

    A unique identifier for the SecureChannel SecurityToken used to secure the Message.
    This identifier is returned by the Server in an OpenSecureChannel response Message.
    If a Server receives a TokenId which it does not recognize it shall return an appropriate
    transport layer error.
    

    Except that we are able to change it without the server return the appropriate error. I modified this field for the message useful to create and active session and both were accepted.

    commit: fd38c6470b234804b537b3dfe281171ff1c199d2 commit date: Sat Nov 5 21:49:43 2022 +0100 application tested: demo-server

    opened by artfire52 0
  • Implement error handling

    Implement error handling

    This patch implements the first step to proper error handling instead of just logging errors using the log crate.


    There's a lot to do in this crate to bring error handling and config validation up to the state of art. This is only the first step, basically "to get the foot into the door" for doing error handling the proper way here.

    Let me know what you think!

    opened by matthiasbeyer 3
Owner
null
🦀 REST API client implementation for freee, auto-generated from OpenAPI specification.

freee-rs REST API client implementation for freee, auto-generated from OpenAPI specification. Getting Started Add to your Cargo.toml as follows: [depe

Naoki Ikeguchi 3 Jul 14, 2022
This Intelligent Transportation Systems (ITS) MQTT client based on the JSon ETSI specification transcription provides a ready to connect project for the mobility

This Intelligent Transportation Systems (ITS) MQTT client based on the JSon ETSI specification transcription provides a ready to connect project for the mobility (connected and autonomous vehicles, road side units, vulnerable road users,...). Let's connect your device or application to our Intelligent Transport Systems (ITS) platform!

Orange 4 Nov 29, 2022
Implementation of the Web Cryptography specification in Rust.

[wip] webcrypto Implementation of the Web Cryptography specification in Rust. This crate hopes to ease interoperability between WASM and native target

Divy Srivastava 5 Mar 7, 2022
Implementation of the WebUSB specification in Rust.

Implementation of the WebUSB specification in Rust.

Divy Srivastava 38 Dec 4, 2022
A Kubernetes implementation of the Open Application Model specification

Rudr ?? NOTE: Rudr is deprecated in favor of the upcoming open application platform project as its successor. There are no plans to produce future rel

Open Application Model 1.6k Jan 4, 2023
An implementation of WICG Import Maps specification

import_map A Rust implementation of WICG Import Maps specification. This crates is used in Deno project. The implementation is tested against WPT test

Deno Land 20 Nov 21, 2022
Experimental implementation of the Privacy Preserving Measurement (PPM) specification.

janus Janus is an experimental implementation of the Privacy Preserving Measurement (PPM) specification. It is currently in active development. Runnin

Divvi Up (ISRG) 33 Dec 12, 2022
An implementation of the append-only log described in the Certificate Transparency specification (RFC 6962)

CT Merkle This is an implementation of the append-only log described in the Certificate Transparency specification (RFC 6962). The log is a Merkle tre

Michael Rosenberg 30 Dec 2, 2022
ANISE provides an open-source and open-governed library and algorithmic specification for most computations for astrodynamics

ANISE provides an open-source and open-governed library and algorithmic specification for most computations for astrodynamics. It is heavily inspired by NAIF SPICE, and may be considered as an open-source modern rewrite of SPICE.

ANISE 4 Mar 9, 2022
A rust library containing typings and utility functions dealing with the Public specification of the Internet Computer.

IC Types Contributing Please follow the guidelines in the CONTRIBUTING.md document. Goal This library contains typings and utility functions dealing w

DFINITY 5 Nov 28, 2022
Rust SDK for the core C2PA (Coalition for Content Provenance and Authenticity) specification

C2PA Rust SDK The Coalition for Content Provenance and Authenticity (C2PA) addresses the prevalence of misleading information online through the devel

Content Authenticity Initiative 46 Jun 30, 2023
Runc - CLI tool for spawning and running containers according to the OCI specification

runc Introduction runc is a CLI tool for spawning and running containers on Linux according to the OCI specification. Releases You can find official r

Open Container Initiative 9.9k Jan 5, 2023
Basic Redis Protocol specification in Rust

Basic Redis Protocol specification in Rust

Bruno 1 Jan 20, 2022
turbocommit is a Rust-based CLI tool that generates high-quality git commit messages in accordance with the Conventional Commits specification, using OpenAI's

turbocommit is a Rust-based CLI tool that generates high-quality git commit messages in accordance with the Conventional Commits specification, using OpenAI's `gpt-3.5-turbo` language model. It is easy to use and a cost-effective way to keep git commit history at a higher quality, helping developers stay on track with their work.

Sett 16 Mar 26, 2023
Black-box fuzzer that fuzzes APIs based on OpenAPI specification. Find bugs for free!

OpenAPI fuzzer Black-box fuzzer that fuzzes APIs based on OpenAPI specification. All you need to do is to supply URL of the API and its specification.

Matúš Ferech 406 Dec 31, 2022
Soufflé is a variant of Datalog for tool designers crafting analyses in Horn clauses. Soufflé synthesizes a native parallel C++ program from a logic specification.

Welcome! This is the official repository for the Soufflé language project. The Soufflé language is similar to Datalog (but has terms known as records)

The Soufflé Project 672 Dec 29, 2022
Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password.

nostr-irc Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password. Experimental code, use

null 11 Dec 26, 2022
QUIC proxy that allows to use QUIC to connect to an SSH server without needing to patch the client or the server.

quicssh-rs ?? quicssh-rs is a QUIC proxy that allows to use QUIC to connect to an SSH server without needing to patch the client or the server. quicss

Jun Ouyang 18 May 5, 2023
REC2 (Rusty External Command and Control) is client and server tool allowing auditor to execute command from VirusTotal and Mastodon APIs written in Rust. 🦀

Information: REC2 is an old personal project (early 2023) that I didn't continue development on. It's part of a list of projects that helped me to lea

Quentin Texier (g0h4n) 104 Oct 7, 2023
RDE1 (Rusty Data Exfiltrator) is client and server tool allowing auditor to extract files from DNS and HTTPS protocols written in Rust. 🦀

Information: RDE1 is an old personal project (end 2022) that I didn't continue development on. It's part of a list of projects that helped me to learn

Quentin Texier (g0h4n) 32 Oct 6, 2023