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/Network.h"
12 :
13 : #include "someip/INetworkListener.h"
14 : #include "someip/NetworkConfig.h"
15 : #include "someip/SomeIpConstants.h"
16 : #include "someip/logger.h"
17 :
18 : #include <etl/error_handler.h>
19 : #include <ip/to_str.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 ::util::logger::SOMEIP;
27 :
28 15 : Network::Network(NetworkConfig const& config) : _config(config), _started(false) {}
29 :
30 3 : void Network::setSdListener(INetworkListener& listener)
31 : {
32 3 : if (!isStarted())
33 : {
34 3 : _config._udpConfig._sdProxies.setListener(listener);
35 : }
36 3 : }
37 :
38 6 : void Network::setRpcListener(INetworkListener& listener)
39 : {
40 6 : if (!isStarted())
41 : {
42 6 : _config._udpConfig._rpcProxies.setListener(listener);
43 6 : _config._tcpConfig._tcpProxies.setListener(listener);
44 : }
45 6 : }
46 :
47 2 : bool Network::initSdPort(uint16_t const port)
48 : {
49 2 : if (!isStarted())
50 : {
51 2 : return _config._udpConfig._sdProxies.initPort(port);
52 : }
53 :
54 0 : return false;
55 : }
56 :
57 2 : bool Network::initUdpPort(uint16_t const port)
58 : {
59 2 : if (!isStarted())
60 : {
61 2 : return _config._udpConfig._rpcProxies.initPort(port);
62 : }
63 :
64 0 : if (nullptr != _config._udpConfig._rpcProxies.getOpenProxy(port))
65 : {
66 0 : return true; // already open
67 : }
68 :
69 0 : INFO_LOG(SOMEIP, "Network: open udp-proxy on port: %d", port);
70 :
71 0 : return openUdp(port);
72 : }
73 :
74 0 : void Network::shutdownUdpPort(uint16_t const port)
75 : {
76 0 : if (isStarted())
77 : {
78 0 : return;
79 : }
80 :
81 0 : _config._udpConfig._rpcProxies.shutdownPort(port);
82 : }
83 :
84 2 : bool Network::initTcpPort(uint16_t const port)
85 : {
86 2 : if (!isStarted())
87 : {
88 2 : return _config._tcpConfig._tcpServers.initPort(port);
89 : }
90 :
91 0 : if (nullptr != _config._tcpConfig._tcpServers.getOpenServer(port))
92 : {
93 0 : return true; // already open
94 : }
95 :
96 0 : INFO_LOG(SOMEIP, "Network: open tcp-server on port: %d", port);
97 0 : TcpServer* const server = getIdleServer();
98 0 : if (server != nullptr)
99 : {
100 0 : return openTcp(port, *server);
101 : }
102 :
103 0 : ERROR_LOG(SOMEIP, "Network: No idle server available!");
104 0 : return false;
105 : }
106 :
107 1 : bool Network::initTcpPortWithExternalBuffers(
108 : uint16_t port, ::etl::ivector<::etl::span<uint8_t>>& buffers)
109 : {
110 1 : ETL_ASSERT(
111 : _config._tcpConfig._tcpProxies.getBufferType() == TcpProxyConfig::BufferType::External,
112 : ETL_ERROR_GENERIC("tcp proxies must use external buffer type"));
113 :
114 1 : if (!_config._tcpConfig._tcpServers.setBufferPool(port, buffers))
115 : {
116 0 : ERROR_LOG(SOMEIP, "Network: init tcp server, fail to set buffer for port: %d", port);
117 0 : return false;
118 : }
119 1 : return initTcpPort(port);
120 : }
121 :
122 0 : void Network::shutdownTcpPort(uint16_t const port)
123 : {
124 0 : if (isStarted())
125 : {
126 0 : return;
127 : }
128 :
129 0 : TcpServer* const server = _config._tcpConfig._tcpServers.getOpenServer(port);
130 :
131 0 : if (nullptr != server)
132 : {
133 0 : server->close();
134 : }
135 : }
136 :
137 19 : bool Network::isStarted() const { return _started; }
138 :
139 3 : bool Network::start()
140 : {
141 3 : if (isStarted())
142 : {
143 0 : return true;
144 : }
145 :
146 3 : INFO_LOG(SOMEIP, "Network: start");
147 :
148 3 : if (startSd())
149 : {
150 3 : if (startUdp())
151 : {
152 3 : if (startTcp())
153 : {
154 3 : _started = true;
155 : }
156 : }
157 : }
158 :
159 3 : return _started;
160 : }
161 :
162 1 : void Network::stop()
163 : {
164 1 : if (!isStarted())
165 : {
166 0 : return;
167 : }
168 :
169 1 : INFO_LOG(SOMEIP, "Network: stop");
170 :
171 1 : stopSd();
172 1 : stopUdp();
173 1 : stopTcp();
174 :
175 1 : _started = false;
176 : }
177 :
178 0 : ::ip::IPAddress const& Network::getMulticastIp() const { return _config._multicastIp; }
179 :
180 3 : ::ip::IPAddress const& Network::getLocalIp() const { return _config._localIp; }
181 :
182 3 : uint8_t Network::getSubnetId() const { return _config._subnetId; }
183 :
184 1 : ::etl::expected<port::type, PortError> Network::getSdPort(bool const multicast) const
185 : {
186 1 : size_t const idx = (multicast ? static_cast<size_t>(0U) : static_cast<size_t>(1U));
187 :
188 1 : if (_config._udpConfig._sdProxies.getSize() > idx)
189 : {
190 0 : return _config._udpConfig._sdProxies.getPort(idx);
191 : }
192 :
193 2 : return ::etl::unexpected<PortError>(PortError::NOT_AVAILABLE);
194 : }
195 :
196 : ::etl::optional<NetworkChannel>
197 1 : Network::getSdChannel(uint16_t const localPort, ::ip::IPEndpoint const& remoteEndpoint) const
198 : {
199 1 : UdpProxy* const proxy = _config._udpConfig._sdProxies.getOpenProxy(localPort);
200 1 : if (proxy != nullptr)
201 : {
202 0 : return NetworkChannel(*proxy, remoteEndpoint);
203 : }
204 :
205 : char remoteEndpointStr[::ip::MAX_ENDPOINT_STRING_LENGTH];
206 1 : WARN_LOG(
207 : SOMEIP,
208 : "Network: no sd-channel at port %d to %s",
209 : localPort,
210 : ::ip::to_str(remoteEndpoint, remoteEndpointStr).data());
211 :
212 1 : return {};
213 : }
214 :
215 1 : ::etl::optional<NetworkChannel> Network::getRpcChannel(
216 : uint16_t const localPort, ::ip::IPEndpoint const& remoteEndpoint, uint8_t proto) const
217 : {
218 1 : if (proto == proto::SD_L4_PROTO_UDP)
219 : {
220 1 : UdpProxy* const udpProxy = _config._udpConfig._rpcProxies.getOpenProxy(localPort);
221 1 : if (udpProxy != nullptr)
222 : {
223 0 : return NetworkChannel(*udpProxy, remoteEndpoint);
224 : }
225 : }
226 0 : else if (proto == proto::SD_L4_PROTO_TCP)
227 : {
228 : TcpProxy* const tcpProxy
229 0 : = _config._tcpConfig._tcpProxies.getOpenProxy(localPort, remoteEndpoint);
230 0 : if (tcpProxy != nullptr)
231 : {
232 0 : return NetworkChannel(*tcpProxy, remoteEndpoint, false, _config._useMagicCookie);
233 : }
234 : }
235 : else
236 : {
237 0 : ERROR_LOG(SOMEIP, "Network:getRpcChannel invalid proto parameter");
238 0 : return ::etl::optional<NetworkChannel>();
239 : }
240 :
241 : char remoteEndpointStr[::ip::MAX_ENDPOINT_STRING_LENGTH];
242 1 : WARN_LOG(
243 : SOMEIP,
244 : "Network: no %s rpc-channel at port %d to %s",
245 : proto == proto::SD_L4_PROTO_UDP ? "UDP" : "TCP",
246 : localPort,
247 : ::ip::to_str(remoteEndpoint, remoteEndpointStr).data());
248 :
249 1 : return ::etl::optional<NetworkChannel>();
250 : }
251 :
252 : ::etl::optional<NetworkChannel>
253 3 : Network::openUdpChannel(port::type const localPort, ::ip::IPEndpoint const& remoteEndpoint)
254 : {
255 3 : ::ip::IPAddress const remoteIp = remoteEndpoint.getAddress();
256 3 : bool const isMulticast = ::ip::isMulticastAddress(remoteIp);
257 :
258 : // find a proxy that is already open on the requested port
259 3 : UdpProxy* proxy = _config._udpConfig._rpcProxies.getOpenProxy(localPort);
260 3 : if (proxy != nullptr)
261 : {
262 1 : if (isMulticast)
263 : {
264 : // The remoteIp is a multicast address in this context.
265 1 : if (!proxy->join(remoteIp))
266 : {
267 : // Since the sockets of all proxies are bound to the interface of the local ip, we
268 : // can add a multicast group to any open proxy with matching port.
269 0 : ERROR_LOG(SOMEIP, "Network: failed to join existing proxy to multicast group");
270 0 : return {};
271 : }
272 : }
273 1 : return NetworkChannel(*proxy, remoteEndpoint);
274 : }
275 :
276 2 : proxy = _config._udpConfig._rpcProxies.nextProxy();
277 :
278 2 : if (proxy == nullptr)
279 : {
280 0 : ERROR_LOG(SOMEIP, "Network: no free udp-proxy");
281 0 : return {};
282 : }
283 :
284 2 : if (!openLocalUdpProxy(*proxy, localPort))
285 : {
286 1 : ERROR_LOG(SOMEIP, "Network: failed to open udp-proxy");
287 1 : return {};
288 : }
289 :
290 1 : if (isMulticast)
291 : {
292 : // the remoteIp is a multicast address in this context
293 0 : if (!proxy->join(remoteIp))
294 : {
295 0 : ERROR_LOG(SOMEIP, "Network: failed to join multicast group");
296 0 : return {};
297 : }
298 : }
299 :
300 1 : return NetworkChannel(*proxy, remoteEndpoint);
301 : }
302 :
303 : TcpProxy*
304 4 : Network::getTcpProxy(port::type const localPort, ::ip::IPEndpoint const& remoteEndpoint) const
305 : {
306 4 : TcpProxy* proxy = _config._tcpConfig._tcpProxies.getOpenProxy(localPort, remoteEndpoint);
307 4 : if (proxy == nullptr)
308 : {
309 3 : proxy = _config._tcpConfig._tcpProxies.nextProxy();
310 3 : if (proxy == nullptr)
311 : {
312 2 : ERROR_LOG(SOMEIP, "Network: no free tcp-proxy");
313 : }
314 : }
315 :
316 4 : return proxy;
317 : }
318 :
319 : ::etl::optional<NetworkChannel>
320 0 : Network::openTcpChannel(port::type const localPort, ::ip::IPEndpoint const& remoteEndpoint)
321 : {
322 0 : ETL_ASSERT(
323 : _config._tcpConfig._tcpProxies.getBufferType() == TcpProxyConfig::BufferType::Internal,
324 : ETL_ERROR_GENERIC("tcp proxies must use internal buffer type"));
325 :
326 : return openTcpChannelWithExternalReassembleBuffer(
327 0 : localPort, remoteEndpoint, ::etl::span<uint8_t>());
328 : }
329 :
330 4 : ::etl::optional<NetworkChannel> Network::openTcpChannelWithExternalReassembleBuffer(
331 : uint16_t const localPort, ::ip::IPEndpoint const& remoteEndpoint, ::etl::span<uint8_t> buffer)
332 : {
333 4 : TcpProxy* proxy = getTcpProxy(localPort, remoteEndpoint);
334 :
335 4 : if (proxy != nullptr)
336 : {
337 2 : if (!proxy->isOpen())
338 : {
339 1 : if (_config._tcpConfig._tcpProxies.getBufferType()
340 1 : == TcpProxyConfig::BufferType::External)
341 : {
342 1 : ETL_ASSERT(
343 : buffer.size() > 0U,
344 : ETL_ERROR_GENERIC("external buffer size must be greater than 0"));
345 1 : proxy->setInternalBuffer(buffer);
346 : }
347 :
348 1 : ::ip::IPEndpoint const localEndpoint(_config._localIp, localPort);
349 1 : if (!proxy->open(localEndpoint, remoteEndpoint))
350 : {
351 0 : proxy = nullptr;
352 : }
353 : }
354 : }
355 :
356 4 : if (proxy == nullptr)
357 : {
358 2 : return {};
359 : }
360 2 : return NetworkChannel(*proxy, remoteEndpoint, false, _config._useMagicCookie);
361 : }
362 :
363 3 : bool Network::startSd() const
364 : {
365 3 : size_t const numProxies = _config._udpConfig._sdProxies.getSize();
366 :
367 5 : for (size_t i = 0U; i < numProxies; ++i)
368 : {
369 2 : auto const portResult = _config._udpConfig._sdProxies.getPort(i);
370 2 : if (!portResult.has_value())
371 : {
372 1 : continue;
373 : }
374 :
375 1 : uint16_t const port = portResult.value();
376 :
377 1 : INFO_LOG(SOMEIP, "Network: open sd-proxy[%d] on port: %d", i, port);
378 :
379 1 : UdpProxy* const proxy = _config._udpConfig._sdProxies.nextProxy();
380 1 : if (proxy == nullptr)
381 : {
382 0 : ERROR_LOG(SOMEIP, "Network: no free sd-proxy");
383 0 : return false;
384 : }
385 :
386 1 : bool const resultOpen = openLocalUdpProxy(*proxy, port);
387 1 : if (!resultOpen)
388 : {
389 0 : ERROR_LOG(SOMEIP, "Network: failed to open sd-proxy");
390 0 : return false;
391 : }
392 :
393 1 : if (i == 0U)
394 : {
395 1 : bool const resultJoin = proxy->join(_config._multicastIp);
396 1 : if (!resultJoin)
397 : {
398 0 : ERROR_LOG(SOMEIP, "Network: failed to join multicast group");
399 0 : return false;
400 : }
401 : }
402 :
403 1 : _config._udpConfig._sdProxies.addToServers(*proxy);
404 : }
405 :
406 3 : return true;
407 : }
408 :
409 1 : void Network::stopSd() const { _config._udpConfig._sdProxies.close(); }
410 :
411 3 : bool Network::startUdp() const
412 : {
413 3 : size_t const numProxies = _config._udpConfig._rpcProxies.getSize();
414 :
415 6 : for (size_t i = 0U; i < numProxies; ++i)
416 : {
417 3 : auto const portResult = _config._udpConfig._rpcProxies.getPort(i);
418 3 : if (!portResult.has_value())
419 : {
420 1 : continue;
421 : }
422 :
423 2 : uint16_t const port = portResult.value();
424 :
425 2 : INFO_LOG(SOMEIP, "Network: open udp-proxy[%d] on port: %d", i, port);
426 2 : if (!openUdp(port))
427 : {
428 0 : return false;
429 : }
430 : }
431 :
432 3 : return true;
433 : }
434 :
435 2 : bool Network::openUdp(port::type const port) const
436 : {
437 2 : UdpProxy* const proxy = _config._udpConfig._rpcProxies.nextProxy();
438 2 : if (proxy == nullptr)
439 : {
440 0 : ERROR_LOG(SOMEIP, "Network: no free udp-proxy");
441 0 : return false;
442 : }
443 :
444 2 : if (!openLocalUdpProxy(*proxy, port))
445 : {
446 0 : ERROR_LOG(SOMEIP, "Network: failed to open udp-proxy");
447 0 : return false;
448 : }
449 2 : _config._udpConfig._rpcProxies.addToServers(*proxy);
450 2 : return true;
451 : }
452 :
453 1 : void Network::stopUdp() const { _config._udpConfig._rpcProxies.close(); }
454 :
455 5 : bool Network::openLocalUdpProxy(UdpProxy& proxy, port::type const port) const
456 : {
457 5 : ::ip::IPEndpoint const localEndpoint(_config._localIp, port);
458 10 : return proxy.open(localEndpoint);
459 : }
460 :
461 3 : bool Network::startTcp() const
462 : {
463 3 : size_t const numServers = _config._tcpConfig._tcpServers.getSize();
464 :
465 6 : for (size_t i = 0U; i < numServers; ++i)
466 : {
467 3 : auto const portResult = _config._tcpConfig._tcpServers.getPort(i);
468 3 : if (!portResult.has_value())
469 : {
470 2 : continue;
471 : }
472 :
473 1 : uint16_t const port = portResult.value();
474 :
475 1 : INFO_LOG(SOMEIP, "Network: open tcp-server[%d] on port: %d", i, port);
476 1 : TcpServer* const server = getIdleServer();
477 :
478 1 : if (server == nullptr)
479 : {
480 0 : return false;
481 : }
482 1 : if (!openTcp(port, *server))
483 : {
484 0 : return false;
485 : }
486 : }
487 :
488 3 : return true;
489 : }
490 :
491 1 : TcpServer* Network::getIdleServer() const
492 : {
493 1 : TcpServer* const server = _config._tcpConfig._tcpServers.nextServer();
494 1 : if (server == nullptr)
495 : {
496 0 : ERROR_LOG(SOMEIP, "Network: no free tcp-server");
497 : }
498 1 : return server;
499 : }
500 :
501 1 : bool Network::openTcp(port::type const port, TcpServer& server) const
502 : {
503 1 : ::ip::IPEndpoint const localEndpoint(_config._localIp, port);
504 :
505 1 : if (_config._tcpConfig._tcpProxies.getBufferType() == TcpProxyConfig::BufferType::External)
506 : {
507 : TcpServer::ClientBufferPool* const pool
508 0 : = _config._tcpConfig._tcpServers.getBufferPool(port);
509 0 : if (pool == nullptr)
510 : {
511 0 : ERROR_LOG(SOMEIP, "Network: failed to open tcp-server, no reassembly buffer");
512 0 : return false;
513 : }
514 0 : server.setClientBufferPool(*pool);
515 : }
516 1 : if (!server.open(localEndpoint))
517 : {
518 0 : ERROR_LOG(SOMEIP, "Network: failed to open tcp-server");
519 0 : return false;
520 : }
521 :
522 1 : return true;
523 : }
524 :
525 1 : void Network::stopTcp() const
526 : {
527 1 : _config._tcpConfig._tcpProxies.close();
528 1 : _config._tcpConfig._tcpServers.close();
529 1 : }
530 :
531 : } // namespace someip
532 :
533 : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
|