LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - TcpServer.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.4 % 92 85
Test Date: 2026-09-11 12:05:06 Functions: 100.0 % 13 13

            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/TcpServer.h"
      12              : 
      13              : #include "someip/TcpConfig.h"
      14              : #include "someip/logger.h"
      15              : 
      16              : #include <etl/error_handler.h>
      17              : #include <ip/to_str.h>
      18              : 
      19              : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
      20              : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
      21              : 
      22              : namespace someip
      23              : {
      24              : using ::ip::IPAddress;
      25              : using ::ip::IPEndpoint;
      26              : using ::tcp::AbstractServerSocket;
      27              : using ::tcp::AbstractSocket;
      28              : using ::util::logger::SOMEIP;
      29              : 
      30           55 : TcpServer::TcpServer(::tcp::AbstractServerSocket& socket, TcpProxyConfig& tcpClientPool)
      31           55 : : _socket(socket), _tcpClientPool(tcpClientPool), _pClientBufferPool(nullptr)
      32              : {
      33           55 :     _socket.setSocketProvidingConnectionListener(*this);
      34           55 : }
      35              : 
      36           46 : bool TcpServer::isInitialized() const { return _tcpClientPool.getSize() > 0U; }
      37              : 
      38            9 : AbstractServerSocket& TcpServer::getServerSocket() const { return _socket; }
      39              : 
      40            1 : size_t TcpServer::getNumProxies() const { return _tcpClientPool.getSize(); }
      41              : 
      42            2 : void TcpServer::setClientBufferPool(ClientBufferPool& buffers)
      43              : {
      44            2 :     ETL_ASSERT(
      45              :         _tcpClientPool.getBufferType() == TcpProxyConfig::BufferType::External,
      46              :         ETL_ERROR_GENERIC("tcp client pool must use external buffer type"));
      47            2 :     _pClientBufferPool = &buffers;
      48            2 : }
      49              : 
      50            1 : TcpProxy* TcpServer::getProxy(size_t const pos) const { return _tcpClientPool.getProxy(pos); }
      51              : 
      52           17 : bool TcpServer::isOpen() const { return isInitialized() && (!_socket.isClosed()); }
      53              : 
      54            6 : bool TcpServer::open(IPEndpoint const& localEndpoint)
      55              : {
      56            6 :     if ((_tcpClientPool.getBufferType() == TcpProxyConfig::BufferType::External)
      57            6 :         && (_pClientBufferPool == nullptr))
      58              :     {
      59            0 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::open() no client reassembly buffer", this);
      60            0 :         return false;
      61              :     }
      62              : 
      63            6 :     if (!isInitialized())
      64              :     {
      65            1 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::open() not initialized", this);
      66            1 :         return false;
      67              :     }
      68              : 
      69            5 :     if (isOpen())
      70              :     {
      71            1 :         return true;
      72              :     }
      73              : 
      74            4 :     if (!localEndpoint.isSet())
      75              :     {
      76            0 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::open() no local endpoint", this);
      77            0 :         return false;
      78              :     }
      79              : 
      80              :     char localEndpointStr[::ip::MAX_ENDPOINT_STRING_LENGTH];
      81            4 :     INFO_LOG(
      82              :         SOMEIP,
      83              :         "TcpServer[%p]::open() at: %s",
      84              :         this,
      85              :         ::ip::to_str(localEndpoint, localEndpointStr).data());
      86              : 
      87            4 :     if (!_socket.bind(localEndpoint.getAddress(), localEndpoint.getPort()))
      88              :     {
      89            1 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::open() bind failed", this);
      90            1 :         return false;
      91              :     }
      92              : 
      93            3 :     if (!_socket.accept())
      94              :     {
      95            1 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::open() accept failed", this);
      96            1 :         return false;
      97              :     }
      98              : 
      99            2 :     return true;
     100              : }
     101              : 
     102            2 : void TcpServer::close()
     103              : {
     104            2 :     if (!isOpen())
     105              :     {
     106            1 :         return;
     107              :     }
     108              : 
     109            1 :     INFO_LOG(SOMEIP, "TcpServer[%p]: close", this);
     110              : 
     111            1 :     _socket.close();
     112              : }
     113              : 
     114           11 : ::etl::expected<uint16_t, PortError> TcpServer::getLocalPort() const
     115              : {
     116           11 :     if (isInitialized())
     117              :     {
     118           11 :         return _socket.getLocalPort();
     119              :     }
     120              : 
     121            0 :     return ::etl::unexpected<PortError>(PortError::NOT_INITIALIZED);
     122              : }
     123              : 
     124              : // virtual
     125            9 : AbstractSocket* TcpServer::getSocket(IPAddress const& ipAddr, uint16_t const port)
     126              : {
     127            9 :     if (!isInitialized())
     128              :     {
     129            1 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::getSocket() not initialized", this);
     130            1 :         return nullptr;
     131              :     }
     132              : 
     133            8 :     if (::ip::isUnspecified(ipAddr))
     134              :     {
     135            0 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::getSocket() no address", this);
     136            0 :         return nullptr;
     137              :     }
     138              : 
     139              :     // First search if this is the same client connecting again.
     140              :     // This would be a sign that we didn't catch the connection close correctly. In this case we
     141              :     // have to abort the existing connection and reuse it.
     142              :     // This also means that only one TCP client connection is allowed between
     143              :     // a remote and the local ECU, which holds true by current requirements.
     144              : 
     145            8 :     ::ip::IPEndpoint const endpoint(ipAddr, port);
     146            8 :     auto const localPortResult = getLocalPort();
     147            8 :     TcpProxy* proxy            = nullptr;
     148              : 
     149            8 :     if (localPortResult.has_value())
     150              :     {
     151            8 :         proxy = _tcpClientPool.getOpenProxy(localPortResult.value(), endpoint);
     152              :     }
     153              : 
     154            8 :     if (proxy != nullptr)
     155              :     {
     156            1 :         proxy->abort();
     157            1 :         WARN_LOG(SOMEIP, "TcpServer[%p]: reusing proxy[%p]", this, proxy);
     158              :     }
     159              :     else
     160              :     {
     161            7 :         proxy = _tcpClientPool.nextProxy();
     162              :     }
     163              : 
     164            8 :     if (proxy != nullptr)
     165              :     {
     166            6 :         if (_tcpClientPool.getBufferType() == TcpProxyConfig::BufferType::External)
     167              :         {
     168            5 :             ETL_ASSERT(
     169              :                 _pClientBufferPool != nullptr,
     170              :                 ETL_ERROR_GENERIC("client buffer pool must not be null"));
     171            5 :             if (_pClientBufferPool->empty())
     172              :             {
     173            1 :                 ERROR_LOG(SOMEIP, "TcpServer[%p]::getSocket() no free client socket buffer", this);
     174            1 :                 return nullptr;
     175              :             }
     176              : 
     177            4 :             proxy->setInternalBuffer(_pClientBufferPool->back());
     178            4 :             _pClientBufferPool->pop_back();
     179              :         }
     180              : 
     181            5 :         IPEndpoint const remote(ipAddr, port);
     182              :         char endpointStr[::ip::MAX_ENDPOINT_STRING_LENGTH];
     183              : 
     184            5 :         INFO_LOG(
     185              :             SOMEIP,
     186              :             "TcpServer[%p]: acquire proxy[%p] for: %s",
     187              :             this,
     188              :             proxy,
     189              :             ::ip::to_str(remote, endpointStr).data());
     190            5 :         proxy->_pParentServerListener = this;
     191            5 :         return &(proxy->getSocket());
     192              :     }
     193              : 
     194            2 :     ERROR_LOG(SOMEIP, "TcpServer[%p]::getSocket() no free socket", this);
     195            2 :     return nullptr;
     196              : }
     197              : 
     198              : // virtual
     199            3 : void TcpServer::connectionAccepted(::tcp::AbstractSocket& socket)
     200              : {
     201            3 :     socket.disableNagleAlgorithm();
     202              : 
     203            3 :     IPEndpoint const remote(socket.getRemoteIPAddress(), socket.getRemotePort());
     204              :     char endpointStr[::ip::MAX_ENDPOINT_STRING_LENGTH];
     205              : 
     206            3 :     uint16_t const localPort = socket.getLocalPort();
     207              : 
     208            3 :     INFO_LOG(
     209              :         SOMEIP,
     210              :         "TcpServer[%p]: accepted connection at port: %d from : %s",
     211              :         this,
     212              :         localPort,
     213              :         ::ip::to_str(remote, endpointStr).data());
     214              : 
     215            3 :     TcpProxy* const proxy = _tcpClientPool.getProxy(socket);
     216            3 :     if (proxy == nullptr)
     217              :     {
     218            1 :         ERROR_LOG(SOMEIP, "TcpServer[%p]::connectionAccepted() invalid socket", this);
     219              :     }
     220              :     else
     221              :     {
     222            2 :         proxy->incRefCounter();
     223            2 :         proxy->openConnection(localPort);
     224              :     }
     225            3 : }
     226              : 
     227            3 : void TcpServer::connectionChanged(TcpProxy& proxy)
     228              : {
     229            3 :     if (!proxy.isOpen())
     230              :     {
     231            2 :         proxy.decRefCounter();
     232            2 :         if (_tcpClientPool.getBufferType() == TcpProxyConfig::BufferType::External)
     233              :         {
     234            1 :             ETL_ASSERT(
     235              :                 _pClientBufferPool != nullptr,
     236              :                 ETL_ERROR_GENERIC("client buffer pool must not be null"));
     237            1 :             _pClientBufferPool->push_back(proxy.getInternalBuffer());
     238              :         }
     239            2 :         proxy._pParentServerListener = nullptr;
     240              :     }
     241            3 : }
     242              : 
     243              : } // namespace someip
     244              : 
     245              : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
        

Generated by: LCOV version 2.0-1