forked from OpenVPN/openvpn3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
msgwin.hpp
181 lines (156 loc) · 4.78 KB
/
msgwin.hpp
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