OpenVPN 3 Core Library
Loading...
Searching...
No Matches
gremlin.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#ifndef OPENVPN_TRANSPORT_GREMLIN_H
13#define OPENVPN_TRANSPORT_GREMLIN_H
14
15#include <memory>
16#include <deque>
17#include <vector>
18#include <utility>
19#include <sstream>
20
21#include <openvpn/common/rc.hpp>
27
29
30OPENVPN_EXCEPTION(gremlin_error);
31
32struct DelayedQueue : public RC<thread_unsafe_refcount>
33{
34 public:
36
37 DelayedQueue(openvpn_io::io_context &io_context,
38 const unsigned int delay_ms)
39 : dur(Time::Duration::milliseconds(delay_ms)),
40 next_event(io_context)
41 {
42 }
43
44 template <class F>
45 void queue(F &&func_arg)
46 {
47 const bool empty = events.empty();
48 events.emplace_back(new Event<F>(Time::now() + dur, std::move(func_arg)));
49 if (empty)
50 set_timer();
51 }
52
53 size_t size() const
54 {
55 return events.size();
56 }
57
58 void stop()
59 {
60 next_event.cancel();
61 }
62
63 private:
64 struct EventBase
65 {
66 virtual void call() = 0;
67 virtual const Time &fire_time() = 0;
68 virtual ~EventBase() = default;
69 };
70
71 template <class F>
72 struct Event : public EventBase
73 {
74 public:
75 Event(Time fire_arg, F &&func_arg)
76 : fire(fire_arg),
77 func(std::move(func_arg))
78 {
79 }
80
81 void call() override
82 {
83 func();
84 }
85
86 const Time &fire_time() override
87 {
88 return fire;
89 }
90
91 private:
94 };
95
96 void set_timer()
97 {
98 if (events.empty())
99 return;
100 EventBase &ev = *events.front();
102 next_event.async_wait([self = Ptr(this)](const openvpn_io::error_code &error)
103 {
104 if (!error)
105 {
106 EventBase& ev = *self->events.front();
107 ev.call();
108 self->events.pop_front();
109 self->set_timer();
110 } });
111 }
112
113 Time::Duration dur;
115 std::deque<std::unique_ptr<EventBase>> events;
116};
117
118class Config : public RC<thread_unsafe_refcount>
119{
120 public:
122
123 Config(const std::string &config_str)
124 {
125 const std::vector<std::string> parms = string::split(config_str, ',');
126 if (parms.size() < 4)
127 throw gremlin_error("need 4 comma-separated values for send_delay_ms, recv_delay_ms, send_drop_prob, recv_drop_prob");
129 throw gremlin_error("send_delay_ms");
131 throw gremlin_error("recv_delay_ms");
133 throw gremlin_error("send_drop_probability");
135 throw gremlin_error("recv_drop_probability");
136 }
137
138 std::string to_string() const
139 {
140 std::ostringstream os;
141 os << '[' << send_delay_ms << ',' << recv_delay_ms << ',' << send_drop_probability << ',' << recv_drop_probability << ']';
142 return os.str();
143 }
144
145 unsigned int send_delay_ms = 0;
146 unsigned int recv_delay_ms = 0;
147 unsigned int send_drop_probability = 0;
148 unsigned int recv_drop_probability = 0;
149};
150
152{
153 public:
154 SendRecvQueue(openvpn_io::io_context &io_context,
155 const Config::Ptr &conf_arg,
156 const bool tcp_arg)
157 : conf(conf_arg),
158 send(new DelayedQueue(io_context, conf->send_delay_ms)),
159 recv(new DelayedQueue(io_context, conf->recv_delay_ms)),
160 tcp(tcp_arg)
161 {
162 }
163
164 template <class F>
165 void send_queue(F &&func_arg)
166 {
167 if (tcp || flip(conf->send_drop_probability))
168 send->queue(std::move(func_arg));
169 }
170
171 template <class F>
172 void recv_queue(F &&func_arg)
173 {
174 if (tcp || flip(conf->recv_drop_probability))
175 recv->queue(std::move(func_arg));
176 }
177
178 size_t send_size() const
179 {
180 return send->size();
181 }
182
183 size_t recv_size() const
184 {
185 return recv->size();
186 }
187
188 void stop()
189 {
190 send->stop();
191 recv->stop();
192 }
193
194 private:
195 bool flip(const unsigned int prob)
196 {
197 if (prob)
198 return ri.randrange(prob) != 0;
199 else
200 return true;
201 }
202
207 bool tcp;
208};
209} // namespace openvpn::Gremlin
210
211#endif
std::size_t expires_at(const Time &t)
Definition asiotimer.hpp:64
unsigned int send_delay_ms
Definition gremlin.hpp:145
std::string to_string() const
Definition gremlin.hpp:138
unsigned int recv_drop_probability
Definition gremlin.hpp:148
unsigned int recv_delay_ms
Definition gremlin.hpp:146
Config(const std::string &config_str)
Definition gremlin.hpp:123
unsigned int send_drop_probability
Definition gremlin.hpp:147
RCPtr< Config > Ptr
Definition gremlin.hpp:121
SendRecvQueue(openvpn_io::io_context &io_context, const Config::Ptr &conf_arg, const bool tcp_arg)
Definition gremlin.hpp:154
void recv_queue(F &&func_arg)
Definition gremlin.hpp:172
bool flip(const unsigned int prob)
Definition gremlin.hpp:195
void send_queue(F &&func_arg)
Definition gremlin.hpp:165
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
T randrange(const T end)
Return a uniformly distributed random number in the range [0, end)
Definition randapi.hpp:117
static TimeType now()
Definition time.hpp:305
#define OPENVPN_EXCEPTION(C)
std::vector< T > split(const T &str, const typename T::value_type sep, const int maxsplit=-1)
Definition string.hpp:492
std::string trim_copy(const std::string &str)
Definition string.hpp:559
bool parse_number(const char *str, T &retval, const bool nondigit_term=false)
Definition number.hpp:34
const Time & fire_time() override
Definition gremlin.hpp:86
Event(Time fire_arg, F &&func_arg)
Definition gremlin.hpp:75
void queue(F &&func_arg)
Definition gremlin.hpp:45
DelayedQueue(openvpn_io::io_context &io_context, const unsigned int delay_ms)
Definition gremlin.hpp:37
RCPtr< DelayedQueue > Ptr
Definition gremlin.hpp:35
std::deque< std::unique_ptr< EventBase > > events
Definition gremlin.hpp:115
std::ostringstream os