Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of up-transport-vsomeip-rust #2

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9037a72
Adding a refactored vsomeip-sys.
PLeVasseur May 28, 2024
f990f07
Added docs for all public API surfaces.
PLeVasseur May 29, 2024
f8de2cb
Updated the revision we point to for up-rust.
PLeVasseur May 29, 2024
bc476bb
Initial implementation of up-transport-vsomeip-rust
PLeVasseur May 29, 2024
1a66d1a
Fixing vsomeip-sys build script to point to local downloaded tarball …
PLeVasseur Jun 12, 2024
ce12f2f
PR feedback fixes:
PLeVasseur Jun 12, 2024
43ce45b
Update name to up-transport-vsomeip
PLeVasseur Jun 12, 2024
0b7dadd
Adjusting version of tokio to match up-client-zenoh-rust
PLeVasseur Jun 13, 2024
5eed9d0
Updated to have source and sink swapped when registering for uStreame…
PLeVasseur Jun 13, 2024
1b362ce
If payload data_ptr is null, then return an empty Vec<u8> when callin…
PLeVasseur Jun 13, 2024
c1c7327
Moving more shared functionality into functions
PLeVasseur Jun 14, 2024
0c143a7
cargo clippy
PLeVasseur Jun 14, 2024
0b42c81
Added validation to send()
PLeVasseur Jun 14, 2024
bf02708
Added additional checks and removed TODOs
PLeVasseur Jun 14, 2024
0e3e2bc
Protecting us against a case where we failed to find a vsomeip applic…
PLeVasseur Jun 14, 2024
0d6ccbc
Adding safe wrapper around function on vsomeip application to be info…
PLeVasseur Jun 16, 2024
0ba0dd5
Updating to up-rust referencing UCode separate .proto fix
PLeVasseur Jun 17, 2024
6566a39
Printing attempt at deserializing vsomeip payload
PLeVasseur Jun 19, 2024
4dbc786
Add some more checking around setting payload
PLeVasseur Jun 19, 2024
91e60ee
Showed that publish makes its way through with payload to the subscriber
PLeVasseur Jun 19, 2024
5dd056a
Looks like the Request came through from the client through to the se…
PLeVasseur Jun 19, 2024
1ba60db
Checking in some work related to listening for subscription status ch…
PLeVasseur Jun 19, 2024
db97c69
Workaround for tricky bug wherein if we try to pass back out a Messag…
PLeVasseur Jun 20, 2024
b51c00f
Fixing bug with publish / subscribe
PLeVasseur Jun 23, 2024
cc9e998
Firewall code accessing lazy_static!{} variables to within their own …
PLeVasseur Jul 1, 2024
15ddcb6
Reorganize to clarify transport_inner as internal analog
PLeVasseur Jul 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ Cargo.lock

.vscode/
.idea/

perf.data*
*.svg
13 changes: 11 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ exclude = [
]
keywords = ["uProtocol", "SDK", "vsomeip", "SOMEIP"]
license = "Apache-2.0"
name = "up-client-vsomeip-rust"
name = "up-transport-vsomeip"
readme = "README.md"
repository = "https://github.com/eclipse-uprotocol/up-client-vsomeip-rust"
rust-version = "1.72"
Expand All @@ -34,13 +34,22 @@ version = "0.1.0"
[dependencies]
async-trait = { version = "0.1" }
bytes = { version = "1.5" }
cxx = { version = "1.0" }
rand = { version = "0.8" }
regex = { version = "1.10" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
up-rust = { git = "https://github.com/eclipse-uprotocol/up-rust", version = "0.1.5" }
tokio = { version = "1.35.1", features = ["rt", "rt-multi-thread", "macros", "sync", "time"] }
up-rust = { git = "https://github.com/eclipse-uprotocol/up-rust", rev = "3a50104421a801d52e1d9c68979db54c013ce43d" }
url = { version = "2.5" }
uuid = { version = "1.7", features = ["v8"] }
vsomeip-proc-macro = { path = "vsomeip-proc-macro" }
vsomeip-sys = { path = "vsomeip-sys" }
lazy_static = "1.4.0"
protobuf = "3.4.0"
env_logger = "0.11.3"
log = { version = "0.4.21", features = [] }
once_cell = "1.19.0"

[dev-dependencies]
test-case = { version = "3.3" }
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,19 @@ This library implements a uTransport client for vsomeip in Rust following the uP

### Building the Library

To build the library, run `cargo build` in the project root directory. Tests can be run with `cargo test`. This library leverages the [up-rust](https://github.com/eclipse-uprotocol/up-rust/tree/main) library for data types and models specified by uProtocol.
To build the library, run `cargo build` in the project root directory. This library leverages the [up-rust](https://github.com/eclipse-uprotocol/up-rust/tree/main) library for data types and models specified by uProtocol.

### Running the Tests

To run the tests, run
```bash
LD_LIBRARY_PATH=<YOUR-PATH-TO-VSOMEIP-SHARED-LIB> VSOMEIP_LIB_DIR==<YOUR-PATH-TO-VSOMEIP-SHARED-LIB> cargo test -- --test-threads 1
```

Breaking this down:
* `LD_LIBRARY_PATH` will, at run-time, tell where you have installed the vsomeip shared libraries (i.e. where `vsomeip3.so` is located)
* `VSOMEIP_LIB_DIR` will, at compile-time, tell where you have installed the vsomeip shared libraries
* We need to pass in `-- --test-threads 1` because the tests refer to the same configurations and will fall over if they are run simultaneously. So we instruct to use a single thread, i.e. run the tests in serial.

### Using the Library

Expand Down
87 changes: 87 additions & 0 deletions src/determine_message_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/********************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

use crate::{ClientId, RegistrationType, UeId};
use up_rust::{UStatus, UUri};

// infer the type of message desired based on the filters provided
pub(crate) fn determine_registration_type(
source_filter: &UUri,
sink_filter: &Option<UUri>,
my_ue_id: UeId,
) -> Result<RegistrationType, UStatus> {
determine_type(
source_filter,
sink_filter,
Some(my_ue_id),
DeterminationType::Register,
)
}

pub(crate) fn determine_send_type(
source_filter: &UUri,
sink_filter: &Option<UUri>,
) -> Result<RegistrationType, UStatus> {
determine_type(source_filter, sink_filter, None, DeterminationType::Send)
}

enum DeterminationType {
Register,
Send,
}

fn determine_type(
source_filter: &UUri,
sink_filter: &Option<UUri>,
my_ue_id: Option<UeId>,
determination_type: DeterminationType,
) -> Result<RegistrationType, UStatus> {
if let Some(sink_filter) = &sink_filter {
// determine if we're in the uStreamer use-case of capturing all point-to-point messages
let streamer_use_case = {
source_filter.authority_name == "*"
&& source_filter.ue_id == 0x0000_FFFF
&& source_filter.ue_version_major == 0xFF
&& source_filter.resource_id == 0xFFFF
&& sink_filter.authority_name != "*"
&& sink_filter.ue_id == 0x0000_FFFF
&& sink_filter.ue_version_major == 0xFF
&& sink_filter.resource_id == 0xFFFF
};

if streamer_use_case {
return Ok(RegistrationType::AllPointToPoint(0xFFFF));
}

let client_id = match determination_type {
DeterminationType::Register => sink_filter.ue_id as ClientId,
DeterminationType::Send => source_filter.ue_id as ClientId,
};

if sink_filter.resource_id == 0 {
Ok(RegistrationType::Response(client_id))
} else {
Ok(RegistrationType::Request(client_id))
}
} else {
let client_id = match determination_type {
DeterminationType::Register => {
my_ue_id.expect("Should have been an own ue_id available in this path")
}
DeterminationType::Send => source_filter.ue_id as ClientId,
};
Ok(RegistrationType::Publish(client_id))
}
}

// TODO: Add unit tests
161 changes: 160 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,165 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

use std::path::{Path, PathBuf};
use std::sync::Arc;
use tokio::sync::RwLock;
use up_rust::{UCode, UListener, UStatus, UUri, UUID};

pub mod transport;

pub struct UPClientVsomeip {}
mod message_conversions;

mod determine_message_type;

mod listener_registry;
mod rpc_correlation;
mod transport_inner;
mod vsomeip_config;
mod vsomeip_offered_requested;
use transport_inner::UPTransportVsomeipInner;

// TODO: use function from up-rust when merged
pub(crate) fn any_uuri() -> UUri {
UUri {
authority_name: "*".to_string(),
ue_id: 0x0000_FFFF, // any instance, any service
ue_version_major: 0xFF, // any
resource_id: 0xFFFF, // any
..Default::default()
}
}

// TODO: upstream into up-rust
pub(crate) fn any_uuri_fixed_authority_id(authority_name: &AuthorityName, ue_id: UeId) -> UUri {
UUri {
authority_name: authority_name.to_string(),
ue_id: ue_id as u32,
ue_version_major: 0xFF, // any
resource_id: 0xFFFF, // any
..Default::default()
}
}

// TODO: upstream this into up-rust
pub(crate) fn split_u32_to_u16(value: u32) -> (u16, u16) {
let most_significant_bits = (value >> 16) as u16;
let least_significant_bits = (value & 0xFFFF) as u16;
(most_significant_bits, least_significant_bits)
}

// TODO: upstream this into up-rust
pub(crate) fn split_u32_to_u8(value: u32) -> (u8, u8, u8, u8) {
let byte1 = (value >> 24) as u8;
let byte2 = (value >> 16 & 0xFF) as u8;
let byte3 = (value >> 8 & 0xFF) as u8;
let byte4 = (value & 0xFF) as u8;
(byte1, byte2, byte3, byte4)
}

// TODO: upstream this into up-rust
pub(crate) fn create_request_id(client_id: ClientId, session_id: SessionId) -> RequestId {
((client_id as u32) << 16) | (session_id as u32)
}

type ApplicationName = String;
type AuthorityName = String;
type UeId = u16;
type ClientId = u16;
type ReqId = UUID;
type SessionId = u16;
type RequestId = u32;
type EventId = u16;
type ServiceId = u16;
type InstanceId = u16;
type MethodId = u16;

#[derive(Clone, Debug, PartialEq)]
enum RegistrationType {
Publish(ClientId),
Request(ClientId),
Response(ClientId),
AllPointToPoint(ClientId),
}

impl RegistrationType {
pub fn client_id(&self) -> ClientId {
match self {
RegistrationType::Publish(client_id) => *client_id,
RegistrationType::Request(client_id) => *client_id,
RegistrationType::Response(client_id) => *client_id,
RegistrationType::AllPointToPoint(client_id) => *client_id,
}
}
}

pub struct UPTransportVsomeip {
inner_transport: UPTransportVsomeipInner,
authority_name: AuthorityName,
remote_authority_name: AuthorityName,
ue_id: UeId,
config_path: Option<PathBuf>,
// if this is not None, indicates that we are in a dedicated point-to-point mode
point_to_point_listener: RwLock<Option<Arc<dyn UListener>>>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why a RwLock is needed and why you chose to wrap the Option rather than Option<RwLock<...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure -- I used a RwLock here because I needed a means to ensure thread-safety of the Option<> since it's used within different async functions.

}

impl UPTransportVsomeip {
pub fn new_with_config(
authority_name: &AuthorityName,
remote_authority_name: &AuthorityName,
ue_id: UeId,
config_path: &Path,
) -> Result<Self, UStatus> {
if !config_path.exists() {
return Err(UStatus::fail_with_code(
UCode::NOT_FOUND,
format!("Configuration file not found at: {:?}", config_path),
));
}
Self::new_internal(
authority_name,
remote_authority_name,
ue_id,
Some(config_path),
)
}

pub fn new(
authority_name: &AuthorityName,
remote_authority_name: &AuthorityName,
ue_id: UeId,
) -> Result<Self, UStatus> {
Self::new_internal(authority_name, remote_authority_name, ue_id, None)
}

fn new_internal(
authority_name: &AuthorityName,
remote_authority_name: &AuthorityName,
ue_id: UeId,
config_path: Option<&Path>,
) -> Result<Self, UStatus> {
let inner_transport = UPTransportVsomeipInner::new(config_path);
let config_path: Option<PathBuf> = config_path.map(|p| p.to_path_buf());

Ok(Self {
inner_transport,
authority_name: authority_name.to_string(),
remote_authority_name: remote_authority_name.to_string(),
ue_id,
point_to_point_listener: None.into(),
config_path,
})
}
}

// TODO: We need to ensure that we properly cleanup / unregister all message handlers
// and then remove the application
// impl Drop for UPClientVsomeip {
// fn drop(&mut self) {
// // TODO: Should do this a bit more carefully, for now we will just stop all active vsomeip
// // applications
// // - downside of doing this drastic option is that _if_ you wanted to keep one client
// // active and let another be dropped, this would put your client in a bad state
//
// }
// }
Loading
Loading