LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - SdMessageBuilder.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 80.8 % 526 425
Test Date: 2026-09-11 12:05:06 Functions: 100.0 % 37 37

            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/SdMessageBuilder.h"
      12              : 
      13              : #include "someip/SdConstants.h"
      14              : #include "someip/SdMessageConstants.h"
      15              : #include "someip/SomeIpConstants.h"
      16              : #include "someip/logger.h"
      17              : 
      18              : #include <ip/IPAddress.h>
      19              : #include <ip/to_str.h>
      20              : 
      21              : #include <etl/algorithm.h>
      22              : #include <etl/error_handler.h>
      23              : #include <etl/span.h>
      24              : #include <etl/unaligned_type.h>
      25              : 
      26              : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
      27              : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
      28              : 
      29              : namespace someip
      30              : {
      31              : using ::util::logger::SOMEIP;
      32              : 
      33              : namespace
      34              : {
      35              : // ETL has no 24 bit unaligned type, so the SOME/IP-SD TTL field uses the lower 3 bytes of an
      36              : // ::etl::be_uint32_t (same approach as ::uds::PositiveResponse::appendUint24).
      37           62 : void writeBe24(uint8_t* const ptr, uint32_t const value)
      38              : {
      39           62 :     auto const be = ::etl::be_uint32_t(value);
      40           62 :     (void)::etl::copy_n(be.data() + 1, 3U, ptr);
      41           62 : }
      42              : 
      43              : enum class MessageOffset : uint32_t
      44              : {
      45              :     // in order of appearance in memory
      46              :     MESSAGE_OFFSET_MESSAGE_ID        = 0U,
      47              :     MESSAGE_OFFSET_LENGTH            = 4U,
      48              :     MESSAGE_OFFSET_REQUEST_ID        = 8U,
      49              :     MESSAGE_OFFSET_PROTOCOL_VERSION  = 12U,
      50              :     MESSAGE_OFFSET_INTERFACE_VERSION = 13U,
      51              :     MESSAGE_OFFSET_MESSAGE_TYPE      = 14U,
      52              :     MESSAGE_OFFSET_RETURN_CODE       = 15U,
      53              :     MESSAGE_OFFSET_FLAGS             = 16U,
      54              :     MESSAGE_OFFSET_RESERVED          = 17U,
      55              :     MESSAGE_OFFSET_LENGTH_OF_ENTRIES = 20U,
      56              :     MESSAGE_OFFSET_ENTRIES           = 24U
      57              : };
      58              : 
      59              : enum class MessageEndpointOptionType : uint8_t
      60              : {
      61              :     MESSAGE_ENDPOINT_OPTION_TYPE_IPV4           = 0x04,
      62              :     MESSAGE_ENDPOINT_OPTION_TYPE_IPV6           = 0x06,
      63              :     MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV4 = 0x14,
      64              :     MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV6 = 0x16
      65              : };
      66              : 
      67              : enum : uint8_t
      68              : {
      69              :     INVALID_OPTION_INDEX = 0xFFU
      70              : };
      71              : 
      72              : enum class TtlConstants : uint32_t
      73              : {
      74              :     SET_ZERO_TTL = 0U,
      75              :     PRESERVE_TTL = 1U
      76              : };
      77              : 
      78              : using TtlHandling = TtlConstants;
      79              : 
      80          206 : uint32_t getEntriesLength(internal::Message const& message)
      81              : {
      82          412 :     return ::etl::be_uint32_t(
      83          618 :         &message.data[static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_LENGTH_OF_ENTRIES)]);
      84              : }
      85              : 
      86           66 : void setEntriesLength(internal::Message& message, uint32_t const length)
      87              : {
      88           66 :     ::etl::be_uint32_ext_t{
      89           66 :         &message.data[static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_LENGTH_OF_ENTRIES)]}
      90          132 :     = length;
      91           66 : }
      92              : 
      93           76 : uint32_t getFreeBytesForEntries(internal::Message const& message)
      94              : {
      95              :     auto const entriesEnd
      96           76 :         = getEntriesLength(message) + static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES);
      97              :     return static_cast<uint32_t>(
      98           76 :         static_cast<uint8_t>(message.divider > entriesEnd) * (message.divider - entriesEnd));
      99              : }
     100              : 
     101          245 : uint32_t getOptionsLength(internal::Message const& message)
     102              : {
     103          245 :     return ::etl::be_uint32_t(&message.data[message.divider]);
     104              : }
     105              : 
     106           61 : void setOptionsLength(internal::Message& message, uint32_t const length)
     107              : {
     108           61 :     ::etl::be_uint32_ext_t{&message.data[message.divider]} = length;
     109           61 : }
     110              : 
     111           95 : uint32_t getFreeBytesForOptions(internal::Message const& message)
     112              : {
     113           95 :     auto const optionsEnd = getOptionsLength(message) + message.divider
     114              :                             + static_cast<uint32_t>(static_cast<uint32_t>(
     115           95 :                                 MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY));
     116              :     return static_cast<uint32_t>(
     117           95 :         static_cast<uint8_t>(message.data.size() > optionsEnd)
     118           95 :         * (message.data.size() - optionsEnd));
     119              : }
     120              : 
     121           27 : void writeOption(
     122              :     ::etl::span<uint8_t>& option,
     123              :     MessageEndpointOptionType const optionType,
     124              :     ::ip::IPAddress const& ipAddress,
     125              :     port::type const port,
     126              :     proto::type const proto)
     127              : {
     128           27 :     ::etl::be_uint16_ext_t{&option[0]} = static_cast<uint16_t>(option.size() - 3U);
     129           27 :     option[2]                          = static_cast<uint8_t>(optionType);
     130           27 :     option[3]                          = 0U; // reserved
     131           27 :     option.advance(4);
     132           27 :     switch (optionType)
     133              :     {
     134           27 :         case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_IPV4:
     135              :         case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV4:
     136              :         {
     137           27 :             auto ipBytes = ::ip::ip4_bytes(ipAddress);
     138           27 :             etl::copy(ipBytes.begin(), ipBytes.end(), option.begin());
     139           27 :             option.advance(ipBytes.size());
     140           27 :             break;
     141              :         }
     142            0 :         case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_IPV6:
     143              :         case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV6:
     144              :         {
     145              : #ifdef PLATFORM_SUPPORT_IPV6
     146              :             auto ipBytes = ::ip::ip6_bytes(ipAddress);
     147              :             etl::copy(ipBytes.begin(), ipBytes.end(), option.begin());
     148              :             option.advance(ipBytes.size());
     149              : #else
     150            0 :             option.advance(::ip::IPAddress::IP6LENGTH);
     151              : #endif
     152            0 :             break;
     153              :         }
     154              :     }
     155              : 
     156           27 :     option[0]                          = 0U; // reserved
     157           27 :     option[1]                          = proto;
     158           27 :     ::etl::be_uint16_ext_t{&option[2]} = port;
     159           27 : }
     160              : 
     161           35 : bool findEndpointOption(
     162              :     internal::Message const& message,
     163              :     ::ip::IPAddress const& ipAddress,
     164              :     port::type const port,
     165              :     proto::type const proto,
     166              :     uint8_t& optionIdx)
     167              : {
     168           35 :     if (::ip::isUnspecified(ipAddress))
     169              :     {
     170            0 :         optionIdx = INVALID_OPTION_INDEX;
     171            0 :         return true;
     172              :     }
     173              : 
     174           35 :     bool found               = false;
     175           35 :     size_t idx               = 0U;
     176           35 :     auto const optionsLength = getOptionsLength(message);
     177           35 :     ::ip::IPAddress writtenIpAddress{};
     178              :     auto const options = ::etl::span<uint8_t>(
     179              :         &message.data
     180           35 :              [message.divider
     181              :               + static_cast<uint32_t>(static_cast<uint32_t>(
     182           35 :                   MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))],
     183           35 :         optionsLength);
     184           44 :     while (idx < optionsLength)
     185              :     {
     186              :         // skip option length
     187           11 :         idx += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_LENGTH);
     188              :         MessageEndpointOptionType const optionType
     189           11 :             = static_cast<MessageEndpointOptionType>(options[idx]);
     190           11 :         idx += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_TYPE)
     191              :                + static_cast<uint32_t>(
     192              :                    MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_RESERVED1);
     193           11 :         switch (optionType)
     194              :         {
     195           11 :             case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_IPV4:
     196              :             case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV4:
     197              :             {
     198           11 :                 writtenIpAddress = ::ip::make_ip4(::etl::be_uint32_t(&options[idx]));
     199           11 :                 idx += static_cast<uint32_t>(
     200              :                            MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_IPV4ADDRESS)
     201              :                        + static_cast<uint32_t>(
     202              :                            MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_RESERVED2);
     203           11 :                 break;
     204              :             }
     205              : 
     206            0 :             case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_IPV6:
     207              :             case MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV6:
     208              :             {
     209              : #ifdef PLATFORM_SUPPORT_IPV6
     210              :                 auto const ipv6slice = ::etl::span<uint8_t>(
     211              :                     &options[idx],
     212              :                     static_cast<uint32_t>(
     213              :                         MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_IPV6ADDRESS));
     214              :                 writtenIpAddress = ::ip::make_ip6(ipv6slice);
     215              : #endif
     216            0 :                 idx += static_cast<uint32_t>(
     217              :                            MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_IPV6ADDRESS)
     218              :                        + static_cast<uint32_t>(
     219              :                            MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_RESERVED2);
     220            0 :                 break;
     221              :             }
     222              :         }
     223           11 :         auto const writtenProto = options[idx];
     224           11 :         idx += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_PROTO);
     225           11 :         uint16_t const writtenPort = ::etl::be_uint16_t(&options[idx]);
     226           11 :         idx += static_cast<uint32_t>(
     227              :             MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_OPTION_PORT_NUMBER);
     228           11 :         found = (writtenIpAddress == ipAddress) && (proto == writtenProto) && (port == writtenPort);
     229           11 :         if (found)
     230              :         {
     231            2 :             return true;
     232              :         }
     233            9 :         ++optionIdx;
     234              :     }
     235              : 
     236           33 :     return false;
     237              : }
     238              : 
     239           35 : SdMessageReturnCode checkBuffer(::etl::span<uint8_t> const& buffer)
     240              : {
     241              :     enum : uint32_t
     242              :     {
     243              :         MESSAGE_CONSTANT_MINIMAL_MESSAGE_SIZE
     244              :         = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_MESSAGE_ID)
     245              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH)
     246              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_REQUEST_ID)
     247              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_PROTOCOL_VERSION)
     248              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_INTERFACE_VERSION)
     249              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_MESSAGE_TYPE)
     250              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_RETURN_CODE)
     251              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_FLAGS)
     252              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_RESERVED)
     253              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_ENTRIES_ARRAY)
     254              :           + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY)
     255              :     };
     256              : 
     257              :     // avoiding branching
     258              :     return static_cast<SdMessageReturnCode>(
     259           35 :         (static_cast<uint8_t>(MESSAGE_CONSTANT_MINIMAL_MESSAGE_SIZE > buffer.size())
     260              :          * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_BUFFER_TOO_SMALL))
     261           35 :         + (static_cast<uint8_t>(MESSAGE_CONSTANT_MINIMAL_MESSAGE_SIZE <= buffer.size())
     262           35 :            * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK)));
     263              : }
     264              : 
     265           34 : void resetMessage(
     266              :     internal::Message& message, ::etl::span<uint8_t> const& buffer = ::etl::span<uint8_t>())
     267              : {
     268           34 :     message.data = buffer;
     269              : 
     270              :     /*
     271              :      * Note: this part can be optimized in future in order to put the divider into the right place
     272              :      * to avoid as many memory moves as possible.
     273              :      */
     274           34 :     auto const maxOptionSize =
     275              : #ifdef PLATFORM_SUPPORT_IPV6
     276              :         static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_IPV6_OPTION_LENGTH);
     277              : #else
     278              :         static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_IPV4_OPTION_LENGTH);
     279              : #endif // OPENBSW_NO_IPV6
     280              : 
     281              :     // message.data.size() >= MESSAGE_CONSTANT_MINIMAL_MESSAGE_SIZE
     282              :     auto const freeBytes
     283           34 :         = message.data.size() - static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
     284           34 :           - static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY);
     285              : 
     286              :     // The same number of entries and options
     287           34 :     auto const n
     288              :         = freeBytes
     289              :           / (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY) + maxOptionSize);
     290              : 
     291           34 :     message.divider = static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
     292           34 :                       + n * static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY);
     293           34 : }
     294              : 
     295           35 : uint16_t measureOption(
     296              :     ::ip::IPAddress const& ip, bool const multicast, MessageEndpointOptionType& optionType)
     297              : {
     298          105 :     optionType = static_cast<MessageEndpointOptionType>(
     299              :         // if it's ipv4
     300           70 :         (static_cast<uint8_t>(::ip::isIp4Address(ip))
     301              :          // set type to ipv4 multicast or endpoint
     302           35 :          * ((static_cast<uint8_t>(multicast)
     303              :              * static_cast<uint8_t>(
     304              :                  MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV4))
     305           35 :             + (static_cast<uint8_t>(!multicast)
     306              :                * static_cast<uint8_t>(
     307              :                    MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_IPV4))))
     308              :         // otherwise
     309           35 :         + (static_cast<uint8_t>(::ip::isIp6Address(ip))
     310              :            // set type to ipv6 multicast or endpoint
     311           35 :            * ((static_cast<uint8_t>(multicast)
     312           35 :                * static_cast<uint8_t>(
     313              :                    MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_MULTICAST_IPV6))
     314           35 :               + (static_cast<uint8_t>(!multicast)
     315           35 :                  * static_cast<uint8_t>(
     316              :                      MessageEndpointOptionType::MESSAGE_ENDPOINT_OPTION_TYPE_IPV6)))));
     317              : 
     318              :     // avoid branching while calculating option size
     319           35 :     return static_cast<uint8_t>(::ip::isIp4Address(ip))
     320              :                // if it's ipv4 return option size for ipv4
     321           35 :                * static_cast<uint32_t>(
     322              :                    MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_IPV4_OPTION_LENGTH)
     323              :            // return ipv6 option size otherwise
     324           35 :            + static_cast<uint8_t>(::ip::isIp6Address(ip))
     325           35 :                  * static_cast<uint32_t>(
     326           35 :                      MessageFieldSize::MESSAGE_FIELD_SIZE_ENDPOINT_IPV6_OPTION_LENGTH);
     327              : }
     328              : 
     329           34 : void addHeader(internal::Message& message)
     330              : {
     331           34 :     uint8_t* ptr                = &message.data[0U];
     332           34 :     ::etl::be_uint32_ext_t{ptr} = SD_MESSAGE_ID; // message ID
     333           34 :     ptr += sizeof(uint32_t);
     334           34 :     ::etl::be_uint32_ext_t{ptr} = 0U; // message length (filled in later)
     335           34 :     ptr += sizeof(uint32_t);
     336           34 :     ::etl::be_uint32_ext_t{ptr} = 0U; // client ID, session ID
     337           34 :     ptr += sizeof(uint32_t);
     338           34 :     ::etl::be_uint32_ext_t{ptr} = 0x01010200U; // versions, message type, return code
     339           34 : }
     340              : 
     341           30 : void writeFlags(internal::Message& message, bool const reboot)
     342              : {
     343           30 :     message.data[static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_FLAGS)]
     344           30 :         = static_cast<uint8_t>(SdFlags::SD_FLAG_UNICAST)
     345           30 :           | static_cast<uint8_t>(reboot) * static_cast<uint8_t>(SdFlags::SD_FLAG_REBOOT);
     346           30 :     writeBe24(
     347           30 :         &message.data[static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_RESERVED)],
     348              :         0U); // reserved
     349           30 : }
     350              : 
     351           32 : void writeSdOptions(
     352              :     ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)> const&
     353              :         sdEntry,
     354              :     uint8_t const entry_type,
     355              :     uint8_t const option_idx_1 = 0U,
     356              :     uint8_t const options_num  = 0U)
     357              : {
     358           32 :     sdEntry[0] = entry_type;
     359           32 :     sdEntry[1] = option_idx_1;
     360           32 :     sdEntry[2] = 0U;
     361           32 :     sdEntry[3] = options_num;
     362           32 : }
     363              : 
     364            2 : void writeServiceDescription(
     365              :     ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)> const&
     366              :         sdEntry,
     367              :     service_id::type const serviceId,
     368              :     instance_id::type const instanceId,
     369              :     major_version::type const majorVersion,
     370              :     minor_version::type const minorVersion,
     371              :     ttl::type const ttl,
     372              :     ttl::type const preserveTtl)
     373              : {
     374            2 :     ::etl::be_uint16_ext_t{&sdEntry[4]} = serviceId;
     375            2 :     ::etl::be_uint16_ext_t{&sdEntry[6]} = instanceId;
     376            2 :     sdEntry[8]                          = majorVersion;
     377            2 :     writeBe24(&sdEntry[9], preserveTtl * ttl);
     378            2 :     ::etl::be_uint32_ext_t{&sdEntry[12]} = minorVersion;
     379            2 : }
     380              : 
     381            1 : SdMessageReturnCode writeOffer(
     382              :     internal::Message& message,
     383              :     service_id::type const serviceId,
     384              :     instance_id::type const instanceId,
     385              :     major_version::type const majorVersion,
     386              :     minor_version::type const minorVersion,
     387              :     ttl::type const ttl,
     388              :     uint8_t const optionIdx,
     389              :     TtlHandling const ttlHandling = TtlConstants::PRESERVE_TTL)
     390              : {
     391            1 :     auto const freeBytesForEntries = getFreeBytesForEntries(message);
     392              :     auto const optionsOffset       = static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
     393            1 :                                + getEntriesLength(message)
     394            1 :                                + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY);
     395            1 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     396              :     {
     397              :         // move options section to the right to fit a new entry
     398            0 :         (void)::memmove(
     399            0 :             &message.data[optionsOffset],
     400            0 :             &message.data[message.divider],
     401              :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY)
     402            0 :                 + getOptionsLength(message));
     403            0 :         message.divider = optionsOffset;
     404              :     }
     405              : 
     406              :     auto const sdEntry
     407              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
     408              :             &message.data
     409              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
     410            1 :                   + getEntriesLength(message)],
     411            1 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     412              : 
     413            1 :     writeSdOptions(sdEntry, ENTRY_TYPE_OFFER, optionIdx, 0x10U);
     414            1 :     writeServiceDescription(
     415              :         sdEntry,
     416              :         serviceId,
     417              :         instanceId,
     418              :         majorVersion,
     419              :         minorVersion,
     420              :         ttl,
     421              :         static_cast<uint32_t>(ttlHandling));
     422              : 
     423            1 :     setEntriesLength(
     424              :         message,
     425            1 :         getEntriesLength(message)
     426              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     427            1 :     return SdMessageReturnCode::SD_MESSAGE_OK;
     428              : }
     429              : 
     430           18 : void writeEventGroupDescription(
     431              :     ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)> const&
     432              :         sdEntry,
     433              :     service_id::type const serviceId,
     434              :     instance_id::type const instanceId,
     435              :     eventgroup_id::type const eventGroup,
     436              :     major_version::type const majorVersion,
     437              :     ttl::type const ttl,
     438              :     uint32_t const preserveTtl)
     439              : {
     440           18 :     ::etl::be_uint16_ext_t{&sdEntry[4]} = serviceId;
     441           18 :     ::etl::be_uint16_ext_t{&sdEntry[6]} = instanceId;
     442           18 :     sdEntry[8]                          = majorVersion;
     443           18 :     writeBe24(&sdEntry[9], preserveTtl * ttl);
     444           18 :     ::etl::be_uint16_ext_t{&sdEntry[12]} = 0U; // reserved
     445           18 :     ::etl::be_uint16_ext_t{&sdEntry[14]} = eventGroup;
     446           18 : }
     447              : 
     448            4 : SdMessageReturnCode writePublish(
     449              :     internal::Message& message,
     450              :     service_id::type const serviceId,
     451              :     instance_id::type const instanceId,
     452              :     eventgroup_id::type const eventGroup,
     453              :     major_version::type const majorVersion,
     454              :     ttl::type const ttl,
     455              :     uint8_t const optionIndex,
     456              :     TtlHandling const ttlHandling = TtlConstants::PRESERVE_TTL)
     457              : {
     458            4 :     auto const freeBytesForEntries = getFreeBytesForEntries(message);
     459            4 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     460              :     {
     461              :         // move options section to the right to fit a new entry
     462            0 :         (void)::memmove(
     463              :             &message.data
     464            0 :                  [message.divider
     465              :                   + (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     466            0 :                      - freeBytesForEntries)],
     467            0 :             &message.data[message.divider],
     468              :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY)
     469            0 :                 + getOptionsLength(message));
     470            0 :         message.divider += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     471            0 :                            - freeBytesForEntries;
     472              :     }
     473              :     auto const sdEntry
     474              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
     475              :             &message.data
     476              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
     477            4 :                   + getEntriesLength(message)],
     478            4 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     479              : 
     480            4 :     writeSdOptions(sdEntry, ENTRY_TYPE_PUBLISH, optionIndex, 0x10U);
     481            4 :     writeEventGroupDescription(
     482              :         sdEntry,
     483              :         serviceId,
     484              :         instanceId,
     485              :         eventGroup,
     486              :         majorVersion,
     487              :         ttl,
     488              :         static_cast<uint32_t>(ttlHandling));
     489              : 
     490            4 :     setEntriesLength(
     491              :         message,
     492            4 :         getEntriesLength(message)
     493              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     494            4 :     return SdMessageReturnCode::SD_MESSAGE_OK;
     495              : }
     496              : 
     497           12 : void writeSubscription(
     498              :     ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)> const&
     499              :         sdEntry,
     500              :     service_id::type const serviceId,
     501              :     instance_id::type const instanceId,
     502              :     eventgroup_id::type const eventGroup,
     503              :     major_version::type const majorVersion,
     504              :     minor_version::type const minorVersion,
     505              :     ttl::type const ttl,
     506              :     uint32_t const preserveTtl)
     507              : {
     508           12 :     ::etl::be_uint16_ext_t{&sdEntry[4]} = serviceId;
     509           12 :     ::etl::be_uint16_ext_t{&sdEntry[6]} = instanceId;
     510           12 :     sdEntry[8]                          = majorVersion;
     511           12 :     writeBe24(&sdEntry[9], preserveTtl * ttl);
     512           12 :     ::etl::be_uint16_ext_t{&sdEntry[12]} = static_cast<uint16_t>(minorVersion);
     513           12 :     ::etl::be_uint16_ext_t{&sdEntry[14]} = eventGroup;
     514           12 : }
     515              : 
     516           17 : SdMessageReturnCode associateEndpointOption(
     517              :     internal::Message& message,
     518              :     MessageEndpointOptionType const optionType,
     519              :     uint16_t const optionLength,
     520              :     ::ip::IPAddress const& ipAddress,
     521              :     port::type const port,
     522              :     proto::type const proto)
     523              : {
     524           17 :     if (proto == SomeIpConstants::INVALID_PROTO)
     525              :     {
     526              :         char addressStr[::ip::MAX_ENDPOINT_STRING_LENGTH];
     527            1 :         char* const addressStrPtr = ::ip::to_str(ipAddress, addressStr).data();
     528            1 :         WARN_LOG(
     529              :             SOMEIP,
     530              :             "SdMessageBuilder::associateEndpointOption(ip: %s, port: %d, proto: 0x%X) "
     531              :             "invalid proto",
     532              :             addressStrPtr,
     533              :             port,
     534              :             proto);
     535              :     }
     536              : 
     537           17 :     auto const freeBytesForOptions = getFreeBytesForOptions(message);
     538           17 :     if (freeBytesForOptions < optionLength)
     539              :     {
     540              :         // move options section to the left to fit a new option
     541            0 :         (void)::memmove(
     542            0 :             &message.data[message.divider - (optionLength - freeBytesForOptions)],
     543            0 :             &message.data[message.divider],
     544              :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY)
     545            0 :                 + getOptionsLength(message));
     546            0 :         message.divider -= static_cast<uint16_t>(optionLength - freeBytesForOptions);
     547              :     }
     548              : 
     549           17 :     auto const optionsLength = getOptionsLength(message);
     550              :     auto option              = ::etl::span<uint8_t>(
     551              :         &message.data
     552           17 :              [message.divider
     553              :               + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY)
     554           17 :               + optionsLength],
     555           17 :         optionLength);
     556           17 :     writeOption(option, optionType, ipAddress, port, proto);
     557           17 :     setOptionsLength(message, getOptionsLength(message) + optionLength);
     558           17 :     return SdMessageReturnCode::SD_MESSAGE_OK;
     559              : }
     560              : 
     561           10 : SdMessageReturnCode associateMulticastOption(
     562              :     internal::Message& message,
     563              :     MessageEndpointOptionType const optionType,
     564              :     uint16_t const optionLength,
     565              :     ::ip::IPAddress const& ipAddress,
     566              :     port::type const port,
     567              :     proto::type const proto)
     568              : {
     569           10 :     auto const freeBytesForOptions = getFreeBytesForOptions(message);
     570           10 :     if (freeBytesForOptions < optionLength)
     571              :     {
     572              :         // move options section to the left to fit a new option
     573            0 :         (void)::memmove(
     574            0 :             &message.data[message.divider - (optionLength - freeBytesForOptions)],
     575            0 :             &message.data[message.divider],
     576              :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY)
     577            0 :                 + getOptionsLength(message));
     578            0 :         message.divider -= static_cast<uint32_t>(optionLength - freeBytesForOptions);
     579              :     }
     580              : 
     581           10 :     auto const optionsLength = getOptionsLength(message);
     582              :     auto option              = ::etl::span<uint8_t>(
     583              :         &message.data
     584           10 :              [message.divider
     585              :               + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY)
     586           10 :               + optionsLength],
     587           10 :         optionLength);
     588           10 :     writeOption(option, optionType, ipAddress, port, proto);
     589           10 :     setOptionsLength(message, getOptionsLength(message) + optionLength);
     590           10 :     return SdMessageReturnCode::SD_MESSAGE_OK;
     591              : }
     592              : } // namespace
     593              : 
     594           35 : SdMessageReturnCode SdMessageBuilder::startMessage(::etl::span<uint8_t> const& buffer)
     595              : {
     596           35 :     SdMessageReturnCode const rc = checkBuffer(buffer);
     597           35 :     if (rc != SdMessageReturnCode::SD_MESSAGE_OK)
     598              :     {
     599            1 :         return rc;
     600              :     }
     601              : 
     602           34 :     resetMessage(_message, buffer);
     603           34 :     setEntriesLength(_message, 0U);
     604           34 :     setOptionsLength(_message, 0U);
     605           34 :     addHeader(_message);
     606           34 :     return rc;
     607              : }
     608              : 
     609            2 : SdMessageReturnCode SdMessageBuilder::addFind(
     610              :     service_id::type const serviceId,
     611              :     instance_id::type const instanceId,
     612              :     major_version::type const majorVersion,
     613              :     minor_version::type const minorVersion,
     614              :     ttl::type const ttl)
     615              : {
     616            2 :     DEBUG_LOG(
     617              :         SOMEIP,
     618              :         "SdMessageBuilder::addFind(service: %d, version: %d, instance: %d)",
     619              :         serviceId,
     620              :         majorVersion,
     621              :         instanceId);
     622              : 
     623            2 :     auto const freeBytesForEntries = getFreeBytesForEntries(_message);
     624            2 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     625              :     {
     626            1 :         auto const freeBytesForOptions = getFreeBytesForOptions(_message);
     627            1 :         if ((freeBytesForEntries + freeBytesForOptions)
     628              :             < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     629              :         {
     630            1 :             ERROR_LOG(SOMEIP, "SdMessageBuilder::addSubscribeAck() message is too big");
     631            1 :             return SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE;
     632              :         }
     633              : 
     634              :         // move options section to the right to fit entry
     635            0 :         (void)::memmove(
     636              :             &_message.data
     637            0 :                  [_message.divider
     638              :                   + (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     639            0 :                      - freeBytesForEntries)],
     640            0 :             &_message.data[_message.divider],
     641              :             static_cast<uint32_t>(
     642              :                 static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
     643            0 :                 + getOptionsLength(_message));
     644              : 
     645            0 :         _message.divider += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     646            0 :                             - freeBytesForEntries;
     647              :     }
     648              : 
     649              :     auto const sdEntry
     650              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
     651              :             &_message.data
     652              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
     653            1 :                   + getEntriesLength(_message)],
     654            1 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     655              : 
     656            1 :     writeSdOptions(sdEntry, ENTRY_TYPE_FIND);
     657            1 :     writeServiceDescription(
     658              :         sdEntry,
     659              :         serviceId,
     660              :         instanceId,
     661              :         majorVersion,
     662              :         minorVersion,
     663              :         ttl,
     664              :         static_cast<uint32_t>(TtlConstants::PRESERVE_TTL));
     665              : 
     666            1 :     setEntriesLength(
     667            1 :         _message,
     668            1 :         getEntriesLength(_message)
     669              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     670              : 
     671            1 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
     672              :     // to avoid branching
     673            1 :     return static_cast<SdMessageReturnCode>(
     674              :         static_cast<uint8_t>(
     675              :             freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     676              :             * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
     677              :         + static_cast<uint8_t>(
     678              :               freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     679            1 :               * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK));
     680              : }
     681              : 
     682            1 : SdMessageReturnCode SdMessageBuilder::addOffer(
     683              :     service_id::type const serviceId,
     684              :     instance_id::type const instanceId,
     685              :     major_version::type const majorVersion,
     686              :     minor_version::type const minorVersion,
     687              :     ttl::type const ttl,
     688              :     ::ip::IPAddress const& ipAddress,
     689              :     port::type const port,
     690              :     proto::type const proto)
     691              : {
     692            1 :     DEBUG_LOG(
     693              :         SOMEIP,
     694              :         "SdMessageBuilder::addOffer(service: %d, version: %d, instance: %d)",
     695              :         serviceId,
     696              :         majorVersion,
     697              :         instanceId);
     698              : 
     699            1 :     uint8_t optionIdx      = 0U;
     700            1 :     auto const optionFound = findEndpointOption(_message, ipAddress, port, proto, optionIdx);
     701              :     MessageEndpointOptionType optionType;
     702            1 :     auto const optionLength    = measureOption(ipAddress, false, optionType);
     703            1 :     size_t const spaceRequired = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     704            1 :                                  + static_cast<size_t>(!optionFound) * optionLength;
     705            1 :     if (((getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message))
     706            1 :          < static_cast<uint32_t>(spaceRequired))
     707            1 :         || (optionIdx == INVALID_OPTION_INDEX))
     708              :     {
     709              :         // avoid branching
     710            0 :         return static_cast<SdMessageReturnCode>(
     711            1 :             static_cast<uint8_t>(optionIdx == INVALID_OPTION_INDEX)
     712              :                 * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_INVALID_ADDRESS)
     713            1 :             + static_cast<uint8_t>(optionIdx != INVALID_OPTION_INDEX)
     714            1 :                   * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE));
     715              :     }
     716              : 
     717              :     auto rc
     718            0 :         = writeOffer(_message, serviceId, instanceId, majorVersion, minorVersion, ttl, optionIdx);
     719            0 :     if ((rc == SdMessageReturnCode::SD_MESSAGE_OK) && (!optionFound))
     720              :     {
     721            0 :         rc = associateEndpointOption(_message, optionType, optionLength, ipAddress, port, proto);
     722              :     }
     723              : 
     724            0 :     return rc;
     725              : }
     726              : 
     727            1 : SdMessageReturnCode SdMessageBuilder::addDenounce(
     728              :     service_id::type const serviceId,
     729              :     instance_id::type const instanceId,
     730              :     major_version::type const majorVersion,
     731              :     minor_version::type const minorVersion,
     732              :     ttl::type const ttl,
     733              :     ::ip::IPAddress const& ipAddress,
     734              :     port::type const port,
     735              :     proto::type const proto)
     736              : {
     737            1 :     DEBUG_LOG(
     738              :         SOMEIP,
     739              :         "SdMessageBuilder::addDenounce(service: %d, version: %d, instance: %d)",
     740              :         serviceId,
     741              :         majorVersion,
     742              :         instanceId);
     743              : 
     744            1 :     uint8_t optionIdx      = 0U;
     745            1 :     auto const optionFound = findEndpointOption(_message, ipAddress, port, proto, optionIdx);
     746              :     MessageEndpointOptionType optionType;
     747            1 :     auto const optionLength    = measureOption(ipAddress, false, optionType);
     748            1 :     size_t const spaceRequired = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     749            1 :                                  + static_cast<size_t>(!optionFound) * optionLength;
     750            1 :     if (((getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message))
     751            1 :          < static_cast<uint32_t>(spaceRequired))
     752            1 :         || (optionIdx == INVALID_OPTION_INDEX))
     753              :     {
     754              :         // avoid branching
     755            0 :         return static_cast<SdMessageReturnCode>(
     756            0 :             static_cast<uint8_t>(optionIdx == INVALID_OPTION_INDEX)
     757              :                 * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_INVALID_ADDRESS)
     758            0 :             + static_cast<uint8_t>(optionIdx != INVALID_OPTION_INDEX)
     759            0 :                   * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE));
     760              :     }
     761              : 
     762            2 :     auto rc = writeOffer(
     763            1 :         _message,
     764              :         serviceId,
     765              :         instanceId,
     766              :         majorVersion,
     767              :         minorVersion,
     768              :         ttl,
     769              :         optionIdx,
     770              :         TtlConstants::SET_ZERO_TTL);
     771            1 :     if ((rc == SdMessageReturnCode::SD_MESSAGE_OK) && (!optionFound))
     772              :     {
     773            1 :         rc = associateEndpointOption(_message, optionType, optionLength, ipAddress, port, proto);
     774              :     }
     775              : 
     776            1 :     return rc;
     777              : }
     778              : 
     779            2 : SdMessageReturnCode SdMessageBuilder::addFindEventgroup(
     780              :     service_id::type const serviceId,
     781              :     instance_id::type const instanceId,
     782              :     eventgroup_id::type const eventGroup,
     783              :     major_version::type const majorVersion,
     784              :     ttl::type const ttl)
     785              : {
     786            2 :     DEBUG_LOG(
     787              :         SOMEIP,
     788              :         "SdMessageBuilder::addFindEventgroup(service: %d, version: %d, instance: %d, eventgroup: "
     789              :         "%d)",
     790              :         serviceId,
     791              :         majorVersion,
     792              :         instanceId,
     793              :         eventGroup);
     794              : 
     795            2 :     auto const freeBytesForEntries = getFreeBytesForEntries(_message);
     796            2 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     797              :     {
     798            1 :         auto const freeBytesForOptions = getFreeBytesForOptions(_message);
     799            1 :         if ((freeBytesForEntries + freeBytesForOptions)
     800              :             < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     801              :         {
     802            1 :             ERROR_LOG(SOMEIP, "SdMessageBuilder::addFindEventgroup() message is too big");
     803            1 :             return SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE;
     804              :         }
     805              : 
     806              :         // move options section to the right to fit entry
     807            0 :         (void)::memmove(
     808              :             &_message.data
     809            0 :                  [_message.divider
     810              :                   + (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     811            0 :                      - freeBytesForEntries)],
     812            0 :             &_message.data[_message.divider],
     813              :             static_cast<uint32_t>(
     814              :                 static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
     815            0 :                 + getOptionsLength(_message));
     816              : 
     817            0 :         _message.divider += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     818            0 :                             - freeBytesForEntries;
     819              :     }
     820              : 
     821              :     auto const entry
     822              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
     823              :             &_message.data
     824              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
     825            1 :                   + getEntriesLength(_message)],
     826            1 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     827              : 
     828            1 :     writeSdOptions(entry, ENTRY_TYPE_FIND_EVENTGROUP);
     829            1 :     writeEventGroupDescription(
     830              :         entry,
     831              :         serviceId,
     832              :         instanceId,
     833              :         eventGroup,
     834              :         majorVersion,
     835              :         ttl,
     836              :         static_cast<uint32_t>(TtlConstants::PRESERVE_TTL));
     837              : 
     838            1 :     setEntriesLength(
     839            1 :         _message,
     840            1 :         getEntriesLength(_message)
     841              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
     842              : 
     843            1 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
     844            1 :     return static_cast<SdMessageReturnCode>(
     845              :         static_cast<uint8_t>(
     846              :             freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     847              :             * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
     848              :         + static_cast<uint8_t>(
     849              :               freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     850            1 :               * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK));
     851              : }
     852              : 
     853            4 : SdMessageReturnCode SdMessageBuilder::addPublish(
     854              :     service_id::type const serviceId,
     855              :     instance_id::type const instanceId,
     856              :     eventgroup_id::type const eventGroup,
     857              :     major_version::type const majorVersion,
     858              :     ttl::type const ttl,
     859              :     ::ip::IPAddress const& ipAddress,
     860              :     port::type const port,
     861              :     proto::type const proto)
     862              : {
     863            4 :     DEBUG_LOG(
     864              :         SOMEIP,
     865              :         "SdMessageBuilder::addPublish(service: %d, version: %d, instance: %d, eventgroup: %d)",
     866              :         serviceId,
     867              :         majorVersion,
     868              :         instanceId,
     869              :         eventGroup);
     870              : 
     871            4 :     uint8_t optionIdx      = 0U;
     872            4 :     auto const optionFound = findEndpointOption(_message, ipAddress, port, proto, optionIdx);
     873              :     MessageEndpointOptionType optionType;
     874            4 :     auto const optionLength    = measureOption(ipAddress, false, optionType);
     875            4 :     size_t const spaceRequired = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     876            4 :                                  + static_cast<size_t>(!optionFound) * optionLength;
     877            4 :     if (((getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message))
     878            4 :          < static_cast<uint32_t>(spaceRequired))
     879            4 :         || (optionIdx == INVALID_OPTION_INDEX))
     880              :     {
     881              :         // avoid branching
     882            0 :         return static_cast<SdMessageReturnCode>(
     883            1 :             static_cast<uint8_t>(optionIdx == INVALID_OPTION_INDEX)
     884              :                 * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_INVALID_ADDRESS)
     885            1 :             + static_cast<uint8_t>(optionIdx != INVALID_OPTION_INDEX)
     886            1 :                   * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE));
     887              :     }
     888              : 
     889              :     auto rc
     890            3 :         = writePublish(_message, serviceId, instanceId, eventGroup, majorVersion, ttl, optionIdx);
     891              : 
     892            3 :     if (!optionFound)
     893              :     {
     894            3 :         rc = associateEndpointOption(_message, optionType, optionLength, ipAddress, port, proto);
     895              :     }
     896              : 
     897            3 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
     898            3 :     return (rc == SdMessageReturnCode::SD_MESSAGE_OK) ? (static_cast<SdMessageReturnCode>(
     899              :                static_cast<uint8_t>(
     900              :                    freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     901              :                    * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
     902              :                + static_cast<uint8_t>(
     903              :                      freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
     904              :                      * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK)))
     905            3 :                                                       : rc;
     906              : }
     907              : 
     908            1 : SdMessageReturnCode SdMessageBuilder::addUnpublish(
     909              :     service_id::type const serviceId,
     910              :     instance_id::type const instanceId,
     911              :     eventgroup_id::type const eventGroup,
     912              :     major_version::type const majorVersion,
     913              :     ttl::type const ttl,
     914              :     ::ip::IPAddress const& ipAddress,
     915              :     port::type const port,
     916              :     proto::type const proto)
     917              : {
     918            1 :     DEBUG_LOG(
     919              :         SOMEIP,
     920              :         "SdMessageBuilder::addUnpublish(service: %d, version: %d, instance: %d, eventgroup: %d)",
     921              :         serviceId,
     922              :         majorVersion,
     923              :         instanceId,
     924              :         eventGroup);
     925              : 
     926            1 :     uint8_t optionIdx      = 0U;
     927            1 :     auto const optionFound = findEndpointOption(_message, ipAddress, port, proto, optionIdx);
     928              :     MessageEndpointOptionType optionType;
     929            1 :     auto const optionLength    = measureOption(ipAddress, false, optionType);
     930            1 :     size_t const spaceRequired = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     931            1 :                                  + static_cast<size_t>(!optionFound) * optionLength;
     932            1 :     if (((getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message))
     933            1 :          < static_cast<uint32_t>(spaceRequired))
     934            1 :         || (optionIdx == INVALID_OPTION_INDEX))
     935              :     {
     936              :         // avoid branching
     937            0 :         return static_cast<SdMessageReturnCode>(
     938            0 :             static_cast<uint8_t>(optionIdx == INVALID_OPTION_INDEX)
     939              :                 * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_INVALID_ADDRESS)
     940            0 :             + static_cast<uint8_t>(optionIdx != INVALID_OPTION_INDEX)
     941            0 :                   * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE));
     942              :     }
     943              : 
     944            2 :     auto rc = writePublish(
     945            1 :         _message,
     946              :         serviceId,
     947              :         instanceId,
     948              :         eventGroup,
     949              :         majorVersion,
     950              :         ttl,
     951              :         optionIdx,
     952              :         TtlConstants::SET_ZERO_TTL);
     953              : 
     954            1 :     if (!optionFound)
     955              :     {
     956            1 :         rc = associateEndpointOption(_message, optionType, optionLength, ipAddress, port, proto);
     957              :     }
     958              : 
     959            1 :     return rc;
     960              : }
     961              : 
     962           14 : SdMessageReturnCode SdMessageBuilder::addSubscribe(
     963              :     service_id::type const serviceId,
     964              :     instance_id::type const instanceId,
     965              :     eventgroup_id::type const eventGroup,
     966              :     major_version::type const majorVersion,
     967              :     ttl::type const ttl,
     968              :     ::ip::IPAddress const& ipAddress,
     969              :     port::type const port,
     970              :     proto::type const proto)
     971              : {
     972           14 :     DEBUG_LOG(
     973              :         SOMEIP,
     974              :         "SdMessageBuilder::addSubscribe(service: %d, version: %d, instance: %d, eventgroup: %d)",
     975              :         serviceId,
     976              :         majorVersion,
     977              :         instanceId,
     978              :         eventGroup);
     979              : 
     980           14 :     uint8_t optionIdx      = 0U;
     981           14 :     auto const optionFound = findEndpointOption(_message, ipAddress, port, proto, optionIdx);
     982              :     MessageEndpointOptionType optionType;
     983           14 :     auto const optionLength    = measureOption(ipAddress, false, optionType);
     984           14 :     size_t const spaceRequired = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
     985           14 :                                  + static_cast<size_t>(!optionFound) * optionLength;
     986           14 :     auto const freeBytesForEntries = getFreeBytesForEntries(_message);
     987           14 :     auto const freeBytesForOptions = getFreeBytesForOptions(_message);
     988           14 :     if (((freeBytesForEntries + freeBytesForOptions) < static_cast<uint32_t>(spaceRequired))
     989           12 :         || (optionIdx == INVALID_OPTION_INDEX))
     990              :     {
     991              :         // avoid branching
     992            0 :         return static_cast<SdMessageReturnCode>(
     993            2 :             static_cast<uint8_t>(optionIdx == INVALID_OPTION_INDEX)
     994              :                 * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_INVALID_ADDRESS)
     995            2 :             + static_cast<uint8_t>(optionIdx != INVALID_OPTION_INDEX)
     996            2 :                   * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE));
     997              :     }
     998              : 
     999           12 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1000              :     {
    1001              :         // move options section to the right to fit the entry
    1002            0 :         (void)::memmove(
    1003              :             &_message.data
    1004            0 :                  [_message.divider
    1005              :                   + (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1006            0 :                      - freeBytesForEntries)],
    1007            0 :             &_message.data[_message.divider],
    1008              :             static_cast<uint32_t>(
    1009              :                 static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
    1010            0 :                 + getOptionsLength(_message));
    1011              : 
    1012            0 :         _message.divider += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1013            0 :                             - freeBytesForEntries;
    1014              :     }
    1015              : 
    1016              :     auto const entry
    1017              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
    1018              :             &_message.data
    1019              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
    1020           12 :                   + getEntriesLength(_message)],
    1021           12 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1022              : 
    1023           12 :     writeSdOptions(entry, ENTRY_TYPE_SUBSCRIBE, optionIdx, 0x10U);
    1024           12 :     writeEventGroupDescription(
    1025              :         entry,
    1026              :         serviceId,
    1027              :         instanceId,
    1028              :         eventGroup,
    1029              :         majorVersion,
    1030              :         ttl,
    1031              :         static_cast<uint32_t>(TtlConstants::PRESERVE_TTL));
    1032              : 
    1033           12 :     setEntriesLength(
    1034           12 :         _message,
    1035           12 :         getEntriesLength(_message)
    1036              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1037              : 
    1038           12 :     auto rc = SdMessageReturnCode::SD_MESSAGE_OK;
    1039           12 :     if (!optionFound)
    1040              :     {
    1041           11 :         rc = associateEndpointOption(_message, optionType, optionLength, ipAddress, port, proto);
    1042              :     }
    1043              : 
    1044           12 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
    1045           12 :     return (rc == SdMessageReturnCode::SD_MESSAGE_OK) ? (static_cast<SdMessageReturnCode>(
    1046              :                static_cast<uint8_t>(
    1047              :                    freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1048              :                    * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
    1049              :                + static_cast<uint8_t>(
    1050              :                      freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1051              :                      * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK)))
    1052           12 :                                                       : rc;
    1053              : }
    1054              : 
    1055            1 : SdMessageReturnCode SdMessageBuilder::addUnsubscribe(
    1056              :     service_id::type const serviceId,
    1057              :     instance_id::type const instanceId,
    1058              :     eventgroup_id::type const eventGroup,
    1059              :     major_version::type const majorVersion,
    1060              :     ttl::type const ttl,
    1061              :     ::ip::IPAddress const& ipAddress,
    1062              :     port::type const port,
    1063              :     proto::type const proto)
    1064              : {
    1065            1 :     DEBUG_LOG(
    1066              :         SOMEIP,
    1067              :         "SdMessageBuilder::addUnsubscribe(service: %d, version: %d, instance: %d, eventgroup: %d)",
    1068              :         serviceId,
    1069              :         majorVersion,
    1070              :         instanceId,
    1071              :         eventGroup);
    1072              : 
    1073            1 :     uint8_t optionIdx      = 0U;
    1074            1 :     auto const optionFound = findEndpointOption(_message, ipAddress, port, proto, optionIdx);
    1075              :     MessageEndpointOptionType optionType;
    1076            1 :     auto const optionLength    = measureOption(ipAddress, false, optionType);
    1077            1 :     size_t const spaceRequired = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1078            1 :                                  + static_cast<size_t>(!optionFound) * optionLength;
    1079            1 :     if (((getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message))
    1080            1 :          < static_cast<uint32_t>(spaceRequired))
    1081            1 :         || (optionIdx == INVALID_OPTION_INDEX))
    1082              :     {
    1083              :         // avoid branching
    1084            0 :         return static_cast<SdMessageReturnCode>(
    1085            0 :             static_cast<uint8_t>(optionIdx == INVALID_OPTION_INDEX)
    1086              :                 * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_INVALID_ADDRESS)
    1087            0 :             + static_cast<uint8_t>(optionIdx != INVALID_OPTION_INDEX)
    1088            0 :                   * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE));
    1089              :     }
    1090              : 
    1091              :     auto const entry
    1092              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
    1093              :             &_message.data
    1094              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
    1095            1 :                   + getEntriesLength(_message)],
    1096            1 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1097              : 
    1098            1 :     writeSdOptions(entry, ENTRY_TYPE_SUBSCRIBE, optionIdx, 0x10U);
    1099            1 :     writeEventGroupDescription(
    1100              :         entry,
    1101              :         serviceId,
    1102              :         instanceId,
    1103              :         eventGroup,
    1104              :         majorVersion,
    1105              :         ttl,
    1106              :         static_cast<uint32_t>(TtlConstants::SET_ZERO_TTL));
    1107              : 
    1108            1 :     setEntriesLength(
    1109            1 :         _message,
    1110            1 :         getEntriesLength(_message)
    1111              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1112              : 
    1113            1 :     auto rc = SdMessageReturnCode::SD_MESSAGE_OK;
    1114            1 :     if (!optionFound)
    1115              :     {
    1116            1 :         rc = associateEndpointOption(_message, optionType, optionLength, ipAddress, port, proto);
    1117              :     }
    1118              : 
    1119            1 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
    1120              :     // to avoid branching
    1121            1 :     return (rc == SdMessageReturnCode::SD_MESSAGE_OK) ? (static_cast<SdMessageReturnCode>(
    1122              :                static_cast<uint8_t>(
    1123              :                    freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1124              :                    * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
    1125              :                + static_cast<uint8_t>(
    1126              :                      freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1127              :                      * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK)))
    1128            1 :                                                       : rc;
    1129              : }
    1130              : 
    1131            1 : SdMessageReturnCode SdMessageBuilder::addSubscribeAck(
    1132              :     service_id::type const serviceId,
    1133              :     instance_id::type const instanceId,
    1134              :     eventgroup_id::type const eventGroup,
    1135              :     major_version::type const majorVersion,
    1136              :     minor_version::type const minorVersion,
    1137              :     ttl::type const ttl)
    1138              : {
    1139            1 :     DEBUG_LOG(
    1140              :         SOMEIP,
    1141              :         "SdMessageBuilder::addSubscribeAck(service: %d, version: %d, instance: %d, eventgroup: %d)",
    1142              :         serviceId,
    1143              :         majorVersion,
    1144              :         instanceId,
    1145              :         eventGroup);
    1146              : 
    1147            1 :     auto const freeBytesForEntries = getFreeBytesForEntries(_message);
    1148            1 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1149              :     {
    1150            1 :         auto const freeBytesForOptions = getFreeBytesForOptions(_message);
    1151            1 :         if ((freeBytesForEntries + freeBytesForOptions)
    1152              :             < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1153              :         {
    1154            1 :             ERROR_LOG(SOMEIP, "SdMessageBuilder::addSubscribeAck() message is too big");
    1155            1 :             return SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE;
    1156              :         }
    1157              : 
    1158              :         // move options section to the right to fit the entry
    1159            0 :         (void)::memmove(
    1160              :             &_message.data
    1161            0 :                  [_message.divider
    1162              :                   + (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1163            0 :                      - freeBytesForEntries)],
    1164            0 :             &_message.data[_message.divider],
    1165              :             static_cast<uint32_t>(
    1166              :                 static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
    1167            0 :                 + getOptionsLength(_message));
    1168              : 
    1169            0 :         _message.divider += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1170            0 :                             - freeBytesForEntries;
    1171              :     }
    1172              : 
    1173              :     auto const entry
    1174              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
    1175              :             &_message.data
    1176              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
    1177            0 :                   + getEntriesLength(_message)],
    1178            0 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1179              : 
    1180            0 :     writeSdOptions(entry, ENTRY_TYPE_SUBSCRIBE_ACK);
    1181            0 :     writeSubscription(
    1182              :         entry,
    1183              :         serviceId,
    1184              :         instanceId,
    1185              :         eventGroup,
    1186              :         majorVersion,
    1187              :         minorVersion,
    1188              :         ttl,
    1189              :         static_cast<uint32_t>(TtlConstants::PRESERVE_TTL));
    1190              : 
    1191            0 :     setEntriesLength(
    1192            0 :         _message,
    1193            0 :         getEntriesLength(_message)
    1194              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1195              : 
    1196            0 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
    1197              :     // to avoid branching
    1198            0 :     return static_cast<SdMessageReturnCode>(
    1199              :         static_cast<uint8_t>(
    1200              :             freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1201              :             * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
    1202              :         + static_cast<uint8_t>(
    1203              :               freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1204            0 :               * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK));
    1205              : }
    1206              : 
    1207            1 : SdMessageReturnCode SdMessageBuilder::addSubscribeNack(
    1208              :     service_id::type const serviceId,
    1209              :     instance_id::type const instanceId,
    1210              :     eventgroup_id::type const eventGroup,
    1211              :     major_version::type const majorVersion,
    1212              :     minor_version::type const minorVersion,
    1213              :     ttl::type const ttl)
    1214              : {
    1215            1 :     DEBUG_LOG(
    1216              :         SOMEIP,
    1217              :         "SdMessageBuilder::addSubscribeNack(service: %d, version: %d, instance: %d, eventgroup: "
    1218              :         "%d)",
    1219              :         serviceId,
    1220              :         majorVersion,
    1221              :         instanceId,
    1222              :         eventGroup);
    1223              : 
    1224            1 :     auto const freeBytesForEntries = getFreeBytesForEntries(_message);
    1225            1 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1226              :     {
    1227            0 :         auto const freeBytesForOptions = getFreeBytesForOptions(_message);
    1228            0 :         if ((freeBytesForEntries + freeBytesForOptions)
    1229              :             < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1230              :         {
    1231            0 :             ERROR_LOG(SOMEIP, "SdMessageBuilder::addSubscribeNack() message is too big");
    1232            0 :             return SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE;
    1233              :         }
    1234              : 
    1235              :         // move options section to the right to fit entry
    1236            0 :         (void)::memmove(
    1237              :             &_message.data
    1238            0 :                  [_message.divider
    1239              :                   + (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1240            0 :                      - freeBytesForEntries)],
    1241            0 :             &_message.data[_message.divider],
    1242              :             static_cast<uint32_t>(
    1243              :                 static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
    1244            0 :                 + getOptionsLength(_message));
    1245              : 
    1246            0 :         _message.divider += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1247            0 :                             - freeBytesForEntries;
    1248              :     }
    1249              : 
    1250              :     auto const entry
    1251              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
    1252              :             &_message.data
    1253              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
    1254            1 :                   + getEntriesLength(_message)],
    1255            1 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1256              : 
    1257            1 :     writeSdOptions(entry, ENTRY_TYPE_SUBSCRIBE_ACK);
    1258            1 :     writeSubscription(
    1259              :         entry,
    1260              :         serviceId,
    1261              :         instanceId,
    1262              :         eventGroup,
    1263              :         majorVersion,
    1264              :         minorVersion,
    1265              :         ttl,
    1266              :         static_cast<uint32_t>(TtlConstants::SET_ZERO_TTL));
    1267              : 
    1268            1 :     setEntriesLength(
    1269            1 :         _message,
    1270            1 :         getEntriesLength(_message)
    1271              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1272              : 
    1273            1 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
    1274              :     // to avoid branching
    1275            1 :     return static_cast<SdMessageReturnCode>(
    1276              :         static_cast<uint8_t>(
    1277              :             freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1278              :             * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
    1279              :         + static_cast<uint8_t>(
    1280              :               freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1281            1 :               * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK));
    1282              : }
    1283              : 
    1284           13 : SdMessageReturnCode SdMessageBuilder::addSubscribeAckMulticast(
    1285              :     service_id::type const serviceId,
    1286              :     instance_id::type const instanceId,
    1287              :     eventgroup_id::type const eventGroup,
    1288              :     major_version::type const majorVersion,
    1289              :     minor_version::type const minorVersion,
    1290              :     ttl::type const ttl,
    1291              :     ::ip::IPAddress const& ipAddress,
    1292              :     port::type const port,
    1293              :     proto::type const proto)
    1294              : {
    1295           13 :     DEBUG_LOG(
    1296              :         SOMEIP,
    1297              :         "SdMessageBuilder::addSubscribeAckMulticast(service: %d, version: %d, instance: %d, "
    1298              :         "eventgroup: %d)",
    1299              :         serviceId,
    1300              :         majorVersion,
    1301              :         instanceId,
    1302              :         eventGroup);
    1303              : 
    1304           13 :     uint8_t optionIdx      = 0U;
    1305           13 :     auto const optionFound = findEndpointOption(_message, ipAddress, port, proto, optionIdx);
    1306              :     MessageEndpointOptionType optionType;
    1307           13 :     auto const optionLength    = measureOption(ipAddress, true, optionType);
    1308           13 :     size_t const spaceRequired = static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1309           13 :                                  + static_cast<size_t>(!optionFound) * optionLength;
    1310           13 :     auto const freeBytesForEntries = getFreeBytesForEntries(_message);
    1311           13 :     auto const freeBytesForOptions = getFreeBytesForOptions(_message);
    1312           13 :     if (((freeBytesForEntries + freeBytesForOptions) < static_cast<uint32_t>(spaceRequired))
    1313           11 :         || (optionIdx == INVALID_OPTION_INDEX))
    1314              :     {
    1315              :         // avoid branching
    1316            0 :         return static_cast<SdMessageReturnCode>(
    1317            2 :             static_cast<uint8_t>(optionIdx == INVALID_OPTION_INDEX)
    1318              :                 * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_INVALID_ADDRESS)
    1319            2 :             + static_cast<uint8_t>(optionIdx != INVALID_OPTION_INDEX)
    1320            2 :                   * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_NOT_ENOUGH_SPACE));
    1321              :     }
    1322              : 
    1323           11 :     if (freeBytesForEntries < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1324              :     {
    1325              :         // move options section to the right to fit the entry
    1326            2 :         (void)::memmove(
    1327              :             &_message.data
    1328            1 :                  [_message.divider
    1329              :                   + (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1330            1 :                      - freeBytesForEntries)],
    1331            1 :             &_message.data[_message.divider],
    1332              :             static_cast<uint32_t>(
    1333              :                 static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
    1334            1 :                 + getOptionsLength(_message));
    1335              : 
    1336            1 :         _message.divider += static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)
    1337            1 :                             - freeBytesForEntries;
    1338              :     }
    1339              : 
    1340              :     auto const entry
    1341              :         = ::etl::span<uint8_t, static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY)>(
    1342              :             &_message.data
    1343              :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES)
    1344           11 :                   + getEntriesLength(_message)],
    1345           11 :             static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1346              : 
    1347           11 :     writeSdOptions(entry, ENTRY_TYPE_SUBSCRIBE_ACK, optionIdx, 0x10U);
    1348           11 :     writeSubscription(
    1349              :         entry,
    1350              :         serviceId,
    1351              :         instanceId,
    1352              :         eventGroup,
    1353              :         majorVersion,
    1354              :         minorVersion,
    1355              :         ttl,
    1356              :         static_cast<uint32_t>(TtlConstants::PRESERVE_TTL));
    1357              : 
    1358           11 :     setEntriesLength(
    1359           11 :         _message,
    1360           11 :         getEntriesLength(_message)
    1361              :             + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY));
    1362              : 
    1363           11 :     auto rc = SdMessageReturnCode::SD_MESSAGE_OK;
    1364           11 :     if (!optionFound)
    1365              :     {
    1366           10 :         rc = associateMulticastOption(_message, optionType, optionLength, ipAddress, port, proto);
    1367              :     }
    1368              : 
    1369           11 :     auto const freeBytes = getFreeBytesForEntries(_message) + getFreeBytesForOptions(_message);
    1370              :     // to avoid branching
    1371           11 :     return (rc == SdMessageReturnCode::SD_MESSAGE_OK) ? (static_cast<SdMessageReturnCode>(
    1372              :                static_cast<uint8_t>(
    1373              :                    freeBytes < static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1374              :                    * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_IS_FULL)
    1375              :                + static_cast<uint8_t>(
    1376              :                      freeBytes >= static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_ENTRY))
    1377              :                      * static_cast<uint8_t>(SdMessageReturnCode::SD_MESSAGE_OK)))
    1378           11 :                                                       : rc;
    1379              : }
    1380              : 
    1381              : ::etl::span<uint8_t const>
    1382           31 : SdMessageBuilder::finishMessage(uint16_t const sessionId, bool const reboot)
    1383              : {
    1384           31 :     if (_message.data.size() == 0)
    1385              :     {
    1386            1 :         return {};
    1387              :     }
    1388              : 
    1389           30 :     writeFlags(_message, reboot);
    1390              : 
    1391           30 :     auto const optionsLength = getOptionsLength(_message);
    1392           30 :     auto const entriesLength = getEntriesLength(_message);
    1393           30 :     if (static_cast<uint32_t>(_message.divider)
    1394           30 :         != (static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES) + entriesLength))
    1395              :     {
    1396           26 :         (void)::memmove(
    1397              :             &_message.data
    1398           13 :                  [static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES) + entriesLength],
    1399           13 :             &_message.data[_message.divider],
    1400              :             static_cast<uint32_t>(
    1401              :                 static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
    1402           13 :                 + optionsLength);
    1403              : 
    1404              :         _message.divider
    1405           13 :             = static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES) + entriesLength;
    1406              :     }
    1407              : 
    1408              :     auto const messageLength
    1409           30 :         = static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_ENTRIES) + getEntriesLength(_message)
    1410              :           + static_cast<uint32_t>(
    1411              :               static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH_OF_OPTIONS_ARRAY))
    1412           30 :           + getOptionsLength(_message);
    1413            0 :     ::etl::be_uint32_ext_t{
    1414           30 :         &_message.data[static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_LENGTH)]}
    1415              :     = messageLength
    1416              :       - (static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_LENGTH)
    1417           60 :          + static_cast<uint32_t>(MessageFieldSize::MESSAGE_FIELD_SIZE_MESSAGE_ID));
    1418              : 
    1419              :     // update session id
    1420            0 :     ::etl::be_uint32_ext_t{
    1421           30 :         &_message.data[static_cast<uint32_t>(MessageOffset::MESSAGE_OFFSET_REQUEST_ID)]}
    1422           60 :     = sessionId;
    1423              : 
    1424           30 :     auto const fullMessage = _message.data.first(messageLength);
    1425           30 :     _message.data          = decltype(_message.data){};
    1426              : 
    1427           30 :     return fullMessage;
    1428              : }
    1429              : 
    1430            2 : void SdMessageBuilder::discardMessage() { _message.data = decltype(_message.data){}; }
    1431              : 
    1432            5 : bool SdMessageBuilder::isEmpty() const { return getEntriesLength(_message) == 0U; }
    1433              : 
    1434              : } // namespace someip
    1435              : 
    1436              : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
        

Generated by: LCOV version 2.0-1