Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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