Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
5b7ac017
Commit
5b7ac017
authored
Jul 20, 2012
by
JINMEI Tatuya
Browse files
[2091a] added revised version of LabelSequence (de)serialization
parent
9cc4ac55
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/lib/dns/labelsequence.cc
View file @
5b7ac017
...
...
@@ -51,6 +51,37 @@ LabelSequence::LabelSequence(const uint8_t* data,
}
}
LabelSequence
::
LabelSequence
(
const
void
*
buf
)
{
if
(
buf
==
NULL
)
{
isc_throw
(
BadValue
,
"Null pointer passed to LabelSequence constructor"
);
}
const
uint8_t
*
bp
=
reinterpret_cast
<
const
uint8_t
*>
(
buf
);
first_label_
=
0
;
const
uint8_t
offsets_len
=
*
bp
++
;
if
(
offsets_len
==
0
||
offsets_len
>
Name
::
MAX_LABELS
)
{
isc_throw
(
BadValue
,
"Bad offsets len in serialized LabelSequence data: "
<<
static_cast
<
unsigned
int
>
(
offsets_len
));
}
last_label_
=
offsets_len
-
1
;
offsets_
=
bp
;
data_
=
bp
+
offsets_len
;
// Check the integrity on the offsets and the name data
const
uint8_t
*
dp
=
data_
;
for
(
size_t
cur_offset
=
0
;
cur_offset
<
offsets_len
;
++
cur_offset
)
{
if
(
offsets_
[
cur_offset
]
>
Name
::
MAX_LABELLEN
||
dp
-
data_
!=
offsets_
[
cur_offset
])
{
isc_throw
(
BadValue
,
"Broken offset or name data in serialized "
"LabelSequence data"
);
}
dp
+=
(
1
+
*
dp
);
}
}
const
uint8_t
*
LabelSequence
::
getData
(
size_t
*
len
)
const
{
...
...
@@ -74,6 +105,33 @@ LabelSequence::getDataLength() const {
return
(
offsets_
[
last_label_
]
-
offsets_
[
first_label_
]
+
last_label_len
);
}
size_t
LabelSequence
::
getSerializedLength
()
const
{
return
(
1
+
getLabelCount
()
+
getDataLength
());
}
void
LabelSequence
::
serialize
(
void
*
buf
,
size_t
buf_len
)
const
{
const
size_t
expected_size
=
getSerializedLength
();
if
(
expected_size
>
buf_len
)
{
isc_throw
(
BadValue
,
"buffer too short for LabelSequence::serialize"
);
}
const
size_t
offsets_len
=
getLabelCount
();
assert
(
offsets_len
<
256
);
// should be in the 8-bit range
uint8_t
*
bp
=
reinterpret_cast
<
uint8_t
*>
(
buf
);
*
bp
++
=
offsets_len
;
for
(
size_t
i
=
0
;
i
<
offsets_len
;
++
i
)
{
*
bp
++
=
offsets_
[
first_label_
+
i
]
-
offsets_
[
first_label_
];
}
const
size_t
ndata_len
=
getDataLength
();
memcpy
(
bp
,
&
data_
[
offsets_
[
first_label_
]],
ndata_len
);
bp
+=
ndata_len
;
assert
(
bp
-
reinterpret_cast
<
const
uint8_t
*>
(
buf
)
==
expected_size
);
}
bool
LabelSequence
::
equals
(
const
LabelSequence
&
other
,
bool
case_sensitive
)
const
{
size_t
len
,
other_len
;
...
...
src/lib/dns/labelsequence.h
View file @
5b7ac017
...
...
@@ -79,6 +79,24 @@ public:
const
uint8_t
*
offsets
,
size_t
offsets_size
);
/// \brief Constructor from serialized image.
///
/// This constructor restores a \c LabelSequence object from a serialized
/// binary image previously generated by \c serialize(). Any other input
/// to this constructor will result in undefined behavior.
///
/// The binary data passed to this constructor MUST remain in scope and
/// MUST NOT be modified during the lifetime of this LabelSequence.
///
/// As long as the data were previously generated by a call to
/// \c serialize() on a valid \c LabelSequence object, this constructor
/// should succeed. While any other case is undefined, this constructor
/// may perform some validity checks internally for safety. Nevertheless,
/// applications must not rely on such checks.
///
/// \param buf Pointer to the serialized image generated by \c serialize().
explicit
LabelSequence
(
const
void
*
buf
);
/// \brief Copy constructor.
///
/// \note The associated data MUST remain in scope during the lifetime
...
...
@@ -136,6 +154,52 @@ public:
/// \return The length of the data of the label sequence in octets.
size_t
getDataLength
()
const
;
/// \brief Max possible size of serialized image generated by \c serialize
///
/// A fixed length buffer of this size can be always passed to
/// \c serialize() safely. (But the application shouldn't use the
/// specific size value; it must use this constant variable).
static
const
size_t
MAX_SERIALIZED_LENGTH
=
Name
::
MAX_WIRE
+
Name
::
MAX_LABELS
+
1
;
/// \brief Return the size of serialized image of the \c LabelSequence.
///
/// This method calculates the size of necessary storage to store
/// serialized image of this \c LabelSequence (which would be dumped by
/// \c serialize()) and returns it. The size is in bytes.
///
/// \throw none.
///
/// \return The size of serialized image of the \c LabelSequence.
size_t
getSerializedLength
()
const
;
/// \brief Serialize the \c LabelSequence object in to a buffer.
///
/// This method dumps a serialized image of this \c LabelSequence
/// that would be restored by the corresponding constructor into the
/// given buffer. The buffer size must be at least equal to
/// the value returned by getSerializedLength() (it can be larger than
/// that).
///
/// The serialized image would be as follows:
/// - olen: number of offsets (1 byte)
/// - binary sequence of offsets (olen bytes, verbatim copy of offsets_
/// of this size)
/// - binary sequence of name data (length determined by itself, verbatim
/// copy of data_ of the corresponding size)
///
/// Applications must use the resulting image opaque value and must not
/// use it for other purposes than input to the corresponding constructor
/// to restore it. Application behavior that assumes the specific
/// organization of the image is not guaranteed.
///
/// \throw isc::BadValue buf_len is too short (this method never throws
/// otherwise)
///
/// \param buf Pointer to the placeholder to dump the serialized image
/// \param buf_len The size of available region in \c buf
void
serialize
(
void
*
buf
,
size_t
buf_len
)
const
;
/// \brief Compares two label sequences for equality.
///
/// Performs a (optionally case-insensitive) comparison between this
...
...
src/lib/dns/tests/labelsequence_unittest.cc
View file @
5b7ac017
...
...
@@ -21,11 +21,17 @@
#include <boost/functional/hash.hpp>
#include <string>
#include <vector>
#include <utility>
#include <set>
using
namespace
isc
::
dns
;
using
namespace
std
;
// XXX: this is defined as class static constants, but some compilers
// seemingly cannot find the symbols when used in the EXPECT_xxx macros.
const
size_t
LabelSequence
::
MAX_SERIALIZED_LENGTH
;
namespace
{
class
LabelSequenceTest
:
public
::
testing
::
Test
{
...
...
@@ -38,6 +44,13 @@ public:
n10
(
"
\\
000xample.org"
),
n11
(
"
\\
000xample.com"
),
n12
(
"
\\
000xamplE.com"
),
n_maxlabel
(
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6"
),
ls1
(
n1
),
ls2
(
n2
),
ls3
(
n3
),
ls4
(
n4
),
ls5
(
n5
),
ls6
(
n6
),
ls7
(
n7
),
ls8
(
n8
),
ls9
(
n9
),
ls10
(
n10
),
ls11
(
n11
),
ls12
(
n12
)
...
...
@@ -46,6 +59,7 @@ public:
// the labelsequences
Name
n1
,
n2
,
n3
,
n4
,
n5
,
n6
,
n7
,
n8
;
Name
n9
,
n10
,
n11
,
n12
;
const
Name
n_maxlabel
;
LabelSequence
ls1
,
ls2
,
ls3
,
ls4
,
ls5
,
ls6
,
ls7
,
ls8
;
LabelSequence
ls9
,
ls10
,
ls11
,
ls12
;
...
...
@@ -654,14 +668,7 @@ TEST_F(LabelSequenceTest, toText) {
"012345678901234567890123456789"
"0123456789012345678901234567890"
,
ls_long1
.
toText
());
Name
n_long2
(
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6"
);
LabelSequence
ls_long2
(
n_long2
);
LabelSequence
ls_long2
(
n_maxlabel
);
EXPECT_EQ
(
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
...
...
@@ -843,4 +850,120 @@ TEST(LabelSequence, badRawConstruction) {
EXPECT_THROW
(
LabelSequence
(
data
,
offsets_noincrease
,
3
),
isc
::
BadValue
);
}
TEST_F
(
LabelSequenceTest
,
serializedLength
)
{
// Initially, the labels are "example.org."
const
size_t
base_size
=
n1
.
getLength
()
+
n1
.
getLabelCount
()
+
1
;
EXPECT_EQ
(
base_size
,
ls1
.
getSerializedLength
());
// Strip off the trailing dot. We'll lose 1 label and 1-byte data
LabelSequence
ls1_stripped
=
ls1
;
ls1_stripped
.
stripRight
(
1
);
EXPECT_EQ
(
base_size
-
2
,
ls1_stripped
.
getSerializedLength
());
// Strip off the leftmost label (example). We'll lose 1 label and
// 8-byte data (1 + len('example')).
ls1_stripped
=
ls1
;
ls1_stripped
.
stripLeft
(
1
);
EXPECT_EQ
(
base_size
-
9
,
ls1_stripped
.
getSerializedLength
());
// Longest possible serialized length. Confirm there's indeed such a case.
EXPECT_EQ
(
LabelSequence
::
MAX_SERIALIZED_LENGTH
,
LabelSequence
(
n_maxlabel
).
getSerializedLength
());
}
TEST_F
(
LabelSequenceTest
,
serialize
)
{
// placeholder for serialized data
uint8_t
labels_buf
[
LabelSequence
::
MAX_SERIALIZED_LENGTH
];
// vector to store expected and actual data
vector
<
LabelSequence
>
actual_labelseqs
;
typedef
pair
<
size_t
,
const
uint8_t
*>
DataPair
;
vector
<
DataPair
>
expected
;
// An absolute sequence directly constructed from a valid name.
// labels = 3, offset sequence = 0, 8, 12, data = "example.com."
actual_labelseqs
.
push_back
(
ls1
);
const
uint8_t
const
expected_data1
[]
=
{
3
,
0
,
8
,
12
,
7
,
'e'
,
'x'
,
'a'
,
'm'
,
'p'
,
'l'
,
'e'
,
3
,
'o'
,
'r'
,
'g'
,
0
};
expected
.
push_back
(
DataPair
(
sizeof
(
expected_data1
),
expected_data1
));
// Strip the original one from right.
// labels = 2, offset sequence = 0, 8, data = "example.com" (non absolute)
LabelSequence
ls_rstripped
=
ls1
;
ls_rstripped
.
stripRight
(
1
);
actual_labelseqs
.
push_back
(
ls_rstripped
);
const
uint8_t
const
expected_data2
[]
=
{
2
,
0
,
8
,
7
,
'e'
,
'x'
,
'a'
,
'm'
,
'p'
,
'l'
,
'e'
,
3
,
'o'
,
'r'
,
'g'
};
expected
.
push_back
(
DataPair
(
sizeof
(
expected_data2
),
expected_data2
));
// Strip the original one from left.
// labels = 2, offset sequence = 0, 4, data = "com."
// Note that offsets are adjusted so that they begin with 0.
LabelSequence
ls_lstripped
=
ls1
;
ls_lstripped
.
stripLeft
(
1
);
actual_labelseqs
.
push_back
(
ls_lstripped
);
const
uint8_t
const
expected_data3
[]
=
{
2
,
0
,
4
,
3
,
'o'
,
'r'
,
'g'
,
0
};
expected
.
push_back
(
DataPair
(
sizeof
(
expected_data3
),
expected_data3
));
// Root label.
LabelSequence
ls_root
(
Name
::
ROOT_NAME
());
actual_labelseqs
.
push_back
(
ls_root
);
const
uint8_t
const
expected_data4
[]
=
{
1
,
0
,
0
};
expected
.
push_back
(
DataPair
(
sizeof
(
expected_data4
),
expected_data4
));
// Non absolute single-label.
LabelSequence
ls_single
=
ls_rstripped
;
ls_single
.
stripRight
(
1
);
actual_labelseqs
.
push_back
(
ls_single
);
const
uint8_t
const
expected_data5
[]
=
{
1
,
0
,
7
,
'e'
,
'x'
,
'a'
,
'm'
,
'p'
,
'l'
,
'e'
};
expected
.
push_back
(
DataPair
(
sizeof
(
expected_data5
),
expected_data5
));
// For each data set, serialize the labels and compare the data to the
// expected one.
vector
<
DataPair
>::
const_iterator
it
=
expected
.
begin
();
vector
<
LabelSequence
>::
const_iterator
itl
=
actual_labelseqs
.
begin
();
for
(;
it
!=
expected
.
end
();
++
it
,
++
itl
)
{
SCOPED_TRACE
(
itl
->
toText
());
const
size_t
serialized_len
=
itl
->
getSerializedLength
();
ASSERT_GE
(
LabelSequence
::
MAX_SERIALIZED_LENGTH
,
serialized_len
);
itl
->
serialize
(
labels_buf
,
serialized_len
);
EXPECT_EQ
(
it
->
first
,
serialized_len
);
EXPECT_EQ
(
0
,
memcmp
(
it
->
second
,
labels_buf
,
serialized_len
));
EXPECT_EQ
(
NameComparisonResult
::
EQUAL
,
LabelSequence
(
labels_buf
).
compare
(
*
itl
).
getRelation
());
}
EXPECT_THROW
(
ls1
.
serialize
(
labels_buf
,
ls1
.
getSerializedLength
()
-
1
),
isc
::
BadValue
);
}
TEST_F
(
LabelSequenceTest
,
badDeserialize
)
{
EXPECT_THROW
(
LabelSequence
(
NULL
),
isc
::
BadValue
);
const
uint8_t
const
zero_offsets
[]
=
{
0
};
EXPECT_THROW
(
LabelSequence
ls
(
zero_offsets
),
isc
::
BadValue
);
const
uint8_t
const
toomany_offsets
[]
=
{
Name
::
MAX_LABELS
+
1
};
EXPECT_THROW
(
LabelSequence
ls
(
toomany_offsets
),
isc
::
BadValue
);
// exceed MAX_LABEL_LEN
const
uint8_t
const
offsets_toolonglabel
[]
=
{
2
,
0
,
64
};
EXPECT_THROW
(
LabelSequence
ls
(
offsets_toolonglabel
),
isc
::
BadValue
);
// Inconsistent data: an offset is lower than the previous offset
const
uint8_t
const
offsets_lower
[]
=
{
3
,
// # of offsets
0
,
2
,
1
,
// offsets
1
,
'a'
,
1
,
'b'
,
0
};
EXPECT_THROW
(
LabelSequence
ls
(
offsets_lower
),
isc
::
BadValue
);
// Inconsistent data: an offset is equal to the previous offset
const
uint8_t
const
offsets_noincrease
[]
=
{
2
,
0
,
0
,
0
,
0
};
EXPECT_THROW
(
LabelSequence
ls
(
offsets_noincrease
),
isc
::
BadValue
);
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment