Coverage Report

Created: 2026-09-14 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Fast-DDS/src/cpp/rtps/writer/BaseWriter.cpp
Line
Count
Source
1
// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
 * @file BaseWriter.cpp
17
 */
18
19
#include <rtps/writer/BaseWriter.hpp>
20
21
#include <cassert>
22
#include <chrono>
23
#include <cstdint>
24
#include <exception>
25
#include <memory>
26
#include <mutex>
27
#include <string>
28
#include <vector>
29
30
#include <fastdds/dds/core/policy/QosPolicies.hpp>
31
#include <fastdds/dds/log/Log.hpp>
32
#include <fastdds/rtps/Endpoint.hpp>
33
#include <fastdds/rtps/attributes/PropertyPolicy.hpp>
34
#include <fastdds/rtps/attributes/ResourceManagement.hpp>
35
#include <fastdds/rtps/attributes/WriterAttributes.hpp>
36
#include <fastdds/rtps/builtin/data/SubscriptionBuiltinTopicData.hpp>
37
#include <fastdds/rtps/common/CacheChange.hpp>
38
#include <fastdds/rtps/common/Guid.hpp>
39
#include <fastdds/rtps/common/GuidPrefix_t.hpp>
40
#include <fastdds/rtps/common/LocatorSelectorEntry.hpp>
41
#include <fastdds/rtps/common/RemoteLocators.hpp>
42
#include <fastdds/rtps/common/SequenceNumber.hpp>
43
#include <fastdds/rtps/common/Time_t.hpp>
44
#include <fastdds/rtps/history/IChangePool.hpp>
45
#include <fastdds/rtps/history/IPayloadPool.hpp>
46
#include <fastdds/rtps/history/WriterHistory.hpp>
47
#include <fastdds/rtps/transport/NetworkBuffer.hpp>
48
#include <fastdds/rtps/writer/RTPSWriter.hpp>
49
#include <fastdds/rtps/writer/WriterListener.hpp>
50
#include <fastdds/statistics/IListeners.hpp>
51
#include <fastdds/utils/TimedMutex.hpp>
52
53
#include <rtps/builtin/data/ReaderProxyData.hpp>
54
#include <rtps/DataSharing/WriterPool.hpp>
55
#include <rtps/flowcontrol/FlowController.hpp>
56
#include <rtps/participant/RTPSParticipantImpl.hpp>
57
#include <rtps/writer/LocatorSelectorSender.hpp>
58
#include <statistics/rtps/messages/RTPSStatisticsMessages.hpp>
59
60
namespace eprosima {
61
namespace fastdds {
62
namespace rtps {
63
64
BaseWriter::BaseWriter(
65
        RTPSParticipantImpl* impl,
66
        const GUID_t& guid,
67
        const WriterAttributes& att,
68
        FlowController* flow_controller,
69
        WriterHistory* hist,
70
        WriterListener* listen)
71
0
    : RTPSWriter(impl, guid, att)
72
0
    , flow_controller_(flow_controller)
73
0
    , history_(hist)
74
0
    , listener_(listen)
75
0
    , is_async_(att.mode == SYNCHRONOUS_WRITER ? false : true)
76
0
    , separate_sending_enabled_(att.separate_sending)
77
0
    , liveliness_kind_(att.liveliness_kind)
78
0
    , liveliness_lease_duration_(att.liveliness_lease_duration)
79
0
    , liveliness_announcement_period_(att.liveliness_announcement_period)
80
0
    , transport_priority_(att.transport_priority)
81
0
{
82
0
    init(att);
83
84
0
    history_->mp_writer = this;
85
0
    history_->mp_mutex = &mp_mutex;
86
87
0
    flow_controller_->register_writer(this);
88
89
0
    EPROSIMA_LOG_INFO(RTPS_WRITER, "RTPSWriter created");
90
0
}
91
92
BaseWriter* BaseWriter::downcast(
93
        RTPSWriter* writer)
94
0
{
95
0
    assert(nullptr != dynamic_cast<BaseWriter*>(writer));
96
0
    return static_cast<BaseWriter*>(writer);
97
0
}
98
99
BaseWriter* BaseWriter::downcast(
100
        Endpoint* endpoint)
101
0
{
102
0
    assert(nullptr != dynamic_cast<BaseWriter*>(endpoint));
103
0
    return static_cast<BaseWriter*>(endpoint);
104
0
}
105
106
BaseWriter::~BaseWriter()
107
0
{
108
0
    EPROSIMA_LOG_INFO(RTPS_WRITER, "RTPSWriter destructor");
109
110
    // Deletion of the events has to be made in child destructor.
111
    // Also at this point all CacheChange_t must have been released by the child destructor
112
113
0
    history_->mp_writer = nullptr;
114
0
    history_->mp_mutex = nullptr;
115
0
}
116
117
bool BaseWriter::matched_reader_add(
118
        const SubscriptionBuiltinTopicData& rqos)
119
0
{
120
0
    const auto& alloc = mp_RTPSParticipant->get_attributes().allocation;
121
0
    ReaderProxyData rdata(alloc.data_limits, rqos);
122
123
0
    return matched_reader_add_edp(rdata);
124
0
}
125
126
WriterListener* BaseWriter::get_listener() const
127
0
{
128
0
    return listener_;
129
0
}
130
131
bool BaseWriter::set_listener(
132
        WriterListener* listener)
133
0
{
134
0
    listener_ = listener;
135
0
    return true;
136
0
}
137
138
bool BaseWriter::is_async() const
139
0
{
140
0
    return is_async_;
141
0
}
142
143
int32_t BaseWriter::get_transport_priority() const
144
0
{
145
0
    return transport_priority_;
146
0
}
147
148
void BaseWriter::update_attributes(
149
        const WriterAttributes& att)
150
0
{
151
0
    transport_priority_ = att.transport_priority;
152
0
}
153
154
#ifdef FASTDDS_STATISTICS
155
156
bool BaseWriter::add_statistics_listener(
157
        std::shared_ptr<fastdds::statistics::IListener> listener)
158
0
{
159
0
    return add_statistics_listener_impl(listener);
160
0
}
161
162
bool BaseWriter::remove_statistics_listener(
163
        std::shared_ptr<fastdds::statistics::IListener> listener)
164
0
{
165
0
    return remove_statistics_listener_impl(listener);
166
0
}
167
168
void BaseWriter::set_enabled_statistics_writers_mask(
169
        uint32_t enabled_writers)
170
0
{
171
0
    set_enabled_statistics_writers_mask_impl(enabled_writers);
172
0
}
173
174
#endif // FASTDDS_STATISTICS
175
176
uint32_t BaseWriter::get_max_allowed_payload_size()
177
0
{
178
0
    uint32_t flow_max = flow_controller_->get_max_payload();
179
0
    uint32_t part_max = mp_RTPSParticipant->getMaxMessageSize();
180
0
    uint32_t max_size = flow_max > part_max ? part_max : flow_max;
181
0
    if (max_output_message_size_ < max_size)
182
0
    {
183
0
        max_size = max_output_message_size_;
184
0
    }
185
186
0
    max_size = calculate_max_payload_size(max_size);
187
0
    return max_size &= ~3;
188
0
}
189
190
uint32_t BaseWriter::calculate_max_payload_size(
191
        uint32_t datagram_length)
192
0
{
193
0
    constexpr uint32_t info_dst_message_length = 16;
194
0
    constexpr uint32_t info_ts_message_length = 12;
195
0
    constexpr uint32_t data_frag_submessage_header_length = 36;
196
0
    constexpr uint32_t heartbeat_message_length = 32;
197
198
0
    uint32_t max_data_size = mp_RTPSParticipant->calculateMaxDataSize(datagram_length);
199
0
    uint32_t overhead = info_dst_message_length +
200
0
            info_ts_message_length +
201
0
            data_frag_submessage_header_length +
202
0
            heartbeat_message_length;
203
204
#if HAVE_SECURITY
205
    if (getAttributes().security_attributes().is_submessage_protected)
206
    {
207
        overhead += mp_RTPSParticipant->security_manager().calculate_extra_size_for_rtps_submessage(m_guid);
208
    }
209
210
    if (getAttributes().security_attributes().is_payload_protected)
211
    {
212
        overhead += mp_RTPSParticipant->security_manager().calculate_extra_size_for_encoded_payload(m_guid);
213
    }
214
#endif // if HAVE_SECURITY
215
216
0
#ifdef FASTDDS_STATISTICS
217
0
    overhead += eprosima::fastdds::statistics::rtps::statistics_submessage_length;
218
0
#endif // FASTDDS_STATISTICS
219
220
0
    constexpr uint32_t min_fragment_size = 4;
221
0
    if ((overhead + min_fragment_size) > max_data_size)
222
0
    {
223
0
        auto min_datagram_length = overhead + min_fragment_size + 1 + (datagram_length - max_data_size);
224
0
        EPROSIMA_LOG_ERROR(RTPS_WRITER, "Datagram length '" << datagram_length << "' is too small."
225
0
                                                            << "At least " << min_datagram_length
226
0
                                                            <<
227
0
                " bytes are needed to send a message. Fixing fragments to "
228
0
                                                            << min_fragment_size << " bytes.");
229
0
        return min_fragment_size;
230
0
    }
231
232
0
    max_data_size -= overhead;
233
0
    return max_data_size;
234
0
}
235
236
void BaseWriter::add_statistics_sent_submessage(
237
        CacheChange_t* change,
238
        size_t num_locators)
239
0
{
240
0
    static_cast<void>(change);
241
0
    static_cast<void>(num_locators);
242
243
0
#ifdef FASTDDS_STATISTICS
244
0
    change->writer_info.num_sent_submessages += num_locators;
245
0
    on_data_generated(num_locators);
246
0
#endif // ifdef FASTDDS_STATISTICS
247
0
}
248
249
bool BaseWriter::send_nts(
250
        const std::vector<eprosima::fastdds::rtps::NetworkBuffer>& buffers,
251
        const uint32_t& total_bytes,
252
        const LocatorSelectorSender& locator_selector,
253
        std::chrono::steady_clock::time_point& max_blocking_time_point) const
254
0
{
255
0
    RTPSParticipantImpl* participant = get_participant_impl();
256
257
0
    return locator_selector.locator_selector.selected_size() == 0 ||
258
0
           participant->sendSync(buffers, total_bytes, m_guid, locator_selector.locator_selector.begin(),
259
0
                   locator_selector.locator_selector.end(), max_blocking_time_point, transport_priority_);
260
0
}
261
262
const dds::LivelinessQosPolicyKind& BaseWriter::get_liveliness_kind() const
263
0
{
264
0
    return liveliness_kind_;
265
0
}
266
267
const dds::Duration_t& BaseWriter::get_liveliness_lease_duration() const
268
0
{
269
0
    return liveliness_lease_duration_;
270
0
}
271
272
const dds::Duration_t& BaseWriter::get_liveliness_announcement_period() const
273
0
{
274
0
    return liveliness_announcement_period_;
275
0
}
276
277
void BaseWriter::liveliness_lost()
278
0
{
279
0
    std::unique_lock<RecursiveTimedMutex> lock(mp_mutex);
280
281
0
    liveliness_lost_status_.total_count++;
282
0
    liveliness_lost_status_.total_count_change++;
283
0
    if (listener_ != nullptr)
284
0
    {
285
0
        listener_->on_liveliness_lost(this, liveliness_lost_status_);
286
0
    }
287
0
    liveliness_lost_status_.total_count_change = 0u;
288
0
}
289
290
bool BaseWriter::is_datasharing_compatible() const
291
0
{
292
0
    return (m_att.data_sharing_configuration().kind() != dds::OFF);
293
0
}
294
295
bool BaseWriter::is_datasharing_compatible_with(
296
        const dds::DataSharingQosPolicy& qos) const
297
0
{
298
0
    if (!is_datasharing_compatible() || qos.kind() == fastdds::dds::OFF)
299
0
    {
300
0
        return false;
301
0
    }
302
303
0
    for (auto id : qos.domain_ids())
304
0
    {
305
0
        if (std::find(m_att.data_sharing_configuration().domain_ids().begin(),
306
0
                m_att.data_sharing_configuration().domain_ids().end(), id)
307
0
                != m_att.data_sharing_configuration().domain_ids().end())
308
0
        {
309
0
            return true;
310
0
        }
311
0
    }
312
0
    return false;
313
0
}
314
315
SequenceNumber_t BaseWriter::get_seq_num_min()
316
0
{
317
0
    CacheChange_t* change;
318
0
    if (history_->get_min_change(&change) && change != nullptr)
319
0
    {
320
0
        return change->sequenceNumber;
321
0
    }
322
0
    else
323
0
    {
324
0
        return c_SequenceNumber_Unknown;
325
0
    }
326
0
}
327
328
SequenceNumber_t BaseWriter::get_seq_num_max()
329
0
{
330
0
    CacheChange_t* change;
331
0
    if (history_->get_max_change(&change) && change != nullptr)
332
0
    {
333
0
        return change->sequenceNumber;
334
0
    }
335
0
    else
336
0
    {
337
0
        return c_SequenceNumber_Unknown;
338
0
    }
339
0
}
340
341
void BaseWriter::add_guid(
342
        LocatorSelectorSender& locator_selector,
343
        const GUID_t& remote_guid)
344
0
{
345
0
    const GuidPrefix_t& prefix = remote_guid.guidPrefix;
346
0
    locator_selector.all_remote_readers.push_back(remote_guid);
347
0
    if (std::find(locator_selector.all_remote_participants.begin(),
348
0
            locator_selector.all_remote_participants.end(), prefix) ==
349
0
            locator_selector.all_remote_participants.end())
350
0
    {
351
0
        locator_selector.all_remote_participants.push_back(prefix);
352
0
    }
353
0
}
354
355
void BaseWriter::compute_selected_guids(
356
        LocatorSelectorSender& locator_selector)
357
0
{
358
0
    locator_selector.all_remote_readers.clear();
359
0
    locator_selector.all_remote_participants.clear();
360
361
0
    for (LocatorSelectorEntry* entry : locator_selector.locator_selector.transport_starts())
362
0
    {
363
0
        if (entry->enabled)
364
0
        {
365
0
            add_guid(locator_selector, entry->remote_guid);
366
0
        }
367
0
    }
368
0
}
369
370
void BaseWriter::update_cached_info_nts(
371
        LocatorSelectorSender& locator_selector)
372
0
{
373
0
    locator_selector.locator_selector.reset(true);
374
0
    mp_RTPSParticipant->network_factory().select_locators(locator_selector.locator_selector);
375
0
}
376
377
void BaseWriter::init(
378
        const WriterAttributes& att)
379
0
{
380
0
    {
381
0
        const std::string* max_size_property =
382
0
                PropertyPolicyHelper::find_property(att.endpoint.properties, "fastdds.max_message_size");
383
0
        if (max_size_property != nullptr)
384
0
        {
385
0
            try
386
0
            {
387
0
                max_output_message_size_ = std::stoul(*max_size_property);
388
0
            }
389
0
            catch (const std::exception& e)
390
0
            {
391
0
                EPROSIMA_LOG_ERROR(RTPS_WRITER, "Error parsing max_message_size property: " << e.what());
392
0
            }
393
0
        }
394
0
    }
395
396
0
    fixed_payload_size_ = 0;
397
0
    if (history_->m_att.memoryPolicy == PREALLOCATED_MEMORY_MODE)
398
0
    {
399
0
        fixed_payload_size_ = history_->m_att.payloadMaxSize;
400
0
    }
401
402
0
    if (att.endpoint.data_sharing_configuration().kind() != dds::OFF)
403
0
    {
404
0
        std::shared_ptr<WriterPool> pool = std::dynamic_pointer_cast<WriterPool>(history_->get_payload_pool());
405
0
        if (!pool || !pool->init_shared_memory(this, att.endpoint.data_sharing_configuration().shm_directory()))
406
0
        {
407
0
            EPROSIMA_LOG_ERROR(RTPS_WRITER, "Could not initialize DataSharing writer pool");
408
0
        }
409
0
    }
410
0
}
411
412
void BaseWriter::local_actions_on_writer_removed()
413
0
{
414
    // First, unregister changes from FlowController. This action must be protected.
415
0
    {
416
0
        std::lock_guard<RecursiveTimedMutex> guard(mp_mutex);
417
0
        for (auto it = history_->changesBegin(); it != history_->changesEnd(); ++it)
418
0
        {
419
0
            flow_controller_->remove_change(*it, std::chrono::steady_clock::now() + std::chrono::hours(24));
420
0
        }
421
422
0
        for (auto it = history_->changesBegin(); it != history_->changesEnd(); ++it)
423
0
        {
424
0
            history_->release_change(*it);
425
0
        }
426
427
0
        history_->m_changes.clear();
428
0
    }
429
0
    flow_controller_->unregister_writer(this);
430
0
}
431
432
} // namespace rtps
433
} // namespace fastdds
434
} // namespace eprosima