Coverage Report

Created: 2025-06-13 06:46

/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