summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/rrparamregistry.h
blob: 01d9059fc2147d2a45e302e08cddc46d991375ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef RRPARAMREGISTRY_H
#define RRPARAMREGISTRY_H

#include <string>

#include <stdint.h>

#include <boost/shared_ptr.hpp>

#include <dns/exceptions.h>

#include <dns/rdata.h>

namespace isc {
namespace dns {

// forward declarations
struct RRParamRegistryImpl;

///
/// \brief A standard DNS module exception that is thrown if a new RR type is
/// being registered with a different type string.
///
class RRTypeExists : public isc::dns::Exception {
public:
    RRTypeExists(const char* file, size_t line, const char* what) :
        isc::dns::Exception(file, line, what) {}
};

///
/// \brief A standard DNS module exception that is thrown if a new RR class is
/// being registered with a different type string.
///
class RRClassExists : public isc::dns::Exception {
public:
    RRClassExists(const char* file, size_t line, const char* what) :
        isc::dns::Exception(file, line, what) {}
};

namespace rdata {
/// \brief The \c AbstractRdataFactory class is an abstract base class to
/// encapsulate a set of Rdata factory methods in a polymorphic way.
///
/// An external developer who wants to introduce a new or experimental RR type
/// is expected to define a corresponding derived class of \c
/// AbstractRdataFactory and register it via \c RRParamRegistry.
///
/// Other users of this API normally do not have to care about this class
/// or its derived classes; this class is generally intended to be used
/// as an internal utility of the API implementation.
class AbstractRdataFactory {
    ///
    /// \name Constructors and Destructor
    ///
    //@{
protected:
    /// The default constructor
    ///
    /// This is intentionally defined as \c protected as this base class should
    /// never be instantiated (except as part of a derived class).
    AbstractRdataFactory() {}
public:
    /// The destructor.
    virtual ~AbstractRdataFactory() {};
    //@}

    ///
    /// \name Factory methods for polymorphic creation.
    ///
    //@{

    /// \brief Create RDATA from a string.
    ///
    /// This method creates from a string an \c Rdata object of specific class
    /// corresponding to the specific derived class of \c AbstractRdataFactory.
    ///
    /// \param rdata_str A string of textual representation of the \c Rdata.
    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
    virtual RdataPtr create(const std::string& rdata_str) const = 0;

    /// \brief Create RDATA from wire-format data.
    ///
    /// This method creates from wire-format binary data an \c Rdata object
    /// of specific class corresponding to the specific derived class of
    /// \c AbstractRdataFactory.
    ///
    /// \param buffer A reference to an \c InputBuffer object storing the
    /// \c Rdata to parse.
    /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
    virtual RdataPtr create(isc::util::InputBuffer& buffer,
                            size_t rdata_len) const = 0;

    /// \brief Create RDATA from another \c Rdata object of the same type.
    ///
    /// This method creates an \c Rdata object of specific class corresponding
    /// to the specific derived class of \c AbstractRdataFactory, copying the
    /// content of the given \c Rdata, \c source.
    ///
    /// \c source must be an object of the concrete derived class corresponding
    /// to the specific derived class of \c AbstractRdataFactory;
    /// otherwise, an exception of class \c std::bad_cast will be thrown.
    ///
    /// \param source A reference to an \c Rdata object whose content is to
    /// be copied to the created \c Rdata object.
    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
    virtual RdataPtr create(const rdata::Rdata& source) const = 0;

    /// \brief Create RDATA using MasterLexer.
    ///
    /// This version of the method defines the entry point of factory
    /// of a specific RR type and class for \c RRParamRegistry::createRdata()
    /// that uses \c MasterLexer.  See its description for the expected
    /// behavior and meaning of the parameters.
    virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
                            MasterLoader::Options options,
                            MasterLoaderCallbacks& callbacks) const = 0;
    //@}
};

///
/// The \c RdataFactoryPtr type is a pointer-like type, pointing to an
/// object of some concrete derived class of \c AbstractRdataFactory.
///
typedef boost::shared_ptr<AbstractRdataFactory> RdataFactoryPtr;
} // end of namespace rdata

///
/// The \c RRParamRegistry class represents a registry of parameters to
/// manipulate DNS resource records (RRs).
///
/// A \c RRParamRegistry class object stores a mapping between RR types or
/// classes and their textual representations.  It will also have knowledge of
/// how to create an RDATA object for a specific pair of RR type and class
/// (not implemented in this version).
///
/// Normal applications that only handle standard DNS protocols won't have to
/// care about this class.  This is mostly an internal class to the DNS library
/// to manage standard parameters.  Some advanced applications may still need
/// to use this class explicitly.  For example, if an application wants to
/// define and use an experimental non-standard RR type, it may want to register
/// related protocol parameters for its convenience.  This class is designed to
/// allow such usage without modifying the library source code or rebuilding
/// the library.
///
/// It is assumed that at most one instance of this class can exist so that
/// the application uses the consistent set of registered parameters.  To ensure
/// this, this class is designed and implemented as a "singleton class": the
/// constructor is intentionally private, and applications must get access to
/// the single instance via the \c getRegistry() static member function.
///
/// In the current implementation, access to the singleton \c RRParamRegistry
/// object is not thread safe.
/// The application should ensure that multiple threads don't race in the
/// first invocation of \c getRegistry(), and, if the registry needs to
/// be changed dynamically, read and write operations are performed
/// exclusively.
/// Since this class should be static in common usage this restriction would
/// be acceptable in practice.
/// In the future, we may extend the implementation so that multiple threads can
/// get access to the registry fully concurrently without any restriction.
///
/// Note: the implementation of this class is incomplete: we should at least
/// add RDATA related parameters.  This will be done in a near future version,
/// at which point some of method signatures will be changed.
class RRParamRegistry {
    ///
    /// \name Constructors and Destructor
    ///
    /// These are intentionally hidden (see the class description).
    //@{
private:
    RRParamRegistry();
    RRParamRegistry(const RRParamRegistry& orig);
    ~RRParamRegistry();
    //@}
public:
    ///
    /// \brief Return the singleton instance of \c RRParamRegistry.
    ///
    /// This method is a unified access point to the singleton instance of
    /// the RR parameter registry (\c RRParamRegistry).
    /// On first invocation it internally constructs an instance of the
    /// \c RRParamRegistry class and returns a reference to it.
    /// This is a static object inside this method and will remain valid
    /// throughout the rest of the application lifetime.
    /// On subsequent calls this method simply returns a reference to the
    /// singleton object.
    ///
    /// If resource allocation fails in the first invocation,
    /// a corresponding standard exception will be thrown.
    /// This method never fails otherwise.  In particular, this method
    /// doesn't throw an exception once the singleton instance is constructed.
    ///
    /// \return A reference to the singleton instance of \c RRParamRegistry.
    static RRParamRegistry& getRegistry();

    ///
    /// \name Registry Update Methods
    ///
    //@{
    ///
    /// \brief Add a set of parameters for a pair of RR type and class.
    ///
    /// This method adds to the registry a specified set of RR parameters,
    /// including mappings between type/class codes and their textual
    /// representations.
    ///
    /// Regarding the mappings between textual representations and integer
    /// codes, this method behaves in the same way as \c addType() and
    /// \c addClass().  That is, it ignores any overriding attempt as
    /// long as the mapping is the same; otherwise the corresponding exception
    /// will be thrown.
    ///
    /// This method provides the strong exception guarantee: unless an
    /// exception is thrown the entire specified set of parameters must be
    /// stored in the registry; if this method throws an exception the
    /// registry will remain in the state before this method is called.
    ///
    /// \param type_string The textual representation of the RR type.
    /// \param type_code The integer code of the RR type.
    /// \param class_string The textual representation of the RR class.
    /// \param class_code The integer code of the RR class.
    /// \param rdata_factory An \c RdataFactoryPtr object pointing to a
    /// concrete RDATA factory.
    void add(const std::string& type_string, uint16_t type_code,
             const std::string& class_string, uint16_t class_code,
             rdata::RdataFactoryPtr rdata_factory);

    /// \brief Add a set of parameters for a class-independent RR type.
    ///
    /// This method behaves as exactly same as the other \c add method except
    /// that it handles class-independent types (such as NS, CNAME, or SOA).
    ///
    /// \param type_string The textual representation of the RR type.
    /// \param type_code The integer code of the RR type.
    /// \param rdata_factory An \c RdataFactoryPtr object pointing to a
    /// concrete RDATA factory.
    void add(const std::string& type_string, uint16_t type_code,
             rdata::RdataFactoryPtr rdata_factory);

    /// \brief Add mappings between RR type code and textual representation.
    ///
    /// This method adds a mapping from the type code of an RR to its textual
    /// representation and the reverse mapping in the registry.
    ///
    /// If the given RR type is already registered with the same textual
    /// representation, this method simply ignores the duplicate mapping;
    /// if the given type is registered and a new pair with a different
    /// textual representation is being added,an exception of class
    /// \c RRTypeExist will be thrown.
    /// To replace an existing mapping with a different textual representation,
    /// the existing one must be removed by the \c removeType() method
    /// beforehand.
    ///
    /// In addition, if resource allocation for the new mapping entries fails,
    /// a corresponding standard exception will be thrown.
    ///
    /// This method provides the strong exception guarantee: unless an exception
    /// is thrown the specified mappings must be stored in the registry
    /// (although it may be an already existing one) on completion of the
    /// method; if this method throws an exception the registry will remain
    /// in the state before this method is called.
    ///
    /// \param type_string The textual representation of the RR type.
    /// \param type_code The integer code of the RR type.
    /// \return \c true if a new mapping is added to the repository; \c false
    /// if the same mapping is already registered.
    bool addType(const std::string& type_string, uint16_t type_code);

    /// \brief Remove mappings between RR type code and textual representation
    /// for a given type.
    ///
    /// This method can safely be called whether or not the specified mappings
    /// exist in the registry.  If not, this method simply ignores the attempt
    /// and returns \c false.
    ///
    /// This method never throws an exception.
    ///
    /// \param type_code The integer code of the RR type.
    /// \return \c true if mappings for the specified RR type exists and is
    /// removed; \c false if no such mapping is in the registry.
    bool removeType(uint16_t type_code);

    /// \brief Add mappings between RR class code and textual representation.
    ///
    /// This method adds a mapping from the class code of an RR to its textual
    /// representation and the reverse mapping in the registry.
    ///
    /// If the given RR class is already registered with the same textual
    /// representation, this method simply ignores the duplicate mapping;
    /// if the given class is registered and a new pair with a different
    /// textual representation is being added,an exception of class
    /// \c RRClassExist will be thrown.
    /// To replace an existing mapping with a different textual representation,
    /// the existing one must be removed by the \c removeClass() method
    /// beforehand.
    ///
    /// In addition, if resource allocation for the new mapping entries fails,
    /// a corresponding standard exception will be thrown.
    ///
    /// This method provides the strong exception guarantee: unless an exception
    /// is thrown the specified mappings must be stored in the registry
    /// (although it may be an already existing one) on completion of the
    /// method; if this method throws an exception the registry will remain
    /// in the state before this method is called.
    ///
    /// \param class_string The textual representation of the RR class.
    /// \param class_code The integer code of the RR class.
    /// \return \c true if a new mapping is added to the repository; \c false
    /// if the same mapping is already registered.
    bool addClass(const std::string& class_string, uint16_t class_code);

    /// \brief Remove mappings between RR class code and textual representation
    /// for a given class.
    ///
    /// This method can safely be called whether or not the specified mappings
    /// exist in the registry.  If not, this method simply ignores the attempt
    /// and returns \c false.
    ///
    /// This method never throws an exception.
    ///
    /// \param class_code The integer code of the RR class.
    /// \return \c true if mappings for the specified RR type exists and is
    /// removed; \c false if no such mapping is in the registry.
    bool removeClass(uint16_t class_code);

    /// \brief Remove registered RDATA factory for the given pair of \c RRType
    /// and \c RRClass.
    ///
    /// This method can safely be called whether or not the specified factory
    /// object exist in the registry.  If not, this method simply ignores the
    /// attempt and returns \c false.
    ///
    /// This method never throws an exception.
    ///
    /// \param rrtype An \c RRType object specifying the type/class pair.
    /// \param rrclass An \c RRClass object specifying the type/class pair.
    /// \return \c true if a factory object for the specified RR type/class
    /// pair exists and is removed; \c false if no such object is in the
    /// registry.
    bool removeRdataFactory(const RRType& rrtype, const RRClass& rrclass);

    /// \brief Remove registered RDATA factory for the given pair of \c RRType
    /// and \c RRClass.
    ///
    /// This method can safely be called whether or not the specified factory
    /// object exist in the registry.  If not, this method simply ignores the
    /// attempt and returns \c false.
    ///
    /// This method never throws an exception.
    ///
    /// \param rrtype An \c RRType object specifying the type/class pair.
    /// \return \c true if a factory object for the specified RR type/class
    /// pair exists and is removed; \c false if no such object is in the
    /// registry.
    bool removeRdataFactory(const RRType& rrtype);
    //@}

    ///
    /// \name Parameter Conversion Methods
    ///
    //@{
    /// \brief Convert a textual representation of an RR type to the
    /// corresponding 16-bit integer code.
    ///
    /// This method searches the \c RRParamRegistry for the mapping from
    /// the given textual representation of RR type to the corresponding
    /// integer code. If a mapping is found, it returns true with the
    /// associated type code in \c type_code; otherwise, if the given
    /// string is in the form of "TYPEnnnn", it returns true with the
    /// corresponding number as the type code in \c type_code;
    /// otherwise, it returns false and \c type_code is untouched.
    ///
    /// It returns \c false and avoids throwing an exception in the case
    /// of an error to avoid the exception overhead in some situations.
    ///
    /// \param type_string The textual representation of the RR type.
    /// \param type_code Returns the RR type code in this argument.
    /// \return true if conversion is successful, false otherwise.
    bool textToTypeCode(const std::string& type_string,
                        uint16_t& type_code) const;

    /// \brief Convert type code into its textual representation.
    ///
    /// This method searches the \c RRParamRegistry for the mapping from the
    /// given RR type code to its textual representation.
    /// If a mapping is found, it returns (a copy of) the associated string;
    /// otherwise, this method creates a new string in the form of "TYPEnnnn"
    /// where "nnnn" is the decimal representation of the type code, and
    /// returns the new string.
    ///
    /// If resource allocation for the returned string fails,
    /// a corresponding standard exception will be thrown.
    /// This method never fails otherwise.
    ///
    /// \param type_code The integer code of the RR type.
    /// \return A textual representation of the RR type for code \c type_code.
    std::string codeToTypeText(uint16_t type_code) const;

    /// \brief Convert a textual representation of an RR class to the
    /// corresponding 16-bit integer code.
    ///
    /// This method searches the \c RRParamRegistry for the mapping from
    /// the given textual representation of RR class to the
    /// corresponding integer code.  If a mapping is found, it returns
    /// true with the associated class code in \c class_code; otherwise,
    /// if the given string is in the form of "CLASSnnnn", it returns
    /// true with the corresponding number as the class code in
    /// \c class_code; otherwise, it returns false and \c class_code is
    /// untouched.
    ///
    /// It returns \c false and avoids throwing an exception in the case
    /// of an error to avoid the exception overhead in some situations.
    ///
    /// \param class_string The textual representation of the RR class.
    /// \param class_code Returns the RR class code in this argument.
    /// \return true if conversion is successful, false otherwise.
    bool textToClassCode(const std::string& class_string,
                         uint16_t& class_code) const;

    /// \brief Convert class code into its textual representation.
    ///
    /// This method searches the \c RRParamRegistry for the mapping from the
    /// given RR class code to its textual representation.
    /// If a mapping is found, it returns (a copy of) the associated string;
    /// otherwise, this method creates a new string in the form of "CLASSnnnn"
    /// where "nnnn" is the decimal representation of the class code, and
    /// returns the new string.
    ///
    /// If resource allocation for the returned string fails,
    /// a corresponding standard exception will be thrown.
    /// This method never fails otherwise.
    ///
    /// \param class_code The integer code of the RR class.
    /// \return A textual representation of the RR class for code \c class_code.
    std::string codeToClassText(uint16_t class_code) const;
    //@}

    ///
    /// \name RDATA Factories
    ///
    /// This set of methods provide a unified interface to create an
    /// \c rdata::Rdata object in a parameterized polymorphic way,
    /// that is, these methods take a pair of \c RRType and \c RRClass
    /// objects and data specific to that pair, and create an object of
    /// the corresponding concrete derived class of \c rdata::Rdata.
    ///
    /// These methods first search the \c RRParamRegistry for a factory
    /// method (a member of a concrete derived class of
    /// \c AbstractRdataFactory) for the given RR type and class pair.
    /// If the search fails, they then search for a factory method for
    /// the given type ignoring the class, in case a RRClass independent
    /// factory method is registered.
    /// If it still fails, these methods assume the RDATA is of an "unknown"
    /// type, and creates a new object by calling a constructor of the
    /// \c rdata::generic::Generic class.
    ///
    //@{
    /// \brief Create RDATA of a given pair of RR type and class from a string.
    ///
    /// This method creates from a string an \c Rdata object of the given pair
    /// of RR type and class.
    ///
    /// \param rrtype An \c RRType object specifying the type/class pair.
    /// \param rrclass An \c RRClass object specifying the type/class pair.
    /// \param rdata_string A string of textual representation of the \c Rdata.
    /// \return An \c rdata::RdataPtr object pointing to the created \c Rdata
    /// object.
    rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                const std::string& rdata_string);
    /// \brief Create RDATA of a given pair of RR type and class from
    /// wire-format data.
    ///
    /// This method creates from wire-format binary data an \c Rdata object
    /// of the given pair of RR type and class.
    ///
    /// \param rrtype An \c RRType object specifying the type/class pair.
    /// \param rrclass An \c RRClass object specifying the type/class pair.
    /// \param buffer A reference to an \c InputBuffer object storing the
    /// \c Rdata to parse.
    /// \param len The length in buffer of the \c Rdata.  In bytes.
    /// \return An \c rdata::RdataPtr object pointing to the created \c Rdata
    /// object.
    rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                isc::util::InputBuffer& buffer, size_t len);
    /// \brief Create RDATA of a given pair of RR type and class, copying
    /// of another RDATA of same kind.
    ///
    /// This method creates an \c Rdata object of the given pair of
    /// RR type and class, copying the  content of the given \c Rdata,
    /// \c source.
    ///
    /// \c source must be an object of the concrete derived class of
    /// \c rdata::Rdata for the given pair of RR type and class;
    /// otherwise, an exception of class \c std::bad_cast will be thrown.
    /// In case the \c RRParamRegistry doesn't have a factory method for
    /// the given pair and it is assumed to be of an "unknown" type,
    /// \c source must reference an object of class
    /// \c rdata::generic::Generic; otherwise, an exception of class
    /// \c std::bad_cast will be thrown.
    ///
    /// \param rrtype An \c RRType object specifying the type/class pair.
    /// \param rrclass An \c RRClass object specifying the type/class pair.
    /// \param source A reference to an \c rdata::Rdata object whose content
    /// is to be copied to the created \c rdata::Rdata object.
    /// \return An \c rdata::RdataPtr object pointing to the created
    /// \c rdata::Rdata object.
    rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                const rdata::Rdata& source);

    /// \brief Create RDATA using MasterLexer
    ///
    /// This method is expected to be used as the underlying implementation
    /// of the same signature of \c rdata::createRdata().  One main
    /// difference is that this method is only responsible for constructing
    /// the Rdata; it doesn't update the lexer to reach the end of line or
    /// file or doesn't care about whether there's an extra (garbage) token
    /// after the textual RDATA representation.  Another difference is that
    /// this method can throw on error and never returns a null pointer.
    ///
    /// For other details and parameters, see the description of
    /// \c rdata::createRdata().
    rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                MasterLexer& lexer, const Name* origin,
                                MasterLoader::Options options,
                                MasterLoaderCallbacks& callbacks);
    //@}

private:
    boost::shared_ptr<RRParamRegistryImpl> impl_;
};

}
}
#endif  // RRPARAMREGISTRY_H