Commit afd926e8 authored by Paul Querna's avatar Paul Querna
Browse files

* server/core.c: Add new directive: 'AcceptFilter'.

* server/core.c: Enable 'httpready' by default on systems that support it.  Use dataready filters for others.
* server/listen.c: Move bits that determined which accept filter is applied to core.c.
* server/listen.c: Add bits to find the correct accept filter based on the core's configuration.
* include/http_core.h: Add the accf_map table to the core_server_config structure

Tested on Linux using TCP_DEFER_ACCEPT. 
Needs testing on FreeBSD to make sure that Accept Filters actually work.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/listen-protocol@171031 13f79535-47bb-0310-9956-ffa450edef68
parent 816b1cf5
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -547,6 +547,7 @@ typedef struct {
    int subreq_limit;   /* maximum nesting level of subrequests */

    const char *protocol;
    apr_table_t *accf_map;
} core_server_config;

/* for AddOutputFiltersByType in core.c */
+43 −0
Original line number Diff line number Diff line
@@ -461,6 +461,26 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
    conf->subreq_limit = 0;

    conf->protocol = NULL;
    conf->accf_map = apr_table_make(a, 5);

#ifdef APR_TCP_DEFER_ACCEPT
    apr_table_set(conf->accf_map, "http", "data");
    apr_table_set(conf->accf_map, "https", "data");
#endif

#if APR_HAS_SO_ACCEPTFILTER
#ifndef ACCEPT_FILTER_NAME
#define ACCEPT_FILTER_NAME "httpready"
#ifdef __FreeBSD_version
#if __FreeBSD_version < 411000 /* httpready broken before 4.1.1 */
#undef ACCEPT_FILTER_NAME
#define ACCEPT_FILTER_NAME "dataready"
#endif
#endif
#endif 
    apr_table_set(conf->accf_map, "http", ACCEPT_FILTER_NAME);
    apr_table_set(conf->accf_map, "https", "dataready");
#endif

    return (void *)conf;
}
@@ -2187,6 +2207,27 @@ static const char *set_server_alias(cmd_parms *cmd, void *dummy,
    return NULL;
}

static const char *set_accf_map(cmd_parms *cmd, void *dummy,
                                const char *iproto, const char* iaccf)
{
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
    core_server_config *conf = ap_get_module_config(cmd->server->module_config,
                                                    &core_module);
    char* proto;
    char* accf;
    if (err != NULL) {
        return err;
    }

    proto = apr_pstrdup(cmd->pool, iproto);
    ap_str_tolower(proto);
    accf = apr_pstrdup(cmd->pool, iaccf);
    ap_str_tolower(accf);
    apr_table_set(conf->accf_map, proto, accf);

    return NULL;
}

AP_DECLARE(const char*) ap_get_server_protocol(server_rec* s) 
{
    core_server_config *conf = ap_get_module_config(s->module_config,
@@ -3160,6 +3201,8 @@ AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,

AP_INIT_TAKE1("Protocol", set_protocol, NULL, RSRC_CONF,
  "Set the Protocol for httpd to use."),
AP_INIT_TAKE2("AcceptFilter", set_accf_map, NULL, RSRC_CONF,
  "Set the Accept Filter to use for a protocol"),
AP_INIT_TAKE1("Port", ap_set_deprecated, NULL, RSRC_CONF,
  "Port was replaced with Listen in Apache 2.0"),
AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL,
+74 −31
Original line number Diff line number Diff line
@@ -168,32 +168,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
    }
#endif

#if APR_HAS_SO_ACCEPTFILTER
#ifndef ACCEPT_FILTER_NAME
#define ACCEPT_FILTER_NAME "httpready"
#ifdef __FreeBSD_version
#if __FreeBSD_version < 411000 /* httpready broken before 4.1.1 */
#undef ACCEPT_FILTER_NAME
#define ACCEPT_FILTER_NAME "dataready"
#endif
#endif
#endif
    stat = apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
    if (stat != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(stat)) {
        ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p,
                      "Failed to enable the '%s' Accept Filter",
                      ACCEPT_FILTER_NAME);
    }
#else
#ifdef APR_TCP_DEFER_ACCEPT
    stat = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 1);   
    if (stat != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(stat)) {
        ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p,
                              "Failed to enable APR_TCP_DEFER_ACCEPT");
    }
#endif
#endif

    server->sd = s;
    server->active = 1;

@@ -206,6 +180,61 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
    return APR_SUCCESS;
}

static const char* find_accf_name(server_rec *s, const char *proto)
{
    const char* accf;
    core_server_config *conf = ap_get_module_config(s->module_config,
                                                    &core_module);
    if (!proto) {
        return NULL;
    }

    accf = apr_table_get(conf->accf_map, proto);

    if (accf && !strcmp("none", accf)) {
        return NULL;
    }

    return accf;
}

static void ap_apply_accept_filter(apr_pool_t *p, ap_listen_rec *lis, 
                                           server_rec *server)
{
    apr_socket_t *s = lis->sd;
    const char *accf;
    apr_status_t rv;
    const char *proto;

    proto = lis->protocol;

    if (!proto) {
        proto = ap_get_server_protocol(server);
    }


    accf = find_accf_name(server, proto);

    if (accf) {
#if APR_HAS_SO_ACCEPTFILTER
        rv = apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
        if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
            ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p,
                          "Failed to enable the '%s' Accept Filter",
                          ACCEPT_FILTER_NAME);
        }
#else
#ifdef APR_TCP_DEFER_ACCEPT
        rv = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 1);   
        if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
            ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p,
                              "Failed to enable APR_TCP_DEFER_ACCEPT");
        }
#endif
#endif
    }
}

static apr_status_t close_listeners_on_exec(void *v)
{
    ap_listen_rec *lr;
@@ -459,27 +488,27 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s)
    ap_listen_rec *lr;
    int num_listeners = 0;
    const char* proto;
    int nfound;
    int found;

    for (ls = s; ls; ls = ls->next) {
        proto = ap_get_server_protocol(ls);
        if (!proto) {
            nfound = 1;
            found = 0;
            /* No protocol was set for this vhost, 
             * use the default for this listener. 
             */
            for (addr = ls->addrs; addr && nfound; addr = addr->next) {
            for (addr = ls->addrs; addr && !found; addr = addr->next) {
                for (lr = ap_listeners; lr; lr = lr->next) {
                    if (apr_sockaddr_equal(lr->bind_addr, addr->host_addr) &&
                        lr->bind_addr->port == addr->host_port) {
                        ap_set_server_protocol(ls, lr->protocol);
                        nfound = 0;
                        found = 1;
                        break;
                    }
                }
            }

            if (nfound) {
            if (!found) {
                /* TODO: set protocol defaults per-Port, eg 25=smtp */
                ap_set_server_protocol(ls, "http");
            }
@@ -492,6 +521,20 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s)

    for (lr = ap_listeners; lr; lr = lr->next) {
        num_listeners++;
        found = 0;
        for (ls = s; ls && !found; ls = ls->next) {
            for (addr = ls->addrs; addr && !found; addr = addr->next) {
                if (apr_sockaddr_equal(lr->bind_addr, addr->host_addr) &&
                    lr->bind_addr->port == addr->host_port) {
                    found = 1;
                    ap_apply_accept_filter(s->process->pool, lr, ls);
                }
            }
        }

        if (!found) {
            ap_apply_accept_filter(s->process->pool, lr, s);
        }
    }

    return num_listeners;