Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ docs/_build/

# Test output
test_results.xml
test_results.json
test_report.json
test_report.html

Expand Down
47 changes: 47 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
FROM ubuntu:22.04

# Install build dependencies
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential \
cmake \
ca-certificates \
git \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*

# Install test dependencies
RUN pip3 install --no-cache-dir \
pytest \
pytest-cov \
coverage \
junit-xml

# Set working directory
WORKDIR /workspace

# Copy source code
COPY . .

# Clean and build the project with tests enabled
RUN rm -rf build && \
mkdir -p build && \
cd build && \
cmake .. \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTS=ON \
-DBUILD_EXAMPLES=OFF \
-DCOVERAGE=ON && \
make -j$(nproc)

# Create a non-root user for running tests
RUN useradd --create-home --shell /bin/bash testuser && \
chown -R testuser:testuser /workspace
USER testuser

# Set the working directory to the build directory
WORKDIR /workspace/build

# Default command to run SD tests (can be overridden)
CMD ["ctest", "--output-on-failure", "-R", "SdTest"]
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_subdirectory(basic/method_calls)
add_subdirectory(advanced/complex_types)
add_subdirectory(advanced/large_messages)
add_subdirectory(advanced/multi_service)
add_subdirectory(advanced/udp_config)

# Interoperability Testing (requires vsomeip3 and Boost - off by default)
if(BUILD_VSOMEIP_INTEROP)
Expand Down
3 changes: 3 additions & 0 deletions examples/advanced/udp_config/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# UDP Configuration Example
add_executable(udp_config_example udp_config_example.cpp)
target_link_libraries(udp_config_example someip-transport someip-core)
145 changes: 145 additions & 0 deletions examples/advanced/udp_config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# UDP Transport Configuration Examples

This example demonstrates different UDP transport configurations for various use cases.

## Overview

The SOME/IP UDP transport supports configurable blocking/non-blocking I/O modes and various socket options. This allows you to optimize for different scenarios:

- **Blocking mode (default)**: Efficient for most applications, eliminates busy loops
- **Non-blocking mode**: For integration with event loops or high-performance servers
- **Custom buffer sizes**: Tune socket buffers for your network requirements
- **Broadcast support**: Enable UDP broadcasting when needed

## Examples

### 1. Default Blocking Configuration

```cpp
#include <transport/udp_transport.h>

using namespace someip::transport;

// Default configuration - blocking I/O, good for most use cases
UdpTransport transport(Endpoint{"127.0.0.1", 0});
```

### 2. Non-Blocking Configuration

```cpp
#include <transport/udp_transport.h>

using namespace someip::transport;

// Non-blocking for event-driven applications
UdpTransportConfig config;
config.blocking = false; // Enable non-blocking I/O

UdpTransport transport(Endpoint{"127.0.0.1", 0}, config);
```

### 3. High-Performance Configuration

```cpp
#include <transport/udp_transport.h>

using namespace someip::transport;

// Optimized for high-throughput applications
UdpTransportConfig config;
config.blocking = true;
config.receive_buffer_size = 262144; // 256KB receive buffer
config.send_buffer_size = 262144; // 256KB send buffer
config.reuse_address = true;

UdpTransport transport(Endpoint{"127.0.0.1", 0}, config);
```

### 4. Broadcast-Enabled Configuration

```cpp
#include <transport/udp_transport.h>

using namespace someip::transport;

// Enable UDP broadcasting
UdpTransportConfig config;
config.blocking = true;
config.enable_broadcast = true; // Allow sending broadcast packets

UdpTransport transport(Endpoint{"192.168.1.100", 12345}, config);

// Send broadcast message
Message msg;
// ... configure message ...
Endpoint broadcast_addr{"255.255.255.255", 12345};
transport.send_message(msg, broadcast_addr);
```

### 5. Low-Latency Configuration

```cpp
#include <transport/udp_transport.h>

using namespace someip::transport;

// Minimal buffers for low latency
UdpTransportConfig config;
config.blocking = true;
config.receive_buffer_size = 8192; // Small buffers
config.send_buffer_size = 8192;

UdpTransport transport(Endpoint{"127.0.0.1", 0}, config);
```

## Configuration Options

| Option | Default | Description |
|--------|---------|-------------|
| `blocking` | `true` | Use blocking I/O (recommended) |
| `receive_buffer_size` | `65536` | Socket receive buffer size |
| `send_buffer_size` | `65536` | Socket send buffer size |
| `reuse_address` | `true` | Allow address reuse |
| `enable_broadcast` | `false` | Enable UDP broadcasting |

## Performance Considerations

### Blocking Mode (Recommended)
- **Pros**: Low CPU usage, no busy loops, simple threading
- **Cons**: Thread blocks until data arrives or shutdown
- **Best for**: Most SOME/IP applications, RPC clients, service discovery

### Non-Blocking Mode
- **Pros**: Integrates with event loops, responsive shutdown
- **Cons**: Requires polling logic, potential busy loops if not handled properly
- **Best for**: High-performance servers, event-driven frameworks

## Running the Examples

```bash
# Build the examples
cd build
make

# Run individual examples
./bin/udp_config_example
```

## Integration Notes

When using non-blocking mode, ensure your application properly handles the receive loop:

```cpp
// For non-blocking UDP transport
while (running) {
MessagePtr msg = transport.receive_message();
if (msg) {
// Process message
} else {
// No message available, do other work
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
```

For blocking mode, the transport handles waiting internally and is more efficient.
180 changes: 180 additions & 0 deletions examples/advanced/udp_config/udp_config_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/********************************************************************************
* Copyright (c) 2025 Vinicius Tadeu Zein
*
* 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
********************************************************************************/

#include <iostream>
#include <thread>
#include <chrono>
#include <transport/udp_transport.h>
#include <transport/transport.h>
#include <someip/message.h>

using namespace someip;
using namespace someip::transport;

/**
* @brief Simple listener for demonstration
*/
class DemoListener : public ITransportListener {
public:
void on_message_received(MessagePtr message, const Endpoint& sender) override {
std::cout << "Received message from " << sender.get_address() << ":" << sender.get_port()
<< " - Service: 0x" << std::hex << message->get_service_id()
<< ", Method: 0x" << message->get_method_id() << std::dec << std::endl;
}

void on_connection_lost(const Endpoint& endpoint) override {
std::cout << "Connection lost to " << endpoint.get_address() << ":" << endpoint.get_port() << std::endl;
}

void on_connection_established(const Endpoint& endpoint) override {
std::cout << "Connection established to " << endpoint.get_address() << ":" << endpoint.get_port() << std::endl;
}

void on_error(Result error) override {
std::cout << "Transport error: " << static_cast<int>(error) << std::endl;
}
};

/**
* @brief Demonstrate different UDP transport configurations
*/
void demonstrate_configurations() {
DemoListener listener;

std::cout << "=== UDP Transport Configuration Examples ===\n" << std::endl;

// 1. Default blocking configuration
std::cout << "1. Default Blocking Configuration:" << std::endl;
UdpTransport default_transport(Endpoint{"127.0.0.1", 0});
default_transport.set_listener(&listener);
default_transport.start();
std::cout << " Started on port: " << default_transport.get_local_endpoint().get_port() << std::endl;
std::cout << " Blocking mode: Yes (default)" << std::endl;
default_transport.stop();
std::cout << std::endl;

// 2. Non-blocking configuration
std::cout << "2. Non-Blocking Configuration:" << std::endl;
UdpTransportConfig non_blocking_config;
non_blocking_config.blocking = false;
UdpTransport non_blocking_transport(Endpoint{"127.0.0.1", 0}, non_blocking_config);
non_blocking_transport.set_listener(&listener);
non_blocking_transport.start();
std::cout << " Started on port: " << non_blocking_transport.get_local_endpoint().get_port() << std::endl;
std::cout << " Blocking mode: No" << std::endl;
non_blocking_transport.stop();
std::cout << std::endl;

// 3. High-performance configuration
std::cout << "3. High-Performance Configuration:" << std::endl;
UdpTransportConfig perf_config;
perf_config.blocking = true;
perf_config.receive_buffer_size = 262144; // 256KB
perf_config.send_buffer_size = 262144; // 256KB
perf_config.reuse_address = true;
UdpTransport perf_transport(Endpoint{"127.0.0.1", 0}, perf_config);
perf_transport.set_listener(&listener);
perf_transport.start();
std::cout << " Started on port: " << perf_transport.get_local_endpoint().get_port() << std::endl;
std::cout << " Receive buffer: " << perf_config.receive_buffer_size << " bytes" << std::endl;
std::cout << " Send buffer: " << perf_config.send_buffer_size << " bytes" << std::endl;
perf_transport.stop();
std::cout << std::endl;

// 4. Low-latency configuration
std::cout << "4. Low-Latency Configuration:" << std::endl;
UdpTransportConfig latency_config;
latency_config.blocking = true;
latency_config.receive_buffer_size = 4096; // Small buffers for low latency
latency_config.send_buffer_size = 4096;
UdpTransport latency_transport(Endpoint{"127.0.0.1", 0}, latency_config);
latency_transport.set_listener(&listener);
latency_transport.start();
std::cout << " Started on port: " << latency_transport.get_local_endpoint().get_port() << std::endl;
std::cout << " Small buffers for minimal latency" << std::endl;
latency_transport.stop();
std::cout << std::endl;

std::cout << "=== Configuration demonstration complete ===" << std::endl;
}

/**
* @brief Demonstrate message exchange between two transports
*/
void demonstrate_message_exchange() {
std::cout << "\n=== Message Exchange Demonstration ===\n" << std::endl;

DemoListener listener1, listener2;

// Create two transports
UdpTransport transport1(Endpoint{"127.0.0.1", 0});
UdpTransport transport2(Endpoint{"127.0.0.1", 0});

transport1.set_listener(&listener1);
transport2.set_listener(&listener2);

// Start both transports
transport1.start();
transport2.start();

Endpoint addr1 = transport1.get_local_endpoint();
Endpoint addr2 = transport2.get_local_endpoint();

std::cout << "Transport 1 listening on: " << addr1.get_address() << ":" << addr1.get_port() << std::endl;
std::cout << "Transport 2 listening on: " << addr2.get_address() << ":" << addr2.get_port() << std::endl;

// Create and send a message from transport1 to transport2
Message message;
message.set_service_id(0x1234);
message.set_method_id(0x5678);
message.set_client_id(0xABCD);
message.set_session_id(0x0001);
message.set_protocol_version(1);
message.set_interface_version(1);
message.set_message_type(MessageType::REQUEST);
message.set_return_code(ReturnCode::E_OK);

std::vector<uint8_t> payload = {'H', 'e', 'l', 'l', 'o', '!'};
message.set_payload(payload);

std::cout << "\nSending message from Transport 1 to Transport 2..." << std::endl;
Result result = transport1.send_message(message, addr2);
if (result == Result::SUCCESS) {
std::cout << "Message sent successfully!" << std::endl;
} else {
std::cout << "Failed to send message: " << static_cast<int>(result) << std::endl;
}

// Give some time for message processing
std::this_thread::sleep_for(std::chrono::milliseconds(100));

// Clean up
transport1.stop();
transport2.stop();

std::cout << "=== Message exchange demonstration complete ===" << std::endl;
}

int main() {
try {
demonstrate_configurations();
demonstrate_message_exchange();

std::cout << "\nAll demonstrations completed successfully!" << std::endl;
return 0;

} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}
Loading