在/etc/ftpaccess里面加上: throughput /home/ftp * * 64000 0.5 *
意思是下载带宽对所有IP(最后那个*)限制在64K,每下一个文件速度减半(那个0 .5).
我用的是2.5.x,man page里面很全的. 用man ftpaccess就可以.:-)
◇ ProFTPD 流量控制 ---------------------------------------------------------------------- ----------发信人: charley.bbs@swallow.twbbs.org (喘气中...), 看板: Lin ux 标 题: ProFTPD 流量控制 发信站: 临风小□ BBS 站 (Tue Mar 9 15:55:30 1999) @cyndi.cis.nctu.edu .tw 转信站: Maxwell!bbs.ee.ntu!freebsd.ntu!news.cs.nthu!news.cis.nctu!Wind
这是自己改的 Proftpd 1.2.0pre2 流量控制的 patch. 需要原来 proftpd source! 相关程式可以在 ftp://swallow.twbbs.org/Linux/FTP/ 下找到
用法: 1. 如果你的 proftpd-1.2.0pre2.tar.gz 解在 proftpd-1.2.0pre2/
将本 patch 放跟 proftpd-1.2.0pre2/ 同一层目录, 打 patch < proftpd-1.2.0pre2-bandwidth.patch 如果放在 proftpd-1.2.0pre2/ 下 patch -p1 < proftpd-1.2.0pre2-bandwidth.patch 2. 重新 Make 你的 source!
系统设定: 1. 提供三个控制流量功能(只有下传) 可以设在 server config,,
BandWidth : 总频宽 MaxBandWidth : 每线最大频宽 MinBandWidth : 每线最小频宽
必需为整数,代表 位元组/秒(Bytes/second)
三个功能的关系: MinBandWidth > MaxBandWidth > BandWidth
2. □例1. 设定 BandWidth 4096
如果有4人在线上,每个人的流量为 4096%424 位元组/秒
□例2. 设定 BandWidth 4096 MaxBandWidth 3072
如果有1人在线上,每个人的流量为 3072 位元组/秒 如果有2人在线上,每个人的流量为 4096%2 48 位元组/秒
以下类推
□例3. 设定 BandWidth 3072 MinBandWidth 1024
如果有1人在线上,每个人的流量为 3072 位元组/秒 如果有2人在线上,每个人的流量为 3072%236 位元组/秒
如果有3人在线上,每个人的流量为 3072%324 位元组/秒
如果有4人在线上,每个人的流量为 1024 位元组/秒 以下类推
详细的说明请看 patch 过的 mod_xfer.c
--- start proftpd-1.2.0pre2-bandwidth.patch ---
--- proftpd-1.2.0pre2.orig/modules/mod_xfer.c Fri Feb 19 15:11:11 19 99 +++ proftpd-1.2.0pre2/modules/mod_xfer.c Mon Feb 22 14:38:19 19 99 @@ -31,10 +31,140 @@ * */
+/******************************************************************** ******** + * Title : Bandwidth management + * File : mod_xfer.c (need orig source from proftpd-1.2.0pre2. tar.gz) + * Author : Albert Chiu (albert@swallow.twbbs.org.tw) + * Date : 22 Feb 1999 + * Version : 0.9p2 + * + * Description : + * Provide bandwidth usage limitation on per connection. + * + * Revision : + * Ver 0.9p2 + * - Add Bandwidth and MinBandWidth. + * Ver 0.9p1 + * - Fix unpredictable disconnect bugs. + * - Port patch to proftpd-1.2.0pre2 + * Ver 0.9 + * - First patch version base on proftpd-1.2.0pre1. + * - Only include MaxBandWidth. + * + ******************************************************************** ******* + * Copyright (c)1999 Albert Chiu ( Chiu Yang-Li ). All rights reserve d. + * Modify for the ProFTPD Group by : + * + * Albert Chiu + * albert@swallow.twbbs.org.tw + * http://swallow.twbbs.org.tw/~albert + * + * I get some idea and good function from Apache Module Collection. I 'd looked + * at mod_bandwidth, this one is almost what i want, so i use the ide a and + * rewrite it for ProFTPD 1.2.0pre1. + * But i find the select() function which mod_bandwidth use is usuall y bad + * performance, so i use setitimer() to replace it. + * + * you can get the collection from Apache Homepage (http://www.apache .org/). + * mod_bandwidth 1.0 is written by Yann Stettler (stettler@cohprog.co m). + * + ******************************************************************** *******/ + +/* + * Instruction : + * ------------- + * + * Note : this modify was writen for ProFTPD 1.2.0pre2 and tested on it + * + * Installation : + * + * Just make all source again is enough. :> + * + * + * Server configuration directive : + * ----------------------------------- + * - BandWidth + * Syntax : BandWidth + * Default : none + * Context : server config,, + * + * Limit the total bandwidth for file-transfer (retr only) + * Final each rate is depend of the number of connections. + * + * The is in Bytes/second. + * A of "0" means no bandwidth limit. + * + * Example : + * BandWidth 4096 + * + * If there are 4 users online , this will limit the bandwith + * for file-transfer to 4096/4 □24Bytes/sec. + * + * Note : If transfer file size is lower than the "BandWidth"/"Users" rate, + * it will ignore the limit. + * + * - MaxBandWidth + * Syntax : MaxBandWidth + * Default : none + * Context : server config,, + * + * Limit the bandwidth for file-transfer (retr only) + * This over-ride BandWidth rules as well as the calculated rate + * based on the number of connections. + * + * The is in Bytes/second. + * A of "0" means no bandwidth limit. + * + * Example : + * If BandWidth is set to "4096" (4KBytes/sec) and MaxBandWidth + * is set to "3072" (2KBytes/sec) that means : + * - if there is one connection, the file will be transfered + * at 3072 Bytes/sec. (Maximal of 3072 Bytes/sec). + * - if there is two connections, each files will be transfered
+ * at 2048 Bytes/sec. + * - if there is three or more connections, each files will be
+ * transfered at "4096/connections" Bytes/sec. + * + * Note : If transfer file size is lower than the "MaxBandWidth" rate , + * it will ignore the limit. + * + * - MinBandWidth + * Syntax : MinBandWidth + * Default : none + * Context : server config,, + * + * Set a minimal bandwidth to use for file-transfer. (retr only) + * This over-ride both BandWidth and MaxBandWidth rules as well + * as the calculated rate based on the number of connections. + * + * The is in Bytes/second. + * A of "0" means no bandwidth limit. + * + * Example : + * If BandWidth is set to "3072" (2KBytes/sec) and MinBandWidth + * is set to "1024" (1KBytes/sec) that means : + * - if there is one connection, the file will be transfered + * at 3072 Bytes/sec. + * - if there is two connections, each files will be transfered
+ * at 1536 Bytes/sec. + * - if there is three or more connections, each files will be
+ * transfered at 1024 Bytes/sec. (Minimal of 1024 Bytes/sec).
+ * + * Note : If transfer file size is lower than the "MinBandWidth" rate , + * it will ignore the limit. + * + */ + #include "conf.h" #ifdef HAVE_REGEX_H #include #endif +#include + +#undef timerisset +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_us ec) +#undef timerclear +#define timerclear(tvp) ((tvp)->tv_sec tvp)->tv_usec □
extern module auth_module; extern pid_t mpid; @@ -51,6 +181,7 @@ static int stor_fd; static int retr_fd;
+ module xfer_module;
static void _log_transfer(char direction) @@ -129,6 +260,48 @@ retr_file ULL; }
+static struct timeval timediff(struct timeval *a, struct timeval *b)
+{ + struct timeval rslt, tmp; + + tmp a; + + if ((rslt.tv_usec mp.tv_usec - b->tv_usec) < 0) { + rslt.tv_usec +□00000; + --(tmp.tv_sec); + } + if ((rslt.tv_sec mp.tv_sec - b->tv_sec) < 0) { + rslt.tv_usec □ + rslt.tv_sec □ + } + return (rslt); +} + +void handler(int sig) +{ + return; +} + +int sleep_msec(struct timeval *a) +{ + struct timeval tmp; + struct itimerval itimer; + void handler(); + + tmp a; + + if (timerisset(&tmp)) { + signal(SIGALRM,handler); + timerclear(&itimer.it_interval); + itimer.it_value.tv_usecp.tv_usec; + itimer.it_value.tv_secp.tv_sec; + setitimer(ITIMER_REAL,&itimer,(struct itimerval *)0); + pause(); + timerclear(&itimer.it_value); + setitimer(ITIMER_REAL,&itimer,(struct itimerval *)0); + } +} + /* cmd_pre_stor is a PRE_CMD handler which checks security, etc, and
* places the full filename to receive in cmd->private [note that we CANNOT * use cmd->tmp_pool for this, as tmp_pool only lasts for the duratio n @@ -384,9 +557,11 @@ struct stat sbuf; char *lbuf; int bufsize,len; + long cur_rate □max_rate □min_rate □cur_user □ unsigned long respos □cnt □cnt_steps □cnt_next □ privdata_t *p; - + struct timeval opt_time, last_time, now, timespent, timeout; + p od_privdata_find(cmd,"retr_filename",NULL);
if(!p) { @@ -433,10 +608,53 @@ cnt espos; log_add_run(mpid,NULL,session.user,NULL,0,session.xfer.file_size, 0,NULL);
+ /* Calculate bandwidth transfer time + * + * if "BandWidth" , "MaxBandWidth" or "MinBandWidth" not be defin ed or + * be defined error. i will turn off bandwidth limit. + */ + + cur_user long)get_param_int(cmd->server->conf,"CURRENT-CLIENTS",F ALSE)+1; + cur_rate long)get_param_int(cmd->server->conf,"Bandwidth",FALSE);
+ max_rate long)get_param_int(cmd->server->conf,"MaxBandwidth",FALS E); + min_rate long)get_param_int(cmd->server->conf,"MinBandwidth",FALS E); + + cur_rate □r_rate / cur_user; + + if(max_rate <□) + max_rate □; + if(min_rate <□) + min_rate □; + if(cur_rate <□) + { + if(max_rate > 0L) + cur_rate ax_rate; + else if(min_rate > 0L) + cur_rate in_rate; + else + cur_rate □; + } + + if((cur_rate > max_rate) && (max_rate > 0L)) + cur_rate ax_rate; + if(min_rate > cur_rate) + cur_rate in_rate; + + if(cur_rate > 0L) { + opt_time.tv_sec long int) bufsize / cur_rate; + opt_time.tv_usec long int) ((float) bufsize * 1000000 / cur_rat e - opt_time.tv_sec * 1000000); + log_debug(DEBUG1, "Current Bandwidth : %ld bytes/sec",cur_rate) ; + } + while((len s_read(retr_file,retr_fd,lbuf,bufsize)) > 0) { if(XFER_ABORTED) break;
+ /* record transfer start time */ + if(cur_rate > 0L) { + gettimeofday(&last_time, (struct timezone *) 0); + } + len □ta_xfer(lbuf,len); if(len < 0) { _retr_abort(); @@ -450,6 +668,21 @@ log_add_run(mpid,NULL,session.user,NULL,0,session.xfer.file_ size,cnt,NULL); } } + + /* calculate spent time and set up timer */ + if((cur_rate > 0L) && (session.xfer.file_size > cur_rate)) { + gettimeofday(&now, (struct timezone *) 0); + timespent imediff(&now, &last_time); + timeout imediff(&opt_time, ×pent); + log_debug(DEBUG5, "bandwidth : Sleep : %ld/%ld (Op time : %ld /%ld Spent : %ld/%ld)", + timeout.tv_sec, timeout.tv_usec, opt_time.tv_sec, opt_time.tv_usec, + timespent.tv_sec, timespent.tv_usec); + /* We sleep... */ + sleep_msec(&timeout); + if(TimeoutIdle) + reset_timer(TIMER_IDLE,ANY_MODULE); + } + }
if(XFER_ABORTED) { @@ -519,6 +752,57 @@ return DECLINED(cmd); }
+MODRET set_bandwidth(cmd_rec *cmd) +{ + long s_cur_rate + + CHECK_ARGS(cmd,1); + CHECK_CONF(cmd,CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL); + + s_cur_rate □oi(cmd->argv[1]); + + if(s_cur_rate < 0) + CONF_ERROR(cmd,"value must be lager then 0"); + + add_config_param_set(&cmd->server->conf,"Bandwidth",1,(void*)s_cur_ rate); + + return HANDLED(cmd); +} + +MODRET set_maximumbandwidth(cmd_rec *cmd) +{ + long s_cur_rate + + CHECK_ARGS(cmd,1); + CHECK_CONF(cmd,CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL); + + s_cur_rate □oi(cmd->argv[1]); + + if(s_cur_rate < 0) + CONF_ERROR(cmd,"value must be lager then 0"); + + add_config_param_set(&cmd->server->conf,"MaxBandwidth",1,(void*)s_c ur_rate); + + return HANDLED(cmd); +} + +MODRET set_minimumbandwidth(cmd_rec *cmd) +{ + long s_cur_rate + + CHECK_ARGS(cmd,1); + CHECK_CONF(cmd,CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL); + + s_cur_rate □oi(cmd->argv[1]); + + if(s_cur_rate < 0) + CONF_ERROR(cmd,"value must be lager then 0"); + + add_config_param_set(&cmd->server->conf,"MinBandwidth",1,(void*)s_c ur_rate); + + return HANDLED(cmd); +} + static int _noxfer_timeout(CALLBACK_FRAME) { if(session.flags & SF_XFER) @@ -542,6 +826,13 @@ return 0; }
+static conftable xfer_config[] + { "BandWidth", set_bandwidth, NULL } , + { "MaxBandWidth", set_maximumbandwidth, NULL } , + { "MinBandWidth", set_minimumbandwidth, NULL } , + { NULL, NULL, NULL }
+}; + cmdtable xfer_commands[] { CMD, C_TYPE, G_NONE, cmd_type, TRUE, FALSE, CL_MISC }, { PRE_CMD, C_RETR, G_READ, pre_cmd_retr, TRUE, FALSE }, @@ -562,7 +853,7 @@ NULL,NULL, /* Always NULL */ 0x20, /* API Version */ "xfer", /* Module name */ - NULL, /* No config */ + xfer_config, /* Config name */ xfer_commands, NULL, NULL,xfer_init_child
--- end proftpd-1.2.0pre2-bandwidth.patch ---
|