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 172 173 174 175 176 177 178 179 180 181
|
// 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-2022 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#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
|