LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - Network.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 69.1 % 223 154
Test Date: 2026-09-11 12:05:06 Functions: 87.5 % 32 28

            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)
        

Generated by: LCOV version 2.0-1