Skip to content

Gateway Architecture

All opensomeip gateways follow a consistent architectural pattern that promotes code reuse, testability, and clean separation of concerns.

Class Hierarchy

classDiagram
    class IGateway {
        <<interface>>
        +start() Result
        +stop() Result
        +on_someip_message(Message) Result
        +is_running() bool
        +get_name() string
        +get_protocol() string
        +get_stats() GatewayStats
    }

    class GatewayBase {
        #set_running(bool)
        #record_someip_to_external(bytes)
        #record_external_to_someip(bytes)
        #record_translation_error()
        #find_mapping_for_service(sid, iid)
        #should_forward_to_external(mapping)
        #should_forward_to_someip(mapping)
        +add_service_mapping(ServiceMapping)
        +get_service_mappings() vector
        +set_external_message_callback(cb)
    }

    class MessageTranslator {
        +someip_to_external(msg, id) ExternalMessage
        +external_to_someip(ext, sid, mid, type) Message
        +build_topic(prefix, sid, iid, mid)$ string
        +format_service_id(id)$ string
        +payload_to_json(msg)$ bytes
        +json_to_payload(data)$ bytes
    }

    class ConcreteGateway {
        +start() Result
        +stop() Result
        +on_someip_message(msg) Result
        -protocol_translator_
        -protocol_client_
    }

    class ProtocolTranslator {
        +protocol_specific_methods()
    }

    IGateway <|-- GatewayBase
    GatewayBase <|-- ConcreteGateway
    MessageTranslator <|-- ProtocolTranslator
    ConcreteGateway *-- ProtocolTranslator

Data Flow

SOME/IP → External Protocol

sequenceDiagram
    participant UDP as SOME/IP Network
    participant Listener as GatewayUdpBridgeListener
    participant GW as ConcreteGateway
    participant Trans as ProtocolTranslator
    participant Proto as External Protocol

    UDP->>Listener: SOME/IP message
    Listener->>GW: on_someip_message(msg)
    GW->>GW: find_mapping_for_service()
    GW->>GW: should_forward_to_external()
    GW->>Trans: translate(msg, mapping)
    Trans-->>GW: protocol-specific payload
    GW->>Proto: publish / send
    GW->>GW: record_someip_to_external(bytes)

External Protocol → SOME/IP

sequenceDiagram
    participant Proto as External Protocol
    participant GW as ConcreteGateway
    participant Trans as ProtocolTranslator
    participant RPC as RpcClient / EventPublisher
    participant Sink as SomeipOutboundSink

    Proto->>GW: inject / callback
    GW->>GW: find_mapping_by_topic()
    GW->>GW: should_forward_to_someip()
    GW->>Trans: translate to SOME/IP
    Trans-->>GW: someip::Message
    alt Has RPC client
        GW->>RPC: call_method_sync()
    else Has outbound sink
        GW->>Sink: someip_outbound_sink_(msg)
    end
    GW->>GW: record_external_to_someip(bytes)

Service Mapping

The ServiceMapping struct is the declarative routing table for every gateway:

struct ServiceMapping {
    uint16_t someip_service_id;
    uint16_t someip_instance_id;
    std::vector<uint16_t> someip_method_ids;
    std::vector<uint16_t> someip_event_group_ids;
    std::string external_identifier;     // Protocol-specific name/topic/key
    GatewayDirection direction;          // SOMEIP_TO_EXTERNAL, EXTERNAL_TO_SOMEIP, BIDIRECTIONAL
    TranslationMode mode;               // OPAQUE (raw bytes) or TYPED (JSON envelope)
};

A typical YAML configuration:

service_mappings:
  - someip_service_id: 0x1234
    someip_instance_id: 0x0001
    someip_method_ids: [0x0001, 0x0002]
    someip_event_group_ids: [0x0001]
    external_identifier: "vehicle/speed"
    direction: bidirectional
    translation_mode: opaque

Thread Safety

Component Strategy
GatewayStats counters std::atomic — lock-free increment
Service mappings std::mutex — copy-on-read via get_service_mappings()
Running state std::atomic<bool> with acquire/release ordering
External callbacks std::mutex — guards callback assignment and invocation
Protocol-specific state Pimpl pattern isolates per-protocol resources

Design Patterns

Pattern Where Why
Template Method GatewayBase → concrete gateways Common lifecycle, specific protocol hooks
Strategy MessageTranslator hierarchy Protocol-specific payload transformation
Observer ExternalMessageCallback, SomeipOutboundSink Decouple message delivery from handling
Pimpl ROS 2, D-Bus, DDS gateways Hide heavyweight SDK headers from public API
Bridge GatewayUdpBridgeListener Adapt ITransportListener to IGateway
RAII unique_ptr for all owned resources Automatic cleanup on stop/destroy

Build System

Each gateway is an independent CMake target:

opensomeip-gateways/
├── CMakeLists.txt              # Root: options, GTest, subdirectories
├── common/                     # opensomeip-gateway-common library
├── gateway-iceoryx2/           # opensomeip-gateway-iceoryx2
├── gateway-mqtt/               # opensomeip-gateway-mqtt
├── gateway-grpc/               # opensomeip-gateway-grpc
├── gateway-ros2/               # opensomeip-gateway-ros2
├── gateway-zenoh/              # opensomeip-gateway-zenoh
├── gateway-dbus/               # opensomeip-gateway-dbus
└── gateway-dds/                # opensomeip-gateway-dds

Dependency graph:

graph TD
    COMMON["opensomeip-gateway-common"]
    CORE["opensomeip (core)"]
    IOX["gateway-iceoryx2"]
    MQTT["gateway-mqtt"]
    GRPC["gateway-grpc"]
    ROS2["gateway-ros2"]
    ZENOH["gateway-zenoh"]
    DBUS["gateway-dbus"]
    DDS["gateway-dds"]

    COMMON --> CORE
    IOX --> COMMON
    MQTT --> COMMON
    GRPC --> COMMON
    ROS2 --> COMMON
    ZENOH --> COMMON
    DBUS --> COMMON
    DDS --> COMMON