perf_pkt6.cc 6.66 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
#include <exceptions/exceptions.h>
16 17 18 19 20 21 22 23 24 25 26 27
#include <dhcp/libdhcp++.h>
#include <dhcp/dhcp6.h>

#include "perf_pkt6.h"

using namespace std;
using namespace isc;

namespace isc {
namespace perfdhcp {


28 29 30 31 32 33 34
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
                                             uint16_t type,
                                             const dhcp::OptionBuffer& data) :
    dhcp::Option(u, type, data),
    position_(0) {
}

35 36 37
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
                                             uint16_t type,
                                             const dhcp::OptionBuffer& data,
38
                                             const size_t position) :
39 40 41 42
    dhcp::Option(u, type, data),
    position_(position) {
}

43 44 45 46 47 48 49 50
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
                                             uint16_t type,
                                             dhcp::OptionBufferConstIter first,
                                             dhcp::OptionBufferConstIter last) :
    dhcp::Option(u, type, first, last),
    position_(0) {
}

51 52 53 54
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
                                             uint16_t type,
                                             dhcp::OptionBufferConstIter first,
                                             dhcp::OptionBufferConstIter last,
55
                                             const size_t position) :
56 57 58 59
    dhcp::Option(u, type, first, last),
    position_(position) {
}

60
PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, size_t transid_offset) :
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
    Pkt6(buf, len, dhcp::Pkt6::UDP),
    transid_offset_(transid_offset) {

    // Let's reset timestamp of the packet
    memset(static_cast<void*>(&time_stamp_), 0, sizeof(time_stamp_));
}

void
PerfPkt6::stampedPack() {
    // This function simply wraps pack() function from parent class
    // and then updates timestamp.
    if (!pack()) {
        isc_throw(isc::Unexpected, "Failed to prepare packet to send");
    }
    // Update pack time for RTT calculations.
    updateTimestamp();
}

void
PerfPkt6::stampedUnpack() {
    // Update timestamp of the packet for RTT calculations.
    // We do this before unpacking the packet so as unpack
    // time will not affect the timestamp.
    updateTimestamp();

    // Unpack the incoming packet.
    if (!unpack()) {
        isc_throw(isc::Unexpected, "Failed to unpack incoming packet");
    }
}

void
PerfPkt6::stampedRawPack() {
    try {
        // Always override the packet if function is called.
        bufferOut_.clear();
        // Write whole buffer to output buffer.
        bufferOut_.writeData(&data_[0], data_.size());
        // We already have packet template stored in out buffer
        // but still some options have to be updated if client
        // specified them along with their offsets in the buffer.
        updateOptions();
    } catch (Exception& e) {
        isc_throw(isc::Unexpected, "Failed to build packet from buffer");
    }
    // Update packet timestamp for RTT calculations - do not include pack time.
    updateTimestamp();
}

void
PerfPkt6::stampedRawUnpack() {
    // Update packet timestamp for RTT calculations but do not include unpack time.
    updateTimestamp();

    // Read transaction id from the packet at the given offset.
116 117
    transid_ = ( (data_[transid_offset_]) << 16 ) +
        ((data_[transid_offset_ + 1]) << 8) + (data_[transid_offset_ + 2]);
118 119 120 121
    transid_ = transid_ & 0xffffff;

    // Get message type - assume it is first octet in the packet.
    msg_type_ = data_[0];
122 123

    rawUnpackOptions();
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
void
PerfPkt6::updateOptions() {
    try {
        // If there are any options on the list we will use provided options offsets
        // to override them in the output buffer with new contents.
        for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
             it != options_.end(); ++it) {
            // Get options with their position (offset).
            boost::shared_ptr<PositionedOption> option = boost::dynamic_pointer_cast<PositionedOption>(it->second);
            uint32_t position = option->getOptionPosition();
            // If position is specified w need to seek to it.
            if (position > 0) {
                bufferOut_.clear();
                bufferOut_.skip(position);
            }
            // Replace existing option with new value.
            option->pack(bufferOut_);
        }
    }
    catch (const Exception&) {
        isc_throw(isc::Unexpected, "Failed to build packet (Option build failed");
    }
}

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
void
PerfPkt6::rawUnpackOptions() {
    for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
         it != options_.end(); ++it) {

        PositionedOptionPtr option = boost::dynamic_pointer_cast<PositionedOption>(it->second);
        size_t opt_pos = option->getOptionPosition();

        if (opt_pos == 0) {
            isc_throw(isc::BadValue, "Failed to unpack packet from raw buffer "
                      "(Option position not specified)");
        } else if (opt_pos + 4 > data_.size()) {
            isc_throw(isc::BadValue, "Failed to unpack options from from raw buffer "
                      "(Option position out of bounds)");
        }

        size_t offset = opt_pos;
        //        uint16_t opt_type = data_[offset] * 256 + data_[offset + 1];
        offset += 2;
        uint16_t opt_len = data_[offset] * 256 + data_[offset + 1];
        offset += 2;

        if (offset + opt_len > data_.size()) {
            isc_throw(isc::BadValue,
                      "Failed to unpack option from raw buffer (Option truncated)");
        }
        option->setData(data_.begin() + offset, data_.begin() + offset + opt_len);
    }
}

181 182 183 184 185 186 187 188 189
void
PerfPkt6::updateTimestamp() {
    if (clock_gettime(CLOCK_REALTIME, &time_stamp_) < 0) {
        isc_throw(isc::Unexpected, "Failed to get timestamp for packet");
    }
}

} // namespace perfdhcp
} // namespace isc