160 lines
3.6 KiB
C
160 lines
3.6 KiB
C
/*
|
|
VTun - Virtual Tunnel over TCP/IP network.
|
|
|
|
Copyright (C) 1998-2008 Maxim Krasnyansky <max_mk@yahoo.com>
|
|
|
|
VTun has been derived from VPPP package by Maxim Krasnyansky.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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.
|
|
*/
|
|
|
|
/*
|
|
* $Id: lfd_shaper.c,v 1.7.2.3 2013/07/07 19:54:48 mtbishop Exp $
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <syslog.h>
|
|
|
|
#include "vtun.h"
|
|
#include "linkfd.h"
|
|
#include "lib.h"
|
|
|
|
/*
|
|
* Shaper module.
|
|
*/
|
|
|
|
#ifdef HAVE_SHAPER
|
|
|
|
static unsigned long bytes, max_speed;
|
|
static struct timeval curr_time, last_time;
|
|
|
|
/*
|
|
* Initialization function.
|
|
*/
|
|
static int shaper_init(struct vtun_host *host)
|
|
{
|
|
/* Calculate max speed bytes/sec */
|
|
max_speed = host->spd_out / 8 * 1024;
|
|
|
|
/* Compensation for delays, nanosleep and so on */
|
|
max_speed += 400;
|
|
|
|
bytes = 0;
|
|
|
|
vtun_syslog(LOG_INFO,"Traffic shaping(speed %dK) initialized.", host->spd_out);
|
|
return 0;
|
|
}
|
|
|
|
/* Shaper counter */
|
|
static int shaper_counter(int len, char *in, char **out)
|
|
{
|
|
/* Just count incoming bytes */
|
|
bytes += len;
|
|
|
|
*out = in;
|
|
return len;
|
|
}
|
|
|
|
/* Convert tv struct to milisec */
|
|
static unsigned long inline tv2ms(struct timeval tv)
|
|
{
|
|
register unsigned long ms = (tv.tv_sec * 1000)+(tv.tv_usec / 1000);
|
|
return ms ? ms : 1;
|
|
}
|
|
|
|
#ifndef timersub
|
|
/* Some includes doesn't contain this macro */
|
|
#define timersub(a, b, result) \
|
|
do { \
|
|
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
|
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
|
|
if ((result)->tv_usec < 0) { \
|
|
--(result)->tv_sec; \
|
|
(result)->tv_usec += 1000000; \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
|
|
/*
|
|
* Main shaper function.
|
|
* Compute current speed in bytes/sec and if it is
|
|
* higher than maximal speed stop accepting input
|
|
* until the speed become lower or equal to maximal.
|
|
*/
|
|
static int shaper_avail(void)
|
|
{
|
|
static struct timeval tv;
|
|
register unsigned long speed;
|
|
|
|
/* Let me know if you have faster and better time source. */
|
|
gettimeofday(&curr_time,NULL);
|
|
|
|
timersub(&curr_time,&last_time,&tv);
|
|
|
|
/* Calculate current speed bytes/sec.
|
|
* (tv2ms never returns 0) */
|
|
speed = bytes * 1000 / tv2ms(tv);
|
|
|
|
if( speed > max_speed ){
|
|
/*
|
|
* Sleep about 1 microsec(actual sleep might be longer).
|
|
* This is actually the hack to reduce CPU usage.
|
|
* Without this delay we will consume 100% CPU.
|
|
*/
|
|
static struct timespec ts = {0,1000};
|
|
nanosleep(&ts,NULL);
|
|
|
|
/* Don't accept input */
|
|
return 0;
|
|
}
|
|
|
|
if( curr_time.tv_sec > last_time.tv_sec ){
|
|
last_time = curr_time;
|
|
bytes = 0;
|
|
}
|
|
|
|
/* Accept input */
|
|
return 1;
|
|
}
|
|
|
|
struct lfd_mod lfd_shaper = {
|
|
"Shaper",
|
|
shaper_init,
|
|
shaper_counter,
|
|
shaper_avail,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
#else /* HAVE_SHAPER */
|
|
|
|
static int no_shaper(struct vtun_host *host)
|
|
{
|
|
vtun_syslog(LOG_INFO, "Traffic shaping is not supported");
|
|
return -1;
|
|
}
|
|
|
|
struct lfd_mod lfd_shaper = {
|
|
"Shaper",
|
|
no_shaper, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
|
};
|
|
|
|
#endif /* HAVE_SHAPER */
|