mirror of
https://github.com/apache/httpd.git
synced 2025-10-28 20:34:59 +03:00
MPMs, core: make duplicated listeners (SO_REUSEPORT) introduced in r1599531
less intrusive. Submitted by: Yingqi Lu <yingqi.lu@intel.com> Modified/Committed by: ylavic Add ListenCoresBucketsRatio which is a configurable ratio between the number of CPU cores (online) and the number of listeners buckets to create, defaulting to zero (so that listeners buckets become an opt-in, ie. ncpus / ratio > 1). This could also be made an opt-out by using the previous hardcoded value (8) as default. Make ap_close_listeners() act on all the listeners (including duplicated ones), since the function is also called externally (eg. mod_cgid, mod_ssl_ct and possibly any third party module) to cleanup opened descriptors when a process is forked (the duplicated listeners are kept in a scoped/static variable). Add ap_close_listeners_ex() to close a single bucket of listeners, used by the children to close unused duplicates and internally by ap_close_listeners(). Make ap_duplicate_listeners() compute the number of buckets to be used, instead of each MPM. This number is now based on the above ratio and will not change unless asked to (given *num_buckets < 1, that is when the MPM does not run in one-process mode nor after a graceful restart). Remove some global variables (mpm_listen, enable_default_listeners) previously used to communicate between MPMs and ap_listen, since ap_duplicate_listeners() API can now be used to do so. Also rename num_buckets as ap_num_listen_buckets, and prefix have_so_reuseport with ap_ (both printed by ap_log_common(), hence kept global). Detect ap_have_so_reuseport once only at startup. Restore dummy_connection() as before r1599531 since sending POD signals should not depend on the number of listeners buckets (there is still one single socket receiving the connections). For each MPM (concerned), move the bucket data (pod, listeners and eventually accept mutex) into a struct and instanciate an array of them (sized by the number of buckets), for each child to use its own data according to its bucket index, and the parent to maintain the whole. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1635521 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -615,7 +615,6 @@ static apr_status_t dummy_connection(ap_pod_t *pod)
|
||||
apr_pool_t *p;
|
||||
apr_size_t len;
|
||||
ap_listen_rec *lp;
|
||||
int i;
|
||||
|
||||
/* create a temporary pool for the socket. pconf stays around too long */
|
||||
rv = apr_pool_create(&p, pod->p);
|
||||
@@ -627,89 +626,87 @@ static apr_status_t dummy_connection(ap_pod_t *pod)
|
||||
* plain-HTTP, not SSL; using an SSL port would either be
|
||||
* expensive to do correctly (performing a complete SSL handshake)
|
||||
* or cause log spam by doing incorrectly (simply sending EOF). */
|
||||
for (i = 0; i < num_buckets; i++) {
|
||||
lp = mpm_listen[i];
|
||||
while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
|
||||
lp = lp->next;
|
||||
}
|
||||
if (!lp) {
|
||||
lp = mpm_listen[i];
|
||||
}
|
||||
|
||||
rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
|
||||
if (rv != APR_SUCCESS) {
|
||||
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00054)
|
||||
"get socket to connect to listener");
|
||||
apr_pool_destroy(p);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* on some platforms (e.g., FreeBSD), the kernel won't accept many
|
||||
* queued connections before it starts blocking local connects...
|
||||
* we need to keep from blocking too long and instead return an error,
|
||||
* because the MPM won't want to hold up a graceful restart for a
|
||||
* long time
|
||||
*/
|
||||
rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
|
||||
if (rv != APR_SUCCESS) {
|
||||
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00055)
|
||||
"set timeout on socket to connect to listener");
|
||||
apr_socket_close(sock);
|
||||
apr_pool_destroy(p);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = apr_socket_connect(sock, lp->bind_addr);
|
||||
if (rv != APR_SUCCESS) {
|
||||
int log_level = APLOG_WARNING;
|
||||
|
||||
if (APR_STATUS_IS_TIMEUP(rv)) {
|
||||
/* probably some server processes bailed out already and there
|
||||
* is nobody around to call accept and clear out the kernel
|
||||
* connection queue; usually this is not worth logging
|
||||
*/
|
||||
log_level = APLOG_DEBUG;
|
||||
}
|
||||
|
||||
ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, APLOGNO(00056)
|
||||
"connect to listener on %pI", lp->bind_addr);
|
||||
apr_pool_destroy(p);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (lp->protocol && strcasecmp(lp->protocol, "https") == 0) {
|
||||
/* Send a TLS 1.0 close_notify alert. This is perhaps the
|
||||
* "least wrong" way to open and cleanly terminate an SSL
|
||||
* connection. It should "work" without noisy error logs if
|
||||
* the server actually expects SSLv3/TLSv1. With
|
||||
* SSLv23_server_method() OpenSSL's SSL_accept() fails
|
||||
* ungracefully on receipt of this message, since it requires
|
||||
* an 11-byte ClientHello message and this is too short. */
|
||||
static const unsigned char tls10_close_notify[7] = {
|
||||
'\x15', /* TLSPlainText.type = Alert (21) */
|
||||
'\x03', '\x01', /* TLSPlainText.version = {3, 1} */
|
||||
'\x00', '\x02', /* TLSPlainText.length = 2 */
|
||||
'\x01', /* Alert.level = warning (1) */
|
||||
'\x00' /* Alert.description = close_notify (0) */
|
||||
};
|
||||
data = (const char *)tls10_close_notify;
|
||||
len = sizeof(tls10_close_notify);
|
||||
}
|
||||
else /* ... XXX other request types here? */ {
|
||||
/* Create an HTTP request string. We include a User-Agent so
|
||||
* that adminstrators can track down the cause of the
|
||||
* odd-looking requests in their logs. A complete request is
|
||||
* used since kernel-level filtering may require that much
|
||||
* data before returning from accept(). */
|
||||
data = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ",
|
||||
ap_get_server_description(),
|
||||
" (internal dummy connection)\r\n\r\n", NULL);
|
||||
len = strlen(data);
|
||||
}
|
||||
|
||||
apr_socket_send(sock, data, &len);
|
||||
apr_socket_close(sock);
|
||||
lp = ap_listeners;
|
||||
while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
|
||||
lp = lp->next;
|
||||
}
|
||||
if (!lp) {
|
||||
lp = ap_listeners;
|
||||
}
|
||||
|
||||
rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
|
||||
if (rv != APR_SUCCESS) {
|
||||
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00054)
|
||||
"get socket to connect to listener");
|
||||
apr_pool_destroy(p);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* on some platforms (e.g., FreeBSD), the kernel won't accept many
|
||||
* queued connections before it starts blocking local connects...
|
||||
* we need to keep from blocking too long and instead return an error,
|
||||
* because the MPM won't want to hold up a graceful restart for a
|
||||
* long time
|
||||
*/
|
||||
rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
|
||||
if (rv != APR_SUCCESS) {
|
||||
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00055)
|
||||
"set timeout on socket to connect to listener");
|
||||
apr_socket_close(sock);
|
||||
apr_pool_destroy(p);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = apr_socket_connect(sock, lp->bind_addr);
|
||||
if (rv != APR_SUCCESS) {
|
||||
int log_level = APLOG_WARNING;
|
||||
|
||||
if (APR_STATUS_IS_TIMEUP(rv)) {
|
||||
/* probably some server processes bailed out already and there
|
||||
* is nobody around to call accept and clear out the kernel
|
||||
* connection queue; usually this is not worth logging
|
||||
*/
|
||||
log_level = APLOG_DEBUG;
|
||||
}
|
||||
|
||||
ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, APLOGNO(00056)
|
||||
"connect to listener on %pI", lp->bind_addr);
|
||||
apr_pool_destroy(p);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (lp->protocol && strcasecmp(lp->protocol, "https") == 0) {
|
||||
/* Send a TLS 1.0 close_notify alert. This is perhaps the
|
||||
* "least wrong" way to open and cleanly terminate an SSL
|
||||
* connection. It should "work" without noisy error logs if
|
||||
* the server actually expects SSLv3/TLSv1. With
|
||||
* SSLv23_server_method() OpenSSL's SSL_accept() fails
|
||||
* ungracefully on receipt of this message, since it requires
|
||||
* an 11-byte ClientHello message and this is too short. */
|
||||
static const unsigned char tls10_close_notify[7] = {
|
||||
'\x15', /* TLSPlainText.type = Alert (21) */
|
||||
'\x03', '\x01', /* TLSPlainText.version = {3, 1} */
|
||||
'\x00', '\x02', /* TLSPlainText.length = 2 */
|
||||
'\x01', /* Alert.level = warning (1) */
|
||||
'\x00' /* Alert.description = close_notify (0) */
|
||||
};
|
||||
data = (const char *)tls10_close_notify;
|
||||
len = sizeof(tls10_close_notify);
|
||||
}
|
||||
else /* ... XXX other request types here? */ {
|
||||
/* Create an HTTP request string. We include a User-Agent so
|
||||
* that adminstrators can track down the cause of the
|
||||
* odd-looking requests in their logs. A complete request is
|
||||
* used since kernel-level filtering may require that much
|
||||
* data before returning from accept(). */
|
||||
data = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ",
|
||||
ap_get_server_description(),
|
||||
" (internal dummy connection)\r\n\r\n", NULL);
|
||||
len = strlen(data);
|
||||
}
|
||||
|
||||
apr_socket_send(sock, data, &len);
|
||||
apr_socket_close(sock);
|
||||
apr_pool_destroy(p);
|
||||
|
||||
return rv;
|
||||
|
||||
Reference in New Issue
Block a user