Bug#284115: apache-common: mod_bandwidth breaks resumes/multiple downloads
On Sun, Feb 06, 2005 at 12:57:09PM +0100, Piotr Krukowiecki wrote:
> Fix: e.g. use attached file instead of 504_mod_bandwidth_paths
> (it changes MASTER_DIR and LINK_DIR so you may want to change to retain
> backward compability)
Of course forgot to attache the file.
--
Piotrek
irc: #debian.pl
Mors Drosophilis melanogastribus!
--- build-tree/apache-contrib-1.0.8a/mod_bandwidth/mod_bandwidth.c 1999-08-20 09:59:02.000000000 +0200
+++ build-tree/apache-contrib-1.0.8a/mod_bandwidth/mod_bandwidth.c.mine 2004-12-06 21:16:11.000000000 +0100
@@ -54,8 +54,8 @@
* Title : Bandwidth management
* File : mod_bandwidth.c
* Author : Yann Stettler (stettler@cohprog.com)
- * Date : 17 July 1999
- * Version : 2.0 for Apache 1.3+
+ * Date : 12 January 2003
+ * Version : 2.0.6 for Apache 1.3+
*
* Description :
* Provide bandwidth usage limitation either on the whole server or
@@ -71,10 +71,17 @@
*
* Allow the use of the network/mask format when
* setting a bandwidth for a remote host/network.
- * (Thanks to Sami Kuhmonen for the patch)
+ * (Thanks to Sami Kuhmonen for the patch)
*
* New directive BandWidthPulse
*
+ * 10/14/00 - Minor bug fixed
+ * 12/15/00 - Bug fix when using mmap
+ * 08/29/01 - Add a directive to change the data directory
+ * (Thanks to Awesome Walrus <walrus@amur.ru> )
+ * 01/12/03 - Add MaxConnection directive to limit the number
+ * of simultaneous connections.
+ *
***************************************************************************
* Copyright (c)1997 Yann Stettler and CohProg SaRL. All rights reserved.
* Written for the Apache Group by :
@@ -97,27 +104,53 @@
* Instruction :
* -------------
*
- * Note : this module was writen for Apache 1.2b7 and tested on it
+ * Note : this module was writen for Apache 1.3.x and tested on it
*
* Installation :
*
* 1) Insert the following line at the end of the "Configuration" file :
* Module bandwidth_module mod_bandwidth.o
*
+ * WARNING : This behaviour is not the same between the various main versions
+ * of Apache. Please, read the instruction on our website for the
+ * instructions concerning the latest release :
+ * http://www.cohprog.com/v3/bandwidth/doc-en.html
+ *
* 2) Run the "Configure" program and re-compile the server with "make".
*
* 3) Create the following directories with "rwx" permission to everybody :
+ * (or rwx for the user under which Apache run : Usualy "nobody")
* /tmp/apachebw
* /tmp/apachebw/link
* /tmp/apachebw/master
*
+ * /==== by Awesome Walrus <walrus@amur.ru> =====================\
+ * Or you may change this name by using BandWidthDataDir global
+ * configuration directive. See below for details.
+ * \==== by Awesome Walrus <walrus@amur.ru> =====================/
+ *
* Note that if any of those directories doesn't exist, or if they can't
* be accessed by the server, the module is totaly disabled except for
* logging an error message in the logfile.
*
+ * Be careful that on some systems the content of the /tmp directory
+ * is deleted at boot time or every so often by a cronjob. If that the
+ * case, either disable this feature or change the location of the
+ * directories used by the module in the sources bellow.
+ *
* Server configuration directive :
* --------------------------------
*
+ * /==== by Awesome Walrus <walrus@amur.ru> =====================\
+ * - BandWidthDataDir
+ * Syntax : BandWidthDataDir <directory>
+ * Default : "/tmp/apachebw"
+ * Context : server config
+ *
+ * Sets the name of the directory used by mod_bandwidth to store
+ * its internal temporary information.
+ * \==== by Awesome Walrus <walrus@amur.ru> =====================/
+ *
* - BandWidthModule
* Syntax : BandWidthModule <On|Off>
* Default : Off
@@ -250,7 +283,7 @@
* <rate> is in bytes per second.
*
* A rate of "0" explicitly means to use the default minimal
- * value (256 KBytes/sec).
+ * value (256 Bytes/sec).
*
* A rate of "-1" means that the minimal rate is equal to the
* actual rate defined by BandWidth and LargeFileLimit.
@@ -291,6 +324,16 @@
* basis. (Ie: each virtual server will have that limit,
* _independantly_ of the other servers)
*
+ * - MaxConnection
+ * Syntax : MaxConnection <connections>
+ * Default : 0 (illimited)
+ * Context : per directory, .htaccess
+ *
+ * Restrict the number of maximum simultanous connections. If the
+ * limit is reached, new connections will be rejected.
+ "
+ * A value of 0 mean that there isn't any limits.
+ *
* Implementation notes :
* ----------------------
*
@@ -314,7 +357,7 @@
* no faster than the limited rate :) ...
*
* 4) Some kind of buffering is done as side effect. Data are
- * sent in packet of 1024 KBytes which seems a good value
+ * sent in packet of 1024 Bytes which seems a good value
* for TCP/IP.
* If another packet size is wanted, change the value of
* "#define PACKET" in the codes bellow.
@@ -340,22 +383,26 @@
#define MIN_BW_DEFAULT 256 /* Minimal bandwidth defaulted to 256Bps */
#define PACKET 1024 /* Sent packet of 1024 bytes */
-#define MASTER_DIR "/tmp/apachebw/master"
-#define LINK_DIR "/tmp/apachebw/link"
+/* #define MASTER_DIR "/tmp/apachebw/master"
+ * #define LINK_DIR "/tmp/apachebw/link"
+ */
-#ifdef USE_MMAP_FILES
-#include <unistd.h>
-#include <sys/mman.h>
+#define MASTER_DIR "master"
+#define LINK_DIR "link"
/* Define BWDEBUG for debuging purpose only ! */
/* #define BWDEBUG */
#ifdef BWDEBUG
#undef BWDEBUG
-#endif
+#endif
#define BANDWIDTH_DISABLED 1<<0
#define BANDWIDTH_ENABLED 1<<1
+#ifdef USE_MMAP_FILES
+#include <unistd.h>
+#include <sys/mman.h>
+
/* mmap support for static files based on ideas from John Heidemann's
* patch against 1.0.5. See
* <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
@@ -391,6 +438,7 @@ typedef struct {
array_header *limits;
array_header *minlimits;
array_header *sizelimits;
+ int maxconnection;
char *directory;
} bandwidth_config;
@@ -405,6 +453,8 @@ module bandwidth_module;
static long int BWPulse=0;
+char bandwidth_data_dir[MAX_STRING_LEN]="/var/lib/apache/mod-bandwidth";
+
/***************************************************************************
* Configuration functions *
***************************************************************************/
@@ -416,6 +466,7 @@ static void *create_bw_config(pool *p, c
new->minlimits=ap_make_array(p,20,sizeof(bw_entry));
new->sizelimits=ap_make_array(p,10,sizeof(bw_sizel));
new->directory=ap_pstrdup(p, path);
+ new->maxconnection=0;
return (void *)new;
}
@@ -442,6 +493,16 @@ static const char *bandwidthmodule(cmd_p
return NULL;
}
+static const char *set_bandwidth_data_dir(cmd_parms *cmd, void *dummy, char *arg) {
+ arg = ap_os_canonical_filename(cmd->pool, arg);
+
+ if (!ap_is_directory(arg)) {
+ return "BandWidthDataDir must be a valid directory";
+ }
+ ap_cpystrn(bandwidth_data_dir, arg, sizeof(bandwidth_data_dir));
+ return NULL;
+}
+
static const char *setpulse(cmd_parms *cmd, bandwidth_config *dconf, char *pulse) {
long int temp;
@@ -451,13 +512,30 @@ static const char *setpulse(cmd_parms *c
return "Invalid argument";
if (temp<0)
- return "BandWidth must be a number of bytes/s";
+ return "Pulse must be a number of microseconds/s";
BWPulse=temp;
return NULL;
}
+static const char *MaxConnection(cmd_parms *cmd, void *s, char *maxc) {
+ bandwidth_config *conf=(bandwidth_config *)s;
+ int temp;
+
+ if (maxc && *maxc && isdigit(*maxc))
+ temp = atoi(maxc);
+ else
+ return "Invalid argument";
+
+ if (temp<0)
+ return "Connections must be a number of simultaneous connections allowed/s";
+
+ conf->maxconnection=temp;
+
+ return NULL;
+}
+
static const char *bandwidth(cmd_parms *cmd, void *s, char *from, char *bw) {
bandwidth_config *conf=(bandwidth_config *)s;
bw_entry *a;
@@ -529,10 +607,14 @@ static command_rec bw_cmds[] = {
"a domain (or ip, or all for all) and a minimal bandwidth limit (in bytes/s)" },
{ "LargeFileLimit", largefilelimit, NULL, RSRC_CONF | OR_LIMIT, TAKE2,
"a filesize (in Kbytes) and a bandwidth limit (in bytes/s)" },
+{ "MaxConnection", MaxConnection, NULL, RSRC_CONF | OR_LIMIT, TAKE1,
+ "A number of allowed simultaneous connections" },
{ "BandWidthModule", bandwidthmodule, NULL, OR_FILEINFO, FLAG,
"On or Off to enable or disable (default) the whole bandwidth module" },
{ "BandWidthPulse", setpulse, NULL, OR_FILEINFO, TAKE1,
"a number of microseconds" },
+{ "BandWidthDataDir", set_bandwidth_data_dir, NULL, RSRC_CONF, TAKE1,
+ "A writable directory where temporary bandwidth info is to be stored" },
{ NULL }
};
@@ -578,7 +660,7 @@ static int in_ip(char *domain, char *wha
* "allow from 204.26.2" shouldn't let in people from 204.26.23
*/
int a, b, c, d, e;
- unsigned long in, out, inmask;
+ unsigned long in, out, inmask, outmask;
if (sscanf(domain, "%i.%i.%i.%i/%i", &a, &b, &c, &d, &e) < 5) {
int l = strlen(domain);
@@ -693,7 +775,7 @@ static int handle_bw(request_rec *r) {
bandwidth_server_config *sconf =
(bandwidth_server_config *)ap_get_module_config(r->server->module_config, &bandwidth_module);
long int bw_rate=0, bw_min=0, bw_f_rate=0, cur_rate;
- int bwlast=0, fd;
+ int nolimit=0, bwlast=0, fd;
long int tosend, bytessent, filelength;
struct stat fdata;
struct timeval opt_time, last_time, now, timespent, timeout;
@@ -724,7 +806,15 @@ static int handle_bw(request_rec *r) {
bw_min=get_bw_rate(r, conf->minlimits);
bw_f_rate=get_bw_filesize(r, conf->sizelimits , r->finfo.st_size);
- if ((bw_rate==0 && bw_f_rate==0) || bw_f_rate < 0 || !directory) return DECLINED;
+ if (!directory) return DECLINED;
+
+ if ((bw_rate==0 && bw_f_rate==0) || bw_f_rate < 0) {
+ if (!conf->maxconnection) {
+ return DECLINED;
+ } else {
+ nolimit=1;
+ }
+ }
if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
ap_log_reason("File does not exist", r->filename, r);
@@ -745,11 +835,11 @@ static int handle_bw(request_rec *r) {
* directory.
*/
- if (stat(directory, &fdata) < -1) {
+ if (stat(directory, &fdata) < 0) {
/* Dunno if this may happen... but well... */
return DECLINED;
}
- sprintf(masterfile,"%s/%d:%ld", MASTER_DIR, (short int)fdata.st_dev, (long int)fdata.st_ino);
+ sprintf(masterfile,"%s/%s/%d:%ld", bandwidth_data_dir, MASTER_DIR, (short int)fdata.st_dev, (long int)fdata.st_ino);
/*
* Check if master file already exist, else create it.
@@ -761,7 +851,15 @@ static int handle_bw(request_rec *r) {
}
close(fd);
- sprintf(filelink,"%s/%d", LINK_DIR, getpid());
+ /*
+ * Check if the maximum number of connections allowed is reached
+ */
+ if (conf->maxconnection && (conf->maxconnection <= current_connection(masterfile))) {
+/* return HTTP_SERVICE_UNAVAILABLE; */
+ return FORBIDDEN;
+ }
+
+ sprintf(filelink,"%s/%s/%d", bandwidth_data_dir, LINK_DIR, getpid());
if (link(masterfile, filelink) < 0) {
ap_log_printf(r->server, "mod_bandwidth : Can't create hard link %s", filelink);
return DECLINED;
@@ -772,6 +870,7 @@ static int handle_bw(request_rec *r) {
if (f == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR, r->server,
"file permissions deny server access: %s", r->filename);
+ unlink(filelink);
return FORBIDDEN;
}
@@ -815,7 +914,7 @@ static int handle_bw(request_rec *r) {
if (mm == (caddr_t)-1) {
ap_unblock_alarms();
- if (r->finfo.st_size >= MMAP_THRESHOLD) {
+ if ((r->finfo.st_size >= MMAP_THRESHOLD) && (!r->header_only)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, r->server,
"mmap_handler: mmap failed: %s", r->filename);
}
@@ -846,9 +945,13 @@ static int handle_bw(request_rec *r) {
* this case, I feel that I have the moral right to do so :)
*/
- opt_time.tv_sec=(long int) PACKET / cur_rate;
- opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
-
+ if (nolimit) {
+ opt_time.tv_sec=0;
+ opt_time.tv_usec=0;
+ } else {
+ opt_time.tv_sec=(long int) PACKET / cur_rate;
+ opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
+ }
tosend=PACKET;
if (tosend+bytessent >= filelength) {
tosend=filelength-bytessent;
@@ -858,7 +961,10 @@ static int handle_bw(request_rec *r) {
opt_time.tv_sec=(long int)BWPulse/1000000;
opt_time.tv_usec=BWPulse-opt_time.tv_sec*1000000;
- tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
+ if (nolimit)
+ tosend=filelength;
+ else
+ tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
if (tosend+bytessent >= filelength) {
tosend=filelength-bytessent;
bwlast=1;
@@ -905,8 +1011,13 @@ static int handle_bw(request_rec *r) {
cur_rate=bw_min;
if (BWPulse <= 0) {
- opt_time.tv_sec=(long int) PACKET / cur_rate;
- opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
+ if (nolimit) {
+ opt_time.tv_sec=0;
+ opt_time.tv_usec=0;
+ } else {
+ opt_time.tv_sec=(long int) PACKET / cur_rate;
+ opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
+ }
tosend=PACKET;
if (tosend+bytessent >= filelength) {
@@ -916,8 +1027,11 @@ static int handle_bw(request_rec *r) {
} else {
opt_time.tv_sec=(long int)BWPulse/1000000;
opt_time.tv_usec=BWPulse-opt_time.tv_sec*1000000;
-
- tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
+
+ if (nolimit)
+ tosend=filelength;
+ else
+ tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
if (tosend+bytessent >= filelength) {
tosend=filelength-bytessent;
bwlast=1;
@@ -987,8 +1101,13 @@ static int handle_bw(request_rec *r) {
* this case, I feel that I have the moral right to do so :)
*/
- opt_time.tv_sec=(long int) PACKET / cur_rate;
- opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
+ if (nolimit) {
+ opt_time.tv_sec=0;
+ opt_time.tv_usec=0;
+ } else {
+ opt_time.tv_sec=(long int) PACKET / cur_rate;
+ opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
+ }
tosend=PACKET;
if (tosend+bytessent >= filelength) {
@@ -999,7 +1118,10 @@ static int handle_bw(request_rec *r) {
opt_time.tv_sec=(long int)BWPulse/1000000;
opt_time.tv_usec=BWPulse-opt_time.tv_sec*1000000;
- tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
+ if (nolimit)
+ tosend=filelength;
+ else
+ tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
if (tosend+bytessent >= filelength) {
tosend=filelength-bytessent;
bwlast=1;
@@ -1044,8 +1166,13 @@ static int handle_bw(request_rec *r) {
cur_rate=bw_min;
if (BWPulse <= 0) {
- opt_time.tv_sec=(long int) PACKET / cur_rate;
- opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
+ if (nolimit) {
+ opt_time.tv_sec=0;
+ opt_time.tv_usec=0;
+ } else {
+ opt_time.tv_sec=(long int) PACKET / cur_rate;
+ opt_time.tv_usec=(long int)PACKET*1000000/cur_rate-opt_time.tv_sec*1000000;
+ }
tosend=PACKET;
if (tosend+bytessent >= filelength) {
@@ -1056,7 +1183,10 @@ static int handle_bw(request_rec *r) {
opt_time.tv_sec=(long int)BWPulse/1000000;
opt_time.tv_usec=BWPulse-opt_time.tv_sec*1000000;
- tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
+ if (nolimit)
+ tosend=filelength;
+ else
+ tosend=(long int)((double)BWPulse/(double)1000000*(double)cur_rate);
if (tosend+bytessent >= filelength) {
tosend=filelength-bytessent;
bwlast=1;
@@ -1069,7 +1199,7 @@ static int handle_bw(request_rec *r) {
#endif
gettimeofday(&last_time, (struct timezone *) 0);
- ap_send_mmap(mm, r, offset, tosend);
+ ap_send_mmap(mm, r, offset+bytessent, tosend);
bytessent += tosend;
if (r->connection->aborted)
break;
Reply to: