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