Line data Source code
1 : /********************************************************************************
2 : * Copyright (c) 2026 Accenture
3 : *
4 : * This program and the accompanying materials are made available under the
5 : * terms of the Apache License Version 2.0 which is available at
6 : * https://www.apache.org/licenses/LICENSE-2.0
7 : *
8 : * SPDX-License-Identifier: Apache-2.0
9 : ********************************************************************************/
10 :
11 : #include "someip/RpcChannel.h"
12 :
13 : #include "someip/INetwork.h"
14 : #include "someip/IRpcSender.h"
15 : #include "someip/NetworkResource.h"
16 : #include "someip/RpcClosure.h"
17 : #include "someip/SomeIpConstants.h"
18 : #include "someip/logger.h"
19 :
20 : #include <udp/DatagramPacket.h>
21 : #include <util/timeout/ITimeoutManager2.h>
22 :
23 : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
24 : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
25 :
26 : namespace someip
27 : {
28 : using ::udp::DatagramPacket;
29 : using ::util::logger::SOMEIP;
30 :
31 : using ::common::ITimeoutManager2;
32 :
33 10 : RpcChannel::RpcChannel(INetwork& network, IRpcSender& sender)
34 10 : : _network(network)
35 10 : , _sender(sender)
36 10 : , _timeoutExpiredFunction(
37 20 : ::async::Function::CallType::create<RpcChannel, &RpcChannel::timeoutExpired>(*this))
38 20 : , _timeoutExpiredTimeout()
39 10 : {}
40 :
41 2 : bool RpcChannel::isOpen() const
42 : {
43 2 : if (_networkChannel.has_value())
44 : {
45 0 : return _networkChannel.value().isOpen();
46 : }
47 :
48 2 : return false;
49 : }
50 :
51 4 : void RpcChannel::openUdp(
52 : service_id::type const serviceId,
53 : ::ip::IPEndpoint const& remoteEndpoint,
54 : port::type const localPort)
55 : {
56 4 : close();
57 :
58 4 : _serviceId = serviceId;
59 4 : _networkChannel = _network.openUdpChannel(localPort, remoteEndpoint);
60 4 : }
61 :
62 1 : void RpcChannel::openTcp(
63 : service_id::type const serviceId,
64 : ::ip::IPEndpoint const& remoteEndpoint,
65 : port::type const localPort)
66 : {
67 1 : close();
68 :
69 1 : _serviceId = serviceId;
70 1 : _networkChannel = _network.openTcpChannel(localPort, remoteEndpoint);
71 1 : }
72 :
73 1 : void RpcChannel::openTcpWithExternalReassembleBuffer(
74 : service_id::type const serviceId,
75 : ::ip::IPEndpoint const& remoteEndpoint,
76 : port::type const localPort,
77 : ::etl::span<uint8_t> const buffer)
78 : {
79 1 : close();
80 :
81 1 : _serviceId = serviceId;
82 : _networkChannel
83 1 : = _network.openTcpChannelWithExternalReassembleBuffer(localPort, remoteEndpoint, buffer);
84 1 : }
85 :
86 9 : void RpcChannel::close()
87 : {
88 9 : _networkChannel.reset();
89 9 : _serviceId = 0;
90 9 : }
91 :
92 4 : service_id::type RpcChannel::getServiceId() const { return _serviceId; }
93 :
94 1 : uint16_t RpcChannel::getClientId() const { return _clientId; }
95 :
96 0 : uint16_t RpcChannel::getSessionId() const { return _sessionId; }
97 :
98 0 : void RpcChannel::setSessionId(uint16_t const sessionId) { _sessionId = sessionId; }
99 :
100 1 : void RpcChannel::setClientId(uint16_t const clientId) { _clientId = clientId; }
101 :
102 7 : ::ip::IPEndpoint const& RpcChannel::getRemoteIp() const
103 : {
104 7 : if (!_networkChannel.has_value())
105 : {
106 7 : return NetworkResource::INVALID_ADDRESS;
107 : }
108 :
109 0 : return _networkChannel->getRemoteEndpoint();
110 : }
111 :
112 3 : ::etl::expected<uint16_t, PortError> RpcChannel::getLocalPort() const
113 : {
114 3 : if (!_networkChannel.has_value())
115 : {
116 4 : return ::etl::unexpected<PortError>(PortError::NOT_INITIALIZED);
117 : }
118 :
119 1 : return _networkChannel->getLocalPort();
120 : }
121 :
122 2 : uint8_t RpcChannel::getProto() const
123 : {
124 2 : if (!_networkChannel.has_value())
125 : {
126 1 : return SomeIpConstants::INVALID_PROTO;
127 : }
128 :
129 1 : return _networkChannel->getProto();
130 : }
131 :
132 2 : ServiceResultCode RpcChannel::callMethod(
133 : uint16_t const methodId,
134 : ISomeIpSerializable const* const pRequest,
135 : uint8_t const interfaceVersion,
136 : ISomeIpSerializable* const pResponse,
137 : CallDoneClosure& done,
138 : uint32_t timeout)
139 : {
140 2 : if (!_networkChannel.has_value())
141 : {
142 1 : return COULD_NOT_DELIVER;
143 : }
144 :
145 1 : if (_pPendingCallback != nullptr)
146 : {
147 0 : return BUSY_ERROR;
148 : }
149 :
150 1 : INFO_LOG(SOMEIP, "RpcChannel::callMethod(%d)", methodId);
151 :
152 1 : _pPendingResponse = pResponse;
153 1 : _pPendingCallback = &done;
154 :
155 2 : ServiceResultCode const rc = _sender.sendRequest(
156 1 : pRequest, _serviceId, methodId, interfaceVersion, true, *this, timeout);
157 :
158 1 : if (rc != RPC_SENT_SUCCESSFULLY)
159 : {
160 0 : _pPendingCallback = nullptr;
161 : }
162 :
163 1 : return rc;
164 : }
165 :
166 1 : ServiceResultCode RpcChannel::callFireAndForgetMethod(
167 : uint16_t const methodId,
168 : ISomeIpSerializable const* const pRequest,
169 : uint8_t const interfaceVersion)
170 : {
171 1 : if (!_networkChannel.has_value())
172 : {
173 1 : return COULD_NOT_DELIVER;
174 : }
175 :
176 0 : INFO_LOG(SOMEIP, "RpcChannel::callFireAndForgetMethod(%d)", methodId);
177 :
178 : ServiceResultCode const rc
179 0 : = _sender.sendRequest(pRequest, _serviceId, methodId, interfaceVersion, false, *this, 0);
180 :
181 0 : return (rc != RPC_SENT_SUCCESSFULLY) ? rc : RPC_SENT_SUCCESSFULLY_NO_RESPONSE_EXPECTED;
182 : }
183 :
184 2 : ISomeIpSerializable* RpcChannel::getResponse()
185 : {
186 2 : return (_pPendingCallback != nullptr) ? _pPendingResponse : nullptr;
187 : }
188 :
189 0 : void RpcChannel::responseReceived(ServiceResultCode result)
190 : {
191 0 : INFO_LOG(SOMEIP, "RpcChannel::responseReceived(%d)", result);
192 :
193 0 : if (_pPendingCallback == nullptr)
194 : {
195 0 : ERROR_LOG(SOMEIP, "RpcChannel::responseReceived() no callback");
196 0 : return;
197 : }
198 :
199 0 : CallDoneClosure& done = *_pPendingCallback;
200 0 : _pPendingCallback = nullptr;
201 :
202 0 : done(result);
203 : }
204 :
205 0 : void RpcChannel::cancelTimeout() { _timeoutExpiredTimeout.cancel(); }
206 :
207 0 : void RpcChannel::setTimeout(::async::ContextType const context, uint32_t timeout)
208 : {
209 0 : async::schedule(
210 : context,
211 : _timeoutExpiredFunction,
212 0 : _timeoutExpiredTimeout,
213 : timeout,
214 : ::async::TimeUnit::MILLISECONDS);
215 0 : }
216 :
217 : // private
218 0 : void RpcChannel::timeoutExpired()
219 : {
220 0 : WARN_LOG(SOMEIP, "RpcChannel::timeoutExpired()");
221 :
222 0 : if (_pPendingCallback == nullptr)
223 : {
224 0 : ERROR_LOG(SOMEIP, "RpcChannel::timeoutExpired() no callback");
225 0 : return;
226 : }
227 :
228 0 : _sender.requestExpired(*this);
229 :
230 0 : CallDoneClosure& done = *_pPendingCallback;
231 0 : _pPendingCallback = nullptr;
232 :
233 0 : done(RPC_TIMEOUT);
234 : }
235 :
236 : } // namespace someip
237 :
238 : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
|