From 88148c9c0d3638daef215b88325ba8c29d25dfae Mon Sep 17 00:00:00 2001 From: sosherof Date: Tue, 26 Oct 2021 11:13:56 -0700 Subject: [PATCH 01/15] Updated fixes for Windows timer resolution. Added client bandwidth tracking to bypass sleeping if client's bandwidth is already less than available. --- .gitattributes | 63 +++++++++ .gitignore | 363 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 426 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file From 4598bcff9f8fdd67fb31e6dffcb8332f8d6179c0 Mon Sep 17 00:00:00 2001 From: sosherof Date: Tue, 26 Oct 2021 11:27:43 -0700 Subject: [PATCH 02/15] Updated fixes for Windows timer resolution. Added client bandwidth tracking to bypass sleeping if client's bandwidth is already less than available. --- .gitignore | 366 +---------------------------------------------------- 1 file changed, 4 insertions(+), 362 deletions(-) diff --git a/.gitignore b/.gitignore index 9491a2f..eaf39de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,363 +1,5 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Oo]ut/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +/.vs/mod_bw/v16 From 794ee8d1fbe55eed26455b6cd20bb0bca31c304a Mon Sep 17 00:00:00 2001 From: Sam Osheroff Date: Tue, 26 Oct 2021 11:29:26 -0700 Subject: [PATCH 03/15] Delete .gitattributes --- .gitattributes | 63 -------------------------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 1ff0c42..0000000 --- a/.gitattributes +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain From b0eba9cde8771a9136a09f277c45d9649ffb3c80 Mon Sep 17 00:00:00 2001 From: Sam Osheroff Date: Tue, 26 Oct 2021 11:29:41 -0700 Subject: [PATCH 04/15] Delete .gitignore --- .gitignore | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index eaf39de..0000000 --- a/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -################################################################################ -# This .gitignore file was automatically created by Microsoft(R) Visual Studio. -################################################################################ - -/.vs/mod_bw/v16 From 2406866ca6281d93cb18781f4ffa611df82a89bd Mon Sep 17 00:00:00 2001 From: sosherof Date: Tue, 26 Oct 2021 11:33:30 -0700 Subject: [PATCH 05/15] Updated fix for Windows sleep time resolution. Added client bandwidth calcuations to avoid sleeping if client bandwidth is less than available. --- mod_bw.c | 582 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 322 insertions(+), 260 deletions(-) diff --git a/mod_bw.c b/mod_bw.c index 2b24696..33959ad 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -24,11 +24,11 @@ Platform : Linux/x86 (Tested with Fedora Core 4, Suse, etc) Notes : This is a stable version of mod_bw. It should work with almost any MPM (tested with WinNT/prefork/Worker MPM). - We are reaching the End of mod_bw series 0.x. As soon as this + We are reaching the End of mod_bw series 0.x. As soon as this last changes are confirmed by the users (perhaps some changes at request), i'll set this release to version 1.0 final. -Limitations : This mod doesn't know how fast the client is +Limitations : This mod doesn't know how fast the client is downloading a file, so it just divides the bw assigned between the users. MaxConnections works only for the given scope. (i.e , all @@ -39,8 +39,8 @@ Changelog : 2010-07-20 : Fixed ap_get_server_banner unknown on older apache version 2010-05-27 : Fixed weird behaviour on Windows Hosts. (mod_bw.txt) Added high resolution timers for windows. (speed improvements) - Fixed stupid bug that caused crash when mod is enabled but there is - not a single limit. + Fixed stupid bug that caused crash when mod is enabled but there is + not a single limit. 2010-05-24 : Code Cleanup. No more warnings or stuff in Visual Studio 2010-04-28 : Bruce's Birthday Gift : A callback to the stats of the mod :) 2010-04-06 : Fixed "Invisible" memory leak. Only seen when serving HUGE streams. @@ -71,11 +71,11 @@ Changelog : #include "scoreboard.h" #if defined(WIN32) - #include - #include +#include +#include +#include #endif - #define MIN_BW 256 /* Minimal bandwidth 256 bytes */ #define PACKET 8192 /* Default packet at 8192 bytes */ #define MAX_VHOSTS 1024 /* Default number of vhosts to show in stats */ @@ -86,23 +86,23 @@ Changelog : /* Compatibility with regex on apache less than 2.1 */ #if !AP_MODULE_MAGIC_AT_LEAST(20050127,0) - typedef regex_t ap_regex_t; - #define AP_REG_EXTENDED REG_EXTENDED - #define AP_REG_ICASE REG_ICASE +typedef regex_t ap_regex_t; +#define AP_REG_EXTENDED REG_EXTENDED +#define AP_REG_ICASE REG_ICASE #endif /* Compatibility with obsolete ap_get_server_version() */ #if !AP_MODULE_MAGIC_AT_LEAST(20051115,4) - #define ap_get_server_banner ap_get_server_version +#define ap_get_server_banner ap_get_server_version #endif /* Compatibility for APR < 1 */ #if ( defined(APR_MAJOR_VERSION) && (APR_MAJOR_VERSION < 1) ) - #define apr_atomic_inc32 apr_atomic_inc - #define apr_atomic_dec32 apr_atomic_dec - #define apr_atomic_add32 apr_atomic_add - #define apr_atomic_cas32 apr_atomic_cas - #define apr_atomic_set32 apr_atomic_set +#define apr_atomic_inc32 apr_atomic_inc +#define apr_atomic_dec32 apr_atomic_dec +#define apr_atomic_add32 apr_atomic_add +#define apr_atomic_cas32 apr_atomic_cas +#define apr_atomic_set32 apr_atomic_set #endif /* Enum types of "from address" */ @@ -113,7 +113,7 @@ enum from_type { T_AGENT }; -/* +/* - Stats of each conf - - id = Configuration ID @@ -127,10 +127,10 @@ enum from_type { typedef struct { apr_uint32_t id; - char *v_name; + char* v_name; apr_uint32_t connection_count; apr_uint32_t bandwidth; - apr_uint32_t bytes_count; + unsigned long long bytes_count; apr_uint32_t counter; volatile apr_uint32_t lock; apr_time_t time; @@ -139,16 +139,19 @@ typedef struct /* A temporal context to save our splitted brigade */ typedef struct ctx_struct_t { - apr_bucket_brigade *bb; + apr_bucket_brigade* bb; struct timeval wait; + unsigned long long bw_interval_bytes, bw_interval_slept, client_bw; + apr_time_t bw_interval_start_time; + long sleep_bypasses_left, sleep_bypasses_total; } ctx_struct; -/* With sid we count the shared memory needed. +/* With sid we count the shared memory needed. BwBase, is a holder to the shared memory base addres */ -static char *vnames[MAX_VHOSTS]; +static char* vnames[MAX_VHOSTS]; static int sid = 0; -bw_data *bwbase; -apr_shm_t *shm; +bw_data* bwbase; +apr_shm_t* shm; /* Limits for MaxConnections based on directory */ @@ -156,10 +159,10 @@ typedef struct { apr_uint32_t sid; union { - char *from; - apr_ipsubnet_t *ip; + char* from; + apr_ipsubnet_t* ip; } x; - ap_regex_t *agent; + ap_regex_t* agent; enum from_type type; apr_uint32_t max; } bw_maxconn; @@ -169,10 +172,10 @@ typedef struct { apr_uint32_t sid; union { - char *from; - apr_ipsubnet_t *ip; + char* from; + apr_ipsubnet_t* ip; } x; - ap_regex_t *agent; + ap_regex_t* agent; enum from_type type; apr_int32_t rate; } bw_entry; @@ -181,7 +184,7 @@ typedef struct typedef struct { apr_uint32_t sid; - char *file; + char* file; apr_uint32_t size; apr_uint32_t rate; } bw_sizel; @@ -189,13 +192,13 @@ typedef struct /* Per directory configuration structure */ typedef struct { - apr_array_header_t *limits; - apr_array_header_t *minlimits; - apr_array_header_t *sizelimits; - apr_array_header_t *maxconnection; - int packet; + apr_array_header_t* limits; + apr_array_header_t* minlimits; + apr_array_header_t* sizelimits; + apr_array_header_t* maxconnection; + unsigned int packet; int error; - char *directory; + char* directory; } bandwidth_config; /* Per server configuration structure */ @@ -211,39 +214,39 @@ module AP_MODULE_DECLARE_DATA bw_module; /*---------------------------------------------------------------------* * Configurations Directives * *---------------------------------------------------------------------*/ -/* Set the mod enabled ... or disabled */ -static const char *bandwidthmodule(cmd_parms * cmd, void *dconf, int flag) + /* Set the mod enabled ... or disabled */ +static const char* bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) { - bandwidth_server_config *sconf; + bandwidth_server_config* sconf; sconf = - (bandwidth_server_config *) ap_get_module_config(cmd->server-> - module_config, - &bw_module); + (bandwidth_server_config*)ap_get_module_config(cmd->server-> + module_config, + &bw_module); sconf->state = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); return NULL; } /* Set force mode enabled ... or disabled */ -static const char *forcebandwidthmodule(cmd_parms * cmd, void *dconf, - int flag) +static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, + int flag) { - bandwidth_server_config *sconf; + bandwidth_server_config* sconf; sconf = - (bandwidth_server_config *) ap_get_module_config(cmd->server-> - module_config, - &bw_module); + (bandwidth_server_config*)ap_get_module_config(cmd->server-> + module_config, + &bw_module); sconf->force = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); return NULL; } /* Set the packetsize used in the context */ -static const char *setpacket(cmd_parms * cmd, void *s, const char *pack) +static const char* setpacket(cmd_parms* cmd, void* s, const char* pack) { - bandwidth_config *conf = (bandwidth_config *) s; + bandwidth_config* conf = (bandwidth_config*)s; int temp; if (pack && *pack && apr_isdigit(*pack)) @@ -260,9 +263,9 @@ static const char *setpacket(cmd_parms * cmd, void *s, const char *pack) } /* Set the error to send when maxconnections is reached */ -static const char *bandwidtherror(cmd_parms * cmd, void *s, const char *err) +static const char* bandwidtherror(cmd_parms* cmd, void* s, const char* err) { - bandwidth_config *conf = (bandwidth_config *) s; + bandwidth_config* conf = (bandwidth_config*)s; int temp; if (err && *err && apr_isdigit(*err)) @@ -279,14 +282,14 @@ static const char *bandwidtherror(cmd_parms * cmd, void *s, const char *err) } /* Set the maxconnections on a per host basis */ -static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, - const char *maxc) +static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, + const char* maxc) { - bandwidth_config *conf = (bandwidth_config *) s; - bw_maxconn *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_maxconn* a; int temp; - char *str; - char *where = (char *) apr_pstrdup(cmd->pool, from); + char* str; + char* where = (char*)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -297,19 +300,19 @@ static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, if (temp < 0) return - "Connections must be a number of simultaneous connections allowed/s"; + "Connections must be a number of simultaneous connections allowed/s"; - a = (bw_maxconn *) apr_array_push(conf->maxconnection); + a = (bw_maxconn*)apr_array_push(conf->maxconnection); a->x.from = where; - if (!strncasecmp(where,"u:",2)) - { + if (!strncasecmp(where, "u:", 2)) + { /* Do not limit based on origin, but on user agent */ a->type = T_AGENT; - a->agent = ap_pregcomp(cmd->pool, where+2, 0); + a->agent = ap_pregcomp(cmd->pool, where + 2, 0); if (a->agent == NULL) return "Regular expression could not be compiled."; - + } else if (!strcasecmp(where, "all")) { a->type = T_ALL; @@ -317,7 +320,7 @@ static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, else if ((str = strchr(where, '/'))) { *str++ = '\0'; rv = apr_ipsubnet_create(&a->x.ip, where, str, cmd->pool); - if(APR_STATUS_IS_EINVAL(rv)) { + if (APR_STATUS_IS_EINVAL(rv)) { /* looked nothing like an IP address */ return "An IP address was expected"; } @@ -326,14 +329,14 @@ static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, return apr_pstrdup(cmd->pool, msgbuf); } a->type = T_IP; - } + } else if (!APR_STATUS_IS_EINVAL(rv = apr_ipsubnet_create(&a->x.ip, where, NULL, cmd->pool))) { if (rv != APR_SUCCESS) { apr_strerror(rv, msgbuf, sizeof msgbuf); return apr_pstrdup(cmd->pool, msgbuf); } a->type = T_IP; - } + } else { /* no slash, didn't look like an IP address => must be a host */ a->type = T_HOST; } @@ -344,14 +347,14 @@ static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, } /* Set the bandwidth on a per host basis */ -static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, - const char *bw) +static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, + const char* bw) { - bandwidth_config *conf = (bandwidth_config *) s; - bw_entry *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_entry* a; long int temp; - char *str; - char *where = (char *) apr_pstrdup(cmd->pool, from); + char* str; + char* where = (char*)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -364,16 +367,16 @@ static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, if (temp < 0) return "BandWidth must be a number of bytes/s"; - a = (bw_entry *) apr_array_push(conf->limits); + a = (bw_entry*)apr_array_push(conf->limits); a->x.from = where; - if (!strncasecmp(where,"u:",2)) + if (!strncasecmp(where, "u:", 2)) { /* Do not limit based on origin, but on user agent */ a->type = T_AGENT; - a->agent = ap_pregcomp(cmd->pool, where+2, 0); + a->agent = ap_pregcomp(cmd->pool, where + 2, 0); if (a->agent == NULL) - return "Regular expression could not be compiled."; - + return "Regular expression could not be compiled."; + } else if (!strcasecmp(where, "all")) { a->type = T_ALL; @@ -381,7 +384,7 @@ static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, else if ((str = strchr(where, '/'))) { *str++ = '\0'; rv = apr_ipsubnet_create(&a->x.ip, where, str, cmd->pool); - if(APR_STATUS_IS_EINVAL(rv)) { + if (APR_STATUS_IS_EINVAL(rv)) { /* looked nothing like an IP address */ return "An IP address was expected"; } @@ -403,8 +406,8 @@ static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, } if (sid < MAX_VHOSTS) { - vnames[sid] = apr_pcalloc(cmd->pool,apr_snprintf(msgbuf,MAX_BUF,"%s,%s",cmd->server->server_hostname,where) ); - vnames[sid] = (char *) apr_pstrdup(cmd->pool, msgbuf); + vnames[sid] = apr_pcalloc(cmd->pool, apr_snprintf(msgbuf, MAX_BUF, "%s,%s", cmd->server->server_hostname, where)); + vnames[sid] = (char*)apr_pstrdup(cmd->pool, msgbuf); } a->rate = temp; a->sid = sid++; @@ -414,14 +417,14 @@ static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, } /* Set the minimum bandwidth to send */ -static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, - const char *bw) +static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, + const char* bw) { - bandwidth_config *conf = (bandwidth_config *) s; - bw_entry *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_entry* a; long int temp; - char *str; - char *where = (char *) apr_pstrdup(cmd->pool, from); + char* str; + char* where = (char*)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -430,13 +433,13 @@ static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, else return "Invalid argument"; - a = (bw_entry *) apr_array_push(conf->minlimits); + a = (bw_entry*)apr_array_push(conf->minlimits); a->x.from = where; - if (!strncasecmp(where,"u:",2)) + if (!strncasecmp(where, "u:", 2)) { /* Do not limit based on origin, but on user agent */ a->type = T_AGENT; - a->agent = ap_pregcomp(cmd->pool, where+2, 0); + a->agent = ap_pregcomp(cmd->pool, where + 2, 0); if (a->agent == NULL) return "Regular expression could not be compiled."; @@ -447,7 +450,7 @@ static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, else if ((str = strchr(where, '/'))) { *str++ = '\0'; rv = apr_ipsubnet_create(&a->x.ip, where, str, cmd->pool); - if(APR_STATUS_IS_EINVAL(rv)) { + if (APR_STATUS_IS_EINVAL(rv)) { /* looked nothing like an IP address */ return "An IP address was expected"; } @@ -474,11 +477,11 @@ static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, } /* Set the large file bandwidth limit */ -static const char *largefilelimit(cmd_parms * cmd, void *s, const char *file, - const char *size, const char *bw) +static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, + const char* size, const char* bw) { - bandwidth_config *conf = (bandwidth_config *) s; - bw_sizel *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_sizel* a; long int temp, tsize; char msgbuf[MAX_BUF]; @@ -501,14 +504,14 @@ static const char *largefilelimit(cmd_parms * cmd, void *s, const char *file, if (tsize < 0) return "File size must be a number of Kbytes"; - a = (bw_sizel *) apr_array_push(conf->sizelimits); - a->file = (char *) file; + a = (bw_sizel*)apr_array_push(conf->sizelimits); + a->file = (char*)file; a->size = tsize; a->rate = temp; if (sid < MAX_VHOSTS) { - vnames[sid] = apr_pcalloc(cmd->pool,apr_snprintf(msgbuf,MAX_BUF,"%s,%s",cmd->server->server_hostname,file) ); - vnames[sid] = (char *) apr_pstrdup(cmd->pool, msgbuf); + vnames[sid] = apr_pcalloc(cmd->pool, apr_snprintf(msgbuf, MAX_BUF, "%s,%s", cmd->server->server_hostname, file)); + vnames[sid] = (char*)apr_pstrdup(cmd->pool, msgbuf); } a->sid = sid++; @@ -520,11 +523,11 @@ static const char *largefilelimit(cmd_parms * cmd, void *s, const char *file, * Helper Functions * *----------------------------------------------------------------------------*/ -/* Match the input, as part of a domain */ -static int in_domain(const char *domain, const char *what) + /* Match the input, as part of a domain */ +static int in_domain(const char* domain, const char* what) { - int dl = strlen(domain); - int wl = strlen(what); + size_t dl = strlen(domain); + size_t wl = strlen(what); if ((wl - dl) >= 0) { if (strcasecmp(domain, &what[wl - dl]) != 0) @@ -544,27 +547,27 @@ static int in_domain(const char *domain, const char *what) } /* Get the bandwidth limit based on from address */ -static long get_bw_rate(request_rec * r, apr_array_header_t * a) +static long get_bw_rate(request_rec* r, apr_array_header_t* a) { - bw_entry *e = (bw_entry *) a->elts; - const char *remotehost = NULL; + bw_entry* e = (bw_entry*)a->elts; + const char* remotehost = NULL; int i; int gothost = 0; - const char *uastr = NULL; + const char* uastr = NULL; for (i = 0; i < a->nelts; i++) { switch (e[i].type) { case T_AGENT: uastr = apr_table_get(r->headers_in, "User-Agent"); - if (e[i].agent && uastr && ap_regexec(e[i].agent, uastr, 0, NULL, 0)==0 ) + if (e[i].agent && uastr && ap_regexec(e[i].agent, uastr, 0, NULL, 0) == 0) return (e[i].rate); break; case T_ALL: return e[i].rate; case T_IP: - if (apr_ipsubnet_test(e[i].x.ip, r->connection->remote_addr)) { + if (apr_ipsubnet_test(e[i].x.ip, r->connection->client_addr)) { return e[i].rate; } break; @@ -573,7 +576,7 @@ static long get_bw_rate(request_rec * r, apr_array_header_t * a) int remotehost_is_ip; remotehost = ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_DOUBLE_REV, &remotehost_is_ip); + REMOTE_DOUBLE_REV, &remotehost_is_ip); if ((remotehost == NULL) || remotehost_is_ip) gothost = 1; @@ -585,16 +588,16 @@ static long get_bw_rate(request_rec * r, apr_array_header_t * a) return (e[i].rate); break; } - + } return 0; } -/* - Match the pattern with the last digist from filename - An asterisk means any. +/* + Match the pattern with the last digist from filename + An asterisk means any. */ -static int match_ext(const char *file, char *match) +static int match_ext(const char* file, char* match) { if (file == NULL || match == NULL) return 0; @@ -611,10 +614,10 @@ static int match_ext(const char *file, char *match) } /* Get the bandwidth limit based on filesize */ -static long get_bw_filesize(request_rec * r, apr_array_header_t * a, - apr_uint32_t filesize, const char *filename) +static long get_bw_filesize(request_rec* r, apr_array_header_t* a, + apr_uint32_t filesize, const char* filename) { - bw_sizel *e = (bw_sizel *) a->elts; + bw_sizel* e = (bw_sizel*)a->elts; int i; apr_uint32_t tmpsize = 0, tmprate = 0; @@ -635,27 +638,27 @@ static long get_bw_filesize(request_rec * r, apr_array_header_t * a, } /* Get the MaxConnections allowed */ -static int get_maxconn(request_rec * r, apr_array_header_t * a) +static int get_maxconn(request_rec* r, apr_array_header_t* a) { - bw_maxconn *e = (bw_maxconn *) a->elts; - const char *remotehost = NULL; + bw_maxconn* e = (bw_maxconn*)a->elts; + const char* remotehost = NULL; int i; int gothost = 0; - const char *uastr = NULL; + const char* uastr = NULL; for (i = 0; i < a->nelts; i++) { switch (e[i].type) { case T_AGENT: uastr = apr_table_get(r->headers_in, "User-Agent"); - if (e[i].agent && uastr && ap_regexec(e[i].agent, uastr, 0, NULL, 0)==0 ) + if (e[i].agent && uastr && ap_regexec(e[i].agent, uastr, 0, NULL, 0) == 0) return (e[i].max); break; case T_ALL: return e[i].max; case T_IP: - if (apr_ipsubnet_test(e[i].x.ip, r->connection->remote_addr)) { + if (apr_ipsubnet_test(e[i].x.ip, r->connection->client_addr)) { return e[i].max; } break; @@ -664,7 +667,7 @@ static int get_maxconn(request_rec * r, apr_array_header_t * a) int remotehost_is_ip; remotehost = ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_DOUBLE_REV, &remotehost_is_ip); + REMOTE_DOUBLE_REV, &remotehost_is_ip); if ((remotehost == NULL) || remotehost_is_ip) gothost = 1; @@ -682,31 +685,31 @@ static int get_maxconn(request_rec * r, apr_array_header_t * a) } /* Get an id based on bandwidth limit */ -static int get_sid(request_rec * r, apr_array_header_t * a) +static int get_sid(request_rec* r, apr_array_header_t* a) { - bw_entry *e = (bw_entry *) a->elts; - const char *remotehost = NULL; + bw_entry* e = (bw_entry*)a->elts; + const char* remotehost = NULL; int i; int gothost = 0; - const char *uastr; + const char* uastr; remotehost = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_HOST, - NULL); + NULL); for (i = 0; i < a->nelts; i++) { switch (e[i].type) { case T_AGENT: uastr = apr_table_get(r->headers_in, "User-Agent"); - if (e[i].agent && uastr && ap_regexec(e[i].agent, uastr, 0, NULL, 0)==0 ) + if (e[i].agent && uastr && ap_regexec(e[i].agent, uastr, 0, NULL, 0) == 0) return (e[i].sid); break; case T_ALL: return e[i].sid; case T_IP: - if (apr_ipsubnet_test(e[i].x.ip, r->connection->remote_addr)) { + if (apr_ipsubnet_test(e[i].x.ip, r->connection->client_addr)) { return e[i].sid; } break; @@ -715,7 +718,7 @@ static int get_sid(request_rec * r, apr_array_header_t * a) int remotehost_is_ip; remotehost = ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_DOUBLE_REV, &remotehost_is_ip); + REMOTE_DOUBLE_REV, &remotehost_is_ip); if ((remotehost == NULL) || remotehost_is_ip) gothost = 1; @@ -733,10 +736,10 @@ static int get_sid(request_rec * r, apr_array_header_t * a) } /* Get an id based on filesize limit */ -static int get_f_sid(request_rec * r, apr_array_header_t * a, apr_uint32_t filesize, - const char *filename) +static int get_f_sid(request_rec* r, apr_array_header_t* a, apr_uint32_t filesize, + const char* filename) { - bw_sizel *e = (bw_sizel *) a->elts; + bw_sizel* e = (bw_sizel*)a->elts; int i; apr_uint32_t tmpsize = 0, tmpsid = -1; @@ -759,7 +762,7 @@ static int get_f_sid(request_rec * r, apr_array_header_t * a, apr_uint32_t files } /* Update memory (shm) counters, which holds the bw data per context */ -static void update_counters(bw_data * bwstat, ap_filter_t * f) +static void update_counters(bw_data* bwstat, ap_filter_t* f) { apr_time_t nowtime; @@ -770,8 +773,8 @@ static void update_counters(bw_data * bwstat, ap_filter_t * f) if (apr_atomic_cas32(&bwstat->lock, 1, 0) == 0) { /* Calculate bw used in the last timeinterval */ - bwstat->bandwidth = (apr_uint32_t) ( - (bwstat->bytes_count / (double) (nowtime - bwstat->time)) * + bwstat->bandwidth = (apr_uint32_t)( + (bwstat->bytes_count / (double)(nowtime - bwstat->time)) * 1000000); /* Reset counters */ @@ -786,29 +789,29 @@ static void update_counters(bw_data * bwstat, ap_filter_t * f) } } -static int callback(request_rec * r) +static int callback(request_rec* r) { int t; - bw_data *bwstat; + bw_data* bwstat; if (r->header_only) { return OK; } - if (r->args && !strncasecmp(r->args,"csv",3)) + if (r->args && !strncasecmp(r->args, "csv", 3)) { ap_set_content_type(r, "text/plain"); - ap_rputs("id,vhost,scope,lock,count,bw,bytes,hits\n",r); - + ap_rputs("id,vhost,scope,lock,count,bw,bytes,hits\n", r); + for (t = 0; t < sid; t++) { bwstat = bwbase + t; - ap_rprintf(r,"%d,%s,%d,%d,%d,%d,%d\n",t,bwstat->v_name,bwstat->lock,bwstat->connection_count,bwstat->bandwidth,bwstat->bytes_count,bwstat->counter); + ap_rprintf(r, "%d,%s,%d,%d,%d,%d,%d\n", t, bwstat->v_name, bwstat->lock, bwstat->connection_count, bwstat->bandwidth, bwstat->bytes_count, bwstat->counter); } return OK; } - + ap_set_content_type(r, "text/html"); ap_rputs(DOCTYPE_HTML_3_2, r); @@ -821,7 +824,7 @@ static int callback(request_rec * r) ap_rputs(" \n", r); ap_rputs("

\n", r); ap_rprintf(r, " Apache HTTP Server version: \"%s\"\n", - ap_get_server_banner()); + ap_get_server_banner()); ap_rputs("
\n", r); ap_rprintf(r, " Server built: \"%s\"\n", ap_get_server_built()); ap_rputs("

\n", r);; @@ -831,20 +834,20 @@ static int callback(request_rec * r) bwstat = bwbase + t; /* This inits the struct that will contain current bw use */ - ap_rputs("
",r); - ap_rprintf(r,"id : %d
",t); - ap_rprintf(r,"name : %s
",bwstat->v_name); - ap_rprintf(r,"lock : %d
",bwstat->lock); - ap_rprintf(r,"count: %d
",bwstat->connection_count); - ap_rprintf(r,"bw : %d
",bwstat->bandwidth); - ap_rprintf(r,"bytes: %d
",bwstat->bytes_count); - ap_rprintf(r,"hits : %d
",bwstat->counter); + ap_rputs("
", r); + ap_rprintf(r, "id : %d
", t); + ap_rprintf(r, "name : %s
", bwstat->v_name); + ap_rprintf(r, "lock : %d
", bwstat->lock); + ap_rprintf(r, "count: %d
", bwstat->connection_count); + ap_rprintf(r, "bw : %d
", bwstat->bandwidth); + ap_rprintf(r, "bytes: %d
", bwstat->bytes_count); + ap_rprintf(r, "hits : %d
", bwstat->counter); } ap_rputs(" \n", r); ap_rputs("\n", r); - return OK; + return OK; } @@ -852,25 +855,25 @@ static int callback(request_rec * r) /*----------------------------------------------------------------------------* * The Handler and the Output Filter. Core of the mod. * *----------------------------------------------------------------------------*/ -/* With this handler, we can *force* the use of the mod. */ -static int handle_bw(request_rec * r) + /* With this handler, we can *force* the use of the mod. */ +static int handle_bw(request_rec* r) { - bandwidth_server_config *sconf = - (bandwidth_server_config *) ap_get_module_config(r->server-> - module_config, - &bw_module); - bandwidth_config *conf = - (bandwidth_config *) ap_get_module_config(r->per_dir_config, - &bw_module); - bw_data *bwstat; + bandwidth_server_config* sconf = + (bandwidth_server_config*)ap_get_module_config(r->server-> + module_config, + &bw_module); + bandwidth_config* conf = + (bandwidth_config*)ap_get_module_config(r->per_dir_config, + &bw_module); + bw_data* bwstat; apr_int32_t confid; /* Only work on main request/no subrequests */ if (r->main) return DECLINED; - if (strcmp(r->handler, "modbw-handler")==0) return callback(r); + if (strcmp(r->handler, "modbw-handler") == 0) return callback(r); /* Return if module is not enabled */ @@ -889,7 +892,7 @@ static int handle_bw(request_rec * r) /* If we are too busy, deny connection */ confid = get_maxconn(r, conf->maxconnection); - if ((bwstat->connection_count >= (apr_uint32_t) confid) && (confid > 0)) + if ((bwstat->connection_count >= (apr_uint32_t)confid) && (confid > 0)) return conf->error; } @@ -901,25 +904,27 @@ static int handle_bw(request_rec * r) return DECLINED; } -static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) +static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) { - request_rec *r = f->r; - bandwidth_config *conf = - (bandwidth_config *) ap_get_module_config(r->per_dir_config, - &bw_module); - bandwidth_server_config *sconf = - (bandwidth_server_config *) ap_get_module_config(r->server-> - module_config, - &bw_module); - ctx_struct *ctx = f->ctx; - apr_bucket *b = APR_BRIGADE_FIRST(bb); - bw_data *bwstat, *bwmaxconn; + request_rec* r = f->r; + bandwidth_config* conf = + (bandwidth_config*)ap_get_module_config(r->per_dir_config, + &bw_module); + bandwidth_server_config* sconf = + (bandwidth_server_config*)ap_get_module_config(r->server-> + module_config, + &bw_module); + ctx_struct* ctx = f->ctx; + apr_bucket* b = APR_BRIGADE_FIRST(bb); + bw_data* bwstat, * bwmaxconn; int confid = -1, connid = -1; apr_size_t packet = conf->packet, bytes = 0; apr_off_t bblen = 0; - long int bw_rate, bw_min, bw_f_rate, cur_rate = 0, sleep; - const char *buf; - const char *filename; + apr_size_t bw_rate, bw_min, bw_f_rate, cur_rate = 0; + apr_interval_time_t sleep; + const char* buf; + const char* filename; + long current_sleep_bypasses = 0; /* Only work on main request/no subrequests */ if (r->main) { @@ -945,7 +950,7 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) /* Get the File Rate. r->finfo.size is not used anymore. */ bblen = r->bytes_sent; - bw_f_rate = get_bw_filesize(r, conf->sizelimits, (off_t) bblen, filename); + bw_f_rate = get_bw_filesize(r, conf->sizelimits, (off_t)bblen, filename); /* Check if we've got an ilimited client */ @@ -960,7 +965,7 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) - If file size is zero, all files apply */ if (bw_f_rate && (bw_rate > bw_f_rate || !bw_rate)) { - confid = get_f_sid(r, conf->sizelimits, (off_t) bblen, filename); + confid = get_f_sid(r, conf->sizelimits, (off_t)bblen, filename); bw_rate = bw_f_rate; } @@ -969,11 +974,17 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) else if (!bw_min) bw_min = MIN_BW; - /* Initialize our temporal space */ + /* Initialize our temporal space, which survives multiple invokations for the same request */ if (ctx == NULL) { - apr_bucket_alloc_t *bucket_alloc = apr_bucket_alloc_create(f->r->pool); + apr_bucket_alloc_t* bucket_alloc = apr_bucket_alloc_create(f->r->pool); f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); ctx->bb = apr_brigade_create(f->r->pool, bucket_alloc); + + ctx->bw_interval_start_time = apr_time_now(); + ctx->bw_interval_slept = 0; + ctx->bw_interval_bytes = 0; + ctx->sleep_bypasses_left = 0; + ctx->sleep_bypasses_total = 0; } /* We "get" the data of the current configuration */ @@ -990,13 +1001,12 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) /* Verbose Output */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "ID: %i Directory : %s Rate : %ld Minimum : %ld Size rate : %ld", - confid, conf->directory, bw_rate, bw_min, bw_f_rate); + "ID: %i; Directory : %s; File : %s; Rate : %ld; Minimum : %ld; Size rate : %ld;", + confid, conf->directory, filename, bw_rate, bw_min, bw_f_rate); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "clients : %d/%d rate/min : %ld,%ld", bwmaxconn->connection_count, - (connid >= 0) ? get_maxconn(r, conf->maxconnection) : 0, - bw_rate, bw_min); - + "clients : %d/%d; rate/min : %ld,%ld", bwmaxconn->connection_count, + (connid >= 0) ? get_maxconn(r, conf->maxconnection) : 0, + bw_rate, bw_min); /* - We get buckets until a sentinel appears @@ -1009,6 +1019,7 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) APR_BUCKET_REMOVE(b); APR_BRIGADE_INSERT_TAIL(ctx->bb, b); ap_pass_brigade(f->next, ctx->bb); + apr_brigade_cleanup(ctx->bb); /* Delete 1 active connection */ apr_atomic_dec32(&bwmaxconn->connection_count); @@ -1017,15 +1028,16 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) if (apr_bucket_read(b, &buf, &bytes, APR_NONBLOCK_READ) == APR_SUCCESS) { + /* This changed, cause of the limit handling error.. see below */ while (bytes > 0) { /* - - Ok, i'm doing lots of things here. The bw the client will have, is + - Ok, i'm doing lots of things here. The bw the client will have, is the bw available divided by the number of clients. - - The minimum bw, will always be MIN_BW. If all bw is used, and new + - The minimum bw, will always be MIN_BW. If all bw is used, and new connections arrives, they'll have MIN_BW bw available. */ - cur_rate = (long int) bw_rate / bwmaxconn->connection_count; + cur_rate = (long int)bw_rate / bwmaxconn->connection_count; if (cur_rate > bw_rate) cur_rate = bw_rate; @@ -1050,21 +1062,58 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) /* Here we get the time we need to sleep to get the specified bw */ sleep = - (long int) (1000000 / - ((double) cur_rate / (double) packet)); + (unsigned long)(1000000 / + ((double)cur_rate / (double)packet)); + + /* if more than 15ms has elapsed, roughly calculate client's actual bandwidth */ + if ((apr_time_now() - ctx->bw_interval_slept) - ctx->bw_interval_start_time > 15000) { + ctx->client_bw = (ctx->bw_interval_bytes * 1000 / (unsigned long long)((apr_time_now() - ctx->bw_interval_slept) - ctx->bw_interval_start_time)) * 1000; + ctx->bw_interval_bytes = 0; + ctx->bw_interval_slept = 0; + ctx->bw_interval_start_time = apr_time_now(); + /* Verbose logging */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Client BW is ~%ld B/s. This %s than available BW (%ld). %s", ctx->client_bw, (ctx->client_bw > cur_rate ? "More" : "Less"), cur_rate, (ctx->client_bw > cur_rate ? "BW Limiting!" : "Not BW limiting!")); + } + #if defined(WIN32) - if (sleep < 200000 && cur_rate > 1024) - { - sleep = 200000; - packet = cur_rate/5; - if (bytes < packet) - packet = bytes; - } + /* For Windows, assume the minimum sleep time is 10ms. If the needed sleep time is less than 10ms, calculate + how many packets to send before sleeping for 10ms. For very small buckets, this can result in an + absurdly high number of packets to send, probably more than there are buckets, so it doesn't matter. */ + if (sleep < 10000 && ctx->client_bw > cur_rate) + { + /* calculate, based on available bandwidth right now, how many packets can be sent in 10 ms */ + current_sleep_bypasses = (long)((double)10000 / (double)(sleep + 1)); /* plus 1 microsecond to avoid divide by zero errors */ + + sleep = 10000; + + if (ctx->sleep_bypasses_left == 0) { /* If not currently counting down packets... */ + ctx->sleep_bypasses_total = current_sleep_bypasses; /* setup counters */ + ctx->sleep_bypasses_left = current_sleep_bypasses; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "File: %s. BW: %ld B/s. Packet: %ld bytes. Bypassing sleep for %i packet(s).", filename, cur_rate, packet, ctx->sleep_bypasses_left); + } + else { + /* If number of packets to send in 10ms has changed since last calc because available bandwidth changed, recalcuate */ + if (ctx->sleep_bypasses_total != current_sleep_bypasses) { + /* new packet counter = packets_per_10ms minus packets already sent */ + ctx->sleep_bypasses_left = current_sleep_bypasses - (ctx->sleep_bypasses_total - ctx->sleep_bypasses_left); + + if (ctx->sleep_bypasses_left < 0) { + ctx->sleep_bypasses_left = 0; /* if new packets to send is less than zero, reset to zero so we sleep now*/ + } + ctx->sleep_bypasses_total = current_sleep_bypasses; /* Update the total packets to send in this period */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "File: %s. Available BW changed to %ld B/s. Now bypassing sleep for %ld more packet(s).", filename, cur_rate, ctx->sleep_bypasses_left); + } + } + } + else { + ctx->sleep_bypasses_left = 0; + } #endif - - /* + /* Here, we are going to split the bucket, and send it on piece at a time, - doing a "delay" between each piece. That way, we send the data at the + doing a "delay" between each piece. That way, we send the data at the specified rate. */ apr_bucket_split(b, packet); @@ -1073,25 +1122,36 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) /* Decrease our counter */ bytes -= packet; + ctx->bw_interval_bytes += packet; /* Flush and move to the next bucket */ ap_pass_brigade(f->next, ctx->bb); + apr_brigade_cleanup(ctx->bb); b = APR_BRIGADE_FIRST(bb); /* Add the number of bytes transferred, so we can get an estimated bw usage */ - apr_atomic_add32(&bwstat->bytes_count, packet); + apr_atomic_add64(&bwstat->bytes_count, packet); /* If the connection goes to hell... go with it ! */ if (r->connection->aborted) { /* Verbose. Tells when the connection was ended */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, - 0, r->server, "Connection to hell"); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, + 0, r, "Connection to hell"); apr_atomic_dec32(&bwmaxconn->connection_count); return APR_SUCCESS; } - /* Sleep ... zZZzZzZzzzz */ - apr_sleep(sleep); + /* Sleep ... but only if the time is right (see Windows clock resolution fix above) */ + if (ctx->sleep_bypasses_left > 0) { + ctx->sleep_bypasses_left--; + } + else { + if (ctx->client_bw > cur_rate) { /* Only sleep if the client's calculated bw is greater than available */ + apr_sleep(sleep); /* bandwidth, otherwise there's no reason to sleep. */ + ctx->bw_interval_slept += sleep; + } + ctx->sleep_bypasses_left = 0; + } /* Refresh counters, so we can keep working :) */ update_counters(bwstat, f); @@ -1102,11 +1162,12 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) APR_BRIGADE_INSERT_TAIL(ctx->bb, b); b = APR_BRIGADE_FIRST(bb); - /* Add the number of bytes to the counter */ - apr_atomic_add32(&bwstat->bytes_count, bytes); + /* Add the number of bytes to the counter - switched to the 64bit counter for bigger files */ + apr_atomic_add64(&bwstat->bytes_count, bytes); /* Pass the final brigade */ ap_pass_brigade(f->next, ctx->bb); + apr_brigade_cleanup(ctx->bb); } /* Delete 1 active connection to the record */ @@ -1121,26 +1182,26 @@ static int bw_filter(ap_filter_t * f, apr_bucket_brigade * bb) /*----------------------------------------------------------------------------* * Module Init functions * *----------------------------------------------------------------------------*/ -static int bw_init(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, - server_rec * s) +static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, + server_rec* s) { apr_status_t status; apr_size_t retsize; apr_size_t shm_size; - bw_data *bwstat; + bw_data* bwstat; int t; #if defined(WIN32) - TIMECAPS resolution; + TIMECAPS resolution; #endif /* These two help ensure that we only init once. */ - void *data; - const char *userdata_key = "ivn_shm_bw_limit_module"; + void* data; + const char* userdata_key = "ivn_shm_bw_limit_module"; apr_pool_userdata_get(&data, userdata_key, s->process->pool); if (!data) { - apr_pool_userdata_set((const void *) 1, userdata_key, - apr_pool_cleanup_null, s->process->pool); + apr_pool_userdata_set((const void*)1, userdata_key, + apr_pool_cleanup_null, s->process->pool); return OK; } @@ -1149,7 +1210,7 @@ static int bw_init(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, if (status != APR_SUCCESS) return HTTP_INTERNAL_SERVER_ERROR; - shm_size = (apr_size_t) sizeof(bw_data) * sid; + shm_size = (apr_size_t)sizeof(bw_data) * sid; /* If there was a memory block already assigned.. destroy it */ @@ -1157,11 +1218,12 @@ static int bw_init(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, status = apr_shm_destroy(shm); if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "mod_bw : Couldn't destroy old memory block\n"); + "mod_bw : Couldn't destroy old memory block\n"); return status; - } else { + } + else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "mod_bw : Old Shared memory block, destroyed."); + "mod_bw : Old Shared memory block, destroyed."); } } @@ -1169,32 +1231,32 @@ static int bw_init(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, status = apr_shm_create(&shm, shm_size, NULL, p); if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "mod_bw : Error creating shm block\n"); + "mod_bw : Error creating shm block\n"); return status; } /* Check size of shared memory block */ retsize = apr_shm_size_get(shm); if (retsize != shm_size) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "mod_bw : Error allocating shared memory block\n"); + "mod_bw : Error allocating shared memory block\n"); return status; } /* Init shm block */ bwbase = apr_shm_baseaddr_get(shm); if (bwbase == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "mod_bw : Error creating status block.\n"); + "mod_bw : Error creating status block.\n"); return status; } memset(bwbase, 0, retsize); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, - "mod_bw : Memory Allocated %d bytes (each conf takes %d bytes)", - (int) retsize, (int) sizeof(bw_data)); + "mod_bw : Memory Allocated %d bytes (each conf takes %d bytes)", + (int)retsize, (int)sizeof(bw_data)); if (retsize < (sizeof(bw_data) * sid)) { ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, - "mod_bw : Not enough memory allocated!! Giving up"); + "mod_bw : Not enough memory allocated!! Giving up"); return HTTP_INTERNAL_SERVER_ERROR; } @@ -1212,66 +1274,66 @@ static int bw_init(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, } ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, - "mod_bw : Version %s - Initialized [%d Confs]", VERSION, - sid); + "mod_bw : Version %s - Initialized [%d Confs]", VERSION, + sid); #if defined(WIN32) - // Set the timer resolution to its minimum - if (timeGetDevCaps (&resolution, sizeof (TIMECAPS)) == TIMERR_NOERROR) + // Set the timer resolution to its minimum + if (timeGetDevCaps(&resolution, sizeof(TIMECAPS)) == TIMERR_NOERROR) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, - "mod_bw : Supported resolution for Timers [ Min: %d Max: %d ]",resolution.wPeriodMin,resolution.wPeriodMax); - - - if (timeBeginPeriod (resolution.wPeriodMin) == TIMERR_NOERROR) ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, - "mod_bw : Enabling High resolution timers [ %d ms ]",resolution.wPeriodMin); - else - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "mod_bw : Can't enable High Resolution timers. Speed might be reduced."); - } + "mod_bw : Supported resolution for Timers [ Min: %d Max: %d ]", resolution.wPeriodMin, resolution.wPeriodMax); + + + if (timeBeginPeriod(resolution.wPeriodMin) == TIMERR_NOERROR) + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, + "mod_bw : Enabling High resolution timers [ %d ms ]", resolution.wPeriodMin); + else + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "mod_bw : Can't enable High Resolution timers. Speed might be reduced."); + } #endif return OK; } -static void *create_bw_config(apr_pool_t * p, char *path) +static void* create_bw_config(apr_pool_t* p, char* path) { - bandwidth_config *new = - (bandwidth_config *) apr_palloc(p, sizeof(bandwidth_config)); + bandwidth_config* new = + (bandwidth_config*)apr_palloc(p, sizeof(bandwidth_config)); new->limits = apr_array_make(p, 20, sizeof(bw_entry)); new->minlimits = apr_array_make(p, 20, sizeof(bw_entry)); new->sizelimits = apr_array_make(p, 10, sizeof(bw_sizel)); new->maxconnection = apr_array_make(p, 10, sizeof(bw_maxconn)); - new->directory = (char *) apr_pstrdup(p, path); + new->directory = (char*)apr_pstrdup(p, path); new->packet = PACKET; new->error = HTTP_SERVICE_UNAVAILABLE; - return (void *) new; + return (void*) new; } -static void *create_bw_server_config(apr_pool_t * p, server_rec * s) +static void* create_bw_server_config(apr_pool_t* p, server_rec* s) { - bandwidth_server_config *new; + bandwidth_server_config* new; new = - (bandwidth_server_config *) apr_pcalloc(p, - sizeof - (bandwidth_server_config)); + (bandwidth_server_config*)apr_pcalloc(p, + sizeof + (bandwidth_server_config)); new->state = BANDWIDTH_DISABLED; new->force = BANDWIDTH_DISABLED; - return (void *) new; + return (void*) new; } /*----------------------------------------------------------------------------* * Apache register functions * *----------------------------------------------------------------------------*/ -static void register_hooks(apr_pool_t * p) +static void register_hooks(apr_pool_t* p) { /* - Register a handler, which enforces mod_bw if needed From 069863957f27b9424d6ae49adcd25131452ac688 Mon Sep 17 00:00:00 2001 From: sosherof Date: Tue, 26 Oct 2021 11:38:15 -0700 Subject: [PATCH 06/15] Removed math.h include that wasn't needed. --- mod_bw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mod_bw.c b/mod_bw.c index 33959ad..cb1b5f4 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -73,7 +73,6 @@ Changelog : #if defined(WIN32) #include #include -#include #endif #define MIN_BW 256 /* Minimal bandwidth 256 bytes */ From 44dac2a08e33a57ddc74a344915db8bfba3c59b8 Mon Sep 17 00:00:00 2001 From: sosherof Date: Tue, 26 Oct 2021 11:38:15 -0700 Subject: [PATCH 07/15] VS 2019 "corrected" some formatting, making more changes appear in diff than there actually are. Reverted some of these.Removed math.h include that wasn't needed. --- mod_bw.c | 203 +++++++++++++++++++++++++++---------------------------- 1 file changed, 98 insertions(+), 105 deletions(-) diff --git a/mod_bw.c b/mod_bw.c index 33959ad..dec7f29 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -73,7 +73,6 @@ Changelog : #if defined(WIN32) #include #include -#include #endif #define MIN_BW 256 /* Minimal bandwidth 256 bytes */ @@ -127,7 +126,7 @@ enum from_type { typedef struct { apr_uint32_t id; - char* v_name; + char *v_name; apr_uint32_t connection_count; apr_uint32_t bandwidth; unsigned long long bytes_count; @@ -139,7 +138,7 @@ typedef struct /* A temporal context to save our splitted brigade */ typedef struct ctx_struct_t { - apr_bucket_brigade* bb; + apr_bucket_brigade *bb; struct timeval wait; unsigned long long bw_interval_bytes, bw_interval_slept, client_bw; apr_time_t bw_interval_start_time; @@ -160,7 +159,7 @@ typedef struct apr_uint32_t sid; union { char* from; - apr_ipsubnet_t* ip; + apr_ipsubnet_t *ip; } x; ap_regex_t* agent; enum from_type type; @@ -173,7 +172,7 @@ typedef struct apr_uint32_t sid; union { char* from; - apr_ipsubnet_t* ip; + apr_ipsubnet_t *ip; } x; ap_regex_t* agent; enum from_type type; @@ -192,10 +191,10 @@ typedef struct /* Per directory configuration structure */ typedef struct { - apr_array_header_t* limits; - apr_array_header_t* minlimits; - apr_array_header_t* sizelimits; - apr_array_header_t* maxconnection; + apr_array_header_t *limits; + apr_array_header_t *minlimits; + apr_array_header_t *sizelimits; + apr_array_header_t *maxconnection; unsigned int packet; int error; char* directory; @@ -215,7 +214,7 @@ module AP_MODULE_DECLARE_DATA bw_module; * Configurations Directives * *---------------------------------------------------------------------*/ /* Set the mod enabled ... or disabled */ -static const char* bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) +static const char *bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) { bandwidth_server_config* sconf; @@ -232,10 +231,10 @@ static const char* bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, int flag) { - bandwidth_server_config* sconf; + bandwidth_server_config *sconf; sconf = - (bandwidth_server_config*)ap_get_module_config(cmd->server-> + (bandwidth_server_config *)ap_get_module_config(cmd->server-> module_config, &bw_module); sconf->force = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); @@ -244,9 +243,9 @@ static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, } /* Set the packetsize used in the context */ -static const char* setpacket(cmd_parms* cmd, void* s, const char* pack) +static const char *setpacket(cmd_parms* cmd, void* s, const char* pack) { - bandwidth_config* conf = (bandwidth_config*)s; + bandwidth_config *conf = (bandwidth_config *)s; int temp; if (pack && *pack && apr_isdigit(*pack)) @@ -263,9 +262,9 @@ static const char* setpacket(cmd_parms* cmd, void* s, const char* pack) } /* Set the error to send when maxconnections is reached */ -static const char* bandwidtherror(cmd_parms* cmd, void* s, const char* err) +static const char *bandwidtherror(cmd_parms * cmd, void *s, const char *err) { - bandwidth_config* conf = (bandwidth_config*)s; + bandwidth_config *conf = (bandwidth_config *)s; int temp; if (err && *err && apr_isdigit(*err)) @@ -282,14 +281,14 @@ static const char* bandwidtherror(cmd_parms* cmd, void* s, const char* err) } /* Set the maxconnections on a per host basis */ -static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, - const char* maxc) +static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, + const char *maxc) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_maxconn* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_maxconn *a; int temp; - char* str; - char* where = (char*)apr_pstrdup(cmd->pool, from); + char *str; + char *where = (char *)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -300,16 +299,16 @@ static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, if (temp < 0) return - "Connections must be a number of simultaneous connections allowed/s"; + "Connections must be a number of simultaneous connections allowed/s"; - a = (bw_maxconn*)apr_array_push(conf->maxconnection); + a = (bw_maxconn *)apr_array_push(conf->maxconnection); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { /* Do not limit based on origin, but on user agent */ a->type = T_AGENT; - a->agent = ap_pregcomp(cmd->pool, where + 2, 0); + a->agent = ap_pregcomp(cmd->pool, where+2, 0); if (a->agent == NULL) return "Regular expression could not be compiled."; @@ -347,14 +346,14 @@ static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, } /* Set the bandwidth on a per host basis */ -static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, - const char* bw) +static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, + const char *bw) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_entry* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_entry *a; long int temp; - char* str; - char* where = (char*)apr_pstrdup(cmd->pool, from); + char *str; + char *where = (char *)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -367,7 +366,7 @@ static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, if (temp < 0) return "BandWidth must be a number of bytes/s"; - a = (bw_entry*)apr_array_push(conf->limits); + a = (bw_entry *)apr_array_push(conf->limits); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { @@ -412,19 +411,17 @@ static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, a->rate = temp; a->sid = sid++; - return NULL; } /* Set the minimum bandwidth to send */ -static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, - const char* bw) +static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, const char *bw) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_entry* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_entry *a; long int temp; - char* str; - char* where = (char*)apr_pstrdup(cmd->pool, from); + char *str; + char *where = (char *)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -433,7 +430,7 @@ static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, else return "Invalid argument"; - a = (bw_entry*)apr_array_push(conf->minlimits); + a = (bw_entry *)apr_array_push(conf->minlimits); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { @@ -477,11 +474,11 @@ static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, } /* Set the large file bandwidth limit */ -static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, - const char* size, const char* bw) +static const char *largefilelimit(cmd_parms * cmd, void *s, const char *file, + const char *size, const char *bw) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_sizel* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_sizel *a; long int temp, tsize; char msgbuf[MAX_BUF]; @@ -504,14 +501,14 @@ static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, if (tsize < 0) return "File size must be a number of Kbytes"; - a = (bw_sizel*)apr_array_push(conf->sizelimits); + a = (bw_sizel *)apr_array_push(conf->sizelimits); a->file = (char*)file; a->size = tsize; a->rate = temp; if (sid < MAX_VHOSTS) { vnames[sid] = apr_pcalloc(cmd->pool, apr_snprintf(msgbuf, MAX_BUF, "%s,%s", cmd->server->server_hostname, file)); - vnames[sid] = (char*)apr_pstrdup(cmd->pool, msgbuf); + vnames[sid] = (char *)apr_pstrdup(cmd->pool, msgbuf); } a->sid = sid++; @@ -524,7 +521,7 @@ static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, *----------------------------------------------------------------------------*/ /* Match the input, as part of a domain */ -static int in_domain(const char* domain, const char* what) +static int in_domain(const char *domain, const char *what) { size_t dl = strlen(domain); size_t wl = strlen(what); @@ -547,13 +544,13 @@ static int in_domain(const char* domain, const char* what) } /* Get the bandwidth limit based on from address */ -static long get_bw_rate(request_rec* r, apr_array_header_t* a) +static long get_bw_rate(request_rec *r, apr_array_header_t *a) { - bw_entry* e = (bw_entry*)a->elts; - const char* remotehost = NULL; + bw_entry *e = (bw_entry *)a->elts; + const char *remotehost = NULL; int i; int gothost = 0; - const char* uastr = NULL; + const char *uastr = NULL; for (i = 0; i < a->nelts; i++) { @@ -597,7 +594,7 @@ static long get_bw_rate(request_rec* r, apr_array_header_t* a) Match the pattern with the last digist from filename An asterisk means any. */ -static int match_ext(const char* file, char* match) +static int match_ext(const char *file, char *match) { if (file == NULL || match == NULL) return 0; @@ -614,10 +611,10 @@ static int match_ext(const char* file, char* match) } /* Get the bandwidth limit based on filesize */ -static long get_bw_filesize(request_rec* r, apr_array_header_t* a, - apr_uint32_t filesize, const char* filename) +static long get_bw_filesize(request_rec *r, apr_array_header_t *a, + apr_uint32_t filesize, const char *filename) { - bw_sizel* e = (bw_sizel*)a->elts; + bw_sizel *e = (bw_sizel *)a->elts; int i; apr_uint32_t tmpsize = 0, tmprate = 0; @@ -638,13 +635,13 @@ static long get_bw_filesize(request_rec* r, apr_array_header_t* a, } /* Get the MaxConnections allowed */ -static int get_maxconn(request_rec* r, apr_array_header_t* a) +static int get_maxconn(request_rec *r, apr_array_header_t *a) { - bw_maxconn* e = (bw_maxconn*)a->elts; - const char* remotehost = NULL; + bw_maxconn *e = (bw_maxconn *)a->elts; + const char *remotehost = NULL; int i; int gothost = 0; - const char* uastr = NULL; + const char *uastr = NULL; for (i = 0; i < a->nelts; i++) { @@ -685,13 +682,13 @@ static int get_maxconn(request_rec* r, apr_array_header_t* a) } /* Get an id based on bandwidth limit */ -static int get_sid(request_rec* r, apr_array_header_t* a) +static int get_sid(request_rec *r, apr_array_header_t *a) { - bw_entry* e = (bw_entry*)a->elts; - const char* remotehost = NULL; + bw_entry *e = (bw_entry *)a->elts; + const char *remotehost = NULL; int i; int gothost = 0; - const char* uastr; + const char *uastr; remotehost = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_HOST, @@ -736,10 +733,10 @@ static int get_sid(request_rec* r, apr_array_header_t* a) } /* Get an id based on filesize limit */ -static int get_f_sid(request_rec* r, apr_array_header_t* a, apr_uint32_t filesize, - const char* filename) +static int get_f_sid(request_rec *r, apr_array_header_t *a, apr_uint32_t filesize, + const char *filename) { - bw_sizel* e = (bw_sizel*)a->elts; + bw_sizel *e = (bw_sizel *)a->elts; int i; apr_uint32_t tmpsize = 0, tmpsid = -1; @@ -762,7 +759,7 @@ static int get_f_sid(request_rec* r, apr_array_header_t* a, apr_uint32_t filesiz } /* Update memory (shm) counters, which holds the bw data per context */ -static void update_counters(bw_data* bwstat, ap_filter_t* f) +static void update_counters(bw_data *bwstat, ap_filter_t *f) { apr_time_t nowtime; @@ -789,10 +786,10 @@ static void update_counters(bw_data* bwstat, ap_filter_t* f) } } -static int callback(request_rec* r) +static int callback(request_rec *r) { int t; - bw_data* bwstat; + bw_data *bwstat; if (r->header_only) { return OK; @@ -848,25 +845,23 @@ static int callback(request_rec* r) ap_rputs("\n", r); return OK; - - } /*----------------------------------------------------------------------------* * The Handler and the Output Filter. Core of the mod. * *----------------------------------------------------------------------------*/ /* With this handler, we can *force* the use of the mod. */ -static int handle_bw(request_rec* r) +static int handle_bw(request_rec *r) { - bandwidth_server_config* sconf = - (bandwidth_server_config*)ap_get_module_config(r->server-> + bandwidth_server_config *sconf = + (bandwidth_server_config *)ap_get_module_config(r->server-> module_config, &bw_module); - bandwidth_config* conf = - (bandwidth_config*)ap_get_module_config(r->per_dir_config, + bandwidth_config *conf = + (bandwidth_config *)ap_get_module_config(r->per_dir_config, &bw_module); - bw_data* bwstat; + bw_data * bwstat; apr_int32_t confid; /* Only work on main request/no subrequests */ @@ -875,7 +870,6 @@ static int handle_bw(request_rec* r) if (strcmp(r->handler, "modbw-handler") == 0) return callback(r); - /* Return if module is not enabled */ if (sconf->state == BANDWIDTH_DISABLED) return DECLINED; @@ -904,26 +898,26 @@ static int handle_bw(request_rec* r) return DECLINED; } -static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) +static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) { - request_rec* r = f->r; - bandwidth_config* conf = - (bandwidth_config*)ap_get_module_config(r->per_dir_config, + request_rec *r = f->r; + bandwidth_config *conf = + (bandwidth_config *)ap_get_module_config(r->per_dir_config, &bw_module); - bandwidth_server_config* sconf = - (bandwidth_server_config*)ap_get_module_config(r->server-> + bandwidth_server_config *sconf = + (bandwidth_server_config *)ap_get_module_config(r->server-> module_config, &bw_module); - ctx_struct* ctx = f->ctx; - apr_bucket* b = APR_BRIGADE_FIRST(bb); - bw_data* bwstat, * bwmaxconn; + ctx_struct *ctx = f->ctx; + apr_bucket *b = APR_BRIGADE_FIRST(bb); + bw_data *bwstat, *bwmaxconn; int confid = -1, connid = -1; apr_size_t packet = conf->packet, bytes = 0; apr_off_t bblen = 0; apr_size_t bw_rate, bw_min, bw_f_rate, cur_rate = 0; apr_interval_time_t sleep; - const char* buf; - const char* filename; + const char *buf; + const char *filename; long current_sleep_bypasses = 0; /* Only work on main request/no subrequests */ @@ -1182,8 +1176,8 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) /*----------------------------------------------------------------------------* * Module Init functions * *----------------------------------------------------------------------------*/ -static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, - server_rec* s) +static int bw_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, + server_rec *s) { apr_status_t status; apr_size_t retsize; @@ -1195,12 +1189,12 @@ static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, #endif /* These two help ensure that we only init once. */ - void* data; - const char* userdata_key = "ivn_shm_bw_limit_module"; + void *data; + const char *userdata_key = "ivn_shm_bw_limit_module"; apr_pool_userdata_get(&data, userdata_key, s->process->pool); if (!data) { - apr_pool_userdata_set((const void*)1, userdata_key, + apr_pool_userdata_set((const void *)1, userdata_key, apr_pool_cleanup_null, s->process->pool); return OK; } @@ -1285,7 +1279,6 @@ static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "mod_bw : Supported resolution for Timers [ Min: %d Max: %d ]", resolution.wPeriodMin, resolution.wPeriodMax); - if (timeBeginPeriod(resolution.wPeriodMin) == TIMERR_NOERROR) ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "mod_bw : Enabling High resolution timers [ %d ms ]", resolution.wPeriodMin); @@ -1299,41 +1292,41 @@ static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, } -static void* create_bw_config(apr_pool_t* p, char* path) +static void *create_bw_config(apr_pool_t *p, char *path) { - bandwidth_config* new = - (bandwidth_config*)apr_palloc(p, sizeof(bandwidth_config)); + bandwidth_config *new = + (bandwidth_config *)apr_palloc(p, sizeof(bandwidth_config)); new->limits = apr_array_make(p, 20, sizeof(bw_entry)); new->minlimits = apr_array_make(p, 20, sizeof(bw_entry)); new->sizelimits = apr_array_make(p, 10, sizeof(bw_sizel)); new->maxconnection = apr_array_make(p, 10, sizeof(bw_maxconn)); - new->directory = (char*)apr_pstrdup(p, path); + new->directory = (char *)apr_pstrdup(p, path); new->packet = PACKET; new->error = HTTP_SERVICE_UNAVAILABLE; - return (void*) new; + return (void *) new; } -static void* create_bw_server_config(apr_pool_t* p, server_rec* s) +static void *create_bw_server_config(apr_pool_t *p, server_rec *s) { - bandwidth_server_config* new; + bandwidth_server_config *new; new = - (bandwidth_server_config*)apr_pcalloc(p, + (bandwidth_server_config *)apr_pcalloc(p, sizeof (bandwidth_server_config)); new->state = BANDWIDTH_DISABLED; new->force = BANDWIDTH_DISABLED; - return (void*) new; + return (void *) new; } /*----------------------------------------------------------------------------* * Apache register functions * *----------------------------------------------------------------------------*/ -static void register_hooks(apr_pool_t* p) +static void register_hooks(apr_pool_t *p) { /* - Register a handler, which enforces mod_bw if needed From ea0c24f85f5ca3f96c2daf199f377a962e8d0238 Mon Sep 17 00:00:00 2001 From: sosherof Date: Tue, 26 Oct 2021 12:03:45 -0700 Subject: [PATCH 08/15] More revertion of VS "fixes" to formatting. --- mod_bw.c | 59 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/mod_bw.c b/mod_bw.c index dec7f29..22e038c 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -24,11 +24,11 @@ Platform : Linux/x86 (Tested with Fedora Core 4, Suse, etc) Notes : This is a stable version of mod_bw. It should work with almost any MPM (tested with WinNT/prefork/Worker MPM). - We are reaching the End of mod_bw series 0.x. As soon as this + We are reaching the End of mod_bw series 0.x. As soon as this last changes are confirmed by the users (perhaps some changes at request), i'll set this release to version 1.0 final. -Limitations : This mod doesn't know how fast the client is +Limitations : This mod doesn't know how fast the client is downloading a file, so it just divides the bw assigned between the users. MaxConnections works only for the given scope. (i.e , all @@ -40,7 +40,7 @@ Changelog : 2010-05-27 : Fixed weird behaviour on Windows Hosts. (mod_bw.txt) Added high resolution timers for windows. (speed improvements) Fixed stupid bug that caused crash when mod is enabled but there is - not a single limit. + not a single limit. 2010-05-24 : Code Cleanup. No more warnings or stuff in Visual Studio 2010-04-28 : Bruce's Birthday Gift : A callback to the stats of the mod :) 2010-04-06 : Fixed "Invisible" memory leak. Only seen when serving HUGE streams. @@ -71,8 +71,8 @@ Changelog : #include "scoreboard.h" #if defined(WIN32) -#include -#include + #include + #include #endif #define MIN_BW 256 /* Minimal bandwidth 256 bytes */ @@ -85,23 +85,23 @@ Changelog : /* Compatibility with regex on apache less than 2.1 */ #if !AP_MODULE_MAGIC_AT_LEAST(20050127,0) -typedef regex_t ap_regex_t; -#define AP_REG_EXTENDED REG_EXTENDED -#define AP_REG_ICASE REG_ICASE + typedef regex_t ap_regex_t; + #define AP_REG_EXTENDED REG_EXTENDED + #define AP_REG_ICASE REG_ICASE #endif /* Compatibility with obsolete ap_get_server_version() */ #if !AP_MODULE_MAGIC_AT_LEAST(20051115,4) -#define ap_get_server_banner ap_get_server_version + #define ap_get_server_banner ap_get_server_version #endif /* Compatibility for APR < 1 */ #if ( defined(APR_MAJOR_VERSION) && (APR_MAJOR_VERSION < 1) ) -#define apr_atomic_inc32 apr_atomic_inc -#define apr_atomic_dec32 apr_atomic_dec -#define apr_atomic_add32 apr_atomic_add -#define apr_atomic_cas32 apr_atomic_cas -#define apr_atomic_set32 apr_atomic_set + #define apr_atomic_inc32 apr_atomic_inc + #define apr_atomic_dec32 apr_atomic_dec + #define apr_atomic_add32 apr_atomic_add + #define apr_atomic_cas32 apr_atomic_cas + #define apr_atomic_set32 apr_atomic_set #endif /* Enum types of "from address" */ @@ -112,7 +112,7 @@ enum from_type { T_AGENT }; -/* +/* - Stats of each conf - - id = Configuration ID @@ -147,21 +147,20 @@ typedef struct ctx_struct_t /* With sid we count the shared memory needed. BwBase, is a holder to the shared memory base addres */ -static char* vnames[MAX_VHOSTS]; +static char *vnames[MAX_VHOSTS]; static int sid = 0; -bw_data* bwbase; -apr_shm_t* shm; - +bw_data *bwbase; +apr_shm_t *shm; /* Limits for MaxConnections based on directory */ typedef struct { apr_uint32_t sid; union { - char* from; + char *from; apr_ipsubnet_t *ip; } x; - ap_regex_t* agent; + ap_regex_t *agent; enum from_type type; apr_uint32_t max; } bw_maxconn; @@ -171,10 +170,10 @@ typedef struct { apr_uint32_t sid; union { - char* from; + char *from; apr_ipsubnet_t *ip; } x; - ap_regex_t* agent; + ap_regex_t *agent; enum from_type type; apr_int32_t rate; } bw_entry; @@ -183,7 +182,7 @@ typedef struct typedef struct { apr_uint32_t sid; - char* file; + char *file; apr_uint32_t size; apr_uint32_t rate; } bw_sizel; @@ -197,7 +196,7 @@ typedef struct apr_array_header_t *maxconnection; unsigned int packet; int error; - char* directory; + char *directory; } bandwidth_config; /* Per server configuration structure */ @@ -214,12 +213,12 @@ module AP_MODULE_DECLARE_DATA bw_module; * Configurations Directives * *---------------------------------------------------------------------*/ /* Set the mod enabled ... or disabled */ -static const char *bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) +static const char *bandwidthmodule(cmd_parms * cmd, void *dconf, int flag) { - bandwidth_server_config* sconf; + bandwidth_server_config *sconf; sconf = - (bandwidth_server_config*)ap_get_module_config(cmd->server-> + (bandwidth_server_config *)ap_get_module_config(cmd->server-> module_config, &bw_module); sconf->state = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); @@ -228,7 +227,7 @@ static const char *bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) } /* Set force mode enabled ... or disabled */ -static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, +static const char *forcebandwidthmodule(cmd_parms * cmd, void *dconf, int flag) { bandwidth_server_config *sconf; @@ -243,7 +242,7 @@ static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, } /* Set the packetsize used in the context */ -static const char *setpacket(cmd_parms* cmd, void* s, const char* pack) +static const char *setpacket(cmd_parms * cmd, void *s, const char *pack) { bandwidth_config *conf = (bandwidth_config *)s; int temp; From 125d5f013cf77bce722d9e045ea07c69096a37ec Mon Sep 17 00:00:00 2001 From: sosherof Date: Thu, 18 Nov 2021 12:16:04 -0800 Subject: [PATCH 09/15] * Updated logging to be less frequent but more informative. * Simplified the client_bw math such that sleep time is simply added to the interval start time instead of tracked separately and mathed later. Why not save a variable and some math overhead. --- mod_bw.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/mod_bw.c b/mod_bw.c index 22e038c..1910be3 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -140,7 +140,7 @@ typedef struct ctx_struct_t { apr_bucket_brigade *bb; struct timeval wait; - unsigned long long bw_interval_bytes, bw_interval_slept, client_bw; + unsigned long long bw_interval_bytes, client_bw; apr_time_t bw_interval_start_time; long sleep_bypasses_left, sleep_bypasses_total; } ctx_struct; @@ -918,6 +918,7 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) const char *buf; const char *filename; long current_sleep_bypasses = 0; + unsigned long long new_client_bw = 0; /* Only work on main request/no subrequests */ if (r->main) { @@ -974,10 +975,20 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) ctx->bb = apr_brigade_create(f->r->pool, bucket_alloc); ctx->bw_interval_start_time = apr_time_now(); - ctx->bw_interval_slept = 0; ctx->bw_interval_bytes = 0; ctx->sleep_bypasses_left = 0; ctx->sleep_bypasses_total = 0; + ctx->client_bw = 0; + + /* Verbose Output - but only the first time the filter is called */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "ID: %i; Directory : %s; File : %s; Rate : %ld; Minimum : %ld; Size rate : %ld;", + confid, conf->directory, filename, bw_rate, bw_min, bw_f_rate); + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "clients : %d/%d; rate/min : %ld,%ld", bwmaxconn->connection_count, + (connid >= 0) ? get_maxconn(r, conf->maxconnection) : 0, + bw_rate, bw_min); } /* We "get" the data of the current configuration */ @@ -992,15 +1003,6 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) /* Add 1 active connection to the record */ apr_atomic_inc32(&bwmaxconn->connection_count); - /* Verbose Output */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "ID: %i; Directory : %s; File : %s; Rate : %ld; Minimum : %ld; Size rate : %ld;", - confid, conf->directory, filename, bw_rate, bw_min, bw_f_rate); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "clients : %d/%d; rate/min : %ld,%ld", bwmaxconn->connection_count, - (connid >= 0) ? get_maxconn(r, conf->maxconnection) : 0, - bw_rate, bw_min); - /* - We get buckets until a sentinel appears - Read the content of the bucket, and send it to the next filter, piece @@ -1059,13 +1061,19 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) ((double)cur_rate / (double)packet)); /* if more than 15ms has elapsed, roughly calculate client's actual bandwidth */ - if ((apr_time_now() - ctx->bw_interval_slept) - ctx->bw_interval_start_time > 15000) { - ctx->client_bw = (ctx->bw_interval_bytes * 1000 / (unsigned long long)((apr_time_now() - ctx->bw_interval_slept) - ctx->bw_interval_start_time)) * 1000; + if (apr_time_now() - ctx->bw_interval_start_time > 15000) { + new_client_bw = (ctx->bw_interval_bytes * 1000 / (unsigned long long)(apr_time_now() - ctx->bw_interval_start_time)) * 1000; + /* if the client bandwidth changed more then 1K or is now more than available, log it (if module debug is on) */ + if (ctx->client_bw == 0 || + (unsigned long long)(ctx->client_bw/1024) != (unsigned long long)(new_client_bw/1024) || + new_client_bw > cur_rate) + { + /* Verbose logging */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Client BW is ~%ld B/s. This %s than available BW (%ld). %s", new_client_bw, (new_client_bw > cur_rate ? "More" : "Less"), cur_rate, (new_client_bw > cur_rate ? "BW Limiting!" : "Not BW limiting!")); + } + ctx->client_bw = new_client_bw; ctx->bw_interval_bytes = 0; - ctx->bw_interval_slept = 0; ctx->bw_interval_start_time = apr_time_now(); - /* Verbose logging */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Client BW is ~%ld B/s. This %s than available BW (%ld). %s", ctx->client_bw, (ctx->client_bw > cur_rate ? "More" : "Less"), cur_rate, (ctx->client_bw > cur_rate ? "BW Limiting!" : "Not BW limiting!")); } #if defined(WIN32) @@ -1083,7 +1091,7 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) ctx->sleep_bypasses_total = current_sleep_bypasses; /* setup counters */ ctx->sleep_bypasses_left = current_sleep_bypasses; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "File: %s. BW: %ld B/s. Packet: %ld bytes. Bypassing sleep for %i packet(s).", filename, cur_rate, packet, ctx->sleep_bypasses_left); + "File: %s. Available BW: %ld B/s. Packet: %ld bytes. Bypassing sleep for %i packet(s).", filename, cur_rate, packet, ctx->sleep_bypasses_left); } else { /* If number of packets to send in 10ms has changed since last calc because available bandwidth changed, recalcuate */ @@ -1141,7 +1149,7 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) else { if (ctx->client_bw > cur_rate) { /* Only sleep if the client's calculated bw is greater than available */ apr_sleep(sleep); /* bandwidth, otherwise there's no reason to sleep. */ - ctx->bw_interval_slept += sleep; + ctx->bw_interval_start_time += sleep; /* Adjust interval start time to exclude sleep time. */ } ctx->sleep_bypasses_left = 0; } From bdf31b1eb3a9c79ee21d1d1e5eed1b8e4f02d1ba Mon Sep 17 00:00:00 2001 From: sosherof Date: Thu, 18 Nov 2021 12:41:39 -0800 Subject: [PATCH 10/15] Corrected uninit variable when I moved logging blocks around. --- mod_bw.c | 278 +++++++++++++++++++++++++++---------------------------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/mod_bw.c b/mod_bw.c index 1910be3..31084b9 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -24,11 +24,11 @@ Platform : Linux/x86 (Tested with Fedora Core 4, Suse, etc) Notes : This is a stable version of mod_bw. It should work with almost any MPM (tested with WinNT/prefork/Worker MPM). - We are reaching the End of mod_bw series 0.x. As soon as this + We are reaching the End of mod_bw series 0.x. As soon as this last changes are confirmed by the users (perhaps some changes at request), i'll set this release to version 1.0 final. -Limitations : This mod doesn't know how fast the client is +Limitations : This mod doesn't know how fast the client is downloading a file, so it just divides the bw assigned between the users. MaxConnections works only for the given scope. (i.e , all @@ -71,8 +71,8 @@ Changelog : #include "scoreboard.h" #if defined(WIN32) - #include - #include +#include +#include #endif #define MIN_BW 256 /* Minimal bandwidth 256 bytes */ @@ -85,23 +85,23 @@ Changelog : /* Compatibility with regex on apache less than 2.1 */ #if !AP_MODULE_MAGIC_AT_LEAST(20050127,0) - typedef regex_t ap_regex_t; - #define AP_REG_EXTENDED REG_EXTENDED - #define AP_REG_ICASE REG_ICASE +typedef regex_t ap_regex_t; +#define AP_REG_EXTENDED REG_EXTENDED +#define AP_REG_ICASE REG_ICASE #endif /* Compatibility with obsolete ap_get_server_version() */ #if !AP_MODULE_MAGIC_AT_LEAST(20051115,4) - #define ap_get_server_banner ap_get_server_version +#define ap_get_server_banner ap_get_server_version #endif /* Compatibility for APR < 1 */ #if ( defined(APR_MAJOR_VERSION) && (APR_MAJOR_VERSION < 1) ) - #define apr_atomic_inc32 apr_atomic_inc - #define apr_atomic_dec32 apr_atomic_dec - #define apr_atomic_add32 apr_atomic_add - #define apr_atomic_cas32 apr_atomic_cas - #define apr_atomic_set32 apr_atomic_set +#define apr_atomic_inc32 apr_atomic_inc +#define apr_atomic_dec32 apr_atomic_dec +#define apr_atomic_add32 apr_atomic_add +#define apr_atomic_cas32 apr_atomic_cas +#define apr_atomic_set32 apr_atomic_set #endif /* Enum types of "from address" */ @@ -112,7 +112,7 @@ enum from_type { T_AGENT }; -/* +/* - Stats of each conf - - id = Configuration ID @@ -126,7 +126,7 @@ enum from_type { typedef struct { apr_uint32_t id; - char *v_name; + char* v_name; apr_uint32_t connection_count; apr_uint32_t bandwidth; unsigned long long bytes_count; @@ -138,7 +138,7 @@ typedef struct /* A temporal context to save our splitted brigade */ typedef struct ctx_struct_t { - apr_bucket_brigade *bb; + apr_bucket_brigade* bb; struct timeval wait; unsigned long long bw_interval_bytes, client_bw; apr_time_t bw_interval_start_time; @@ -147,20 +147,20 @@ typedef struct ctx_struct_t /* With sid we count the shared memory needed. BwBase, is a holder to the shared memory base addres */ -static char *vnames[MAX_VHOSTS]; +static char* vnames[MAX_VHOSTS]; static int sid = 0; -bw_data *bwbase; -apr_shm_t *shm; +bw_data* bwbase; +apr_shm_t* shm; /* Limits for MaxConnections based on directory */ typedef struct { apr_uint32_t sid; union { - char *from; - apr_ipsubnet_t *ip; + char* from; + apr_ipsubnet_t* ip; } x; - ap_regex_t *agent; + ap_regex_t* agent; enum from_type type; apr_uint32_t max; } bw_maxconn; @@ -170,10 +170,10 @@ typedef struct { apr_uint32_t sid; union { - char *from; - apr_ipsubnet_t *ip; + char* from; + apr_ipsubnet_t* ip; } x; - ap_regex_t *agent; + ap_regex_t* agent; enum from_type type; apr_int32_t rate; } bw_entry; @@ -182,7 +182,7 @@ typedef struct typedef struct { apr_uint32_t sid; - char *file; + char* file; apr_uint32_t size; apr_uint32_t rate; } bw_sizel; @@ -190,13 +190,13 @@ typedef struct /* Per directory configuration structure */ typedef struct { - apr_array_header_t *limits; - apr_array_header_t *minlimits; - apr_array_header_t *sizelimits; - apr_array_header_t *maxconnection; + apr_array_header_t* limits; + apr_array_header_t* minlimits; + apr_array_header_t* sizelimits; + apr_array_header_t* maxconnection; unsigned int packet; int error; - char *directory; + char* directory; } bandwidth_config; /* Per server configuration structure */ @@ -213,12 +213,12 @@ module AP_MODULE_DECLARE_DATA bw_module; * Configurations Directives * *---------------------------------------------------------------------*/ /* Set the mod enabled ... or disabled */ -static const char *bandwidthmodule(cmd_parms * cmd, void *dconf, int flag) +static const char* bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) { - bandwidth_server_config *sconf; + bandwidth_server_config* sconf; sconf = - (bandwidth_server_config *)ap_get_module_config(cmd->server-> + (bandwidth_server_config*)ap_get_module_config(cmd->server-> module_config, &bw_module); sconf->state = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); @@ -227,13 +227,13 @@ static const char *bandwidthmodule(cmd_parms * cmd, void *dconf, int flag) } /* Set force mode enabled ... or disabled */ -static const char *forcebandwidthmodule(cmd_parms * cmd, void *dconf, +static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, int flag) { - bandwidth_server_config *sconf; + bandwidth_server_config* sconf; sconf = - (bandwidth_server_config *)ap_get_module_config(cmd->server-> + (bandwidth_server_config*)ap_get_module_config(cmd->server-> module_config, &bw_module); sconf->force = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); @@ -242,9 +242,9 @@ static const char *forcebandwidthmodule(cmd_parms * cmd, void *dconf, } /* Set the packetsize used in the context */ -static const char *setpacket(cmd_parms * cmd, void *s, const char *pack) +static const char* setpacket(cmd_parms* cmd, void* s, const char* pack) { - bandwidth_config *conf = (bandwidth_config *)s; + bandwidth_config* conf = (bandwidth_config*)s; int temp; if (pack && *pack && apr_isdigit(*pack)) @@ -261,9 +261,9 @@ static const char *setpacket(cmd_parms * cmd, void *s, const char *pack) } /* Set the error to send when maxconnections is reached */ -static const char *bandwidtherror(cmd_parms * cmd, void *s, const char *err) +static const char* bandwidtherror(cmd_parms* cmd, void* s, const char* err) { - bandwidth_config *conf = (bandwidth_config *)s; + bandwidth_config* conf = (bandwidth_config*)s; int temp; if (err && *err && apr_isdigit(*err)) @@ -280,14 +280,14 @@ static const char *bandwidtherror(cmd_parms * cmd, void *s, const char *err) } /* Set the maxconnections on a per host basis */ -static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, - const char *maxc) +static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, + const char* maxc) { - bandwidth_config *conf = (bandwidth_config *)s; - bw_maxconn *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_maxconn* a; int temp; - char *str; - char *where = (char *)apr_pstrdup(cmd->pool, from); + char* str; + char* where = (char*)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -298,16 +298,16 @@ static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, if (temp < 0) return - "Connections must be a number of simultaneous connections allowed/s"; + "Connections must be a number of simultaneous connections allowed/s"; - a = (bw_maxconn *)apr_array_push(conf->maxconnection); + a = (bw_maxconn*)apr_array_push(conf->maxconnection); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { /* Do not limit based on origin, but on user agent */ a->type = T_AGENT; - a->agent = ap_pregcomp(cmd->pool, where+2, 0); + a->agent = ap_pregcomp(cmd->pool, where + 2, 0); if (a->agent == NULL) return "Regular expression could not be compiled."; @@ -345,14 +345,14 @@ static const char *maxconnection(cmd_parms * cmd, void *s, const char *from, } /* Set the bandwidth on a per host basis */ -static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, - const char *bw) +static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, + const char* bw) { - bandwidth_config *conf = (bandwidth_config *)s; - bw_entry *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_entry* a; long int temp; - char *str; - char *where = (char *)apr_pstrdup(cmd->pool, from); + char* str; + char* where = (char*)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -365,7 +365,7 @@ static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, if (temp < 0) return "BandWidth must be a number of bytes/s"; - a = (bw_entry *)apr_array_push(conf->limits); + a = (bw_entry*)apr_array_push(conf->limits); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { @@ -414,13 +414,13 @@ static const char *bandwidth(cmd_parms * cmd, void *s, const char *from, } /* Set the minimum bandwidth to send */ -static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, const char *bw) +static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, const char* bw) { - bandwidth_config *conf = (bandwidth_config *)s; - bw_entry *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_entry* a; long int temp; - char *str; - char *where = (char *)apr_pstrdup(cmd->pool, from); + char* str; + char* where = (char*)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -429,7 +429,7 @@ static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, cons else return "Invalid argument"; - a = (bw_entry *)apr_array_push(conf->minlimits); + a = (bw_entry*)apr_array_push(conf->minlimits); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { @@ -473,11 +473,11 @@ static const char *minbandwidth(cmd_parms * cmd, void *s, const char *from, cons } /* Set the large file bandwidth limit */ -static const char *largefilelimit(cmd_parms * cmd, void *s, const char *file, - const char *size, const char *bw) +static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, + const char* size, const char* bw) { - bandwidth_config *conf = (bandwidth_config *)s; - bw_sizel *a; + bandwidth_config* conf = (bandwidth_config*)s; + bw_sizel* a; long int temp, tsize; char msgbuf[MAX_BUF]; @@ -500,14 +500,14 @@ static const char *largefilelimit(cmd_parms * cmd, void *s, const char *file, if (tsize < 0) return "File size must be a number of Kbytes"; - a = (bw_sizel *)apr_array_push(conf->sizelimits); + a = (bw_sizel*)apr_array_push(conf->sizelimits); a->file = (char*)file; a->size = tsize; a->rate = temp; if (sid < MAX_VHOSTS) { vnames[sid] = apr_pcalloc(cmd->pool, apr_snprintf(msgbuf, MAX_BUF, "%s,%s", cmd->server->server_hostname, file)); - vnames[sid] = (char *)apr_pstrdup(cmd->pool, msgbuf); + vnames[sid] = (char*)apr_pstrdup(cmd->pool, msgbuf); } a->sid = sid++; @@ -520,7 +520,7 @@ static const char *largefilelimit(cmd_parms * cmd, void *s, const char *file, *----------------------------------------------------------------------------*/ /* Match the input, as part of a domain */ -static int in_domain(const char *domain, const char *what) +static int in_domain(const char* domain, const char* what) { size_t dl = strlen(domain); size_t wl = strlen(what); @@ -543,13 +543,13 @@ static int in_domain(const char *domain, const char *what) } /* Get the bandwidth limit based on from address */ -static long get_bw_rate(request_rec *r, apr_array_header_t *a) +static long get_bw_rate(request_rec* r, apr_array_header_t* a) { - bw_entry *e = (bw_entry *)a->elts; - const char *remotehost = NULL; + bw_entry* e = (bw_entry*)a->elts; + const char* remotehost = NULL; int i; int gothost = 0; - const char *uastr = NULL; + const char* uastr = NULL; for (i = 0; i < a->nelts; i++) { @@ -593,7 +593,7 @@ static long get_bw_rate(request_rec *r, apr_array_header_t *a) Match the pattern with the last digist from filename An asterisk means any. */ -static int match_ext(const char *file, char *match) +static int match_ext(const char* file, char* match) { if (file == NULL || match == NULL) return 0; @@ -610,10 +610,10 @@ static int match_ext(const char *file, char *match) } /* Get the bandwidth limit based on filesize */ -static long get_bw_filesize(request_rec *r, apr_array_header_t *a, - apr_uint32_t filesize, const char *filename) +static long get_bw_filesize(request_rec* r, apr_array_header_t* a, + apr_uint32_t filesize, const char* filename) { - bw_sizel *e = (bw_sizel *)a->elts; + bw_sizel* e = (bw_sizel*)a->elts; int i; apr_uint32_t tmpsize = 0, tmprate = 0; @@ -634,13 +634,13 @@ static long get_bw_filesize(request_rec *r, apr_array_header_t *a, } /* Get the MaxConnections allowed */ -static int get_maxconn(request_rec *r, apr_array_header_t *a) +static int get_maxconn(request_rec* r, apr_array_header_t* a) { - bw_maxconn *e = (bw_maxconn *)a->elts; - const char *remotehost = NULL; + bw_maxconn* e = (bw_maxconn*)a->elts; + const char* remotehost = NULL; int i; int gothost = 0; - const char *uastr = NULL; + const char* uastr = NULL; for (i = 0; i < a->nelts; i++) { @@ -681,13 +681,13 @@ static int get_maxconn(request_rec *r, apr_array_header_t *a) } /* Get an id based on bandwidth limit */ -static int get_sid(request_rec *r, apr_array_header_t *a) +static int get_sid(request_rec* r, apr_array_header_t* a) { - bw_entry *e = (bw_entry *)a->elts; - const char *remotehost = NULL; + bw_entry* e = (bw_entry*)a->elts; + const char* remotehost = NULL; int i; int gothost = 0; - const char *uastr; + const char* uastr; remotehost = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_HOST, @@ -732,10 +732,10 @@ static int get_sid(request_rec *r, apr_array_header_t *a) } /* Get an id based on filesize limit */ -static int get_f_sid(request_rec *r, apr_array_header_t *a, apr_uint32_t filesize, - const char *filename) +static int get_f_sid(request_rec* r, apr_array_header_t* a, apr_uint32_t filesize, + const char* filename) { - bw_sizel *e = (bw_sizel *)a->elts; + bw_sizel* e = (bw_sizel*)a->elts; int i; apr_uint32_t tmpsize = 0, tmpsid = -1; @@ -758,7 +758,7 @@ static int get_f_sid(request_rec *r, apr_array_header_t *a, apr_uint32_t filesiz } /* Update memory (shm) counters, which holds the bw data per context */ -static void update_counters(bw_data *bwstat, ap_filter_t *f) +static void update_counters(bw_data* bwstat, ap_filter_t* f) { apr_time_t nowtime; @@ -785,10 +785,10 @@ static void update_counters(bw_data *bwstat, ap_filter_t *f) } } -static int callback(request_rec *r) +static int callback(request_rec* r) { int t; - bw_data *bwstat; + bw_data* bwstat; if (r->header_only) { return OK; @@ -850,17 +850,17 @@ static int callback(request_rec *r) * The Handler and the Output Filter. Core of the mod. * *----------------------------------------------------------------------------*/ /* With this handler, we can *force* the use of the mod. */ -static int handle_bw(request_rec *r) +static int handle_bw(request_rec* r) { - bandwidth_server_config *sconf = - (bandwidth_server_config *)ap_get_module_config(r->server-> + bandwidth_server_config* sconf = + (bandwidth_server_config*)ap_get_module_config(r->server-> module_config, &bw_module); - bandwidth_config *conf = - (bandwidth_config *)ap_get_module_config(r->per_dir_config, + bandwidth_config* conf = + (bandwidth_config*)ap_get_module_config(r->per_dir_config, &bw_module); - bw_data * bwstat; + bw_data* bwstat; apr_int32_t confid; /* Only work on main request/no subrequests */ @@ -897,26 +897,26 @@ static int handle_bw(request_rec *r) return DECLINED; } -static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) +static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) { - request_rec *r = f->r; - bandwidth_config *conf = - (bandwidth_config *)ap_get_module_config(r->per_dir_config, + request_rec* r = f->r; + bandwidth_config* conf = + (bandwidth_config*)ap_get_module_config(r->per_dir_config, &bw_module); - bandwidth_server_config *sconf = - (bandwidth_server_config *)ap_get_module_config(r->server-> + bandwidth_server_config* sconf = + (bandwidth_server_config*)ap_get_module_config(r->server-> module_config, &bw_module); - ctx_struct *ctx = f->ctx; - apr_bucket *b = APR_BRIGADE_FIRST(bb); - bw_data *bwstat, *bwmaxconn; + ctx_struct* ctx = f->ctx; + apr_bucket* b = APR_BRIGADE_FIRST(bb); + bw_data* bwstat, * bwmaxconn; int confid = -1, connid = -1; apr_size_t packet = conf->packet, bytes = 0; apr_off_t bblen = 0; apr_size_t bw_rate, bw_min, bw_f_rate, cur_rate = 0; apr_interval_time_t sleep; - const char *buf; - const char *filename; + const char* buf; + const char* filename; long current_sleep_bypasses = 0; unsigned long long new_client_bw = 0; @@ -968,6 +968,18 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) else if (!bw_min) bw_min = MIN_BW; + /* We "get" the data of the current configuration */ + bwstat = bwbase + confid; + + /* If we have a valid bandwidth limit per host, get the maxconn limit */ + if (connid >= 0) + bwmaxconn = bwbase + connid; + else + bwmaxconn = bwstat; + + /* Add 1 active connection to the record */ + apr_atomic_inc32(&bwmaxconn->connection_count); + /* Initialize our temporal space, which survives multiple invokations for the same request */ if (ctx == NULL) { apr_bucket_alloc_t* bucket_alloc = apr_bucket_alloc_create(f->r->pool); @@ -991,18 +1003,6 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) bw_rate, bw_min); } - /* We "get" the data of the current configuration */ - bwstat = bwbase + confid; - - /* If we have a valid bandwidth limit per host, get the maxconn limit */ - if (connid >= 0) - bwmaxconn = bwbase + connid; - else - bwmaxconn = bwstat; - - /* Add 1 active connection to the record */ - apr_atomic_inc32(&bwmaxconn->connection_count); - /* - We get buckets until a sentinel appears - Read the content of the bucket, and send it to the next filter, piece @@ -1064,9 +1064,9 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) if (apr_time_now() - ctx->bw_interval_start_time > 15000) { new_client_bw = (ctx->bw_interval_bytes * 1000 / (unsigned long long)(apr_time_now() - ctx->bw_interval_start_time)) * 1000; /* if the client bandwidth changed more then 1K or is now more than available, log it (if module debug is on) */ - if (ctx->client_bw == 0 || - (unsigned long long)(ctx->client_bw/1024) != (unsigned long long)(new_client_bw/1024) || - new_client_bw > cur_rate) + if (ctx->client_bw == 0 || + (unsigned long long)(ctx->client_bw / 1024) != (unsigned long long)(new_client_bw / 1024) || + new_client_bw > cur_rate) { /* Verbose logging */ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Client BW is ~%ld B/s. This %s than available BW (%ld). %s", new_client_bw, (new_client_bw > cur_rate ? "More" : "Less"), cur_rate, (new_client_bw > cur_rate ? "BW Limiting!" : "Not BW limiting!")); @@ -1183,8 +1183,8 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) /*----------------------------------------------------------------------------* * Module Init functions * *----------------------------------------------------------------------------*/ -static int bw_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, - server_rec *s) +static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, + server_rec* s) { apr_status_t status; apr_size_t retsize; @@ -1196,12 +1196,12 @@ static int bw_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, #endif /* These two help ensure that we only init once. */ - void *data; - const char *userdata_key = "ivn_shm_bw_limit_module"; + void* data; + const char* userdata_key = "ivn_shm_bw_limit_module"; apr_pool_userdata_get(&data, userdata_key, s->process->pool); if (!data) { - apr_pool_userdata_set((const void *)1, userdata_key, + apr_pool_userdata_set((const void*)1, userdata_key, apr_pool_cleanup_null, s->process->pool); return OK; } @@ -1299,41 +1299,41 @@ static int bw_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, } -static void *create_bw_config(apr_pool_t *p, char *path) +static void* create_bw_config(apr_pool_t* p, char* path) { - bandwidth_config *new = - (bandwidth_config *)apr_palloc(p, sizeof(bandwidth_config)); + bandwidth_config* new = + (bandwidth_config*)apr_palloc(p, sizeof(bandwidth_config)); new->limits = apr_array_make(p, 20, sizeof(bw_entry)); new->minlimits = apr_array_make(p, 20, sizeof(bw_entry)); new->sizelimits = apr_array_make(p, 10, sizeof(bw_sizel)); new->maxconnection = apr_array_make(p, 10, sizeof(bw_maxconn)); - new->directory = (char *)apr_pstrdup(p, path); + new->directory = (char*)apr_pstrdup(p, path); new->packet = PACKET; new->error = HTTP_SERVICE_UNAVAILABLE; - return (void *) new; + return (void*) new; } -static void *create_bw_server_config(apr_pool_t *p, server_rec *s) +static void* create_bw_server_config(apr_pool_t* p, server_rec* s) { - bandwidth_server_config *new; + bandwidth_server_config* new; new = - (bandwidth_server_config *)apr_pcalloc(p, + (bandwidth_server_config*)apr_pcalloc(p, sizeof (bandwidth_server_config)); new->state = BANDWIDTH_DISABLED; new->force = BANDWIDTH_DISABLED; - return (void *) new; + return (void*) new; } /*----------------------------------------------------------------------------* * Apache register functions * *----------------------------------------------------------------------------*/ -static void register_hooks(apr_pool_t *p) +static void register_hooks(apr_pool_t* p) { /* - Register a handler, which enforces mod_bw if needed From 3652d7f3305f062f32fffd8d9b7562c5b1bc3f76 Mon Sep 17 00:00:00 2001 From: sosherof Date: Wed, 1 Dec 2021 12:08:06 -0800 Subject: [PATCH 11/15] Fixed issue with hook double inserting output filter on subrequests. Made some logging enhancements. --- mod_bw.c | 266 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 135 insertions(+), 131 deletions(-) diff --git a/mod_bw.c b/mod_bw.c index 31084b9..00ccb79 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -36,6 +36,8 @@ Limitations : This mod doesn't know how fast the client is Changelog : +2021 : See github + 2010-07-20 : Fixed ap_get_server_banner unknown on older apache version 2010-05-27 : Fixed weird behaviour on Windows Hosts. (mod_bw.txt) Added high resolution timers for windows. (speed improvements) @@ -126,7 +128,7 @@ enum from_type { typedef struct { apr_uint32_t id; - char* v_name; + char *v_name; apr_uint32_t connection_count; apr_uint32_t bandwidth; unsigned long long bytes_count; @@ -138,7 +140,7 @@ typedef struct /* A temporal context to save our splitted brigade */ typedef struct ctx_struct_t { - apr_bucket_brigade* bb; + apr_bucket_brigade *bb; struct timeval wait; unsigned long long bw_interval_bytes, client_bw; apr_time_t bw_interval_start_time; @@ -147,20 +149,20 @@ typedef struct ctx_struct_t /* With sid we count the shared memory needed. BwBase, is a holder to the shared memory base addres */ -static char* vnames[MAX_VHOSTS]; +static char *vnames[MAX_VHOSTS]; static int sid = 0; -bw_data* bwbase; -apr_shm_t* shm; +bw_data *bwbase; +apr_shm_t *shm; /* Limits for MaxConnections based on directory */ typedef struct { apr_uint32_t sid; union { - char* from; - apr_ipsubnet_t* ip; + char *from; + apr_ipsubnet_t *ip; } x; - ap_regex_t* agent; + ap_regex_t *agent; enum from_type type; apr_uint32_t max; } bw_maxconn; @@ -170,10 +172,10 @@ typedef struct { apr_uint32_t sid; union { - char* from; - apr_ipsubnet_t* ip; + char *from; + apr_ipsubnet_t *ip; } x; - ap_regex_t* agent; + ap_regex_t *agent; enum from_type type; apr_int32_t rate; } bw_entry; @@ -182,7 +184,7 @@ typedef struct typedef struct { apr_uint32_t sid; - char* file; + char *file; apr_uint32_t size; apr_uint32_t rate; } bw_sizel; @@ -190,13 +192,13 @@ typedef struct /* Per directory configuration structure */ typedef struct { - apr_array_header_t* limits; - apr_array_header_t* minlimits; - apr_array_header_t* sizelimits; - apr_array_header_t* maxconnection; + apr_array_header_t *limits; + apr_array_header_t *minlimits; + apr_array_header_t *sizelimits; + apr_array_header_t *maxconnection; unsigned int packet; int error; - char* directory; + char *directory; } bandwidth_config; /* Per server configuration structure */ @@ -213,12 +215,12 @@ module AP_MODULE_DECLARE_DATA bw_module; * Configurations Directives * *---------------------------------------------------------------------*/ /* Set the mod enabled ... or disabled */ -static const char* bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) +static const char *bandwidthmodule(cmd_parms *cmd, void *dconf, int flag) { - bandwidth_server_config* sconf; + bandwidth_server_config *sconf; sconf = - (bandwidth_server_config*)ap_get_module_config(cmd->server-> + (bandwidth_server_config *)ap_get_module_config(cmd->server-> module_config, &bw_module); sconf->state = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); @@ -227,13 +229,13 @@ static const char* bandwidthmodule(cmd_parms* cmd, void* dconf, int flag) } /* Set force mode enabled ... or disabled */ -static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, +static const char *forcebandwidthmodule(cmd_parms *cmd, void *dconf, int flag) { - bandwidth_server_config* sconf; + bandwidth_server_config *sconf; sconf = - (bandwidth_server_config*)ap_get_module_config(cmd->server-> + (bandwidth_server_config *)ap_get_module_config(cmd->server-> module_config, &bw_module); sconf->force = (flag ? BANDWIDTH_ENABLED : BANDWIDTH_DISABLED); @@ -242,9 +244,9 @@ static const char* forcebandwidthmodule(cmd_parms* cmd, void* dconf, } /* Set the packetsize used in the context */ -static const char* setpacket(cmd_parms* cmd, void* s, const char* pack) +static const char *setpacket(cmd_parms *cmd, void *s, const char *pack) { - bandwidth_config* conf = (bandwidth_config*)s; + bandwidth_config *conf = (bandwidth_config *)s; int temp; if (pack && *pack && apr_isdigit(*pack)) @@ -261,9 +263,9 @@ static const char* setpacket(cmd_parms* cmd, void* s, const char* pack) } /* Set the error to send when maxconnections is reached */ -static const char* bandwidtherror(cmd_parms* cmd, void* s, const char* err) +static const char *bandwidtherror(cmd_parms *cmd, void *s, const char *err) { - bandwidth_config* conf = (bandwidth_config*)s; + bandwidth_config *conf = (bandwidth_config *)s; int temp; if (err && *err && apr_isdigit(*err)) @@ -280,14 +282,14 @@ static const char* bandwidtherror(cmd_parms* cmd, void* s, const char* err) } /* Set the maxconnections on a per host basis */ -static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, - const char* maxc) +static const char *maxconnection(cmd_parms *cmd, void *s, const char *from, + const char *maxc) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_maxconn* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_maxconn *a; int temp; - char* str; - char* where = (char*)apr_pstrdup(cmd->pool, from); + char *str; + char *where = (char *)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -300,7 +302,7 @@ static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, return "Connections must be a number of simultaneous connections allowed/s"; - a = (bw_maxconn*)apr_array_push(conf->maxconnection); + a = (bw_maxconn *)apr_array_push(conf->maxconnection); a->x.from = where; if (!strncasecmp(where, "u:", 2)) @@ -345,14 +347,14 @@ static const char* maxconnection(cmd_parms* cmd, void* s, const char* from, } /* Set the bandwidth on a per host basis */ -static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, - const char* bw) +static const char *bandwidth(cmd_parms *cmd, void *s, const char *from, + const char *bw) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_entry* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_entry *a; long int temp; - char* str; - char* where = (char*)apr_pstrdup(cmd->pool, from); + char *str; + char *where = (char *)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -365,7 +367,7 @@ static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, if (temp < 0) return "BandWidth must be a number of bytes/s"; - a = (bw_entry*)apr_array_push(conf->limits); + a = (bw_entry *)apr_array_push(conf->limits); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { @@ -405,7 +407,7 @@ static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, if (sid < MAX_VHOSTS) { vnames[sid] = apr_pcalloc(cmd->pool, apr_snprintf(msgbuf, MAX_BUF, "%s,%s", cmd->server->server_hostname, where)); - vnames[sid] = (char*)apr_pstrdup(cmd->pool, msgbuf); + vnames[sid] = (char *)apr_pstrdup(cmd->pool, msgbuf); } a->rate = temp; a->sid = sid++; @@ -414,13 +416,13 @@ static const char* bandwidth(cmd_parms* cmd, void* s, const char* from, } /* Set the minimum bandwidth to send */ -static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, const char* bw) +static const char *minbandwidth(cmd_parms *cmd, void *s, const char *from, const char *bw) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_entry* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_entry *a; long int temp; - char* str; - char* where = (char*)apr_pstrdup(cmd->pool, from); + char *str; + char *where = (char *)apr_pstrdup(cmd->pool, from); apr_status_t rv; char msgbuf[MAX_BUF]; @@ -429,7 +431,7 @@ static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, const else return "Invalid argument"; - a = (bw_entry*)apr_array_push(conf->minlimits); + a = (bw_entry *)apr_array_push(conf->minlimits); a->x.from = where; if (!strncasecmp(where, "u:", 2)) { @@ -473,11 +475,11 @@ static const char* minbandwidth(cmd_parms* cmd, void* s, const char* from, const } /* Set the large file bandwidth limit */ -static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, - const char* size, const char* bw) +static const char *largefilelimit(cmd_parms *cmd, void *s, const char *file, + const char *size, const char *bw) { - bandwidth_config* conf = (bandwidth_config*)s; - bw_sizel* a; + bandwidth_config *conf = (bandwidth_config *)s; + bw_sizel *a; long int temp, tsize; char msgbuf[MAX_BUF]; @@ -500,14 +502,14 @@ static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, if (tsize < 0) return "File size must be a number of Kbytes"; - a = (bw_sizel*)apr_array_push(conf->sizelimits); - a->file = (char*)file; + a = (bw_sizel *)apr_array_push(conf->sizelimits); + a->file = (char *)file; a->size = tsize; a->rate = temp; if (sid < MAX_VHOSTS) { vnames[sid] = apr_pcalloc(cmd->pool, apr_snprintf(msgbuf, MAX_BUF, "%s,%s", cmd->server->server_hostname, file)); - vnames[sid] = (char*)apr_pstrdup(cmd->pool, msgbuf); + vnames[sid] = (char *)apr_pstrdup(cmd->pool, msgbuf); } a->sid = sid++; @@ -520,7 +522,7 @@ static const char* largefilelimit(cmd_parms* cmd, void* s, const char* file, *----------------------------------------------------------------------------*/ /* Match the input, as part of a domain */ -static int in_domain(const char* domain, const char* what) +static int in_domain(const char *domain, const char *what) { size_t dl = strlen(domain); size_t wl = strlen(what); @@ -543,13 +545,13 @@ static int in_domain(const char* domain, const char* what) } /* Get the bandwidth limit based on from address */ -static long get_bw_rate(request_rec* r, apr_array_header_t* a) +static long get_bw_rate(request_rec *r, apr_array_header_t *a) { - bw_entry* e = (bw_entry*)a->elts; - const char* remotehost = NULL; + bw_entry *e = (bw_entry *)a->elts; + const char *remotehost = NULL; int i; int gothost = 0; - const char* uastr = NULL; + const char *uastr = NULL; for (i = 0; i < a->nelts; i++) { @@ -593,7 +595,7 @@ static long get_bw_rate(request_rec* r, apr_array_header_t* a) Match the pattern with the last digist from filename An asterisk means any. */ -static int match_ext(const char* file, char* match) +static int match_ext(const char *file, char *match) { if (file == NULL || match == NULL) return 0; @@ -610,10 +612,10 @@ static int match_ext(const char* file, char* match) } /* Get the bandwidth limit based on filesize */ -static long get_bw_filesize(request_rec* r, apr_array_header_t* a, - apr_uint32_t filesize, const char* filename) +static long get_bw_filesize(request_rec *r, apr_array_header_t *a, + apr_uint32_t filesize, const char *filename) { - bw_sizel* e = (bw_sizel*)a->elts; + bw_sizel *e = (bw_sizel *)a->elts; int i; apr_uint32_t tmpsize = 0, tmprate = 0; @@ -634,13 +636,13 @@ static long get_bw_filesize(request_rec* r, apr_array_header_t* a, } /* Get the MaxConnections allowed */ -static int get_maxconn(request_rec* r, apr_array_header_t* a) +static int get_maxconn(request_rec *r, apr_array_header_t *a) { - bw_maxconn* e = (bw_maxconn*)a->elts; - const char* remotehost = NULL; + bw_maxconn *e = (bw_maxconn *)a->elts; + const char *remotehost = NULL; int i; int gothost = 0; - const char* uastr = NULL; + const char *uastr = NULL; for (i = 0; i < a->nelts; i++) { @@ -681,13 +683,13 @@ static int get_maxconn(request_rec* r, apr_array_header_t* a) } /* Get an id based on bandwidth limit */ -static int get_sid(request_rec* r, apr_array_header_t* a) +static int get_sid(request_rec *r, apr_array_header_t *a) { - bw_entry* e = (bw_entry*)a->elts; - const char* remotehost = NULL; + bw_entry *e = (bw_entry *)a->elts; + const char *remotehost = NULL; int i; int gothost = 0; - const char* uastr; + const char *uastr; remotehost = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_HOST, @@ -732,10 +734,10 @@ static int get_sid(request_rec* r, apr_array_header_t* a) } /* Get an id based on filesize limit */ -static int get_f_sid(request_rec* r, apr_array_header_t* a, apr_uint32_t filesize, - const char* filename) +static int get_f_sid(request_rec *r, apr_array_header_t *a, apr_uint32_t filesize, + const char *filename) { - bw_sizel* e = (bw_sizel*)a->elts; + bw_sizel *e = (bw_sizel *)a->elts; int i; apr_uint32_t tmpsize = 0, tmpsid = -1; @@ -758,7 +760,7 @@ static int get_f_sid(request_rec* r, apr_array_header_t* a, apr_uint32_t filesiz } /* Update memory (shm) counters, which holds the bw data per context */ -static void update_counters(bw_data* bwstat, ap_filter_t* f) +static void update_counters(bw_data *bwstat, ap_filter_t *f) { apr_time_t nowtime; @@ -785,10 +787,10 @@ static void update_counters(bw_data* bwstat, ap_filter_t* f) } } -static int callback(request_rec* r) +static int callback(request_rec *r) { int t; - bw_data* bwstat; + bw_data *bwstat; if (r->header_only) { return OK; @@ -850,21 +852,21 @@ static int callback(request_rec* r) * The Handler and the Output Filter. Core of the mod. * *----------------------------------------------------------------------------*/ /* With this handler, we can *force* the use of the mod. */ -static int handle_bw(request_rec* r) +static int handle_bw(request_rec *r) { - bandwidth_server_config* sconf = - (bandwidth_server_config*)ap_get_module_config(r->server-> + bandwidth_server_config *sconf = + (bandwidth_server_config *)ap_get_module_config(r->server-> module_config, &bw_module); - bandwidth_config* conf = - (bandwidth_config*)ap_get_module_config(r->per_dir_config, + bandwidth_config *conf = + (bandwidth_config *)ap_get_module_config(r->per_dir_config, &bw_module); - bw_data* bwstat; + bw_data *bwstat; apr_int32_t confid; - /* Only work on main request/no subrequests */ - if (r->main) + /* Only work on main request/no subrequests and no redirets */ + if (r->main || r->prev) return DECLINED; if (strcmp(r->handler, "modbw-handler") == 0) return callback(r); @@ -897,31 +899,34 @@ static int handle_bw(request_rec* r) return DECLINED; } -static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) +static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) { - request_rec* r = f->r; - bandwidth_config* conf = - (bandwidth_config*)ap_get_module_config(r->per_dir_config, + request_rec *r = f->r; + bandwidth_config *conf = + (bandwidth_config *)ap_get_module_config(r->per_dir_config, &bw_module); - bandwidth_server_config* sconf = - (bandwidth_server_config*)ap_get_module_config(r->server-> + bandwidth_server_config *sconf = + (bandwidth_server_config *)ap_get_module_config(r->server-> module_config, &bw_module); - ctx_struct* ctx = f->ctx; - apr_bucket* b = APR_BRIGADE_FIRST(bb); - bw_data* bwstat, * bwmaxconn; + ctx_struct *ctx = f->ctx; + apr_bucket *b = APR_BRIGADE_FIRST(bb); + bw_data *bwstat, *bwmaxconn; int confid = -1, connid = -1; apr_size_t packet = conf->packet, bytes = 0; apr_off_t bblen = 0; apr_size_t bw_rate, bw_min, bw_f_rate, cur_rate = 0; apr_interval_time_t sleep; - const char* buf; - const char* filename; + const char *buf; + const char *filename; long current_sleep_bypasses = 0; unsigned long long new_client_bw = 0; + char sizebuf[5][5]; /* buffers for human-readable size/rate conversion */ /* Only work on main request/no subrequests */ - if (r->main) { + if (r->status != HTTP_OK + || r->main + || (r->handler && strcmp(r->handler, "default-handler") == 0)) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } @@ -982,7 +987,7 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) /* Initialize our temporal space, which survives multiple invokations for the same request */ if (ctx == NULL) { - apr_bucket_alloc_t* bucket_alloc = apr_bucket_alloc_create(f->r->pool); + apr_bucket_alloc_t *bucket_alloc = apr_bucket_alloc_create(f->r->pool); f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); ctx->bb = apr_brigade_create(f->r->pool, bucket_alloc); @@ -992,21 +997,20 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) ctx->sleep_bypasses_total = 0; ctx->client_bw = 0; - /* Verbose Output - but only the first time the filter is called */ + /* Verbose Output - but only the first time the filter is invoked per connection */ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "ID: %i; Directory : %s; File : %s; Rate : %ld; Minimum : %ld; Size rate : %ld;", - confid, conf->directory, filename, bw_rate, bw_min, bw_f_rate); + "ID: %i; Directory : %s; File : %s; Rate : %s; Minimum : %s; Size rate : %s;", + confid, conf->directory, filename, apr_strfsize(bw_rate, sizebuf[0]), apr_strfsize(bw_min, sizebuf[1]), apr_strfsize(bw_f_rate, sizebuf[2])); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "clients : %d/%d; rate/min : %ld,%ld", bwmaxconn->connection_count, + "clients : %d/%d; rate/min : %s/s,%s/s", bwmaxconn->connection_count, (connid >= 0) ? get_maxconn(r, conf->maxconnection) : 0, - bw_rate, bw_min); + apr_strfsize(bw_rate, sizebuf[0]), apr_strfsize(bw_min, sizebuf[1])); } /* - We get buckets until a sentinel appears - - Read the content of the bucket, and send it to the next filter, piece - by piece + - Read the content of the bucket, and send it to the next filter, piece by piece */ while (b != APR_BRIGADE_SENTINEL(bb)) { /* If the bucket is EOS end here */ @@ -1069,7 +1073,7 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) new_client_bw > cur_rate) { /* Verbose logging */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Client BW is ~%ld B/s. This %s than available BW (%ld). %s", new_client_bw, (new_client_bw > cur_rate ? "More" : "Less"), cur_rate, (new_client_bw > cur_rate ? "BW Limiting!" : "Not BW limiting!")); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Client BW: %s/s; Available BW: %s/s; %s", apr_strfsize(new_client_bw, sizebuf[0]), apr_strfsize(cur_rate, sizebuf[1]), (new_client_bw > cur_rate ? "Limiting!" : "Not limiting!")); } ctx->client_bw = new_client_bw; ctx->bw_interval_bytes = 0; @@ -1080,7 +1084,7 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) /* For Windows, assume the minimum sleep time is 10ms. If the needed sleep time is less than 10ms, calculate how many packets to send before sleeping for 10ms. For very small buckets, this can result in an absurdly high number of packets to send, probably more than there are buckets, so it doesn't matter. */ - if (sleep < 10000 && ctx->client_bw > cur_rate) + if (sleep < 10000 && (ctx->client_bw > cur_rate || ctx->client_bw == 0)) { /* calculate, based on available bandwidth right now, how many packets can be sent in 10 ms */ current_sleep_bypasses = (long)((double)10000 / (double)(sleep + 1)); /* plus 1 microsecond to avoid divide by zero errors */ @@ -1091,12 +1095,12 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) ctx->sleep_bypasses_total = current_sleep_bypasses; /* setup counters */ ctx->sleep_bypasses_left = current_sleep_bypasses; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "File: %s. Available BW: %ld B/s. Packet: %ld bytes. Bypassing sleep for %i packet(s).", filename, cur_rate, packet, ctx->sleep_bypasses_left); + "Available BW: %s/s. Packet: %s. Bypassing sleep for %i packet(s). File: %s.", apr_strfsize(cur_rate, sizebuf[0]), apr_strfsize(packet, sizebuf[1]), ctx->sleep_bypasses_left, filename); } else { /* If number of packets to send in 10ms has changed since last calc because available bandwidth changed, recalcuate */ if (ctx->sleep_bypasses_total != current_sleep_bypasses) { - /* new packet counter = packets_per_10ms minus packets already sent */ + /* new packet counter = current_sleep_bypasses minus packets already sent */ ctx->sleep_bypasses_left = current_sleep_bypasses - (ctx->sleep_bypasses_total - ctx->sleep_bypasses_left); if (ctx->sleep_bypasses_left < 0) { @@ -1104,7 +1108,7 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) } ctx->sleep_bypasses_total = current_sleep_bypasses; /* Update the total packets to send in this period */ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "File: %s. Available BW changed to %ld B/s. Now bypassing sleep for %ld more packet(s).", filename, cur_rate, ctx->sleep_bypasses_left); + "*Available BW: %s/s. Packet: %s. Bypassing sleep for %i packet(s). File: %s.", apr_strfsize(cur_rate, sizebuf[0]), apr_strfsize(packet, sizebuf[1]), ctx->sleep_bypasses_left, filename); } } } @@ -1136,8 +1140,7 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) /* If the connection goes to hell... go with it ! */ if (r->connection->aborted) { /* Verbose. Tells when the connection was ended */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, - 0, r, "Connection to hell"); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "ID: %i; Connection went away for %s!", confid, filename); apr_atomic_dec32(&bwmaxconn->connection_count); return APR_SUCCESS; } @@ -1147,8 +1150,9 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) ctx->sleep_bypasses_left--; } else { - if (ctx->client_bw > cur_rate) { /* Only sleep if the client's calculated bw is greater than available */ - apr_sleep(sleep); /* bandwidth, otherwise there's no reason to sleep. */ + /* Only sleep if the client's calculated bw is greater than available or client bw not yet known */ + if (ctx->client_bw > cur_rate || ctx->client_bw == 0) { + apr_sleep(sleep); ctx->bw_interval_start_time += sleep; /* Adjust interval start time to exclude sleep time. */ } ctx->sleep_bypasses_left = 0; @@ -1183,25 +1187,25 @@ static int bw_filter(ap_filter_t* f, apr_bucket_brigade* bb) /*----------------------------------------------------------------------------* * Module Init functions * *----------------------------------------------------------------------------*/ -static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, - server_rec* s) +static int bw_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, + server_rec *s) { apr_status_t status; apr_size_t retsize; apr_size_t shm_size; - bw_data* bwstat; + bw_data *bwstat; int t; #if defined(WIN32) TIMECAPS resolution; #endif /* These two help ensure that we only init once. */ - void* data; - const char* userdata_key = "ivn_shm_bw_limit_module"; + void *data; + const char *userdata_key = "ivn_shm_bw_limit_module"; apr_pool_userdata_get(&data, userdata_key, s->process->pool); if (!data) { - apr_pool_userdata_set((const void*)1, userdata_key, + apr_pool_userdata_set((const void *)1, userdata_key, apr_pool_cleanup_null, s->process->pool); return OK; } @@ -1299,41 +1303,41 @@ static int bw_init(apr_pool_t* p, apr_pool_t* plog, apr_pool_t* ptemp, } -static void* create_bw_config(apr_pool_t* p, char* path) +static void *create_bw_config(apr_pool_t *p, char *path) { - bandwidth_config* new = - (bandwidth_config*)apr_palloc(p, sizeof(bandwidth_config)); + bandwidth_config *new = + (bandwidth_config *)apr_palloc(p, sizeof(bandwidth_config)); new->limits = apr_array_make(p, 20, sizeof(bw_entry)); new->minlimits = apr_array_make(p, 20, sizeof(bw_entry)); new->sizelimits = apr_array_make(p, 10, sizeof(bw_sizel)); new->maxconnection = apr_array_make(p, 10, sizeof(bw_maxconn)); - new->directory = (char*)apr_pstrdup(p, path); + new->directory = (char *)apr_pstrdup(p, path); new->packet = PACKET; new->error = HTTP_SERVICE_UNAVAILABLE; - return (void*) new; + return (void *) new; } -static void* create_bw_server_config(apr_pool_t* p, server_rec* s) +static void *create_bw_server_config(apr_pool_t *p, server_rec *s) { - bandwidth_server_config* new; + bandwidth_server_config *new; new = - (bandwidth_server_config*)apr_pcalloc(p, + (bandwidth_server_config *)apr_pcalloc(p, sizeof (bandwidth_server_config)); new->state = BANDWIDTH_DISABLED; new->force = BANDWIDTH_DISABLED; - return (void*) new; + return (void *) new; } /*----------------------------------------------------------------------------* * Apache register functions * *----------------------------------------------------------------------------*/ -static void register_hooks(apr_pool_t* p) +static void register_hooks(apr_pool_t *p) { /* - Register a handler, which enforces mod_bw if needed From 330a0b79a0713fa08f328ec0bd08f5fe35fb7438 Mon Sep 17 00:00:00 2001 From: Sam Osheroff Date: Wed, 1 Dec 2021 12:51:55 -0800 Subject: [PATCH 12/15] Update README.md --- README.md | 670 ++---------------------------------------------------- 1 file changed, 22 insertions(+), 648 deletions(-) diff --git a/README.md b/README.md index ab44e29..4afae32 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,7 @@ -Apache2 - Mod_bw v0.92 +Apache2.4+ - Mod_bw v0.92 -Author : Ivan Barrera A. (Bruce) - -HomePage : Http://Ivn.cl - -Release Date : 20-Jul-2010 - -Status : Stable +Author : Sam Osheroff +Original Author : Ivan Barrera A. (Bruce) License : Licensed under the Apache Software License v2.0 It must be included as LICENSE in this package. @@ -19,646 +14,25 @@ Platform : Linux/x86 (Tested with Fedora Core 4, Suse, etc) Microsoft Windows (Win XP, Win2003, Win7. Others should work) HP-UX 11 (Thanks to Soumendu Bhattacharya for testing) -Notes : This is a stable version of mod_bw. It should work with - almost any MPM (tested with WinNT/prefork/Worker MPM). - - We are reaching the End of mod_bw series 0.x. As soon as this - last changes are confirmed by the users (perhaps some changes - at request), i'll set this release to version 1.0 final. - -Limitations : This mod doesn't know how fast the client is - downloading a file, so it just divides the bw assigned - between the users. - MaxConnections works only for the given scope. (i.e , all - will limit maxconnections from all,not per ip or user) - -Changelog : - -2010-07-20 : Fixed ap_get_server_banner unknown on older apache version - -2010-05-27 : Fixed weird behaviour on Windows Hosts. (mod_bw.txt) - Added high resolution timers for windows. (speed improvements) - Fixed stupid bug that caused crash when mod is enabled but there is - not a single limit. - -2010-05-24 : Code Cleanup. No more warnings or stuff in Visual Studio - -2010-04-28 : Bruce's Birthday Gift : A callback to the stats of the mod :) - -2010-04-06 : Fixed "Invisible" memory leak. Only seen when serving HUGE streams. - -2010-03-10 : Fixed MinBandwidth screwing limits. Another unsigned/signed screw up. - ------------------------------------------------------------------------------- - - Some time ago, Jacky Yuen contacted me about a bug in the mod. It didn't look like -the mod's fault, but i took a deeper look. - -The issue : - - On his windows server (win2003, and XP) the mod was working, but was unable to -reach high speeds (1MB/s). (i heard something like this before, and all you need is -to change the packet size). - However, doing this, didn't fix the issue. I tried this on my server, and i was -able to get about 500KB/s. Setting the packet size to 16384 gave me 1MB/s. - Jacky told me he still had problems, so i tried all windows systems i got around. - A windows 2003 server, a Windows 7 (32bits) showed the problem (max speed was 490KB/s) -. A Windows 7 64bits -and Win 2003 SP2 didnt. - The most awesome part, is that if you run Google Chrome, a Flash application, or -Windows Media Player, the mod is able to deliver up to 1MB/s. - - Took me a while, but i found that Windows doesnt run a high resolution timer -all the time. In the servers with the issue, the timer run every 10 ms. -Whenever you run some of the mentioned apps, they set the timer to the highest -speed possible (in my equipment, 1 ms). This setting affects all other -applications, so the mod was able to sleep small times to deliver data as it -needed. - So, i wrote 2 fixes. The first one, i didnt wanted to, but i made the mod to -set the timer to the highest resolution possible (it is written to the logs if -you want to peek). And the second, is to avoid waiting small times to send -data. Minimum time to sleep is 200ms now, and data is adjusted for this. (only -for windows). Both fixes are under defines that will compile just for windows, -so linux users won't notice any changes. - The good thing, for windows users, is that with this fixes, i've been able -to get speeds up to 2.45MB/s under windows!. Using apache by itself, i just -got 1.2MB/s. Just enabling the mod and setting a high limit, the speed got -pumped up. - - That's it. Now i'll be back working on the next release. - --- (previous readme.txt text follows dated 24/May/2010) - - Again... It has been a while since i've upted the code. (work, personal -life, money issues, the same stuff we all fight daily) - However, that doesn't mean i forgot about it. I've just been working my -*** off. I've got many emails with suggestions, some bugs, etc.. - I'm doing one of the last updates of this line of mod_bw (0.x). It's -mainly a couple of bugfix, and a little callback to get stats on the running -mod. I hope it wont break anything.. (of course i've tested it a lot). - - Ah!, i said this is one of the last updates. Yes. This is because this line -of code is limiting the possibilities of the mod, so i've started a new mod_bw -using other set of techniques. (so, it is highly experimental, and uses -completely new instructions). This new branch of the mod was born thanks to -the email sent by Borislav Borislavov (icn.bg), who needed some special features -to be implemented, not possible with the current code. - So, if you wanted the mod to do per-ip limiting, traffic limiting, etc.. -keep checking my site. I'll be releasing a new branch of mod_bw to public soon. -(Unfortunately, it won't be released under the Apache license yet). - - Now, back to this mod : - - First, i've fixed two annoying bugs. - - MinBandWidth -1 was screwing things up sometimes. All because i was using -an unsigned integer to store the -1. Yeah, my bad. - - The limiting handler was leaking memory. A few bytes at a time, but for -large files (really, really large) this could mean one of the apache childs -consuming almost all memory. Thanks to Christian Spielberger who insisted -and helped me to find this. (i was sure there was something.. but my servers -recycle apache childs pretty often). Fun Fact : I found the bug, was cleaning -my test code, and he sent me an email with the exact same solution i came up. - Great minds think alike, eh ? :) - - Then, i made a status callback for the mod. This callback will show some -stats on the running mod, for each memory segment used to limit bandwidth. - Is it a simple stat. However, i received many emails asking for this. - - This is easy to achieve : - - In your admin vhost (if you have one.. If not, any vhost you want to check), -use a location to set a handler for the callback. - - Suppose the vhost for 127.0.0.1 : - - - SetHandler modbw-handler - - - - Now you can get information of the mod by visiting http://127.0.0.1/modbw - You can get the same information in csv format at http://127.0.0.1/modbw?csv - - - Please, test this changes, let me know how it works. - If you have some ideas (i.e. information to add in the stats), post them. If -it can or can't be done in this branch of the mod, i'll let you know. - - ------------------------------------------------------------------------------- - - -Contents : - -1 .- Notices - -1.1 - ChangeLog and TODO - -1.2 - Important Caveats - -2 .- Installing - -2.1 - Windows - -2.2 - Linux - -3 .- Getting it to Work, Directives - -3.1 - BandWidthModule - -3.2 - ForceBandWidthModule - -3.3 - BandWidth +Notes : This fork is based on stable version 0.92 of mod_bw. While it was written + to address limitations with Windows, the changes could be useful to other + platforms. -3.4 - MinBandWidth + In Windows, the sleep timer has a minimum resolution of 1ms but the necessary + sleep duration to create the desired bandwidth could esaily be less than 1ms. + The module now calculates roughly how many sleep cycles to "skip" to get 10ms + to pass, then it sleeps for 10ms. This sleep duration was selected because some + Windows editions have a minimum 10ms resolution. -3.5 - LargeFileLimit - -3.6 - BandWidthPacket - -3.7 - BandWidthError - -3.8 - MaxConnection - -3.9 - Status Callback - -4 .- Examples - -4.1 - Misc Examples - -5 .- FAQ - ------------------------------------------------------------------------------- - -1.- Notices - - 1.1 - ChangeLog & TODO : - - This has been moved to the files ChangeLog and TODO. - - 1.2 - Important Caveats : - - There is a couple situations in which you might get unexpected results with - mod_bw. From the emails i've got, most of this situations are when using - mod_proxy, and sometimes mod_php. - If you are using one of this mods, and you see mod_bw output in the error log - but there is no limiting being done, the first think you have to try, is to - change the LoadModule directive on httpd.conf. Put mod_bw directive as the - first one in the list, and then all the others. (or at least, put it before - mod_proxy and mod_php). This should fix the issue. - - Also, there are some static values defined in the code, that *might* cause - weird issues in specific cases. - The main two, are listed here : - - #define MAX_VHOSTS 1024 - #define MAX_BUF 1024 - - For the new status page, the mod assumes you wont have more than 1024 - mod_bw enabled virtual hosts. If you do, please, change this number. It - won't cause any troubles, it just mean the max number of "spaces" to reserve - when storing the vhost names in memory. If you dont fix this number, only - the first MAX_VHOSTS vhosts will show at the status page. - - The second line, is the length of the temporal space the mod uses to - create some strings. If you have really long vhost names, you might find the - status page shows these names truncated at some point, and show incorrect - info. You will need to increase this number. - - ------------------------------------------------------------------------------- - -2.- How To Install : - - 2.1 - Windows - - In Windows, you have to download the binary dll from the site (or compile - one yourself) that matches your apache version, and Install it under modules - on your apache tree. Then edit httpd.conf, and add the LoadModule sentence. - If there is no matching binary dll with your version of apache (the latest) - you can ask me to compile it for you. Post a message in the home site as a - feature request. - - Example : - - Download mod_bw-2.2.14.dll from the home site, to c:\apache2\modules - Edit httpd.conf, and add LoadModule bw_module modules/mod_bw-2.2.14.dll - Restart Apache. - - 2.2 - Linux - - Well.. (under *nix) you *have* to compile it.. (unless your distribution - has it available as a package. Many already do ! Thanks !) - - REQUIREMENTS : - - You will need apache2 headers in the include path. In redhat/suse or others - this mean apache-devel or httpd-devel installed. (or any other that provides - http/apr headers and apxs2 tool) - You also need support for SHM in your OS. Usually you will have this. - - For this to work, you MUST have apxs (or apxs2) installed. You might need - to use its full path (i.e. /usr/sbin/apxs .....). Well, you have to do this : - - apxs -i -a -c mod_bw.c - or - apxs2 -i -a -c mod_bw.c - - This will bring out some stuff... nothing to worry (unless you see an error). - If it says ok, then you are ready. Restart apache (service httpd restart on - redhat, mandrake, and others... apachectl restart .. rcapache2 restart or... - well, you should know) - - Note On Solaris Users : - - If you got problems compiling it on Solaris, remember to check you have - libgcc correctly installed, and the ld_library_path set up correctly. - I didnt, so i compiled this way : - - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib - apxs -i -a -c mod_bw.c -L/usr/local/lib -lgcc_s + The module now attempts to roughly calculate the client's bandwidth over a 15ms + period. If the client's appearant bandwidth is less than the available during + the 15ms interval, no sleeping occurs, since the client's lower bandwidth is + already the limiting factor. - And then started apache, and everything worked fine. - - Note On SuSe Users : - - You NEED to have installed apache2 header files (apache2-devel rpm). - Otherwise you'll get lots of include files error. - - If you didn't manage to get it installed, drop me a letter. But please - be sure you tried everything. Sometimes it is just a forgotten step. - ------------------------------------------------------------------------------- - -3.- Getting it to Work : - - - Ok.. this is the most confusing part. - This mod, is able to limit bandwidth usage on every virtual host or - directory. htaccess files will not be supported on this branch. (0.x) - - * Configuration Directives - ***************************************************************************** - - 3.1 - BandWidthModule [On|Off] - - You need to set this to On for the mod to work.. By default, the mod is - disabled, and wont limit anything. - - Example : - - BandWidthModule On - - 3.2 - ForceBandWidthModule [On|Off] - - By default, the mod wont catch every request. - If you enable it, every request will be processed by the mod. - - Example : - - (normal use) - AddOutputFilterByType MOD_BW text/html text/plain - - (enabling Force) - ForceBandWidthModule On - - - 3.3 - BandWidth [From] [bytes/s] - - This takes 2 parameters. From is the origin of the connections. It could - be a full host, part of a domain, an ip address, a network mask (i.e - 192.168.0.0/24 or 192.168.0.0/255.255.255.0) or all. - The second parameter indicates the total speed available to the Origin. - If speed is 0, there is no limit. - - Example : - - BandWidth localhost 10240 - BandWidth 192.168.218.5 0 - - ( Order is relevant. First entries have precedence ) - - - As for version 0.8, an user agent matching capability was introduced. - If you want to limit all clients using certain browser, you can limit - doing this : - - BandWidth u:[User-Agent] [bytes/s] - - User agent is a regular expression which will match the one sent by the - browser. This is easier to explain with examples : - - Example : - - BandWidth "u:^Mozilla/5(.*)" 10240 - BandWidth "u:wget" 102400 - - First one, will match a browser that identifies itself as Mozilla/5(etc) - Second one, will match a browser that has wget in any part of its id. - - - 3.4 - MinBandWidth [From] [bytes/s] - - This takes 2 parameters. From is the origin of the connections. It could - be a full host, part of a domain, an ip address, a network mask (i.e - 192.168.0.0/24 or 192.168.0.0/255.255.255.0) or all. - The second parameter indicates the minimun speed each client will have. - What does this mean ? If you have a total of 100kbytes speed, and you put - MinBandWidth at 50kbytes, it doesnt matter how many clients you have, all - of them will have a minimun of 50kbytes of total speed to download. - If speed is 0, you will be using the default minimun (256 bytes/s). - There is a special value of -1. This value means that each client will - have a top speed determined by the BandWidth directive. See the examples. - - Examples : - - BandWidth all 102400 - MinBandWidth all 50000 - - The example above will set a top speed of 100kb for the 1º - client. If more clients come, it will be splitted accordingly but - everyone will have at least 50kb (even if you have 50 clients) - - BandWidth all 50000 - MinBandWidth all -1 - - This example, makes everyone have 50kb as top speed. - - 3.5 - LargeFileLimit [Type] [Minimum Size] [bytes/s] - - Type, is the last part of a file, or * for all. You can use .tgz to match - only tar-compressed files, .avi to match video files, or * to match all. - Minimum Size, is the size (in kbytes) of the file, to be matched. That way - you can match huge video files that hog your bandwidth. - The last parameter... is obvious. The speed allowed. - - Example : - - LargeFileLimit .avi 500 10240 - - This limits .avi files over (or equal to) 500kb to 10kbytes/s - - 3.6 - BandWidthPacket [Size] - - Probably you never need to touch this. It defaults to 8192 which is good - for almost any speed. - It must be a size between 1024 and 131072. A Small packet will cause the - top speed to be lower, and the mod using more time splitting. If you use - a Size too big, the mod will adjust it to lower speeds. - If you are using the mod in high speed networks, this is, you want to - set limits of megabits/s, you will be better using packet sizes of - 16384, or 32768. - - 3.7 - BandWidthError [Error] - - This directive is useful to deliver a personalized error code. - By default, when maxconnections is reached, the mod will issue a 503 - HTTP_SERVICE_UNAVAILABLE code. For some users, it is annoying to have an - error message, and don't knowing why. You could use an ErrorDocument to - point error 503 to a page explaining that you are under a heavy load of - connections, but sometimes 503 is issued by the server for other reasons. - So, with this directive, you can set the error code to return when - maxconnections is reached. You can use any error code between 300 and 599. - Please note, that some of the error codes are already used, so before using - any number, take a look to a list of the codes (search for http error codes - in google). - When testing, i've used the error code 510, which hasn't been defined yet. - - And Example, with Personalized Error Page : - - ErrorDocument 510 /errors/maxconexceeded.html - BandWidthError 510 - - Note : Sometimes, the personalized page didn't appear. I'm not sure, but - in many cases, it got fixed, by making the page size over 1024bytes. - Anyways, if you need help using ErrorDocument, refer to the apache - Documentation. - - 3.8 - MaxConnection [From] [Max] - - This takes 2 parameters. From is the origin of the connections. It could - be a full host, part of a domain, an ip address, a network mask (i.e - 192.168.0.0/24 or 192.168.0.0/255.255.255.0) or all. - The second parameter, is the max connections allowed from the origin. Any - connection over Max, will get a 503 Service Temporarily Unavailable - - There is a catch. You NEED to have a BandWidth limit for the same origin. - It doesnt need to be a low limit. But you need one. (unlimited, doesn't - count) - You might wonder why. It's because im using them same memory space of the - bandwidth limit to count the connections, so i can save memory space. - If you dont put a BandWidth using the same origin, MaxConnections will be - ignored. - - Example : - - BandWidth all 102400000 - MaxConnection all 20 - - or - - BandWidth all 102400000 - BandWidth 192.168.0.0/24 10240 - MaxConnection all 20 - MaxConnection 192.168.0.0/24 5 - - - As for version 0.8, an user agent matching capability was introduced. - If you want to limit all clients using certain browser, you can limit - doing this : - - MaxConnection u:[User-Agent] [Max] - - User agent is a regular expression which will match the one sent by the - browser. This is easier to explain with examples : - - Example : - - MaxConnection "u:^Mozilla/5(.*)" 5 - MaxConnection "u:wget" 5 - - First one, will match a browser that identifies itself as Mozilla/5(etc) - Second one, will match a browser that has wget in any part of its id. - - Please, rememeber that every speed, will depend mostly on your connection. - You can't get more speed if you dont have it. - - Remember also.. if you dont follow the instructions, and get some weird - results, recheck your config before sending me an email. - - 3.9 - Status Callback - - Since v0.9, the mod can display a simple status page, showing stats from - the running mod. This stats show the exact information being used by the mod - to do the limiting in that second. - - For this to work, you need to set a handler on any vhost. You might want - to set this under an admin vhost, or set some policies to make it private. - Your call. - - Example (let's assume the vhost is for 127.0.0.1) : - - - SetHandler modbw-handler - - - - Now, you can get the status info at http://127.0.0.1/modbw - ( Or download a CSV of the stats at http://127.0.0.1/modbw?csv ) - - The information provided is the following : - - id : 0 // This is just a correlative number for each config. - name : work.ivn.cl,all // The vhost name, and the scope of the rule - lock : 0 // If the memory segment is being used (0 = no) - count: 0 // Number of users connected to this rule - bw : 0 // Bandwidth currently being used by the rule - bytes: 0 // Number of bytes last sent. Only true if count>0 - hits : 0 // Number of times anyone has accesed this rule. - - Simple, yet useful ! - ------------------------------------------------------------------------------- - -4.- Examples - - 4.1 - Misc examples - - Limit every user to a max of 10Kb/s on a vhost : - - - BandwidthModule On - ForceBandWidthModule On - Bandwidth all 10240 - MinBandwidth all -1 - Servername www.example.com - - - - Limit al internal users (lan) to 1000 kb/s with a minimum of 50kb/s , and - files greater than 500kb to 50kb/s. - - - BandwidthModule On - ForceBandWidthModule On - Bandwidth all 1024000 - MinBandwidth all 50000 - LargeFileLimit * 500 50000 - Servername www.example.com - - - - Limit avi and mpg extensions to 20kb/s. - - - BandwidthModule On - ForceBandWidthModule On - LargeFileLimit .avi 1 20000 - LargeFileLimit .mpg 1 20000 - Servername www.example.com - - - - Using it the "right" way, with output filter by mime type (for text) - to 5kb/s: - - - BandwidthModule On - AddOutputFilterByType MOD_BW text/html text/plain - Bandwidth all 5000 - Servername www.example.com - - - - If you need help on doing more complex setup, post over GitHub. - ------------------------------------------------------------------------------- - -5.- FAQ - -(No particular order) - -1.- Why should i use mod_bw ? - - If you want to restrict the top speed a site is able to use, or limit the - max connections allowed per site, or just to try the mod. - Some people told me, they use it primarily to stop small sites hogging - all the bandwidth when serving video, images, or other content. - -2.- How do i ... ? - - First, read the documentation. it is pretty straightforward to use. - If you can't make it work, or if you want to ask for a feature, visit the - GitHub site, and post a request. Remember to read the documentation and the - faq. If the request is already posted, i'll just delete the duplicates. - -3.- What's the difference with mod_bwshare, mod_throttle, etc ? - - The main difference, is that this mod, is aimed to the Apache 2 API. - Some other differences, is, how this mod works, and the directives it - implements. - I took some ideas from other mods, as the shared memory implementation - (mod_bandwidth2 from Tim Verhoeven). Most of the directives, are in origin - from mod_bandwidth for apache 1. - -4.- How does it works ? - - The mod, will set a shared memory holding all of the configuration you - make. In this space, it will also, keep a "count" of the info currently - using (as current connections, bw used, time, and bytes sent). - When you assign a bw limit, the mod will "split" the data, and will send - it piece by piece, with a small delay between pieces. The delay will be - adjusted so at least 1 piece is sent in a second, thus eviting browser - timeout. - If there are two or more clients downloading from the same vhost, the - limit will be "splitted" too. So, if you have a bw limit of 16Kb and two - clients, each one will have 8Kb to download. You can also set a fixed - download rate, so each client will have a fixed maximun download rate. - This is a simple explanation of how this works. Take a look at the code - if you want to know more about it. - -5.- Can you make it do ... ? - - Post a request for a feature through GitHub. - -6.- Can you make mod_bw work for ... ? - - See question 5. Anyways, if i dont own (or have access) to the hardware - needed, i won't be able to help you. - -7.- I'm having some trouble in windows ... - - Well, thanks to the guys at Microsoft, who kindly offered access to MSDN - to the Apache Community, the dll's i post on my site are produced using - licensed Visual C, and i can help with any Windows Issue! - Post or send me your problem. I'll be glad to (try to) help. - -8.- The mod is not limiting certain Directory - - Ok... first, read the documentation. Then the FAQ. If it isn't working, - then look if you have defined correctly the limits within that directory. - If you have a limit in a vhost, and inside the vhost, a directory with - another limit, a new context with the configs of the directory is created, - and only have the configurations you added there. - - In example : - - - BandWidthModule On - BandWidth all 16384 - LargeFileLimit * 500 4096 - - LargeFileLimit * 100 1024 - - - - This wont limit Directory / to 16384. The Directory wont "inherit" the - settings from the vhost if you use some of the mod's directives. - ------------------------------------------------------------------------------- - - Ivan Barrera A. - - Ivn Systems Software - - + Some enhancements were made to the debug logging. + + Lastly, there was a bug in the hook function (used for forced operations) + where modules that create subrequests caused the output filter to get installed + twice. Inserting the output filter is now skipped when the subrequest + causes an internal redirect. + From 3154cbd67c9a840d5aa311182bcebadce59b7657 Mon Sep 17 00:00:00 2001 From: Sam Osheroff Date: Wed, 1 Dec 2021 12:52:13 -0800 Subject: [PATCH 13/15] Delete TODO --- TODO | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 TODO diff --git a/TODO b/TODO deleted file mode 100644 index a6d89ef..0000000 --- a/TODO +++ /dev/null @@ -1,15 +0,0 @@ -Todo : - - - Test and more tests (before making this final) - - - The following features won't be included in this branch of the -mod. This is because the limitations of the actual code base. - - - Limiting on INPUT - - Per User Bandwidth - - Htaccess support - - As the new code base is already being written, this features will -appear sometime in the development of the new mod. -legacy code. From e9ea4226b26b2aa939d9f12b3a700e498c6f5542 Mon Sep 17 00:00:00 2001 From: Sam Osheroff Date: Wed, 1 Dec 2021 12:52:26 -0800 Subject: [PATCH 14/15] Delete Changelog --- Changelog | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 Changelog diff --git a/Changelog b/Changelog deleted file mode 100644 index 358bdcd..0000000 --- a/Changelog +++ /dev/null @@ -1,51 +0,0 @@ -V0.92 ------------- -2010-07-20 : - -- Fixed ap_get_server_banner unknown on older apache version - -V0.91 ------------- -2010-05-27 : - -- Fixed weird behaviour on Windows Hosts. (mod_bw.txt) -- Added high resolution timers for windows. (speed improvements) -- Fixed stupid bug that caused crash when mod is enabled but there is - not a single limit. - - -v0.9 ------------- -2010-05-24 : - -- Fixed an "invisible" memory leak -- Fixed MinBandWidth X -1 skipping all bw control. -- Added status callback -- Code cleanup. No more warnings or stuff in Visual Studio - -v0.8 ------------- -2007-03-17 : - -- Added user agent match on bandwidth and connections limiting -- Fixed issue of symbols not found on some platforms -- Updated documentation accordingly - - -v0.7 ------------- -2005-08-29 : - -- Changed License to Apache Software License v2.0 -- Changed coded style. Using GNU indent. -- Changed function name from is_filetype to match_ext -- Removed check for "no configurations" (confid < 0) -- Removed BandwidthDebug directive. -- Removed simple allocation on Win32 platform. Using SHM now. -- Removed no-limiting for error pages. -- Added Support for APR > 0.9 -- Added Support for extra-large files (2G, 4G) with APR > 1 -- Borrowed code (in_domain and ip match) from mod_access) -- IPV6 Support - - From e647838499cbb08cf9aefe8c08a9fd42a5e0f7b4 Mon Sep 17 00:00:00 2001 From: sosherof Date: Thu, 2 Dec 2021 14:16:45 -0800 Subject: [PATCH 15/15] Changed all APLOG_DEBUG to APLOG_Trace6. Added APLOG_USE_MODULE statement so logs will contain module name and module level logging can be used. --- mod_bw.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mod_bw.c b/mod_bw.c index 00ccb79..2797e3e 100644 --- a/mod_bw.c +++ b/mod_bw.c @@ -106,6 +106,9 @@ typedef regex_t ap_regex_t; #define apr_atomic_set32 apr_atomic_set #endif + +#pragma message("This file is: " __FILE__) + /* Enum types of "from address" */ enum from_type { T_ALL, @@ -998,11 +1001,11 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) ctx->client_bw = 0; /* Verbose Output - but only the first time the filter is invoked per connection */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, r, "ID: %i; Directory : %s; File : %s; Rate : %s; Minimum : %s; Size rate : %s;", confid, conf->directory, filename, apr_strfsize(bw_rate, sizebuf[0]), apr_strfsize(bw_min, sizebuf[1]), apr_strfsize(bw_f_rate, sizebuf[2])); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, r, "clients : %d/%d; rate/min : %s/s,%s/s", bwmaxconn->connection_count, (connid >= 0) ? get_maxconn(r, conf->maxconnection) : 0, apr_strfsize(bw_rate, sizebuf[0]), apr_strfsize(bw_min, sizebuf[1])); @@ -1073,7 +1076,7 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) new_client_bw > cur_rate) { /* Verbose logging */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Client BW: %s/s; Available BW: %s/s; %s", apr_strfsize(new_client_bw, sizebuf[0]), apr_strfsize(cur_rate, sizebuf[1]), (new_client_bw > cur_rate ? "Limiting!" : "Not limiting!")); + ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, r, "Client BW: %s/s; Available BW: %s/s; %s", apr_strfsize(new_client_bw, sizebuf[0]), apr_strfsize(cur_rate, sizebuf[1]), (new_client_bw > cur_rate ? "Limiting!" : "Not limiting!")); } ctx->client_bw = new_client_bw; ctx->bw_interval_bytes = 0; @@ -1094,7 +1097,7 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) if (ctx->sleep_bypasses_left == 0) { /* If not currently counting down packets... */ ctx->sleep_bypasses_total = current_sleep_bypasses; /* setup counters */ ctx->sleep_bypasses_left = current_sleep_bypasses; - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, r, "Available BW: %s/s. Packet: %s. Bypassing sleep for %i packet(s). File: %s.", apr_strfsize(cur_rate, sizebuf[0]), apr_strfsize(packet, sizebuf[1]), ctx->sleep_bypasses_left, filename); } else { @@ -1107,7 +1110,7 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) ctx->sleep_bypasses_left = 0; /* if new packets to send is less than zero, reset to zero so we sleep now*/ } ctx->sleep_bypasses_total = current_sleep_bypasses; /* Update the total packets to send in this period */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, r, "*Available BW: %s/s. Packet: %s. Bypassing sleep for %i packet(s). File: %s.", apr_strfsize(cur_rate, sizebuf[0]), apr_strfsize(packet, sizebuf[1]), ctx->sleep_bypasses_left, filename); } } @@ -1140,7 +1143,7 @@ static int bw_filter(ap_filter_t *f, apr_bucket_brigade *bb) /* If the connection goes to hell... go with it ! */ if (r->connection->aborted) { /* Verbose. Tells when the connection was ended */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "ID: %i; Connection went away for %s!", confid, filename); + ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, r, "ID: %i; Connection went away for %s!", confid, filename); apr_atomic_dec32(&bwmaxconn->connection_count); return APR_SUCCESS; } @@ -1376,6 +1379,7 @@ static const command_rec bw_cmds[] = { {NULL} }; +APLOG_USE_MODULE(bw); module AP_MODULE_DECLARE_DATA bw_module = { STANDARD20_MODULE_STUFF, create_bw_config, /* dir config creater */