1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25#ifndef SHAPER_H
26#define SHAPER_H
27
28/*#define SHAPER_DEBUG*/
29
30#ifdef ENABLE_FEATURE_SHAPER
31
32#include "basic.h"
33#include "integer.h"
34#include "misc.h"
35#include "error.h"
36#include "interval.h"
37
38/*
39 * A simple traffic shaper for
40 * the output direction.
41 */
42
43#define SHAPER_MIN 100          /* bytes per second */
44#define SHAPER_MAX 100000000
45
46#define SHAPER_MAX_TIMEOUT 10   /* seconds */
47
48#define SHAPER_USE_FP
49
50struct shaper
51{
52  int bytes_per_second;
53  struct timeval wakeup;
54
55#ifdef SHAPER_USE_FP
56  double factor;
57#else
58  int factor;
59#endif
60};
61
62void shaper_msg (struct shaper *s);
63void shaper_reset_wakeup (struct shaper *s);
64
65/*
66 * We want to wake up in delay microseconds.  If timeval is larger
67 * than delay, set timeval to delay.
68 */
69bool shaper_soonest_event (struct timeval *tv, int delay);
70
71/*
72 * inline functions
73 */
74
75static inline void
76shaper_reset (struct shaper *s, int bytes_per_second)
77{
78  s->bytes_per_second = bytes_per_second ? constrain_int (bytes_per_second, SHAPER_MIN, SHAPER_MAX) : 0;
79
80#ifdef SHAPER_USE_FP
81  s->factor = 1000000.0 / (double)s->bytes_per_second;
82#else
83  s->factor = 1000000 / s->bytes_per_second;
84#endif
85}
86
87static inline void
88shaper_init (struct shaper *s, int bytes_per_second)
89{
90  shaper_reset (s, bytes_per_second);
91  shaper_reset_wakeup (s);
92}
93
94static inline int
95shaper_current_bandwidth (struct shaper *s)
96{
97  return s->bytes_per_second;
98}
99
100/*
101 * Returns traffic shaping delay in microseconds relative to current
102 * time, or 0 if no delay.
103 */
104static inline int
105shaper_delay (struct shaper* s)
106{
107  struct timeval tv;
108  int delay = 0;
109
110  if (tv_defined (&s->wakeup))
111    {
112      ASSERT (!openvpn_gettimeofday (&tv, NULL));
113      delay = tv_subtract (&s->wakeup, &tv, SHAPER_MAX_TIMEOUT);
114#ifdef SHAPER_DEBUG
115      dmsg (D_SHAPER_DEBUG, "SHAPER shaper_delay delay=%d", delay);
116#endif
117    }
118
119  return delay > 0 ? delay : 0;
120}
121
122
123/*
124 * We are about to send a datagram of nbytes bytes.
125 *
126 * Compute when we can send another datagram,
127 * based on target throughput (s->bytes_per_second).
128 */
129static inline void
130shaper_wrote_bytes (struct shaper* s, int nbytes)
131{
132  struct timeval tv;
133
134  /* compute delay in microseconds */
135  tv.tv_sec = 0;
136#ifdef SHAPER_USE_FP
137  tv.tv_usec = min_int ((int)((double)max_int (nbytes, 100) * s->factor), (SHAPER_MAX_TIMEOUT*1000000));
138#else
139  tv.tv_usec = s->bytes_per_second
140    ? min_int (max_int (nbytes, 100) * s->factor, (SHAPER_MAX_TIMEOUT*1000000))
141    : 0;
142#endif
143
144  if (tv.tv_usec)
145    {
146      ASSERT (!openvpn_gettimeofday (&s->wakeup, NULL));
147      tv_add (&s->wakeup, &tv);
148
149#ifdef SHAPER_DEBUG
150      dmsg (D_SHAPER_DEBUG, "SHAPER shaper_wrote_bytes bytes=%d delay=%d sec=%d usec=%d",
151	   nbytes,
152	   (int)tv.tv_usec,
153	   (int)s->wakeup.tv_sec,
154	   (int)s->wakeup.tv_usec);
155#endif
156    }
157}
158
159#if 0
160/*
161 * Increase/Decrease bandwidth by a percentage.
162 *
163 * Return true if bandwidth changed.
164 */
165static inline bool
166shaper_change_pct (struct shaper *s, int pct)
167{
168  const int orig_bandwidth = s->bytes_per_second;
169  const int new_bandwidth = orig_bandwidth + (orig_bandwidth * pct / 100);
170  ASSERT (s->bytes_per_second);
171  shaper_reset (s, new_bandwidth);
172  return s->bytes_per_second != orig_bandwidth;
173}
174#endif
175
176#endif /* ENABLE_FEATURE_SHAPER */
177
178#endif
179