summaryrefslogtreecommitdiffstats
path: root/src/bin/perfdhcp/packet_storage.h
blob: 6a416829fced810859174e853edeb1731662cef2 (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
// Copyright (C) 2013 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 PACKET_STORAGE_H
#define PACKET_STORAGE_H

#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <list>
#include <stdint.h>

namespace isc {
namespace perfdhcp {

/// \brief Represents a list of packets with a sequential and random access to
/// list elements.
///
/// The main purpose of this class is to support sending Renew and Release
/// messages from perfdhcp. The Renew and Release messages are sent for existing
/// leases only. Therefore, the typical use case for this class is that it holds
/// a list of Reply messages sent by the server in response to Request messages.
/// The Request messages hold addresses and/or IPv6 prefixes acquired so they
/// can be used to identify existing leases. When perfdhcp needs to send Renew
/// or Release message, it will access one of the elements on this list and
/// will create the Renew or Release message based on its content. Once the
/// element (packet) is returned it is also deleted from the list, so as it is
/// not used again. This class provide either sequential access to the packets
/// or random access. The random access algorithm is much slower but at least
/// it allows to simulate more real scenario when the renewing or releasing
/// client is random.
///
/// \tparam Pkt4 or Pkt6 class, which represents DHCPv4 or DHCPv6 message
/// respectively.
///
/// \note Although the class is intended to hold Pkt4 and Pkt6 objects, the
/// current implementation is generic enough to holds any object wrapped in the
/// boost::shared_ptr.
template<typename T>
class PacketStorage : public boost::noncopyable {
public:
    /// A type which represents the pointer to a packet.
    typedef boost::shared_ptr<T> PacketPtr;

private:
    /// An internal container actually holding packets.
    typedef typename std::list<PacketPtr> PacketContainer;
    /// An iterator to the element in the internal container.
    typedef typename PacketContainer::iterator PacketContainerIterator;

public:

    /// \brief Constructor.
    PacketStorage() { }

    /// \brief Appends the new packet object to the collection.
    ///
    /// \param packet A pointer to an object representing a packet.
    void append(const PacketPtr& packet) {
        storage_.push_back(packet);
        if (storage_.size() == 1) {
            current_pointer_ = storage_.begin();
        }
    }

    /// \brief Removes packets from the storage.
    ///
    /// It is possible to specify a number of packets to be removed
    /// from a storage. Packets are removed from the beginning of the
    /// storage. If specified number is greater than the size of the
    /// storage, all packets are removed.
    ///
    /// @param num A number of packets to be removed. If omitted,
    /// all packets will be removed.
    void clear(const uint64_t num = 0) {
        if (num != 0) {
            PacketContainerIterator last = storage_.begin();
            std::advance(last, num > size() ? size() : num);
            current_pointer_ = storage_.erase(storage_.begin(), last);
        } else {
            storage_.clear();
            current_pointer_ = storage_.begin();
        }
    }

    /// \brief Checks if the storage has no packets.
    ///
    /// \return true if storage is empty, false otherwise.
    bool empty() const {
        return (storage_.empty());
    }

    /// \brief Returns next packet from the storage.
    ///
    /// This function returns packets sequentially (in the same order
    /// in which they have been appended). The returned packet is
    /// instantly removed from the storage.
    ///
    /// \return next packet from the storage.
    PacketPtr getNext() {
        if (storage_.empty()) {
            return (PacketPtr());
        } else if (current_pointer_ == storage_.end()) {
            current_pointer_ = storage_.begin();
        }
        PacketPtr packet = *current_pointer_;
        current_pointer_ = storage_.erase(current_pointer_);
        return (packet);
    }

    /// \brief Returns random packet from the storage.
    ///
    /// This function picks random packet from the storage and returns
    /// it. It is way slower than the @c getNext function because it has to
    /// iterate over all existing entries from the beginning of the storage
    /// to the random packet's position. Therefore, care should be taken
    /// when using this function to access elements when storage is large.
    ///
    /// \return random packet from the storage.
    PacketPtr getRandom() {
        if (empty()) {
            return (PacketPtr());
        }
        current_pointer_ = storage_.begin();
        if (size() > 1) {
            std::advance(current_pointer_, rand() % (size() - 1));
        }
        PacketPtr packet = *current_pointer_;
        current_pointer_ = storage_.erase(current_pointer_);
        return (packet);
    }

    /// \brief Returns number of packets in the storage.
    ///
    /// \return number of packets in the storage.
    uint64_t size() const {
        return (storage_.size());
    }

private:

    std::list<PacketPtr> storage_;            ///< Holds all appended packets.
    PacketContainerIterator current_pointer_; ///< Holds the iterator to the
                                              ///< next element returned.

};

} // namespace perfdhcp
} // namespace isc

#endif // PACKET_STORAGE_H