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
7 changes: 7 additions & 0 deletions src/opensomeip/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,17 @@ class ClientConfig:
- feat_req_someip_850-854: TCP transport configuration
- feat_req_someiptp_403: TP segment size negotiation
- feat_req_someip_102-103: E2E protection configuration

When ``remote_endpoint`` is set, the transport is configured with a
static remote peer address, bypassing Service Discovery. This is
useful for ECUs that do not run SOME/IP-SD.
"""

local_endpoint: Endpoint
sd_config: SdConfig
transport_mode: TransportMode = TransportMode.UDP
multicast_group: str | None = None
remote_endpoint: Endpoint | None = None
enable_tp: bool = False
tp_mtu: int = 1400
e2e_config: E2EConfig | None = None
Expand Down Expand Up @@ -86,10 +91,12 @@ def __init__(self, config: ClientConfig) -> None:
if config.transport_mode == TransportMode.TCP:
self._transport: Transport = TcpTransport(
config.local_endpoint,
config.remote_endpoint,
)
else:
self._transport = UdpTransport(
config.local_endpoint,
config.remote_endpoint,
multicast_group=config.multicast_group,
)

Expand Down
55 changes: 55 additions & 0 deletions tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,61 @@ def test_send_via_tp(self, tp_client_config: ClientConfig) -> None:
client.send(msg)


class TestStaticRemoteEndpoint:
"""Static remote endpoint support (no Service Discovery)."""

def test_remote_endpoint_defaults_to_none(self, client_config: ClientConfig) -> None:
assert client_config.remote_endpoint is None

def test_udp_remote_endpoint_forwarded(self) -> None:
remote = Endpoint("192.168.100.10", 30490)
cfg = ClientConfig(
local_endpoint=Endpoint("0.0.0.0", 0),
sd_config=SdConfig(
multicast_endpoint=Endpoint("239.1.1.1", 30490),
unicast_endpoint=Endpoint("192.168.1.200", 30490),
),
remote_endpoint=remote,
)
client = SomeIpClient(cfg)
assert isinstance(client.transport, UdpTransport)
assert client.transport.remote_endpoint == remote

def test_tcp_remote_endpoint_forwarded(self) -> None:
remote = Endpoint("192.168.100.10", 30490)
cfg = ClientConfig(
local_endpoint=Endpoint("0.0.0.0", 0),
sd_config=SdConfig(
multicast_endpoint=Endpoint("239.1.1.1", 30490),
unicast_endpoint=Endpoint("192.168.1.200", 30490),
),
transport_mode=TransportMode.TCP,
remote_endpoint=remote,
)
client = SomeIpClient(cfg)
assert isinstance(client.transport, TcpTransport)
assert client.transport.remote_endpoint == remote

def test_no_remote_endpoint_preserves_none(self, client_config: ClientConfig) -> None:
client = SomeIpClient(client_config)
assert client.transport.remote_endpoint is None

def test_lifecycle_with_remote_endpoint(self) -> None:
remote = Endpoint("192.168.100.10", 30490)
cfg = ClientConfig(
local_endpoint=Endpoint("0.0.0.0", 0),
sd_config=SdConfig(
multicast_endpoint=Endpoint("239.1.1.1", 30490),
unicast_endpoint=Endpoint("192.168.1.200", 30490),
),
remote_endpoint=remote,
)
with SomeIpClient(cfg) as client:
assert client.is_running is True
assert client.transport.remote_endpoint == remote
assert client.is_running is False


class TestE2EIntegration:
"""feat_req_someip_102-103: E2E protection integration."""

Expand Down
Loading