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/UdpProxy.h"
12 :
13 : #include "someip/INetworkListener.h"
14 : #include "someip/NetworkChannel.h"
15 : #include "someip/SomeIpConstants.h"
16 : #include "someip/logger.h"
17 :
18 : #include <ip/to_str.h>
19 : #include <udp/DatagramPacket.h>
20 :
21 : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
22 : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
23 :
24 : namespace someip
25 : {
26 : using ::ip::IPAddress;
27 : using ::ip::IPEndpoint;
28 : using ::udp::AbstractDatagramSocket;
29 : using ::udp::DatagramPacket;
30 : using ::util::logger::SOMEIP;
31 :
32 84 : UdpProxy::UdpProxy() : _pSocket(nullptr) {}
33 :
34 74 : bool UdpProxy::isInitialized() const
35 : {
36 74 : return NetworkResource::isInitialized() && (_pSocket != nullptr);
37 : }
38 :
39 86 : void UdpProxy::setSocket(AbstractDatagramSocket& socket)
40 : {
41 86 : _pSocket = &socket;
42 86 : _pSocket->setDataListener(this);
43 86 : }
44 :
45 24 : AbstractDatagramSocket* UdpProxy::getSocket() const { return _pSocket; }
46 :
47 41 : bool UdpProxy::isOpen() const { return isInitialized() && _pSocket->isBound(); }
48 :
49 1 : bool UdpProxy::isConnected() const { return false; }
50 :
51 7 : ::etl::expected<uint16_t, PortError> UdpProxy::getLocalPort() const
52 : {
53 7 : if (isInitialized())
54 : {
55 7 : return _pSocket->getLocalPort();
56 : }
57 :
58 0 : return ::etl::unexpected<PortError>(PortError::NOT_INITIALIZED);
59 : }
60 :
61 1 : uint8_t UdpProxy::getProto() const { return proto::SD_L4_PROTO_UDP; }
62 :
63 7 : bool UdpProxy::open(IPEndpoint const& localEndpoint)
64 : {
65 7 : if (!isInitialized())
66 : {
67 2 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::open() not initialized", this);
68 2 : return false;
69 : }
70 :
71 5 : if (isOpen())
72 : {
73 1 : return true;
74 : }
75 :
76 4 : if (!localEndpoint.isSet())
77 : {
78 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::open() no local address", this);
79 0 : return false;
80 : }
81 :
82 : char localEndpointStr[::ip::MAX_ENDPOINT_STRING_LENGTH];
83 4 : INFO_LOG(
84 : SOMEIP,
85 : "UdpProxy[%p]::open() at: %s",
86 : this,
87 : ::ip::to_str(localEndpoint, localEndpointStr).data());
88 :
89 : AbstractDatagramSocket::ErrorCode const result
90 4 : = _pSocket->bind(&localEndpoint.getAddress(), localEndpoint.getPort());
91 :
92 4 : if (AbstractDatagramSocket::ErrorCode::UDP_SOCKET_OK != result)
93 : {
94 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::open() bind failed: %d", this, result);
95 0 : return false;
96 : }
97 :
98 4 : return true;
99 : }
100 :
101 2 : bool UdpProxy::join(IPAddress const& multicastIp)
102 : {
103 2 : if (!isInitialized())
104 : {
105 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::join() not initialized", this);
106 0 : return false;
107 : }
108 :
109 2 : if (!isOpen())
110 : {
111 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::join() not bound", this);
112 0 : return false;
113 : }
114 :
115 2 : if (::ip::isUnspecified(multicastIp))
116 : {
117 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::join() no multicast address", this);
118 0 : close();
119 0 : return false;
120 : }
121 :
122 : char multicastIpStr[::ip::MAX_IP_STRING_LENGTH];
123 2 : INFO_LOG(
124 : SOMEIP,
125 : "UdpProxy[%p]::join(): joining %s",
126 : this,
127 : ::ip::to_str(multicastIp, multicastIpStr).data());
128 :
129 2 : AbstractDatagramSocket::ErrorCode const result = _pSocket->join(multicastIp);
130 :
131 2 : if (AbstractDatagramSocket::ErrorCode::UDP_SOCKET_OK != result)
132 : {
133 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::join() failed: %d", this, result);
134 0 : close();
135 0 : return false;
136 : }
137 :
138 2 : return true;
139 : }
140 :
141 5 : void UdpProxy::close()
142 : {
143 5 : if (!isOpen())
144 : {
145 0 : return;
146 : }
147 :
148 5 : INFO_LOG(SOMEIP, "UdpProxy[%p]::close()", this);
149 :
150 5 : _pSocket->close();
151 : }
152 :
153 2 : bool UdpProxy::send(IPEndpoint const& remoteEndpoint, uint32_t const length)
154 : {
155 2 : uint8_t const ip0 = remoteEndpoint.getAddress().raw[0];
156 2 : uint8_t const ip1 = remoteEndpoint.getAddress().raw[1];
157 2 : uint8_t const ip2 = remoteEndpoint.getAddress().raw[2];
158 2 : uint8_t const ip3 = remoteEndpoint.getAddress().raw[3];
159 2 : uint16_t const port = remoteEndpoint.getPort();
160 :
161 2 : if (!isOpen())
162 : {
163 0 : ERROR_LOG(
164 : SOMEIP,
165 : "UdpProxy[%p]::send() not open. Remote: "
166 : "(%d,%d,%d,%d), Port: %d.",
167 : this,
168 : ip0,
169 : ip1,
170 : ip2,
171 : ip3,
172 : port);
173 0 : return false;
174 : }
175 :
176 2 : if (length == 0U)
177 : {
178 1 : ERROR_LOG(
179 : SOMEIP,
180 : "UdpProxy[%p]::send() no data. Remote: "
181 : "(%d,%d,%d,%d), Port: %d.",
182 : this,
183 : ip0,
184 : ip1,
185 : ip2,
186 : ip3,
187 : port);
188 1 : return false;
189 : }
190 :
191 1 : if (!remoteEndpoint.isSet())
192 : {
193 0 : ERROR_LOG(
194 : SOMEIP,
195 : "UdpProxy[%p]::send() no remote endpoint. Remote: "
196 : "(%d,%d,%d,%d), Port: %d.",
197 : this,
198 : ip0,
199 : ip1,
200 : ip2,
201 : ip3,
202 : port);
203 0 : return false;
204 : }
205 :
206 1 : if (length > _pOutputBuffer.size())
207 : {
208 0 : ERROR_LOG(
209 : SOMEIP,
210 : "UdpProxy[%p]::send() too much data (%d bytes). Remote: "
211 : "(%d,%d,%d,%d), Port: %d.",
212 : this,
213 : length,
214 : ip0,
215 : ip1,
216 : ip2,
217 : ip3,
218 : port);
219 0 : return false;
220 : }
221 :
222 : DatagramPacket const packet(
223 1 : _pOutputBuffer.data(),
224 : static_cast<uint16_t>(length),
225 1 : remoteEndpoint.getAddress(),
226 1 : remoteEndpoint.getPort());
227 :
228 1 : AbstractDatagramSocket::ErrorCode const result = _pSocket->send(packet);
229 :
230 1 : if (AbstractDatagramSocket::ErrorCode::UDP_SOCKET_OK != result)
231 : {
232 1 : ERROR_LOG(
233 : SOMEIP,
234 : "UdpProxy[%p]::send() failed: %d. Remote: "
235 : "(%d,%d,%d,%d), Port: %d.",
236 : this,
237 : result,
238 : ip0,
239 : ip1,
240 : ip2,
241 : ip3,
242 : port);
243 : }
244 :
245 1 : return AbstractDatagramSocket::ErrorCode::UDP_SOCKET_OK == result;
246 : }
247 :
248 1 : bool UdpProxy::send(uint32_t const length) { return NetworkResource::send(length); }
249 :
250 : // virtual
251 3 : void UdpProxy::dataReceived(
252 : AbstractDatagramSocket& /* socket */,
253 : IPAddress const sourceAddress,
254 : uint16_t const sourcePort,
255 : IPAddress const destinationAddress,
256 : uint16_t const length)
257 : {
258 3 : if (::ip::isUnspecified(sourceAddress))
259 : {
260 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::dataReceived() no source address", this);
261 0 : flush(length);
262 0 : return;
263 : }
264 :
265 3 : if (::ip::isUnspecified(destinationAddress))
266 : {
267 0 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::dataReceived() no destination address", this);
268 0 : flush(length);
269 0 : return;
270 : }
271 :
272 3 : IPEndpoint const remoteEndpoint(sourceAddress, sourcePort);
273 3 : bool const isMulticast = ::ip::isMulticastAddress(destinationAddress);
274 :
275 3 : if (length == 0U)
276 : {
277 1 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::received() no data", this);
278 1 : return;
279 : }
280 :
281 2 : if (length > _pInputBuffer.size())
282 : {
283 1 : ERROR_LOG(SOMEIP, "UdpProxy[%p]::received() too much data (%d bytes)", this, length);
284 1 : flush(length);
285 1 : return;
286 : }
287 :
288 : uint16_t const read
289 1 : = static_cast<uint16_t>(_pSocket->read(_pInputBuffer.data(), static_cast<size_t>(length)));
290 :
291 1 : if (read != length)
292 : {
293 0 : ERROR_LOG(
294 : SOMEIP, "UdpProxy[%p]::received() read failed (%d / %d bytes)", this, read, length);
295 0 : flush(length - read);
296 0 : return;
297 : }
298 1 : incRefCounter(); // in case of hanging proxy.
299 : {
300 1 : NetworkChannel channel(*this, remoteEndpoint, isMulticast);
301 1 : if (_pListener != nullptr)
302 : {
303 1 : _pListener->received(channel, length);
304 : }
305 1 : }
306 1 : decRefCounter();
307 : }
308 :
309 1 : void UdpProxy::flush(uint16_t const length)
310 : {
311 1 : if (_pSocket != nullptr)
312 : {
313 1 : (void)_pSocket->read(nullptr, length);
314 : }
315 1 : }
316 :
317 : } // namespace someip
318 :
319 : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
|