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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
#ifndef OPENVPN_COMMON_MSGWIN_H
#define OPENVPN_COMMON_MSGWIN_H
#include <deque>
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
// Fundamental, lowest-level object of OpenVPN protocol reliability layer
namespace openvpn {
// MessageWindow --
// On receiving side: used to order packets which may be received out-of-order
// On sending side: used to buffer unacknowledged packets
// M : message class, must define default constructor, defined(), and erase() methods
// id_t : sequence number object, usually unsigned int
template <typename M, typename id_t>
class MessageWindow
{
public:
OPENVPN_SIMPLE_EXCEPTION(message_window_ref_by_id);
OPENVPN_SIMPLE_EXCEPTION(message_window_rm_head);
MessageWindow()
: head_id_(0), span_(0)
{
}
MessageWindow(const id_t starting_head_id, const id_t span)
: head_id_(starting_head_id), span_(span)
{
}
void init(const id_t starting_head_id, const id_t span)
{
head_id_ = starting_head_id;
span_ = span;
q_.clear();
}
// Return true if id is within current window
bool in_window(const id_t id) const
{
return id >= head_id_ && id < head_id_ + span_;
}
// Return true if id is before current window
bool pre_window(const id_t id) const
{
return id < head_id_;
}
// Return a reference to M object at id, throw exception
// if id is not in current window
M &ref_by_id(const id_t id)
{
if (in_window(id))
{
grow(id);
return q_[id - head_id_];
}
else
throw message_window_ref_by_id();
}
// Remove the M object at id, is a no-op if
// id not in window. Do a purge() as a last
// step to advance the head_id_ if it's now
// pointing at undefined M objects.
void rm_by_id(const id_t id)
{
if (in_window(id))
{
grow(id);
M &m = q_[id - head_id_];
m.erase();
}
purge();
}
// Return true if an object at head of queue is defined
bool head_defined() const
{
return (!q_.empty() && q_.front().defined());
}
// Return the id that the object at the head of the queue
// would have (even if it isn't defined yet).
id_t head_id() const
{
return head_id_;
}
// Return the id of one past the end of the window
id_t tail_id() const
{
return head_id_ + span_;
}
// Return the window size
id_t span() const
{
return span_;
}
// Return a reference to the object at the front of the queue
M &ref_head()
{
return q_.front();
}
// Remove the object at head of queue, throw an exception if undefined
void rm_head()
{
if (head_defined())
rm_head_nocheck();
else
throw message_window_rm_head();
}
// Remove the object at head of queue without error checking (other than
// that provided by std::deque object). Don't call this method unless
// head_defined() returns true.
void rm_head_nocheck()
{
q_.front().erase();
q_.pop_front();
++head_id_;
}
private:
// Expand the queue if necessary so that id maps
// to an object in the queue
void grow(const id_t id)
{
const size_t needed_index = id - head_id_;
while (q_.size() <= needed_index)
q_.push_back(M());
}
// Purge all undefined objects at the head of
// the queue, advancing the head_id_
void purge()
{
while (!q_.empty() && q_.front().erased())
{
q_.pop_front();
++head_id_;
}
}
id_t head_id_; // id of msgs[0]
id_t span_;
std::deque<M> q_;
};
} // namespace openvpn
#endif // OPENVPN_COMMON_MSGWIN_H
|