Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
matsumotory committed Aug 28, 2015
0 parents commit 4fa5e5b
Show file tree
Hide file tree
Showing 6 changed files with 359 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .clang-format
@@ -0,0 +1,6 @@
# requires clang-format >= 3.6
BasedOnStyle: "LLVM"
IndentWidth: 2
ColumnLimit: 120
BreakBeforeBraces: Linux
AllowShortFunctionsOnASingleLine: None
5 changes: 5 additions & 0 deletions .gitignore
@@ -0,0 +1,5 @@
mod_vhost_maxclients.la
mod_vhost_maxclients.lo
mod_vhost_maxclients.o
mod_vhost_maxclients.slo
.libs
45 changes: 45 additions & 0 deletions .travis.yml
@@ -0,0 +1,45 @@
language: c
compiler:
- gcc
- clang
before_install:
- sudo apt-get -qq update
install:
- sudo apt-get -qq install rake bison libcurl4-openssl-dev libhiredis-dev libmarkdown2-dev libapr1-dev libaprutil1-dev apache2 libcap-dev
env:
- HTTPD_VERSION=httpd-2.2.31
APR=apr-1.5.2
APR_UTIL=apr-util-1.5.4
HTTPD_TAR=${HTTPD_VERSION}.tar.gz
APR_TAR=${APR}.tar.gz
APR_UTIL_TAR=${APR_UTIL}.tar.gz
HTTPD_CONFIG_OPT="--enable-module=all --enable-mods-shared=all"
APXS_CHECK_CMD="../${HTTPD_VERSION}/apache/bin/apachectl -v"
- HTTPD_VERSION=httpd-2.4.16
APR=apr-1.5.2
APR_UTIL=apr-util-1.5.4
HTTPD_TAR=${HTTPD_VERSION}.tar.gz
APR_TAR=${APR}.tar.gz
APR_UTIL_TAR=${APR_UTIL}.tar.gz
HTTPD_CONFIG_OPT=
APXS_CHECK_CMD="../${HTTPD_VERSION}/apache/bin/apachectl -v"
before_script:
- cd ../
- wget http://ftp.jaist.ac.jp/pub/apache//httpd/${HTTPD_TAR}
- tar xf ${HTTPD_TAR}
- cd ${HTTPD_VERSION}/srclib
- wget http://ftp.jaist.ac.jp/pub/apache//apr/${APR_TAR}
- wget http://ftp.jaist.ac.jp/pub/apache//apr/${APR_UTIL_TAR}
- tar xf ${APR_TAR}
- tar xf ${APR_UTIL_TAR}
- ln -s ${APR} apr
- ln -s ${APR_UTIL} apr-util
- cd ..
- ./configure --prefix=`pwd`/apache --with-included-apr ${HTTPD_CONFIG_OPT}
- make
- make install
- cd ../mod_vhost_maxclients
script:
- echo ${APXS_CHECK_CMD}
- ${APXS_CHECK_CMD}
- make APXS=../${HTTPD_VERSION}/apache/bin/apxs
45 changes: 45 additions & 0 deletions Makefile
@@ -0,0 +1,45 @@
##
## Makefile -- Build procedure for sample mod_vhost_maxclients Apache module
## MATSUMOTO, Ryosuke
##

# target module source
TARGET=mod_vhost_maxclients.c

# the used tools
APXS=apxs
APACHECTL=apachectl -k

# additional user defines, includes and libraries
DEF=
INC=
LIB=
WC=-Wc,-std=c99

# the default target
all: mod_vhost_maxclients.so

# compile the DSO file
mod_vhost_maxclients.so: $(TARGET)
$(APXS) -c $(DEF) $(INC) $(LIB) $(WC) $(TARGET)

# install the DSO file into the Apache installation
# and activate it in the Apache configuration
install: all
$(APXS) -i -a -n 'vhost_maxclients' .libs/mod_vhost_maxclients.so

# cleanup
clean:
-rm -rf .libs *.o *.so *.lo *.la *.slo *.loT

# reload the module by installing and restarting Apache
reload: install restart

# the general Apache start/restart/stop procedures
start:
$(APACHECTL) start
restart:
$(APACHECTL) restart
stop:
$(APACHECTL) stop

42 changes: 42 additions & 0 deletions README.md
@@ -0,0 +1,42 @@
# mod_vhost_maxclients

MaxClients per vhost, no using shared memory and global lock. mod_vhost_maxclients use only scoreboad for simple implementation.

# Quick Install
- build

```
make
```

- mod_vhost_maxclients.conf

```
LoadModule vhost_maxclients_module modules/mod_vhost_maxclients.so
# mod_vhost_maxclinets use scoreboard
ExtendedStatus On
```

- vhost.conf

```apache
<VirtualHost *>
DocumentRoot /path/to/web
ServerName test001.example.jp
# MaxClients per vhost using mod_vhost_maxclients
VhostMaxClients 3
# Ignore extensions from VhostMaxClients
IgnoreVhostMaxClientsExt .html .js .css
</VirtualHost>
```

- logggin
```
[Thu Aug 27 21:16:54.540685 2015] [vhost_maxclients:debug] [pid 23981] mod_vhost_maxclients.c(93): DEBUG: (increment test001.example.jp:80): 1/3
[Thu Aug 27 21:16:54.540708 2015] [vhost_maxclients:debug] [pid 23981] mod_vhost_maxclients.c(93): DEBUG: (increment test001.example.jp:80): 2/3
[Thu Aug 27 21:16:54.540713 2015] [vhost_maxclients:debug] [pid 23981] mod_vhost_maxclients.c(93): DEBUG: (increment test001.example.jp:80): 3/3
[Thu Aug 27 21:16:54.540716 2015] [vhost_maxclients:debug] [pid 23981] mod_vhost_maxclients.c(93): DEBUG: (increment test001.example.jp:80): 4/3
[Thu Aug 27 21:16:54.540726 2015] [vhost_maxclients:notice] [pid 23981] NOTICE: (return 503 from test001.example.jp:80): 4/3
```
216 changes: 216 additions & 0 deletions mod_vhost_maxclients.c
@@ -0,0 +1,216 @@
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_protocol.h"
#include "http_core.h"
#include "http_log.h"
#include "ap_mpm.h"
#include "apr_strings.h"

#define MODULE_NAME "mod_vhost_maxclients"
#define MODULE_VERSION "0.0.1"

#if (AP_SERVER_MINORVERSION_NUMBER > 2)
#define __APACHE24__
#endif

#ifdef __APACHE24__
#define ap_get_scoreboard_worker ap_get_scoreboard_worker_from_indexes
#endif

#define _log_debug \
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "DEBUG: " MODULE_NAME "/" MODULE_VERSION "%s:%d", __func__, __LINE__)

#ifdef __APACHE24__
#include "http_main.h"
#else
#define ap_server_conf NULL
#endif

#define VHOST_MAXEXTENSIONS 16

#if !defined(__APACHE24__) && defined(_WIN32)
/*
* libhttpd.dll does not export following variables.
* This won't work correctly, but working well for other functional.
*/
int ap_extended_status = 0;
#endif

module AP_MODULE_DECLARE_DATA vhost_maxclients_module;
static int vhost_maxclients_server_limit, vhost_maxclients_thread_limit;

typedef struct {

/* vhost max clinetns */
signed int vhost_maxclients;
apr_array_header_t *ignore_extensions;

} vhost_maxclients_config;

static void *vhost_maxclients_create_server_config(apr_pool_t *p, server_rec *s)
{
vhost_maxclients_config *scfg = (vhost_maxclients_config *)apr_pcalloc(p, sizeof(*scfg));

scfg->vhost_maxclients = 0;
scfg->ignore_extensions = apr_array_make(p, VHOST_MAXEXTENSIONS, sizeof(char *));

return scfg;
}

static int check_extension(char *filename, apr_array_header_t *exts)
{
int i;
for (i = 0; i < exts->nelts; i++) {
const char *extension = ((char **)exts->elts)[i];
ssize_t name_len = strlen(filename) - strlen(extension);
if (name_len >= 0 && strcmp(&filename[name_len], extension) == 0)
return 1;
}
return 0;
}

static char *build_vhostport_name(request_rec *r)
{
ssize_t vhostport_len;
char *vhostport;

vhostport_len = strlen(r->hostname) + sizeof(":65536");
vhostport = apr_pcalloc(r->pool, vhostport_len);
apr_snprintf(vhostport, vhostport_len, "%s:%d", r->hostname, r->connection->local_addr->port);

return vhostport;
}

static int vhost_maxclients_handler(request_rec *r)
{
int i, j;
int vhost_count = 0;
char *vhostport;
vhost_maxclients_config *scfg =
(vhost_maxclients_config *)ap_get_module_config(r->server->module_config, &vhost_maxclients_module);

if (!ap_is_initial_req(r)) {
return DECLINED;
}

if (scfg->vhost_maxclients <= 0) {
return DECLINED;
}

if (r->hostname == NULL) {
return DECLINED;
}

if (!ap_extended_status) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "DEBUG: only used when ExtendedStatus On");
return DECLINED;
}

/* check ignore extesions */
if (check_extension(r->filename, scfg->ignore_extensions)) {
return DECLINED;
}

/* build vhostport name */
vhostport = build_vhostport_name(r);

for (i = 0; i < vhost_maxclients_server_limit; ++i) {
for (j = 0; j < vhost_maxclients_thread_limit; ++j) {
worker_score *ws_record = ap_get_scoreboard_worker(i, j);

switch (ws_record->status) {
case SERVER_BUSY_READ:
case SERVER_BUSY_WRITE:
case SERVER_BUSY_KEEPALIVE:
case SERVER_BUSY_LOG:
case SERVER_BUSY_DNS:
case SERVER_CLOSING:
case SERVER_GRACEFUL:
if (strcmp(vhostport, ws_record->vhost) == 0) {
vhost_count++;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "DEBUG: (increment %s): %d/%d", vhostport,
vhost_count, scfg->vhost_maxclients);
if (vhost_count > scfg->vhost_maxclients) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "NOTICE: (return 503 from %s): %d/%d", vhostport,
vhost_count, scfg->vhost_maxclients);
return HTTP_SERVICE_UNAVAILABLE;
}
break;
}
default:
break;
}
}
}

/* not reached vhost_maxclients */
return DECLINED;
}

static const char *set_vhost_maxclientsvhost(cmd_parms *parms, void *mconfig, const char *arg1)
{
vhost_maxclients_config *scfg =
(vhost_maxclients_config *)ap_get_module_config(parms->server->module_config, &vhost_maxclients_module);
signed long int limit = strtol(arg1, (char **)NULL, 10);

if ((limit > 65535) || (limit < 0)) {
return "Integer overflow or invalid number";
}

scfg->vhost_maxclients = limit;

return NULL;
}

static const char *set_vhost_ignore_extensions(cmd_parms *parms, void *mconfig, const char *arg)
{
vhost_maxclients_config *scfg =
(vhost_maxclients_config *)ap_get_module_config(parms->server->module_config, &vhost_maxclients_module);

if (VHOST_MAXEXTENSIONS < scfg->ignore_extensions->nelts) {
return "the number of ignore extensions exceeded";
}

*(const char **)apr_array_push(scfg->ignore_extensions) = arg;

return NULL;
}

static command_rec vhost_maxclients_cmds[] = {
AP_INIT_TAKE1("VhostMaxClients", set_vhost_maxclientsvhost, NULL, RSRC_CONF | ACCESS_CONF,
"maximum connections per Vhost"),
AP_INIT_ITERATE("IgnoreVhostMaxClientsExt", set_vhost_ignore_extensions, NULL, ACCESS_CONF | RSRC_CONF,
"Set Ignore Extensions."),
{NULL},
};

static int vhost_maxclients_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &vhost_maxclients_thread_limit);
ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &vhost_maxclients_server_limit);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
MODULE_NAME "/" MODULE_VERSION " enabled: %d/%d thread_limit/server_limit",
vhost_maxclients_thread_limit, vhost_maxclients_server_limit);

return OK;
}

static void vhost_maxclients_register_hooks(apr_pool_t *p)
{
ap_hook_post_config(vhost_maxclients_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_access_checker(vhost_maxclients_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

#ifdef __APACHE24__
AP_DECLARE_MODULE(vhost_maxclients) = {
#else
module AP_MODULE_DECLARE_DATA vhost_maxclients_module = {
#endif
STANDARD20_MODULE_STUFF, NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
vhost_maxclients_create_server_config, /* create per-server config
structures */
NULL, /* merge per-server config structures */
vhost_maxclients_cmds, /* table of config file commands */
vhost_maxclients_register_hooks};

0 comments on commit 4fa5e5b

Please sign in to comment.