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
// Copyright (C) 2015-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/.

#include <config.h>

#include <exceptions/exceptions.h>
#include <dhcp/opaque_data_tuple.h>
#include <dhcp/option_opaque_data_tuples.h>
#include <sstream><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace dhcp {

OptionOpaqueDataTuples::OptionOpaqueDataTuples(Option::Universe u,
                                               const uint16_t type,
                                               OpaqueDataTuple::LengthFieldType length_field_type)
    : Option(u, type), length_field_type_(length_field_type) {
    if (length_field_type_ == OpaqueDataTuple::LENGTH_EMPTY) {
        length_field_type_ = OptionDataTypeUtil::getTupleLenFieldType(u);
    }
}

OptionOpaqueDataTuples::OptionOpaqueDataTuples(Option::Universe u,
                                               const uint16_t type,
                                               OptionBufferConstIter begin,
                                               OptionBufferConstIter end,
                                               OpaqueDataTuple::LengthFieldType length_field_type)
    : Option(u, type), length_field_type_(length_field_type) {
    if (length_field_type_ == OpaqueDataTuple::LENGTH_EMPTY) {
        length_field_type_ = OptionDataTypeUtil::getTupleLenFieldType(u);
    }
    unpack(begin, end);
}

OptionPtr
OptionOpaqueDataTuples::clone() const {<--- Derived function 'OptionOpaqueDataTuples::clone'
    return (cloneInternal<OptionOpaqueDataTuples>());
}

void
OptionOpaqueDataTuples::pack(isc::util::OutputBuffer& buf, bool check) const {
    packHeader(buf, check);

    for (auto const& it : tuples_) {
        it.pack(buf);
    }
    // That's it. We don't pack any sub-options here, because this option
    // must not contain sub-options.
}

void
OptionOpaqueDataTuples::unpack(OptionBufferConstIter begin,
                               OptionBufferConstIter end) {
    // We are skipping typical OutOfRange check for Option#unpack(begin, end),
    // since empty collection of tuples is also a valid case where
    // std::distance(begin, end) = 0

    // Start reading opaque data.
    size_t offset = 0;
    while (offset < std::distance(begin, end)) {
        // Parse a tuple.
        OpaqueDataTuple tuple(length_field_type_, begin + offset, end);
        addTuple(tuple);
        // The tuple has been parsed correctly which implies that it is safe to
        // advance the offset by its total length.
        offset += tuple.getTotalLength();
    }
}

void
OptionOpaqueDataTuples::addTuple(const OpaqueDataTuple& tuple) {
    if (tuple.getLengthFieldType() != length_field_type_) {
        isc_throw(isc::BadValue, "attempted to add opaque data tuple having"
                  " invalid size of the length field "
                  << tuple.getDataFieldSize() << " to opaque data tuple option");
    }

    tuples_.push_back(tuple);
}


void
OptionOpaqueDataTuples::setTuple(const size_t at, const OpaqueDataTuple& tuple) {
    if (at >= getTuplesNum()) {
        isc_throw(isc::OutOfRange, "attempted to set an opaque data for the"
                  " opaque data tuple option at position " << at << " which"
                  " is out of range");

    } else if (tuple.getLengthFieldType() != length_field_type_) {
        isc_throw(isc::BadValue, "attempted to set opaque data tuple having"
                  " invalid size of the length field "
                  << tuple.getDataFieldSize() << " to opaque data tuple option");
    }

    tuples_[at] = tuple;
}

OpaqueDataTuple
OptionOpaqueDataTuples::getTuple(const size_t at) const {
    if (at >= getTuplesNum()) {
        isc_throw(isc::OutOfRange, "attempted to get an opaque data for the"
                  " opaque data tuple option at position " << at << " which is"
                  " out of range. There are only " << getTuplesNum() << " tuples");
    }
    return (tuples_[at]);
}

bool
OptionOpaqueDataTuples::hasTuple(const std::string& tuple_str) const {
    // Iterate over existing tuples (there shouldn't be many of them),
    // and try to match the searched one.
    for (auto const& it : tuples_) {<--- Consider using std::any_of algorithm instead of a raw loop.
        if (it == tuple_str) {
            return (true);
        }
    }
    return (false);
}

uint16_t
OptionOpaqueDataTuples::len() const {
    // The option starts with the header.
    uint16_t length = getHeaderLen();
    // Now iterate over existing tuples and add their size.
    for (auto const& it : tuples_) {
        length += it.getTotalLength();<--- Consider using std::accumulate algorithm instead of a raw loop.
    }

    return (length);
}

std::string
OptionOpaqueDataTuples::toText(int indent) const {
    std::ostringstream s;

    // Apply indentation
    s << std::string(indent, ' ');

    // Print type and length
    s << "type=" << getType() << ", len=" << len() - getHeaderLen() << std::dec;
    // Iterate over all tuples and print their size and contents.
    for (unsigned i = 0; i < getTuplesNum(); ++i) {
        // Print the tuple.
        s << ", data-len" << i << "=" << getTuple(i).getLength();
        s << ", data" << i << "='" << getTuple(i) << "'";
    }

    return (s.str());
}

} // namespace isc::dhcp
} // namespace isc