Skip to content

Commit

Permalink
Merge pull request #376 from elfenpiff/iox2-370-domain-separation-c-e…
Browse files Browse the repository at this point in the history
…xample

[#370] domain separation c example
  • Loading branch information
elfenpiff authored Sep 19, 2024
2 parents a9df608 + de507d0 commit 5bd86ec
Show file tree
Hide file tree
Showing 10 changed files with 501 additions and 1 deletion.
1 change: 1 addition & 0 deletions doc/release-notes/iceoryx2-unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
* Add custom user header [#253](https://github.com/eclipse-iceoryx/iceoryx2/issues/253)
* Build the C and C++ language bindings with bazel [#329](https://github.com/eclipse-iceoryx/iceoryx2/issues/329)
* Add `Subscriber::has_samples` [#335](https://github.com/eclipse-iceoryx/iceoryx2/issues/335)
* Example that demonstrates iceoryx2 domains [#370](https://github.com/eclipse-iceoryx/iceoryx2/issues/370)

### Bugfixes

Expand Down
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ they interact and exchange data.
| complex data types | [Rust](rust/complex_data_types) | Send zero-copy compatible versions of `Vec` and `String`. Introduces `PlacementDefault` trait for large data types to perform an in place initialization where otherwise a stack overflow would be encountered.|
| discovery | [C](c/discovery) [C++](cxx/discovery) [Rust](rust/discovery) | List all available services in a system. |
| docker | [all](rust/docker) | Communicate between different docker containers and the host. |
| domains | [C++](cxx/domains) [Rust](rust/domains) | Establish separate domains that operate independently from one another. |
| domains | [C](c/domains) [C++](cxx/domains) [Rust](rust/domains) | Establish separate domains that operate independently from one another. |
| event | [C](c/event) [C++](cxx/event) [Rust](rust/event) | Push notifications - send event signals to wakeup processes that are waiting for them.|
| publish subscribe | [C](c/publish_subscribe) [C++](cxx/publish_subscribe) [Rust](rust/publish_subscribe) | Communication between multiple processes with a [publish subscribe messaging pattern](https://en.wikipedia.org/wiki/Publish–subscribe_pattern). |
| publish subscribe dynamic data | [Rust](rust/publish_subscribe_dynamic_data) | Communication between multiple processes with a [publish subscribe messaging pattern](https://en.wikipedia.org/wiki/Publish–subscribe_pattern) and payload data that has a dynamic size. |
Expand Down
1 change: 1 addition & 0 deletions examples/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ cmake_minimum_required(VERSION 3.22)
project(examples_c LANGUAGES C)

add_subdirectory(discovery)
add_subdirectory(domains)
add_subdirectory(event)
add_subdirectory(publish_subscribe)
add_subdirectory(publish_subscribe_with_user_header)
45 changes: 45 additions & 0 deletions examples/c/domains/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright (c) 2024 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 Software License 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
# which is available at https://opensource.org/licenses/MIT.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")

cc_binary(
name = "example_c_domains_publisher",
srcs = [
"src/publisher.c",
"src/transmission_data.h",
],
deps = [
"//:iceoryx2-c",
],
)

cc_binary(
name = "example_c_domains_subscriber",
srcs = [
"src/subscriber.c",
"src/transmission_data.h",
],
deps = [
"//:iceoryx2-c",
],
)

cc_binary(
name = "example_c_domains_discovery",
srcs = [
"src/discovery.c",
],
deps = [
"//:iceoryx2-c",
],
)
25 changes: 25 additions & 0 deletions examples/c/domains/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright (c) 2024 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 Software License 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
# which is available at https://opensource.org/licenses/MIT.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT

cmake_minimum_required(VERSION 3.22)
project(example_c_domains LANGUAGES C)

find_package(iceoryx2-c 0.3.0 REQUIRED)

add_executable(example_c_domains_publisher src/publisher.c)
target_link_libraries(example_c_domains_publisher iceoryx2-c::static-lib)

add_executable(example_c_domains_subscriber src/subscriber.c)
target_link_libraries(example_c_domains_subscriber iceoryx2-c::static-lib)

add_executable(example_c_domains_discovery src/discovery.c)
target_link_libraries(example_c_domains_discovery iceoryx2-c::static-lib)
67 changes: 67 additions & 0 deletions examples/c/domains/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Domains

Please install all dependencies first, as described in the [C Examples Readme](../README.md).

Let's assume you want to create multiple iceoryx2 groups of processes where the
processes inside a group can communicate and interact with each other. However,
the groups themselves should remain isolated, meaning a process from one group
cannot interact with a process from another group.

In other words, we aim to create different iceoryx2 domains on a local machine
that are strictly separated.

This strict separation can be achieved by using the iceoryx2 configuration.
Within the configuration, a wide range of parameters can be adjusted, such as
the directory used for files containing static service information (a detailed
description of the service) or static node information (a detailed description
of a node). Additionally, the prefix of all files, which is by default `iox2_`,
can be modified.

In this example, we use the prefix to separate the iceoryx2 groups. For all
examples, the user can set the iceoryx2 domain using `-d $DOMAIN_NAME$`. The
domain name must be a valid file name. The example will only operate within
this domain and cannot interact with any services in other domains with
different names.

The `domains_discovery` binary illustrates this by listing all services
available in a given domain. Similarly, the `domains_publisher` will send data
only to subscribers within the same domain. Subscribers in other domains will
not receive any data.

## Implementation

To achieve this, we create a copy of the global configuration, modify the
setting `config.global.prefix` using the user-provided CLI argument, and then
set up the example accordingly.

## Running The Example

You can experiment with this setup by creating multiple publishers and
subscribers with different service names using `-s $SERVICE_NAME`. Only
publisher-subscriber pairs within the same domain will be able to communicate,
and the discovery tool will only detect services from within the same domain.

First you have to build the C++ examples:

```sh
cmake -S . -B target/ffi/build -DBUILD_EXAMPLES=ON
cmake --build target/ffi/build
```

**Terminal 1:** Subscriber in domain "fuu" subscribing to service "bar"

```sh
./target/ffi/build/examples/c/domains/example_c_domains_subscriber "fuu" "bar"
```

**Terminal 2** Publisher in domain "fuu" publishing on service "bar"

```sh
./target/ffi/build/examples/c/domains/example_c_domains_publisher "fuu" "bar"
```

**Terminal 3** List all services of domain "fuu"

```sh
./target/ffi/build/examples/c/domains/example_c_domains_discovery "fuu"
```
50 changes: 50 additions & 0 deletions examples/c/domains/src/discovery.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2024 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 Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include "iox2/iceoryx2.h"
#include <stdio.h>

iox2_callback_progression_e list_callback(const iox2_static_config_t* static_details, void* callback_context) {
printf("Found Service: %s, ServiceID: %s\n", static_details->name, static_details->id);
return iox2_callback_progression_e_CONTINUE;
}

int main(int argc, char** argv) {
if (argc != 2) {
printf("usage: %s DOMAIN_NAME\n", argv[0]);
exit(-1);
}

// create a new config based on the global config
iox2_config_ptr config_ptr = iox2_config_global_config();
iox2_config_h config = NULL;
iox2_config_from_ptr(config_ptr, NULL, &config);
iox2_config_ref_h config_ref = iox2_cast_config_ref_h(config);
config_ptr = iox2_cast_config_ptr(config);

// The domain name becomes the prefix for all resources.
// Therefore, different domain names never share the same resources.
if (iox2_config_global_set_prefix(config_ref, argv[1]) != IOX2_OK) {
iox2_config_drop(config);
printf("invalid domain name\"%s\"\n", argv[1]);
exit(-1);
}

printf("\nServices running in domain \"%s\":\n", argv[1]);

// use the custom config when listing the services
if (iox2_service_list(iox2_service_type_e_IPC, config_ptr, list_callback, NULL) != IOX2_OK) {
printf("Failed to list all services.");
}

iox2_config_drop(config);
}
145 changes: 145 additions & 0 deletions examples/c/domains/src/publisher.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright (c) 2024 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 Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include "iox2/iceoryx2.h"
#include "transmission_data.h"

#ifdef _WIN64
#define alignof __alignof
#else
#include <stdalign.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
if (argc != 3) {
printf("usage: %s DOMAIN_NAME SERVICE_NAME\n", argv[0]);
exit(-1);
}

// create a new config based on the global config
iox2_config_ptr config_ptr = iox2_config_global_config();
iox2_config_h config = NULL;
iox2_config_from_ptr(config_ptr, NULL, &config);
iox2_config_ref_h config_ref = iox2_cast_config_ref_h(config);

// The domain name becomes the prefix for all resources.
// Therefore, different domain names never share the same resources.
if (iox2_config_global_set_prefix(config_ref, argv[1]) != IOX2_OK) {
printf("invalid domain name\"%s\"\n", argv[1]);
goto drop_config;
}

// create new node
iox2_node_builder_h node_builder_handle = iox2_node_builder_new(NULL);
iox2_node_h node_handle = NULL;
iox2_node_builder_ref_h node_builder_ref = iox2_cast_node_builder_ref_h(node_builder_handle);

// use the custom config when creating the custom node
// every service constructed by the node will use this config
iox2_node_builder_set_config(node_builder_ref, config_ref);
if (iox2_node_builder_create(node_builder_handle, NULL, iox2_service_type_e_IPC, &node_handle) != IOX2_OK) {
goto drop_config;
}

// create service name
const char* service_name_value = argv[2];
iox2_service_name_h service_name = NULL;
if (iox2_service_name_new(NULL, service_name_value, strlen(service_name_value), &service_name) != IOX2_OK) {
printf("Unable to create service name!\n");
goto drop_node;
}

// create service builder
iox2_service_name_ptr service_name_ptr = iox2_cast_service_name_ptr(service_name);
iox2_node_ref_h node_ref_handle = iox2_cast_node_ref_h(node_handle);
iox2_service_builder_h service_builder = iox2_node_service_builder(node_ref_handle, NULL, service_name_ptr);
iox2_service_builder_pub_sub_h service_builder_pub_sub = iox2_service_builder_pub_sub(service_builder);
iox2_service_builder_pub_sub_ref_h service_builder_pub_sub_ref =
iox2_cast_service_builder_pub_sub_ref_h(service_builder_pub_sub);

// set pub sub payload type
const char* payload_type_name = "16TransmissionData";
if (iox2_service_builder_pub_sub_set_payload_type_details(service_builder_pub_sub_ref,
iox2_type_variant_e_FIXED_SIZE,
payload_type_name,
strlen(payload_type_name),
sizeof(struct TransmissionData),
alignof(struct TransmissionData))
!= IOX2_OK) {
printf("Unable to set type details\n");
goto drop_node;
}

// create service
iox2_port_factory_pub_sub_h service = NULL;
if (iox2_service_builder_pub_sub_open_or_create(service_builder_pub_sub, NULL, &service) != IOX2_OK) {
printf("Unable to create service!\n");
goto drop_node;
}

// create publisher
iox2_port_factory_pub_sub_ref_h ref_service = iox2_cast_port_factory_pub_sub_ref_h(service);
iox2_port_factory_publisher_builder_h publisher_builder =
iox2_port_factory_pub_sub_publisher_builder(ref_service, NULL);
iox2_publisher_h publisher = NULL;
if (iox2_port_factory_publisher_builder_create(publisher_builder, NULL, &publisher) != IOX2_OK) {
printf("Unable to create publisher!\n");
goto drop_service;
}
iox2_publisher_ref_h publisher_ref = iox2_cast_publisher_ref_h(publisher);

int32_t counter = 0;
while (iox2_node_wait(node_ref_handle, 1, 0) == iox2_node_event_e_TICK) {
counter += 1;

// loan sample
iox2_sample_mut_h sample = NULL;
if (iox2_publisher_loan(publisher_ref, NULL, &sample) != IOX2_OK) {
printf("Failed to loan sample\n");
goto drop_publisher;
}
iox2_sample_mut_ref_h sample_ref = iox2_cast_sample_mut_ref_h(sample);

// write payload
struct TransmissionData* payload = NULL;
iox2_sample_mut_payload_mut(sample_ref, (void**) &payload, NULL);
payload->x = counter;
payload->y = counter * 3;
payload->funky = counter * 812.12; // NOLINT

// send sample
if (iox2_sample_mut_send(sample, NULL) != IOX2_OK) {
printf("Failed to send sample\n");
goto drop_publisher;
}

printf("[domain: \"%s\", service: \"%s\"] Send sample %d ...\n", argv[1], argv[2], counter);
}

drop_publisher:
iox2_publisher_drop(publisher);

drop_service:
iox2_port_factory_pub_sub_drop(service);

drop_node:
iox2_node_drop(node_handle);

drop_config:
iox2_config_drop(config);

end:
return 0;
}
Loading

0 comments on commit 5bd86ec

Please sign in to comment.