src/openvpn/shaper.h
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  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 General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
 #ifndef SHAPER_H
 #define SHAPER_H
 
 /*#define SHAPER_DEBUG*/
 
3d163bc5
 #ifdef ENABLE_FEATURE_SHAPER
6fbf66fa
 
 #include "basic.h"
 #include "integer.h"
 #include "misc.h"
 #include "error.h"
 #include "interval.h"
 
 /*
  * A simple traffic shaper for
  * the output direction.
  */
 
 #define SHAPER_MIN 100          /* bytes per second */
 #define SHAPER_MAX 100000000
 
 #define SHAPER_MAX_TIMEOUT 10   /* seconds */
 
 #define SHAPER_USE_FP
 
81d882d5
 struct shaper
6fbf66fa
 {
81d882d5
     int bytes_per_second;
     struct timeval wakeup;
6fbf66fa
 
 #ifdef SHAPER_USE_FP
81d882d5
     double factor;
6fbf66fa
 #else
81d882d5
     int factor;
6fbf66fa
 #endif
 };
 
81d882d5
 void shaper_msg(struct shaper *s);
 
 void shaper_reset_wakeup(struct shaper *s);
6fbf66fa
 
 /*
  * We want to wake up in delay microseconds.  If timeval is larger
  * than delay, set timeval to delay.
  */
81d882d5
 bool shaper_soonest_event(struct timeval *tv, int delay);
6fbf66fa
 
 /*
  * inline functions
  */
 
 static inline void
81d882d5
 shaper_reset(struct shaper *s, int bytes_per_second)
6fbf66fa
 {
81d882d5
     s->bytes_per_second = constrain_int(bytes_per_second, SHAPER_MIN, SHAPER_MAX);
6fbf66fa
 
 #ifdef SHAPER_USE_FP
81d882d5
     s->factor = 1000000.0 / (double)s->bytes_per_second;
6fbf66fa
 #else
81d882d5
     s->factor = 1000000 / s->bytes_per_second;
6fbf66fa
 #endif
 }
 
 static inline void
81d882d5
 shaper_init(struct shaper *s, int bytes_per_second)
6fbf66fa
 {
81d882d5
     shaper_reset(s, bytes_per_second);
     shaper_reset_wakeup(s);
6fbf66fa
 }
 
 static inline int
81d882d5
 shaper_current_bandwidth(struct shaper *s)
6fbf66fa
 {
81d882d5
     return s->bytes_per_second;
6fbf66fa
 }
 
 /*
  * Returns traffic shaping delay in microseconds relative to current
  * time, or 0 if no delay.
  */
 static inline int
81d882d5
 shaper_delay(struct shaper *s)
6fbf66fa
 {
81d882d5
     struct timeval tv;
     int delay = 0;
6fbf66fa
 
81d882d5
     if (tv_defined(&s->wakeup))
6fbf66fa
     {
81d882d5
         ASSERT(!openvpn_gettimeofday(&tv, NULL));
         delay = tv_subtract(&s->wakeup, &tv, SHAPER_MAX_TIMEOUT);
6fbf66fa
 #ifdef SHAPER_DEBUG
81d882d5
         dmsg(D_SHAPER_DEBUG, "SHAPER shaper_delay delay=%d", delay);
6fbf66fa
 #endif
     }
 
81d882d5
     return delay > 0 ? delay : 0;
6fbf66fa
 }
 
 
 /*
  * We are about to send a datagram of nbytes bytes.
  *
  * Compute when we can send another datagram,
  * based on target throughput (s->bytes_per_second).
  */
 static inline void
81d882d5
 shaper_wrote_bytes(struct shaper *s, int nbytes)
6fbf66fa
 {
81d882d5
     struct timeval tv;
6fbf66fa
 
81d882d5
     /* compute delay in microseconds */
     tv.tv_sec = 0;
6fbf66fa
 #ifdef SHAPER_USE_FP
81d882d5
     tv.tv_usec = min_int((int)((double)max_int(nbytes, 100) * s->factor), (SHAPER_MAX_TIMEOUT*1000000));
6fbf66fa
 #else
81d882d5
     tv.tv_usec = s->bytes_per_second
                  ? min_int(max_int(nbytes, 100) * s->factor, (SHAPER_MAX_TIMEOUT*1000000))
                  : 0;
6fbf66fa
 #endif
 
81d882d5
     if (tv.tv_usec)
6fbf66fa
     {
81d882d5
         ASSERT(!openvpn_gettimeofday(&s->wakeup, NULL));
         tv_add(&s->wakeup, &tv);
6fbf66fa
 
 #ifdef SHAPER_DEBUG
06ad53e0
         dmsg(D_SHAPER_DEBUG, "SHAPER shaper_wrote_bytes bytes=%d delay=%ld sec=%"PRIi64" usec=%ld",
81d882d5
              nbytes,
31b5c0e9
              (long)tv.tv_usec,
06ad53e0
              (int64_t)s->wakeup.tv_sec,
31b5c0e9
              (long)s->wakeup.tv_usec);
6fbf66fa
 #endif
     }
 }
 
 #if 0
 /*
  * Increase/Decrease bandwidth by a percentage.
  *
  * Return true if bandwidth changed.
  */
 static inline bool
81d882d5
 shaper_change_pct(struct shaper *s, int pct)
6fbf66fa
 {
81d882d5
     const int orig_bandwidth = s->bytes_per_second;
     const int new_bandwidth = orig_bandwidth + (orig_bandwidth * pct / 100);
     ASSERT(s->bytes_per_second);
     shaper_reset(s, new_bandwidth);
     return s->bytes_per_second != orig_bandwidth;
6fbf66fa
 }
 #endif
 
3d163bc5
 #endif /* ENABLE_FEATURE_SHAPER */
6fbf66fa
 
81d882d5
 #endif /* ifndef SHAPER_H */