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