LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - RpcReceiver.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.9 % 180 151
Test Date: 2026-09-11 12:05:06 Functions: 100.0 % 16 16

            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/RpcReceiver.h"
      12              : 
      13              : #include "someip/INetwork.h"
      14              : #include "someip/IServiceRegistry.h"
      15              : #include "someip/SomeIpConstants.h"
      16              : #include "someip/SomeIpMessage.h"
      17              : #include "someip/Statistics.h"
      18              : #include "someip/logger.h"
      19              : 
      20              : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
      21              : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
      22              : 
      23              : namespace someip
      24              : {
      25              : using ::util::logger::SOMEIP;
      26              : 
      27              : using ::ip::IPAddress;
      28              : using ::ip::IPEndpoint;
      29              : 
      30           21 : RpcReceiver::RpcReceiver(
      31              :     INetwork& network,
      32              :     ITpTransceiver& tpTransceiver,
      33              :     IEventReceiver& eventReceiver,
      34              :     IServiceRegistry& serviceRegistry,
      35              :     IRpcHandler& rpcHandler,
      36              :     MulticastReceptionList& multicastReceptionList,
      37           21 :     IDiagnosticListener* const diagnosticListener)
      38           21 : : _network(network)
      39           21 : , _tpTransceiver(tpTransceiver)
      40           21 : , _eventReceiver(eventReceiver)
      41           21 : , _pDiagnosticListener(diagnosticListener)
      42           21 : , _serviceRegistry(serviceRegistry)
      43           21 : , _rpcHandler(rpcHandler)
      44           21 : , _pPriorityRpcHandler(nullptr)
      45           21 : , _multicastReceptions(multicastReceptionList)
      46              : {
      47              :     (void)_serviceRegistry;
      48           21 :     _network.setRpcListener(*this);
      49           21 : }
      50              : 
      51            2 : void RpcReceiver::init() { _rpcHandler.setEventReceiver(_eventReceiver); }
      52              : 
      53            2 : void RpcReceiver::shutdown() { _rpcHandler.removeEventReceiver(); }
      54              : 
      55              : // virtual
      56           14 : void RpcReceiver::received(NetworkChannel& channel, uint32_t const length)
      57              : {
      58           14 :     Statistics::incCounter(Statistics::Counter::FRAME_RX);
      59              : 
      60           14 :     ::etl::span<uint8_t> const input = channel.getInputBuffer();
      61              : 
      62           14 :     uint32_t offset = 0U;
      63           23 :     while (offset < length)
      64              :     {
      65           16 :         uint32_t const bytesLeft = length - offset;
      66           16 :         if (bytesLeft < SomeIpMessage::OFFSET_PAYLOAD)
      67              :         {
      68            3 :             ERROR_LOG(
      69              :                 SOMEIP,
      70              :                 "RpcReceiver::dataReceived(): %d bytes left, but no valid header",
      71              :                 bytesLeft);
      72            3 :             Statistics::incCounter(Statistics::Counter::RPC_MALFORMED_MESSAGE_RX);
      73            7 :             return;
      74              :         }
      75              : 
      76           13 :         Statistics::incCounter(Statistics::Counter::PDU_RX);
      77              : 
      78           13 :         SomeIpMessage const message(input.subspan(offset, bytesLeft));
      79              : 
      80           13 :         uint32_t const payloadLength = message.getPayloadLength();
      81           13 :         if (payloadLength <= bytesLeft - SomeIpMessage::OFFSET_PAYLOAD)
      82              :         {
      83           10 :             offset += (payloadLength + SomeIpMessage::OFFSET_PAYLOAD);
      84              :         }
      85              :         else
      86              :         {
      87            3 :             ERROR_LOG(
      88              :                 SOMEIP,
      89              :                 "RpcReceiver::dataReceived(): %d bytes left, but expected is %d",
      90              :                 bytesLeft,
      91              :                 payloadLength + SomeIpMessage::OFFSET_PAYLOAD);
      92            3 :             Statistics::incCounter(Statistics::Counter::RPC_MALFORMED_MESSAGE_RX);
      93            3 :             if ((message.getMessageType() != SomeIpMessage::MessageType::REQUEST_NO_RETURN)
      94            3 :                 && (message.getMessageType() != SomeIpMessage::MessageType::NOTIFICATION))
      95              :             {
      96            1 :                 sendError(channel, message, SomeIpMessage::ReturnCode::SOMEIP_E_MALFORMED_MESSAGE);
      97              :             }
      98            3 :             return;
      99              :         }
     100              : 
     101           10 :         if ((message.getReturnCode() != SomeIpMessage::ReturnCode::SOMEIP_E_OK)
     102           10 :             && (message.getMessageType() != SomeIpMessage::MessageType::EXCEPTION))
     103              :         {
     104            1 :             WARN_LOG(
     105              :                 SOMEIP,
     106              :                 "RpcReceiver::dataReceived(): invalid return code: %d",
     107              :                 message.getReturnCode());
     108            1 :             return; // drop incoming SOME/IP error message
     109              :         }
     110              : 
     111            9 :         if (message.getProtocolVersion() != configuration::PROTOCOL_VERSION)
     112              :         {
     113            3 :             WARN_LOG(
     114              :                 SOMEIP,
     115              :                 "RpcReceiver::dataReceived(): invalid protocol version %d",
     116              :                 message.getProtocolVersion());
     117            3 :             Statistics::incCounter(Statistics::Counter::RPC_WRONG_PROTOCOL_VERSION_RX);
     118            3 :             if ((message.getMessageType() != SomeIpMessage::MessageType::REQUEST_NO_RETURN)
     119            3 :                 && (message.getMessageType() != SomeIpMessage::MessageType::NOTIFICATION))
     120              :             {
     121            1 :                 sendError(
     122              :                     channel, message, SomeIpMessage::ReturnCode::SOMEIP_E_WRONG_PROTOCOL_VERSION);
     123              :             }
     124            5 :             continue; // drop message
     125              :         }
     126              : 
     127            6 :         if (isMagicCookie(message))
     128              :         {
     129            2 :             DEBUG_LOG(
     130              :                 SOMEIP,
     131              :                 "RpcReceiver::dataReceived(): ignore magic-cookie (0x%X)",
     132              :                 message.getMessageId());
     133            2 :             continue; // NYI: ignore message
     134              :         }
     135              : 
     136            4 :         if (ITpTransceiver::isIncomingTpMessage(channel.getProto(), message.getMessageType()))
     137              :         {
     138            0 :             _tpTransceiver.receiveTpMessage(channel, message, *this);
     139              :         }
     140              :         else
     141              :         {
     142            4 :             handleMessage(channel, message);
     143              :         }
     144              :     }
     145              : }
     146              : 
     147              : // virtual
     148            1 : void RpcReceiver::receivedTpMessage(NetworkChannel& channel, SomeIpMessage const& message)
     149              : {
     150            1 :     if ((message.getReturnCode() != SomeIpMessage::ReturnCode::SOMEIP_E_OK)
     151            1 :         && (message.getMessageType() != SomeIpMessage::MessageType::EXCEPTION))
     152              :     {
     153            0 :         WARN_LOG(
     154              :             SOMEIP,
     155              :             "RpcReceiver::receivedTpMessage(): invalid return code: %d",
     156              :             message.getReturnCode());
     157            0 :         return; // drop incoming SOME/IP error message
     158              :     }
     159              : 
     160            1 :     handleMessage(channel, message);
     161              : }
     162              : 
     163              : // virtual
     164            4 : void RpcReceiver::setPriorityRpcHandler(IRpcHandler& priorityRpcHandler)
     165              : {
     166            4 :     _pPriorityRpcHandler = &priorityRpcHandler;
     167            4 : }
     168              : 
     169              : // virtual
     170            1 : void RpcReceiver::removePriorityRpcHandler() { _pPriorityRpcHandler = nullptr; }
     171              : 
     172              : // virtual
     173            5 : bool RpcReceiver::requestMulticastReception(IPEndpoint const& multicastEndpoint)
     174              : {
     175            5 :     uint8_t const ip0   = multicastEndpoint.getAddress().raw[0];
     176            5 :     uint8_t const ip1   = multicastEndpoint.getAddress().raw[1];
     177            5 :     uint8_t const ip2   = multicastEndpoint.getAddress().raw[2];
     178            5 :     uint8_t const ip3   = multicastEndpoint.getAddress().raw[3];
     179            5 :     uint16_t const port = multicastEndpoint.getPort();
     180              : 
     181            5 :     if (_multicastReceptions.full())
     182              :     {
     183            1 :         WARN_LOG(
     184              :             SOMEIP,
     185              :             "RpcReceiver::requestMulticastReception() multicast pool empty. Unable to add "
     186              :             "(%d,%d,%d,%d), Port: %d.",
     187              :             ip0,
     188              :             ip1,
     189              :             ip2,
     190              :             ip3,
     191              :             port);
     192            1 :         return true;
     193              :     }
     194              : 
     195              :     // Check if already exists
     196              :     internal::FindNetworkChannelCondition const condition(
     197            4 :         multicastEndpoint.getAddress(), multicastEndpoint.getPort());
     198            4 :     if (::etl::find_if(_multicastReceptions.begin(), _multicastReceptions.end(), condition)
     199            8 :         != _multicastReceptions.end())
     200              :     {
     201            1 :         INFO_LOG(
     202              :             SOMEIP,
     203              :             "RpcReceiver::requestMulticastReception() channel already present for (%d,%d,%d,%d), "
     204              :             "Port: %d.",
     205              :             ip0,
     206              :             ip1,
     207              :             ip2,
     208              :             ip3,
     209              :             port);
     210            1 :         return true;
     211              :     }
     212              : 
     213              :     // Open a new channel
     214            3 :     auto const channel = _network.openUdpChannel(multicastEndpoint.getPort(), multicastEndpoint);
     215              : 
     216            3 :     if (!channel.has_value())
     217              :     {
     218            1 :         ERROR_LOG(
     219              :             SOMEIP,
     220              :             "RpcReceiver::requestMulticastReception() no channel. Unable to add (%d,%d,%d,%d), "
     221              :             "Port: %d.",
     222              :             ip0,
     223              :             ip1,
     224              :             ip2,
     225              :             ip3,
     226              :             port);
     227            1 :         return false;
     228              :     }
     229              : 
     230              :     // Insert the new channel
     231            2 :     auto insertResult = _multicastReceptions.insert(channel);
     232            2 :     if (!insertResult.second)
     233              :     {
     234            0 :         WARN_LOG(
     235              :             SOMEIP,
     236              :             "RpcReceiver::requestMulticastReception() not able to add channel for "
     237              :             "(%d,%d,%d,%d), Port: %d.",
     238              :             ip0,
     239              :             ip1,
     240              :             ip2,
     241              :             ip3,
     242              :             port);
     243            0 :         return false;
     244              :     }
     245              : 
     246            2 :     INFO_LOG(
     247              :         SOMEIP,
     248              :         "RpcReceiver::requestMulticastReception() channel added for (%d,%d,%d,%d), "
     249              :         "Port: %d.",
     250              :         ip0,
     251              :         ip1,
     252              :         ip2,
     253              :         ip3,
     254              :         port);
     255            2 :     return true;
     256            3 : }
     257              : 
     258              : // virtual
     259            1 : void RpcReceiver::cancelMulticastReception(IPEndpoint const& multicastEndpoint)
     260              : {
     261            1 :     auto channel = _network.getRpcChannel(
     262            1 :         multicastEndpoint.getPort(), multicastEndpoint, proto::SD_L4_PROTO_UDP);
     263              : 
     264            1 :     if (!channel.has_value())
     265              :     {
     266            0 :         WARN_LOG(SOMEIP, "RpcReceiver::cancelMulticastReception() no channel");
     267              :     }
     268              :     else
     269              :     {
     270            1 :         channel->close();
     271              :         internal::FindNetworkChannelCondition const condition(
     272            1 :             multicastEndpoint.getAddress(), multicastEndpoint.getPort());
     273            1 :         auto it = _multicastReceptions.begin();
     274            1 :         while (it != _multicastReceptions.end())
     275              :         {
     276            1 :             if (condition(*it))
     277              :             {
     278            1 :                 _multicastReceptions.erase(it);
     279            1 :                 break; // Found and removed the matching channel
     280              :             }
     281              : 
     282            0 :             ++it;
     283              :         }
     284              :     }
     285            1 : }
     286              : 
     287              : // private
     288              : // static
     289            6 : bool RpcReceiver::isMagicCookie(SomeIpMessage const& message)
     290              : {
     291            6 :     uint32_t const messageId = message.getMessageId();
     292            6 :     uint32_t const requestId = message.getRequestId();
     293              : 
     294              :     return ((MAGIC_COOKIE_CLIENT_MESSAGE_ID == messageId)
     295            5 :             || (MAGIC_COOKIE_SERVER_MESSAGE_ID == messageId))
     296           11 :            && (MAGIC_COOKIE_REQUEST_ID == requestId);
     297              : }
     298              : 
     299              : // private
     300            5 : void RpcReceiver::handleMessage(NetworkChannel& channel, SomeIpMessage const& message)
     301              : {
     302            5 :     IRpcHandler::ErrorCode errorCode = IRpcHandler::ErrorCode::RPC_HANDLER_NOT_RESPONSIBLE;
     303              : 
     304            5 :     if (_pPriorityRpcHandler != nullptr)
     305              :     {
     306            3 :         errorCode = _pPriorityRpcHandler->handleMessage(channel, message);
     307              :     }
     308              : 
     309            5 :     if (errorCode == IRpcHandler::ErrorCode::RPC_HANDLER_NOT_RESPONSIBLE)
     310              :     {
     311            2 :         errorCode = _rpcHandler.handleMessage(channel, message);
     312              :     }
     313              : 
     314            5 :     if ((errorCode != IRpcHandler::ErrorCode::RPC_HANDLER_OK)
     315            2 :         && (errorCode != IRpcHandler::ErrorCode::RPC_HANDLER_NOT_RESPONSIBLE))
     316              :     {
     317            2 :         if ((message.getMessageType() != SomeIpMessage::MessageType::REQUEST_NO_RETURN)
     318            1 :             && ((message.getMessageType() != SomeIpMessage::MessageType::NOTIFICATION)
     319            0 :                 || (errorCode
     320              :                     != IRpcHandler::ErrorCode::RPC_HANDLER_WRONG_MESSAGE_TYPE_REQUEST_RESPONSE))
     321            3 :             && (errorCode
     322              :                 != IRpcHandler::ErrorCode::RPC_HANDLER_WRONG_MESSAGE_TYPE_FIRE_AND_FORGET))
     323              :         {
     324            1 :             sendError(channel, message, getSomeipErrorCode(errorCode));
     325              :         }
     326              :     }
     327            5 : }
     328              : 
     329              : // private
     330            3 : void RpcReceiver::sendError(
     331              :     NetworkChannel& channel,
     332              :     SomeIpMessage const& message,
     333              :     SomeIpMessage::ReturnCode const returnCode)
     334              : {
     335            3 :     DEBUG_LOG(SOMEIP, "RpcReceiver::sendError(0x%x)", returnCode);
     336              : 
     337            3 :     SomeIpMessage error(channel.getOutputBuffer());
     338            3 :     error.setMessageType(SomeIpMessage::MessageType::EXCEPTION);
     339            3 :     error.setRequestId(message.getRequestId());
     340            3 :     error.setServiceId(message.getServiceId());
     341            3 :     error.setMethodId(message.getMethodId());
     342            3 :     error.setPayloadLength(0U);
     343            3 :     error.setProtocolVersion(::someip::configuration::PROTOCOL_VERSION);
     344            3 :     error.setInterfaceVersion(message.getInterfaceVersion());
     345            3 :     error.setReturnCode(returnCode);
     346              : 
     347            3 :     uint16_t const length = static_cast<uint16_t>(error.getTotalLength());
     348            3 :     if (!channel.send(length))
     349              :     {
     350            3 :         WARN_LOG(SOMEIP, "SomeIpSdTransceiver: send failed");
     351              :     }
     352              : 
     353            3 :     if (_pDiagnosticListener != nullptr)
     354              :     {
     355            3 :         _pDiagnosticListener->onError(
     356              :             channel.getRemoteEndpoint(),
     357              :             message,
     358              :             static_cast<SomeIpMessage::ReturnCode>(returnCode));
     359              :     }
     360            3 : }
     361              : 
     362              : // static
     363            1 : SomeIpMessage::ReturnCode RpcReceiver::getSomeipErrorCode(IRpcHandler::ErrorCode const error)
     364              : {
     365            1 :     switch (error)
     366              :     {
     367            0 :         case IRpcHandler::ErrorCode::RPC_HANDLER_OK:
     368              :         {
     369            0 :             return SomeIpMessage::ReturnCode::SOMEIP_E_OK;
     370              :         }
     371            1 :         case IRpcHandler::ErrorCode::RPC_HANDLER_UNKNOWN_SERVICE:
     372              :         {
     373            1 :             return SomeIpMessage::ReturnCode::SOMEIP_E_UNKNOWN_SERVICE;
     374              :         }
     375            0 :         case IRpcHandler::ErrorCode::RPC_HANDLER_UNKNOWN_METHOD:
     376              :         {
     377            0 :             return SomeIpMessage::ReturnCode::SOMEIP_E_UNKNOWN_METHOD;
     378              :         }
     379            0 :         case IRpcHandler::ErrorCode::RPC_HANDLER_WRONG_INTERFACE_VERSION:
     380              :         {
     381            0 :             return SomeIpMessage::ReturnCode::SOMEIP_E_WRONG_INTERFACE_VERSION;
     382              :         }
     383            0 :         case IRpcHandler::ErrorCode::RPC_HANDLER_MALFORMED_MESSAGE:
     384              :         {
     385            0 :             return SomeIpMessage::ReturnCode::SOMEIP_E_MALFORMED_MESSAGE;
     386              :         }
     387            0 :         case IRpcHandler::ErrorCode::RPC_HANDLER_WRONG_MESSAGE_TYPE:
     388              :         {
     389            0 :             return SomeIpMessage::ReturnCode::SOMEIP_E_WRONG_MESSAGE_TYPE;
     390              :         }
     391            0 :         default:
     392              :         {
     393            0 :             return SomeIpMessage::ReturnCode::SOMEIP_E_NOT_OK;
     394              :         }
     395              :     }
     396              : }
     397              : 
     398              : namespace internal
     399              : {
     400              : 
     401            1 : bool NetworkChannelComparator::operator()(
     402              :     ::etl::optional<NetworkChannel> const& lhs, ::etl::optional<NetworkChannel> const& rhs) const
     403              : {
     404              :     // Handle empty optionals (though they shouldn't be inserted)
     405            1 :     if (!lhs.has_value() && !rhs.has_value())
     406              :     {
     407            0 :         return false;
     408              :     }
     409            1 :     if (!lhs.has_value())
     410              :     {
     411            0 :         return true; // Empty sorts before non-empty
     412              :     }
     413            1 :     if (!rhs.has_value())
     414              :     {
     415            0 :         return false; // Non-empty sorts after empty
     416              :     }
     417              : 
     418              :     // Lexicographic comparison for strict weak ordering
     419            1 :     auto const& lhs_addr = lhs.value().getRemoteEndpoint().getAddress();
     420            1 :     auto const& rhs_addr = rhs.value().getRemoteEndpoint().getAddress();
     421              : 
     422              : #ifdef PLATFORM_SUPPORT_IPV6
     423              :     // IPv6-mapped IPv4 addresses: compare bytes 12-15
     424              :     for (size_t i = 12; i < 16; ++i)
     425              : #else
     426              :     // Pure IPv4: compare bytes 0-3
     427            4 :     for (size_t i = 0; i < 4; ++i)
     428              : #endif
     429              :     {
     430            4 :         if (lhs_addr.raw[i] != rhs_addr.raw[i])
     431              :         {
     432            1 :             return lhs_addr.raw[i] < rhs_addr.raw[i];
     433              :         }
     434              :     }
     435              : 
     436            0 :     auto const lhs_port = lhs.value().getLocalPort();
     437            0 :     auto const rhs_port = rhs.value().getLocalPort();
     438              : 
     439            0 :     if (!lhs_port.has_value() || !rhs_port.has_value())
     440              :     {
     441            0 :         return false;
     442              :     }
     443              : 
     444            0 :     return lhs_port.value() < rhs_port.value();
     445              : }
     446              : 
     447            5 : FindNetworkChannelCondition::FindNetworkChannelCondition(
     448            5 :     ::ip::IPAddress const& ipAddr, uint16_t const port)
     449            5 : : _ip(ipAddr), _port(port)
     450            5 : {}
     451              : 
     452            4 : bool FindNetworkChannelCondition::operator()(::etl::optional<NetworkChannel> const& channel) const
     453              : {
     454            4 :     if (!channel.has_value())
     455              :     {
     456            0 :         return false;
     457              :     }
     458            4 :     auto const address = channel->getRemoteEndpoint().getAddress();
     459            4 :     auto const port    = channel->getRemoteEndpoint().getPort();
     460            4 :     return ((_ip == address) && (_port == port));
     461              : }
     462              : 
     463              : } // namespace internal
     464              : 
     465              : } // namespace someip
     466              : 
     467              : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
        

Generated by: LCOV version 2.0-1