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)
|