You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by yl...@apache.org on 2018/02/08 15:08:09 UTC

svn commit: r1823564 - /httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c

Author: ylavic
Date: Thu Feb  8 15:08:09 2018
New Revision: 1823564

URL: http://svn.apache.org/viewvc?rev=1823564&view=rev
Log:
mod_proxy_balancer: follow up tp r1822509.

Rework server_rec ID so that it doesn't change on restart (or stop/start)
unless it's Host(s)/IP(s):port(s), ServerName and/or ServerAlias(es) changed.

The goal being to reuse SHMs (and persisted files) names as much as possible,
with minimal bindings to configuration changes (as far as mod_proxy_balancer
is concerned). So if the ServerName and first Host/IP:port are unique we use
that first, otherwise the ServerAlias(es) and other Host(s)/IP(s):port(s) are
also taken into account, and finally if that's still not enough the server
index is also used (pathological case handled for correctness with regard to
the underlying mod_slotmem_shm's reuse code).


Modified:
    httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c?rev=1823564&r1=1823563&r2=1823564&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c Thu Feb  8 15:08:09 2018
@@ -22,6 +22,7 @@
 #include "apr_version.h"
 #include "ap_hooks.h"
 #include "apr_date.h"
+#include "apr_escape.h"
 #include "mod_watchdog.h"
 
 static const char *balancer_mutex_type = "proxy-balancer-shm";
@@ -730,6 +731,115 @@ static apr_status_t lock_remove(void *da
     return(0);
 }
 
+/*
+ * Compute an ID for a vhost based on what makes it selected by requests.
+ * The second and more Host(s)/IP(s):port(s), and the ServerAlias(es) are
+ * optional (see make_servers_ids() below).
+ */
+ static const char *make_server_id(server_rec *s, apr_pool_t *p, int full)
+{
+    apr_md5_ctx_t md5_ctx;
+    unsigned char md5[APR_MD5_DIGESTSIZE];
+    char host_ip[64]; /* for any IPv[46] string */
+    server_addr_rec *sar;
+    int i;
+
+    apr_md5_init(&md5_ctx);
+    for (sar = s->addrs; sar; sar = sar->next) {
+        host_ip[0] = '\0';
+        apr_sockaddr_ip_getbuf(host_ip, sizeof host_ip, sar->host_addr);
+        apr_md5_update(&md5_ctx, (void *)sar->virthost, strlen(sar->virthost));
+        apr_md5_update(&md5_ctx, (void *)host_ip, strlen(host_ip));
+        apr_md5_update(&md5_ctx, (void *)&sar->host_port,
+                       sizeof(sar->host_port));
+        if (!full) {
+            break;
+        }
+    }
+    if (s->server_hostname) {
+        apr_md5_update(&md5_ctx, (void *)s->server_hostname,
+                       strlen(s->server_hostname));
+    }
+    if (full) {
+        if (s->names) {
+            for (i = 0; i < s->names->nelts; ++i) {
+                const char *name = APR_ARRAY_IDX(s->names, i, char *);
+                apr_md5_update(&md5_ctx, (void *)name, strlen(name));
+            }
+        }
+        if (s->wild_names) {
+            for (i = 0; i < s->wild_names->nelts; ++i) {
+                const char *name = APR_ARRAY_IDX(s->wild_names, i, char *);
+                apr_md5_update(&md5_ctx, (void *)name, strlen(name));
+            }
+        }
+    }
+    apr_md5_final(md5, &md5_ctx);
+
+    return apr_pescape_hex(p, md5, sizeof md5, 0);
+}
+
+/*
+ * First try to compute an unique ID for each vhost with minimal criteria,
+ * that is the first Host/IP:port and ServerName. For most cases this should
+ * be enough and avoids changing the ID unnecessarily accross restart (or
+ * stop/start w.r.t. persisted files) for things that this module does not
+ * care about.
+ *
+ * But if it's not enough (collisions) do a second pass for the full monty,
+ * that is additionally the other Host(s)/IP(s):port(s) and ServerAlias(es).
+ *
+ * Finally, for pathological configs where this is still not enough, let's
+ * append a counter to duplicates, because we really want that ID to be unique
+ * even if the vhost will never be selected to handle requests at run time, at
+ * load time a duplicate may steal the original slotmems (depending on its
+ * balancers' configurations), see how mod_slotmem_shm reuses slots/files based
+ * solely on this ID and resets them if the sizes don't match.
+ */
+static apr_array_header_t *make_servers_ids(server_rec *main_s, apr_pool_t *p)
+{
+    server_rec *s = main_s;
+    apr_array_header_t *ids = apr_array_make(p, 10, sizeof(const char *));
+    apr_hash_t *dups = apr_hash_make(p);
+    int idx, *dup, full_monty = 0;
+    const char *id;
+
+    for (idx = 0, s = main_s; s; s = s->next, ++idx) {
+        id = make_server_id(s, p, 0);
+        dup = apr_hash_get(dups, id, APR_HASH_KEY_STRING);
+        apr_hash_set(dups, id, APR_HASH_KEY_STRING,
+                     apr_pmemdup(p, &idx, sizeof(int)));
+        if (dup) {
+            full_monty = 1;
+            APR_ARRAY_IDX(ids, *dup, const char *) = NULL;
+            APR_ARRAY_PUSH(ids, const char *) = NULL;
+        }
+        else {
+            APR_ARRAY_PUSH(ids, const char *) = id;
+        }
+    }
+    if (full_monty) {
+        apr_hash_clear(dups);
+        for (idx = 0, s = main_s; s; s = s->next, ++idx) {
+            id = APR_ARRAY_IDX(ids, idx, const char *);
+            if (id) {
+                /* Preserve non-duplicates */
+                continue;
+            }
+            id = make_server_id(s, p, 1);
+            if (apr_hash_get(dups, id, APR_HASH_KEY_STRING)) {
+                id = apr_psprintf(p, "%s_%x", id, idx);
+            }
+            else {
+                apr_hash_set(dups, id, APR_HASH_KEY_STRING, (void *)-1);
+            }
+            APR_ARRAY_IDX(ids, idx, const char *) = id;
+        }
+    }
+
+    return ids;
+}
+
 /* post_config hook: */
 static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog,
                          apr_pool_t *ptemp, server_rec *s)
@@ -738,6 +848,8 @@ static int balancer_post_config(apr_pool
     proxy_server_conf *conf;
     ap_slotmem_instance_t *new = NULL;
     apr_time_t tstamp;
+    apr_array_header_t *ids;
+    int idx;
 
     /* balancer_post_config() will be called twice during startup.  So, don't
      * set up the static data the 1st time through. */
@@ -768,14 +880,16 @@ static int balancer_post_config(apr_pool
         return !OK;
     }
 
+    ids = make_servers_ids(s, ptemp);
+
     tstamp = apr_time_now();
     /*
      * Go thru each Vhost and create the shared mem slotmem for
      * each balancer's workers
      */
-    while (s) {
+    for (idx = 0; s; ++idx) {
         int i,j;
-        char *id;
+        const char *id;
         proxy_balancer *balancer;
         ap_slotmem_type_t type;
         void *sconf = s->module_config;
@@ -784,14 +898,7 @@ static int balancer_post_config(apr_pool
          * During create_proxy_config() we created a dummy id. Now that
          * we have identifying info, we can create the real id
          */
-        id = apr_psprintf(pconf, "%s.%s.%d.%s.%s.%u.%s",
-                          (s->server_scheme ? s->server_scheme : "????"),
-                          (s->server_hostname ? s->server_hostname : "???"),
-                          (int)s->port,
-                          (s->server_admin ? s->server_admin : "??"),
-                          (s->defn_name ? s->defn_name : "?"),
-                          s->defn_line_number,
-                          (s->error_fname ? s->error_fname : DEFAULT_ERRORLOG));
+        id = APR_ARRAY_IDX(ids, idx, const char *);
         conf->id = apr_psprintf(pconf, "p%x",
                                 ap_proxy_hashfunc(id, PROXY_HASHFUNC_DEFAULT));
         if (conf->bslot) {