/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* .
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
/*
* mod_sockopts: control SO_RCVBUF and TCP_DEFER_ACCEPT
*
* v1.0
*
* author: dean gaudet
*/
// dunno why ap_check_cmd_context is private...
#define CORE_PRIVATE
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "http_request.h"
#include "http_conf_globals.h"
#include
#include
#include
#include
typedef struct {
int receive_buffer_size;
int tcp_defer_accept;
unsigned receive_buffer_size_set : 1;
unsigned tcp_defer_accept_set : 1;
} sockopts_config;
module MODULE_VAR_EXPORT sockopts_module;
static const char *set_receive_buffer_size(cmd_parms *cmd, void *dummy, char *arg)
{
sockopts_config *config = ap_get_module_config(cmd->server->module_config, &sockopts_module);
int s = atoi(arg);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
if (s < 512 && s != 0) {
return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
}
config->receive_buffer_size = s;
config->receive_buffer_size_set = 1;
return NULL;
}
static const char *set_tcp_defer_accept(cmd_parms *cmd, void *dummy, char *arg)
{
#ifdef TCP_DEFER_ACCEPT
sockopts_config *config = ap_get_module_config(cmd->server->module_config, &sockopts_module);
int s = atoi(arg);
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
config->tcp_defer_accept = s;
config->tcp_defer_accept_set = 1;
return NULL;
#else
return "TCP_DEFER_ACCEPT not supported on your platform";
#endif
}
static void *sockopts_create_config(pool *p, server_rec *s)
{
return ap_pcalloc(p, sizeof(sockopts_config));
}
static void *sockopts_merge_config(pool *p, void *parentv, void *childv)
{
sockopts_config *parent = (sockopts_config *) parentv;
sockopts_config *child = (sockopts_config *) childv;
sockopts_config *config;
config = (sockopts_config *)ap_palloc(p, sizeof(*config));
*config = *parent;
if (child->receive_buffer_size_set) {
config->receive_buffer_size_set = 1;
config->receive_buffer_size = child->receive_buffer_size;
}
if (child->tcp_defer_accept_set) {
config->tcp_defer_accept_set = 1;
config->tcp_defer_accept = child->tcp_defer_accept;
}
return config;
}
static void sockopts_init(server_rec *s, pool *p)
{
sockopts_config *config = ap_get_module_config(s->module_config,
&sockopts_module);
listen_rec *lr;
int val;
lr = ap_listeners;
if (lr == NULL) {
return;
}
do {
// apache initialization sequence is such a mess... we end up
// in here once before any listeners have been allocated... so
// we don't want to try to setsockopt then.
if (lr->fd != -1) {
if (config->receive_buffer_size_set) {
val = config->receive_buffer_size;
if (setsockopt(lr->fd, SOL_SOCKET, SO_RCVBUF, (char *)&val, sizeof(int)) < 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, s,
"failed to setsockopt(SOL_SOCKET, SO_RCVBUF)");
}
}
#ifdef TCP_DEFER_ACCEPT
if (config->tcp_defer_accept_set) {
val = config->tcp_defer_accept;
if (setsockopt(lr->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, (char *)&val, sizeof(int)) < 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, s,
"failed to setsockopt(IPPROTO_TCP, TCP_DEFER_ACCEPT)");
}
}
#endif
}
lr = lr->next;
} while (lr && lr != ap_listeners);
}
static const command_rec sockopts_cmds[] =
{
{ "ReceiveBufferSize", set_receive_buffer_size, NULL, RSRC_CONF, TAKE1,
"Receive buffer size in bytes"
},
{ "TCPDeferAccept", set_tcp_defer_accept, NULL, RSRC_CONF, TAKE1,
"TCP_DEFER_ACCEPT setting in seconds (see tcp(7))"
},
{NULL}
};
module MODULE_VAR_EXPORT sockopts_module =
{
STANDARD_MODULE_STUFF,
sockopts_init, /* module initializer */
NULL, /* per-directory config creator */
NULL, /* dir config merger */
sockopts_create_config, /* server config creator */
sockopts_merge_config, /* server config merger */
sockopts_cmds, /* command table */
NULL, /* [9] list of handlers */
NULL, /* [2] filename-to-URI translation */
NULL, /* [5] check/validate user_id */
NULL, /* [6] check user_id is valid *here* */
NULL, /* [4] check access by host address */
NULL, /* [7] MIME type checker/setter */
NULL, /* [8] fixups */
NULL /* [10] logger */
#if MODULE_MAGIC_NUMBER >= 19970103
,NULL /* [3] header parser */
#endif
#if MODULE_MAGIC_NUMBER >= 19970719
,NULL /* process initializer */
#endif
#if MODULE_MAGIC_NUMBER >= 19970728
,NULL /* process exit/cleanup */
#endif
#if MODULE_MAGIC_NUMBER >= 19970902
,NULL /* [1] post read_request handling */
#endif
};