packet_storage.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef PACKET_STORAGE_H
  15. #define PACKET_STORAGE_H
  16. #include <boost/noncopyable.hpp>
  17. #include <boost/shared_ptr.hpp>
  18. #include <list>
  19. #include <stdint.h>
  20. namespace isc {
  21. namespace perfdhcp {
  22. /// \brief Represents a list of packets with a sequential and random access to
  23. /// list elements.
  24. ///
  25. /// The main purpose of this class is to support sending Renew and Release
  26. /// messages from perfdhcp. The Renew and Release messages are sent for existing
  27. /// leases only. Therefore, the typical use case for this class is that it holds
  28. /// a list of Reply messages sent by the server in response to Request messages.
  29. /// The Request messages hold addresses and/or IPv6 prefixes acquired so they
  30. /// can be used to identify existing leases. When perfdhcp needs to send Renew
  31. /// or Release message, it will access one of the elements on this list and
  32. /// will create the Renew or Release message based on its content. Once the
  33. /// element (packet) is returned it is also deleted from the list, so as it is
  34. /// not used again. This class provide either sequential access to the packets
  35. /// or random access. The random access algorithm is much slower but at least
  36. /// it allows to simulate more real scenario when the renewing or releasing
  37. /// client is random.
  38. ///
  39. /// \tparam Pkt4 or Pkt6 class, which represents DHCPv4 or DHCPv6 message
  40. /// respectively.
  41. ///
  42. /// \note Although the class is intended to hold Pkt4 and Pkt6 objects, the
  43. /// current implementation is generic enough to holds any object wrapped in the
  44. /// boost::shared_ptr.
  45. template<typename T>
  46. class PacketStorage : public boost::noncopyable {
  47. public:
  48. /// A type which represents the pointer to a packet.
  49. typedef boost::shared_ptr<T> PacketPtr;
  50. private:
  51. /// An internal container actually holding packets.
  52. typedef typename std::list<PacketPtr> PacketContainer;
  53. /// An iterator to the element in the internal container.
  54. typedef typename PacketContainer::iterator PacketContainerIterator;
  55. public:
  56. /// \brief Constructor.
  57. PacketStorage() { }
  58. /// \brief Appends the new packet object to the collection.
  59. ///
  60. /// \param packet A pointer to an object representing a packet.
  61. void append(const PacketPtr& packet) {
  62. storage_.push_back(packet);
  63. if (storage_.size() == 1) {
  64. current_pointer_ = storage_.begin();
  65. }
  66. }
  67. /// \brief Removes packets from the storage.
  68. ///
  69. /// It is possible to specify a number of packets to be removed
  70. /// from a storage. Packets are removed from the beginning of the
  71. /// storage. If specified number is greater than the size of the
  72. /// storage, all packets are removed.
  73. ///
  74. /// @param num A number of packets to be removed. If omitted,
  75. /// all packets will be removed.
  76. void clear(const uint64_t num = 0) {
  77. if (num != 0) {
  78. PacketContainerIterator last = storage_.begin();
  79. std::advance(last, num > size() ? size() : num);
  80. current_pointer_ = storage_.erase(storage_.begin(), last);
  81. } else {
  82. storage_.clear();
  83. current_pointer_ = storage_.begin();
  84. }
  85. }
  86. /// \brief Checks if the storage has no packets.
  87. ///
  88. /// \return true if storage is empty, false otherwise.
  89. bool empty() const {
  90. return (storage_.empty());
  91. }
  92. /// \brief Returns next packet from the storage.
  93. ///
  94. /// This function returns packets sequentially (in the same order
  95. /// in which they have been appended). The returned packet is
  96. /// instantly removed from the storage.
  97. ///
  98. /// \return next packet from the storage.
  99. PacketPtr getNext() {
  100. if (storage_.empty()) {
  101. return (PacketPtr());
  102. } else if (current_pointer_ == storage_.end()) {
  103. current_pointer_ = storage_.begin();
  104. }
  105. PacketPtr packet = *current_pointer_;
  106. current_pointer_ = storage_.erase(current_pointer_);
  107. return (packet);
  108. }
  109. /// \brief Returns random packet from the storage.
  110. ///
  111. /// This function picks random packet from the storage and returns
  112. /// it. It is way slower than the @c getNext function because it has to
  113. /// iterate over all existing entries from the beginning of the storage
  114. /// to the random packet's position. Therefore, care should be taken
  115. /// when using this function to access elements when storage is large.
  116. ///
  117. /// \return random packet from the storage.
  118. PacketPtr getRandom() {
  119. if (empty()) {
  120. return (PacketPtr());
  121. }
  122. current_pointer_ = storage_.begin();
  123. if (size() > 1) {
  124. std::advance(current_pointer_, rand() % (size() - 1));
  125. }
  126. PacketPtr packet = *current_pointer_;
  127. current_pointer_ = storage_.erase(current_pointer_);
  128. return (packet);
  129. }
  130. /// \brief Returns number of packets in the storage.
  131. ///
  132. /// \return number of packets in the storage.
  133. uint64_t size() const {
  134. return (storage_.size());
  135. }
  136. private:
  137. std::list<PacketPtr> storage_; ///< Holds all appended packets.
  138. PacketContainerIterator current_pointer_; ///< Holds the iterator to the
  139. ///< next element returned.
  140. };
  141. } // namespace perfdhcp
  142. } // namespace isc
  143. #endif // PACKET_STORAGE_H