/src/Fast-DDS/include/fastdds/rtps/common/Locator.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2016 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 Locator.hpp |
17 | | */ |
18 | | |
19 | | #ifndef FASTDDS_RTPS_COMMON__LOCATOR_HPP |
20 | | #define FASTDDS_RTPS_COMMON__LOCATOR_HPP |
21 | | |
22 | | #include <algorithm> |
23 | | #include <cstdint> |
24 | | #include <cstring> |
25 | | #include <iomanip> |
26 | | #include <sstream> |
27 | | #include <vector> |
28 | | |
29 | | #include <fastdds/config.hpp> |
30 | | #include <fastdds/dds/log/Log.hpp> |
31 | | #include <fastdds/fastdds_dll.hpp> |
32 | | #include <fastdds/rtps/common/Types.hpp> |
33 | | #include <fastdds/utils/IPLocator.hpp> |
34 | | |
35 | | namespace eprosima { |
36 | | namespace fastdds { |
37 | | namespace rtps { |
38 | | |
39 | | /// Initialize locator with invalid values |
40 | 0 | #define LOCATOR_INVALID(loc) {loc.kind = LOCATOR_KIND_INVALID; loc.port = LOCATOR_PORT_INVALID; \ |
41 | 0 | LOCATOR_ADDRESS_INVALID(loc.address); \ |
42 | 0 | } |
43 | | /// Invalid locator kind |
44 | 0 | #define LOCATOR_KIND_INVALID -1 |
45 | | |
46 | | /// Set locator IP address to 0 |
47 | 63 | #define LOCATOR_ADDRESS_INVALID(a) {std::memset(a, 0x00, 16 * sizeof(octet));} |
48 | | |
49 | | /// Invalid locator port |
50 | 0 | #define LOCATOR_PORT_INVALID 0 |
51 | | |
52 | | /// Reserved locator kind |
53 | | #define LOCATOR_KIND_RESERVED 0 |
54 | | /// UDP over IPv4 locator kind |
55 | 63 | #define LOCATOR_KIND_UDPv4 1 |
56 | | /// UDP over IPv6 locator kind |
57 | 0 | #define LOCATOR_KIND_UDPv6 2 |
58 | | /// TCP over IPv4 kind |
59 | 0 | #define LOCATOR_KIND_TCPv4 4 |
60 | | /// TCP over IPv6 locator kind |
61 | 0 | #define LOCATOR_KIND_TCPv6 8 |
62 | | /// Shared memory locator kind |
63 | 328 | #define LOCATOR_KIND_SHM 16 + FASTDDS_VERSION_MAJOR |
64 | | |
65 | | /** |
66 | | * @brief Class Locator_t, uniquely identifies a communication channel for a particular transport. |
67 | | * For example, an address + port combination in the case of UDP. |
68 | | * @ingroup COMMON_MODULE |
69 | | */ |
70 | | class FASTDDS_EXPORTED_API Locator_t |
71 | | { |
72 | | public: |
73 | | |
74 | | /** |
75 | | * @brief Specifies the locator type. Valid values are: |
76 | | * |
77 | | * LOCATOR_KIND_UDPv4 |
78 | | * |
79 | | * LOCATOR_KIND_UDPv6 |
80 | | * |
81 | | * LOCATOR_KIND_TCPv4 |
82 | | * |
83 | | * LOCATOR_KIND_TCPv6 |
84 | | * |
85 | | * LOCATOR_KIND_SHM |
86 | | */ |
87 | | int32_t kind; |
88 | | /// Network port |
89 | | uint32_t port; |
90 | | /// IP address |
91 | | octet address[16]; |
92 | | |
93 | | /// Default constructor |
94 | | Locator_t() |
95 | 63 | : kind(LOCATOR_KIND_UDPv4) |
96 | 63 | { |
97 | 63 | port = 0; |
98 | 63 | LOCATOR_ADDRESS_INVALID(address); |
99 | 63 | } |
100 | | |
101 | | /// Move constructor |
102 | | Locator_t( |
103 | | Locator_t&& loc) |
104 | 0 | : kind(loc.kind) |
105 | 0 | { |
106 | 0 | port = loc.port; |
107 | 0 | std::memcpy(address, loc.address, 16 * sizeof(octet)); |
108 | 0 | } |
109 | | |
110 | | /// Copy constructor |
111 | | Locator_t( |
112 | | const Locator_t& loc) |
113 | 0 | : kind(loc.kind) |
114 | 0 | { |
115 | 0 | port = loc.port; |
116 | 0 | std::memcpy(address, loc.address, 16 * sizeof(octet)); |
117 | 0 | } |
118 | | |
119 | | /// Port constructor |
120 | | Locator_t( |
121 | | uint32_t portin) |
122 | 0 | : kind(LOCATOR_KIND_UDPv4) |
123 | 0 | { |
124 | 0 | port = portin; |
125 | 0 | LOCATOR_ADDRESS_INVALID(address); |
126 | 0 | } |
127 | | |
128 | | /// Kind and port constructor |
129 | | Locator_t( |
130 | | int32_t kindin, |
131 | | uint32_t portin) |
132 | 0 | : kind(kindin) |
133 | 0 | { |
134 | 0 | port = portin; |
135 | 0 | LOCATOR_ADDRESS_INVALID(address); |
136 | 0 | } |
137 | | |
138 | | /// Copy assignment |
139 | | Locator_t& operator =( |
140 | | const Locator_t& loc) |
141 | 0 | { |
142 | 0 | kind = loc.kind; |
143 | 0 | port = loc.port; |
144 | 0 | std::memcpy(address, loc.address, 16 * sizeof(octet)); |
145 | 0 | return *this; |
146 | 0 | } |
147 | | |
148 | | /** |
149 | | * @brief Set the locator IP address using another locator. |
150 | | * |
151 | | * @param other Locator which IP address is used to set this locator IP address. |
152 | | * @return always true. |
153 | | */ |
154 | | bool set_address( |
155 | | const Locator_t& other) |
156 | 0 | { |
157 | 0 | memcpy(address, other.address, sizeof(octet) * 16); |
158 | 0 | return true; |
159 | 0 | } |
160 | | |
161 | | /** |
162 | | * @brief Getter for the locator IP address. |
163 | | * |
164 | | * @return IP address as octet pointer. |
165 | | */ |
166 | | octet* get_address() |
167 | 0 | { |
168 | 0 | return address; |
169 | 0 | } |
170 | | |
171 | | /** |
172 | | * @brief Getter for a specific field of the locator IP address. |
173 | | * |
174 | | * @param field IP address element to be accessed. |
175 | | * @return Octet value for the specific IP address element. |
176 | | */ |
177 | | octet get_address( |
178 | | uint16_t field) const |
179 | 0 | { |
180 | 0 | return address[field]; |
181 | 0 | } |
182 | | |
183 | | /** |
184 | | * @brief Automatic setter for setting locator IP address to invalid address (0). |
185 | | */ |
186 | | void set_Invalid_Address() |
187 | 0 | { |
188 | 0 | LOCATOR_ADDRESS_INVALID(address); |
189 | 0 | } |
190 | | |
191 | | }; |
192 | | |
193 | | /** |
194 | | * @brief Auxiliary method to check that IP address is not invalid (0). |
195 | | * |
196 | | * @param loc Locator which IP address is going to be checked. |
197 | | * @return true if IP address is defined (not 0). |
198 | | * @return false otherwise. |
199 | | */ |
200 | | inline bool IsAddressDefined( |
201 | | const Locator_t& loc) |
202 | 0 | { |
203 | 0 | if (loc.kind == LOCATOR_KIND_UDPv4 || loc.kind == LOCATOR_KIND_TCPv4) // WAN addr in TCPv4 is optional, isn't? |
204 | 0 | { |
205 | 0 | for (uint8_t i = 12; i < 16; ++i) |
206 | 0 | { |
207 | 0 | if (loc.address[i] != 0) |
208 | 0 | { |
209 | 0 | return true; |
210 | 0 | } |
211 | 0 | } |
212 | 0 | } |
213 | 0 | else if (loc.kind == LOCATOR_KIND_UDPv6 || loc.kind == LOCATOR_KIND_TCPv6) |
214 | 0 | { |
215 | 0 | for (uint8_t i = 0; i < 16; ++i) |
216 | 0 | { |
217 | 0 | if (loc.address[i] != 0) |
218 | 0 | { |
219 | 0 | return true; |
220 | 0 | } |
221 | 0 | } |
222 | 0 | } |
223 | 0 | return false; |
224 | 0 | } |
225 | | |
226 | | /** |
227 | | * @brief Auxiliary method to check that locator kind is not LOCATOR_KIND_INVALID (-1). |
228 | | * |
229 | | * @param loc Locator to be checked. |
230 | | * @return true if the locator kind is not LOCATOR_KIND_INVALID. |
231 | | * @return false otherwise. |
232 | | */ |
233 | | inline bool IsLocatorValid( |
234 | | const Locator_t& loc) |
235 | 0 | { |
236 | 0 | return (0 <= loc.kind); |
237 | 0 | } |
238 | | |
239 | | /** |
240 | | * @brief Less than operator. |
241 | | * |
242 | | * @param loc1 Left hand side locator being compared. |
243 | | * @param loc2 Right hand side locator being compared. |
244 | | * @return true if \c loc1 is less than \c loc2. |
245 | | * @return false otherwise. |
246 | | */ |
247 | | inline bool operator <( |
248 | | const Locator_t& loc1, |
249 | | const Locator_t& loc2) |
250 | 0 | { |
251 | 0 | return memcmp(&loc1, &loc2, sizeof(Locator_t)) < 0; |
252 | 0 | } |
253 | | |
254 | | /** |
255 | | * @brief Equal to operator. |
256 | | * |
257 | | * @param loc1 Left hand side locator being compared. |
258 | | * @param loc2 Right hand side locator being compared. |
259 | | * @return true if \c loc1 is equal to \c loc2. |
260 | | * @return false otherwise. |
261 | | */ |
262 | | inline bool operator ==( |
263 | | const Locator_t& loc1, |
264 | | const Locator_t& loc2) |
265 | 0 | { |
266 | 0 | if (loc1.kind != loc2.kind) |
267 | 0 | { |
268 | 0 | return false; |
269 | 0 | } |
270 | 0 | if (loc1.port != loc2.port) |
271 | 0 | { |
272 | 0 | return false; |
273 | 0 | } |
274 | 0 | if (!std::equal(loc1.address, loc1.address + 16, loc2.address)) |
275 | 0 | { |
276 | 0 | return false; |
277 | 0 | } |
278 | 0 | return true; |
279 | 0 | } |
280 | | |
281 | | /** |
282 | | * @brief Not equal to operator. |
283 | | * |
284 | | * @param loc1 Left hand side locator being compared. |
285 | | * @param loc2 Right hand side locator being compared. |
286 | | * @return true if \c loc1 is not equal to \c loc2. |
287 | | * @return false otherwise. |
288 | | */ |
289 | | inline bool operator !=( |
290 | | const Locator_t& loc1, |
291 | | const Locator_t& loc2) |
292 | 0 | { |
293 | 0 | return !(loc1 == loc2); |
294 | 0 | } |
295 | | |
296 | | /** |
297 | | * @brief Insertion operator: serialize a locator |
298 | | * The serialization format is kind:[address]:port |
299 | | * \c kind must be one of the following: |
300 | | * - UDPv4 |
301 | | * - UDPv6 |
302 | | * - TCPv4 |
303 | | * - TCPv6 |
304 | | * - SHM |
305 | | * \c address IP address unless \c kind is SHM |
306 | | * \c port number |
307 | | * |
308 | | * @param output Output stream where the serialized locator is appended. |
309 | | * @param loc Locator to be serialized/inserted. |
310 | | * @return \c std::ostream& Reference to the output stream with the serialized locator appended. |
311 | | */ |
312 | | inline std::ostream& operator <<( |
313 | | std::ostream& output, |
314 | | const Locator_t& loc) |
315 | 0 | { |
316 | | // Stream Locator kind |
317 | 0 | switch (loc.kind) |
318 | 0 | { |
319 | 0 | case LOCATOR_KIND_TCPv4: |
320 | 0 | { |
321 | 0 | output << "TCPv4:["; |
322 | 0 | break; |
323 | 0 | } |
324 | 0 | case LOCATOR_KIND_UDPv4: |
325 | 0 | { |
326 | 0 | output << "UDPv4:["; |
327 | 0 | break; |
328 | 0 | } |
329 | 0 | case LOCATOR_KIND_TCPv6: |
330 | 0 | { |
331 | 0 | output << "TCPv6:["; |
332 | 0 | break; |
333 | 0 | } |
334 | 0 | case LOCATOR_KIND_UDPv6: |
335 | 0 | { |
336 | 0 | output << "UDPv6:["; |
337 | 0 | break; |
338 | 0 | } |
339 | 0 | case LOCATOR_KIND_SHM: |
340 | 0 | { |
341 | 0 | output << "SHM:["; |
342 | 0 | break; |
343 | 0 | } |
344 | 0 | default: |
345 | 0 | { |
346 | 0 | output << "Invalid_locator:[_]:0"; |
347 | 0 | return output; |
348 | 0 | } |
349 | 0 | } |
350 | | |
351 | | // Stream address |
352 | 0 | if (loc.kind == LOCATOR_KIND_UDPv4 || loc.kind == LOCATOR_KIND_TCPv4) |
353 | 0 | { |
354 | 0 | output << IPLocator::toIPv4string(loc); |
355 | 0 | } |
356 | 0 | else if (loc.kind == LOCATOR_KIND_UDPv6 || loc.kind == LOCATOR_KIND_TCPv6) |
357 | 0 | { |
358 | 0 | output << IPLocator::toIPv6string(loc); |
359 | 0 | } |
360 | 0 | else if (loc.kind == LOCATOR_KIND_SHM) |
361 | 0 | { |
362 | 0 | if (loc.address[0] == 'M') |
363 | 0 | { |
364 | 0 | output << "M"; |
365 | 0 | } |
366 | 0 | else |
367 | 0 | { |
368 | 0 | output << "_"; |
369 | 0 | } |
370 | 0 | } |
371 | | |
372 | | // Stream port |
373 | 0 | if (loc.kind == LOCATOR_KIND_TCPv4 || loc.kind == LOCATOR_KIND_TCPv6) |
374 | 0 | { |
375 | 0 | output << "]:" << std::to_string(IPLocator::getPhysicalPort(loc)) << "-" << std::to_string(IPLocator::getLogicalPort( |
376 | 0 | loc)); |
377 | 0 | } |
378 | 0 | else |
379 | 0 | { |
380 | 0 | output << "]:" << loc.port; |
381 | 0 | } |
382 | |
|
383 | 0 | return output; |
384 | 0 | } |
385 | | |
386 | | /** |
387 | | * @brief Extraction operator: deserialize a locator |
388 | | * The deserialization format is kind:[address]:port |
389 | | * \c kind must be one of the following: |
390 | | * - UDPv4 |
391 | | * - UDPv6 |
392 | | * - TCPv4 |
393 | | * - TCPv6 |
394 | | * - SHM |
395 | | * \c address must be either a name which can be resolved by DNS or the IP address unless \c kind is SHM |
396 | | * \c port number |
397 | | * |
398 | | * @param input Input stream where the locator to be deserialized is located. |
399 | | * @param loc Locator where the deserialized locator is saved. |
400 | | * @return \c std::istream& Reference to the input stream after extracting the locator. |
401 | | */ |
402 | | inline std::istream& operator >>( |
403 | | std::istream& input, |
404 | | Locator_t& loc) |
405 | 0 | { |
406 | 0 | std::istream::sentry s(input); |
407 | |
|
408 | 0 | if (s) |
409 | 0 | { |
410 | 0 | std::ios_base::iostate excp_mask = input.exceptions(); |
411 | |
|
412 | 0 | try |
413 | 0 | { |
414 | 0 | input.exceptions(excp_mask | std::ios_base::failbit | std::ios_base::badbit); |
415 | | |
416 | | // Locator info |
417 | 0 | int32_t kind; |
418 | 0 | uint32_t port; |
419 | 0 | std::string address; |
420 | | |
421 | | // Deserialization variables |
422 | 0 | std::stringbuf sb_kind; |
423 | 0 | std::stringbuf sb_address; |
424 | 0 | std::string str_kind; |
425 | 0 | char punct; |
426 | | |
427 | | // Check the locator kind |
428 | 0 | input.get(sb_kind, ':'); |
429 | 0 | str_kind = sb_kind.str(); |
430 | |
|
431 | 0 | if (str_kind == "SHM") |
432 | 0 | { |
433 | 0 | kind = LOCATOR_KIND_SHM; |
434 | 0 | } |
435 | 0 | else if (str_kind == "TCPv4") |
436 | 0 | { |
437 | 0 | kind = LOCATOR_KIND_TCPv4; |
438 | 0 | } |
439 | 0 | else if (str_kind == "TCPv6") |
440 | 0 | { |
441 | 0 | kind = LOCATOR_KIND_TCPv6; |
442 | 0 | } |
443 | 0 | else if (str_kind == "UDPv4") |
444 | 0 | { |
445 | 0 | kind = LOCATOR_KIND_UDPv4; |
446 | 0 | } |
447 | 0 | else if (str_kind == "UDPv6") |
448 | 0 | { |
449 | 0 | kind = LOCATOR_KIND_UDPv6; |
450 | 0 | } |
451 | 0 | else |
452 | 0 | { |
453 | 0 | kind = LOCATOR_KIND_INVALID; |
454 | 0 | loc.kind = LOCATOR_KIND_INVALID; |
455 | 0 | } |
456 | |
|
457 | 0 | if (kind != LOCATOR_KIND_INVALID) |
458 | 0 | { |
459 | | // Get chars :[ |
460 | 0 | input >> punct >> punct; |
461 | | |
462 | | // Get address in string |
463 | 0 | input.get(sb_address, ']'); |
464 | 0 | address = sb_address.str(); |
465 | | |
466 | | // check if this is a valid IPv4 or IPv6 and call DNS if not |
467 | 0 | if ((kind == LOCATOR_KIND_UDPv4 || kind == LOCATOR_KIND_TCPv4) && |
468 | 0 | !IPLocator::isIPv4(address)) |
469 | 0 | { |
470 | 0 | auto addresses = IPLocator::resolveNameDNS(address); |
471 | 0 | if (addresses.first.empty()) |
472 | 0 | { |
473 | 0 | loc.kind = LOCATOR_KIND_INVALID; |
474 | 0 | EPROSIMA_LOG_WARNING(LOCATOR, "Error deserializing Locator"); |
475 | 0 | return input; |
476 | 0 | } |
477 | 0 | address = *addresses.first.begin(); |
478 | 0 | } |
479 | 0 | if ((kind == LOCATOR_KIND_UDPv6 || kind == LOCATOR_KIND_TCPv6) && |
480 | 0 | !IPLocator::isIPv6(address)) |
481 | 0 | { |
482 | 0 | auto addresses = IPLocator::resolveNameDNS(address); |
483 | 0 | if (addresses.second.empty()) |
484 | 0 | { |
485 | 0 | loc.kind = LOCATOR_KIND_INVALID; |
486 | 0 | EPROSIMA_LOG_WARNING(LOCATOR, "Error deserializing Locator"); |
487 | 0 | return input; |
488 | 0 | } |
489 | 0 | address = *addresses.second.begin(); |
490 | 0 | } |
491 | | |
492 | | // Get char ]: |
493 | 0 | input >> punct >> punct; |
494 | | |
495 | | // Get port |
496 | 0 | input >> port; |
497 | |
|
498 | 0 | IPLocator::createLocator(kind, address, port, loc); |
499 | 0 | } |
500 | 0 | } |
501 | 0 | catch (std::ios_base::failure& ) |
502 | 0 | { |
503 | 0 | loc.kind = LOCATOR_KIND_INVALID; |
504 | 0 | EPROSIMA_LOG_WARNING(LOCATOR, "Error deserializing Locator"); |
505 | 0 | } |
506 | | |
507 | 0 | input.exceptions(excp_mask); |
508 | 0 | } |
509 | 0 | return input; |
510 | 0 | } |
511 | | |
512 | | typedef std::vector<Locator_t>::iterator LocatorListIterator; |
513 | | typedef std::vector<Locator_t>::const_iterator LocatorListConstIterator; |
514 | | |
515 | | } // namespace rtps |
516 | | } // namespace fastdds |
517 | | } // namespace eprosima |
518 | | |
519 | | namespace eprosima { |
520 | | namespace fastdds { |
521 | | namespace rtps { |
522 | | |
523 | | using Locator = eprosima::fastdds::rtps::Locator_t; |
524 | | |
525 | | } // namespace rtps |
526 | | } // namespace fastdds |
527 | | } // namespace eprosima |
528 | | |
529 | | #endif // FASTDDS_RTPS_COMMON__LOCATOR_HPP |