Loading CHANGES +2 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,8 @@ Changes with Apache 2.5.0 [Stefan Eissing] *) mod_proxy_http2: Fixed bug in re-attempting proxy requests after connection error. [Stefan Eissing] connection error. Reliability of reconnect handling improved. [Stefan Eissing] *) core: Disallow multiple Listen on the same IP:port when listener buckets are configured (ListenCoresBucketsRatio > 0), consistently with the single Loading docs/log-message-tags/next-number +1 −1 Original line number Diff line number Diff line 10022 10024 modules/http2/h2_mplx.c +1 −1 Original line number Diff line number Diff line Loading @@ -787,7 +787,7 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn) if (task->engine) { if (!m->aborted && !task->c->aborted && !h2_req_engine_is_shutdown(task->engine)) { ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, APLOGNO(10022) "h2_mplx(%ld): task(%s) has not-shutdown " "engine(%s)", m->id, task->id, h2_req_engine_get_id(task->engine)); Loading modules/http2/h2_proxy_util.c +281 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ #include <assert.h> #include <apr_lib.h> #include <apr_strings.h> #include <apr_thread_mutex.h> #include <apr_thread_cond.h> #include <httpd.h> #include <http_core.h> Loading Loading @@ -1053,3 +1055,282 @@ const char *h2_proxy_link_reverse_map(request_rec *r, "link_reverse_map %s --> %s", s, ctx.s); return ctx.s; } /******************************************************************************* * FIFO queue ******************************************************************************/ struct h2_proxy_fifo { void **elems; int nelems; int set; int head; int count; int aborted; apr_thread_mutex_t *lock; apr_thread_cond_t *not_empty; apr_thread_cond_t *not_full; }; static int nth_index(h2_proxy_fifo *fifo, int n) { return (fifo->head + n) % fifo->nelems; } static apr_status_t fifo_destroy(void *data) { h2_proxy_fifo *fifo = data; apr_thread_cond_destroy(fifo->not_empty); apr_thread_cond_destroy(fifo->not_full); apr_thread_mutex_destroy(fifo->lock); return APR_SUCCESS; } static int index_of(h2_proxy_fifo *fifo, void *elem) { int i; for (i = 0; i < fifo->count; ++i) { if (elem == fifo->elems[nth_index(fifo, i)]) { return i; } } return -1; } static apr_status_t create_int(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity, int as_set) { apr_status_t rv; h2_proxy_fifo *fifo; fifo = apr_pcalloc(pool, sizeof(*fifo)); if (fifo == NULL) { return APR_ENOMEM; } rv = apr_thread_mutex_create(&fifo->lock, APR_THREAD_MUTEX_UNNESTED, pool); if (rv != APR_SUCCESS) { return rv; } rv = apr_thread_cond_create(&fifo->not_empty, pool); if (rv != APR_SUCCESS) { return rv; } rv = apr_thread_cond_create(&fifo->not_full, pool); if (rv != APR_SUCCESS) { return rv; } fifo->elems = apr_pcalloc(pool, capacity * sizeof(void*)); if (fifo->elems == NULL) { return APR_ENOMEM; } fifo->nelems = capacity; fifo->set = as_set; *pfifo = fifo; apr_pool_cleanup_register(pool, fifo, fifo_destroy, apr_pool_cleanup_null); return APR_SUCCESS; } apr_status_t h2_proxy_fifo_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity) { return create_int(pfifo, pool, capacity, 0); } apr_status_t h2_proxy_fifo_set_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity) { return create_int(pfifo, pool, capacity, 1); } apr_status_t h2_proxy_fifo_term(h2_proxy_fifo *fifo) { apr_status_t rv; if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { fifo->aborted = 1; apr_thread_mutex_unlock(fifo->lock); } return rv; } apr_status_t h2_proxy_fifo_interrupt(h2_proxy_fifo *fifo) { apr_status_t rv; if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { apr_thread_cond_broadcast(fifo->not_empty); apr_thread_cond_broadcast(fifo->not_full); apr_thread_mutex_unlock(fifo->lock); } return rv; } int h2_proxy_fifo_count(h2_proxy_fifo *fifo) { return fifo->count; } int h2_proxy_fifo_capacity(h2_proxy_fifo *fifo) { return fifo->nelems; } static apr_status_t check_not_empty(h2_proxy_fifo *fifo, int block) { if (fifo->count == 0) { if (!block) { return APR_EAGAIN; } while (fifo->count == 0) { if (fifo->aborted) { return APR_EOF; } apr_thread_cond_wait(fifo->not_empty, fifo->lock); } } return APR_SUCCESS; } static apr_status_t fifo_push(h2_proxy_fifo *fifo, void *elem, int block) { apr_status_t rv; if (fifo->aborted) { return APR_EOF; } if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { if (fifo->set && index_of(fifo, elem) >= 0) { /* set mode, elem already member */ apr_thread_mutex_unlock(fifo->lock); return APR_EEXIST; } else if (fifo->count == fifo->nelems) { if (block) { while (fifo->count == fifo->nelems) { if (fifo->aborted) { apr_thread_mutex_unlock(fifo->lock); return APR_EOF; } apr_thread_cond_wait(fifo->not_full, fifo->lock); } } else { apr_thread_mutex_unlock(fifo->lock); return APR_EAGAIN; } } ap_assert(fifo->count < fifo->nelems); fifo->elems[nth_index(fifo, fifo->count)] = elem; ++fifo->count; if (fifo->count == 1) { apr_thread_cond_broadcast(fifo->not_empty); } apr_thread_mutex_unlock(fifo->lock); } return rv; } apr_status_t h2_proxy_fifo_push(h2_proxy_fifo *fifo, void *elem) { return fifo_push(fifo, elem, 1); } apr_status_t h2_proxy_fifo_try_push(h2_proxy_fifo *fifo, void *elem) { return fifo_push(fifo, elem, 0); } static void *pull_head(h2_proxy_fifo *fifo) { void *elem; ap_assert(fifo->count > 0); elem = fifo->elems[fifo->head]; --fifo->count; if (fifo->count > 0) { fifo->head = nth_index(fifo, 1); if (fifo->count+1 == fifo->nelems) { apr_thread_cond_broadcast(fifo->not_full); } } return elem; } static apr_status_t fifo_pull(h2_proxy_fifo *fifo, void **pelem, int block) { apr_status_t rv; if (fifo->aborted) { return APR_EOF; } if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) { apr_thread_mutex_unlock(fifo->lock); *pelem = NULL; return rv; } ap_assert(fifo->count > 0); *pelem = pull_head(fifo); apr_thread_mutex_unlock(fifo->lock); } return rv; } apr_status_t h2_proxy_fifo_pull(h2_proxy_fifo *fifo, void **pelem) { return fifo_pull(fifo, pelem, 1); } apr_status_t h2_proxy_fifo_try_pull(h2_proxy_fifo *fifo, void **pelem) { return fifo_pull(fifo, pelem, 0); } apr_status_t h2_proxy_fifo_remove(h2_proxy_fifo *fifo, void *elem) { apr_status_t rv; if (fifo->aborted) { return APR_EOF; } if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { int i, rc; void *e; rc = 0; for (i = 0; i < fifo->count; ++i) { e = fifo->elems[nth_index(fifo, i)]; if (e == elem) { ++rc; } else if (rc) { fifo->elems[nth_index(fifo, i-rc)] = e; } } if (rc) { fifo->count -= rc; if (fifo->count + rc == fifo->nelems) { apr_thread_cond_broadcast(fifo->not_full); } rv = APR_SUCCESS; } else { rv = APR_EAGAIN; } apr_thread_mutex_unlock(fifo->lock); } return rv; } modules/http2/h2_proxy_util.h +51 −0 Original line number Diff line number Diff line Loading @@ -201,4 +201,55 @@ const char *h2_proxy_link_reverse_map(request_rec *r, const char *proxy_server_uri, const char *s); /******************************************************************************* * FIFO queue ******************************************************************************/ /** * A thread-safe FIFO queue with some extra bells and whistles, if you * do not need anything special, better use 'apr_queue'. */ typedef struct h2_proxy_fifo h2_proxy_fifo; /** * Create a FIFO queue that can hold up to capacity elements. Elements can * appear several times. */ apr_status_t h2_proxy_fifo_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity); /** * Create a FIFO set that can hold up to capacity elements. Elements only * appear once. Pushing an element already present does not change the * queue and is successful. */ apr_status_t h2_proxy_fifo_set_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity); apr_status_t h2_proxy_fifo_term(h2_proxy_fifo *fifo); apr_status_t h2_proxy_fifo_interrupt(h2_proxy_fifo *fifo); int h2_proxy_fifo_capacity(h2_proxy_fifo *fifo); int h2_proxy_fifo_count(h2_proxy_fifo *fifo); /** * Push en element into the queue. Blocks if there is no capacity left. * * @param fifo the FIFO queue * @param elem the element to push * @return APR_SUCCESS on push, APR_EAGAIN on try_push on a full queue, * APR_EEXIST when in set mode and elem already there. */ apr_status_t h2_proxy_fifo_push(h2_proxy_fifo *fifo, void *elem); apr_status_t h2_proxy_fifo_try_push(h2_proxy_fifo *fifo, void *elem); apr_status_t h2_proxy_fifo_pull(h2_proxy_fifo *fifo, void **pelem); apr_status_t h2_proxy_fifo_try_pull(h2_proxy_fifo *fifo, void **pelem); /** * Remove the elem from the queue, will remove multiple appearances. * @param elem the element to remove * @return APR_SUCCESS iff > 0 elems were removed, APR_EAGAIN otherwise. */ apr_status_t h2_proxy_fifo_remove(h2_proxy_fifo *fifo, void *elem); #endif /* defined(__mod_h2__h2_proxy_util__) */ Loading
CHANGES +2 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,8 @@ Changes with Apache 2.5.0 [Stefan Eissing] *) mod_proxy_http2: Fixed bug in re-attempting proxy requests after connection error. [Stefan Eissing] connection error. Reliability of reconnect handling improved. [Stefan Eissing] *) core: Disallow multiple Listen on the same IP:port when listener buckets are configured (ListenCoresBucketsRatio > 0), consistently with the single Loading
modules/http2/h2_mplx.c +1 −1 Original line number Diff line number Diff line Loading @@ -787,7 +787,7 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn) if (task->engine) { if (!m->aborted && !task->c->aborted && !h2_req_engine_is_shutdown(task->engine)) { ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, APLOGNO(10022) "h2_mplx(%ld): task(%s) has not-shutdown " "engine(%s)", m->id, task->id, h2_req_engine_get_id(task->engine)); Loading
modules/http2/h2_proxy_util.c +281 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ #include <assert.h> #include <apr_lib.h> #include <apr_strings.h> #include <apr_thread_mutex.h> #include <apr_thread_cond.h> #include <httpd.h> #include <http_core.h> Loading Loading @@ -1053,3 +1055,282 @@ const char *h2_proxy_link_reverse_map(request_rec *r, "link_reverse_map %s --> %s", s, ctx.s); return ctx.s; } /******************************************************************************* * FIFO queue ******************************************************************************/ struct h2_proxy_fifo { void **elems; int nelems; int set; int head; int count; int aborted; apr_thread_mutex_t *lock; apr_thread_cond_t *not_empty; apr_thread_cond_t *not_full; }; static int nth_index(h2_proxy_fifo *fifo, int n) { return (fifo->head + n) % fifo->nelems; } static apr_status_t fifo_destroy(void *data) { h2_proxy_fifo *fifo = data; apr_thread_cond_destroy(fifo->not_empty); apr_thread_cond_destroy(fifo->not_full); apr_thread_mutex_destroy(fifo->lock); return APR_SUCCESS; } static int index_of(h2_proxy_fifo *fifo, void *elem) { int i; for (i = 0; i < fifo->count; ++i) { if (elem == fifo->elems[nth_index(fifo, i)]) { return i; } } return -1; } static apr_status_t create_int(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity, int as_set) { apr_status_t rv; h2_proxy_fifo *fifo; fifo = apr_pcalloc(pool, sizeof(*fifo)); if (fifo == NULL) { return APR_ENOMEM; } rv = apr_thread_mutex_create(&fifo->lock, APR_THREAD_MUTEX_UNNESTED, pool); if (rv != APR_SUCCESS) { return rv; } rv = apr_thread_cond_create(&fifo->not_empty, pool); if (rv != APR_SUCCESS) { return rv; } rv = apr_thread_cond_create(&fifo->not_full, pool); if (rv != APR_SUCCESS) { return rv; } fifo->elems = apr_pcalloc(pool, capacity * sizeof(void*)); if (fifo->elems == NULL) { return APR_ENOMEM; } fifo->nelems = capacity; fifo->set = as_set; *pfifo = fifo; apr_pool_cleanup_register(pool, fifo, fifo_destroy, apr_pool_cleanup_null); return APR_SUCCESS; } apr_status_t h2_proxy_fifo_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity) { return create_int(pfifo, pool, capacity, 0); } apr_status_t h2_proxy_fifo_set_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity) { return create_int(pfifo, pool, capacity, 1); } apr_status_t h2_proxy_fifo_term(h2_proxy_fifo *fifo) { apr_status_t rv; if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { fifo->aborted = 1; apr_thread_mutex_unlock(fifo->lock); } return rv; } apr_status_t h2_proxy_fifo_interrupt(h2_proxy_fifo *fifo) { apr_status_t rv; if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { apr_thread_cond_broadcast(fifo->not_empty); apr_thread_cond_broadcast(fifo->not_full); apr_thread_mutex_unlock(fifo->lock); } return rv; } int h2_proxy_fifo_count(h2_proxy_fifo *fifo) { return fifo->count; } int h2_proxy_fifo_capacity(h2_proxy_fifo *fifo) { return fifo->nelems; } static apr_status_t check_not_empty(h2_proxy_fifo *fifo, int block) { if (fifo->count == 0) { if (!block) { return APR_EAGAIN; } while (fifo->count == 0) { if (fifo->aborted) { return APR_EOF; } apr_thread_cond_wait(fifo->not_empty, fifo->lock); } } return APR_SUCCESS; } static apr_status_t fifo_push(h2_proxy_fifo *fifo, void *elem, int block) { apr_status_t rv; if (fifo->aborted) { return APR_EOF; } if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { if (fifo->set && index_of(fifo, elem) >= 0) { /* set mode, elem already member */ apr_thread_mutex_unlock(fifo->lock); return APR_EEXIST; } else if (fifo->count == fifo->nelems) { if (block) { while (fifo->count == fifo->nelems) { if (fifo->aborted) { apr_thread_mutex_unlock(fifo->lock); return APR_EOF; } apr_thread_cond_wait(fifo->not_full, fifo->lock); } } else { apr_thread_mutex_unlock(fifo->lock); return APR_EAGAIN; } } ap_assert(fifo->count < fifo->nelems); fifo->elems[nth_index(fifo, fifo->count)] = elem; ++fifo->count; if (fifo->count == 1) { apr_thread_cond_broadcast(fifo->not_empty); } apr_thread_mutex_unlock(fifo->lock); } return rv; } apr_status_t h2_proxy_fifo_push(h2_proxy_fifo *fifo, void *elem) { return fifo_push(fifo, elem, 1); } apr_status_t h2_proxy_fifo_try_push(h2_proxy_fifo *fifo, void *elem) { return fifo_push(fifo, elem, 0); } static void *pull_head(h2_proxy_fifo *fifo) { void *elem; ap_assert(fifo->count > 0); elem = fifo->elems[fifo->head]; --fifo->count; if (fifo->count > 0) { fifo->head = nth_index(fifo, 1); if (fifo->count+1 == fifo->nelems) { apr_thread_cond_broadcast(fifo->not_full); } } return elem; } static apr_status_t fifo_pull(h2_proxy_fifo *fifo, void **pelem, int block) { apr_status_t rv; if (fifo->aborted) { return APR_EOF; } if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) { apr_thread_mutex_unlock(fifo->lock); *pelem = NULL; return rv; } ap_assert(fifo->count > 0); *pelem = pull_head(fifo); apr_thread_mutex_unlock(fifo->lock); } return rv; } apr_status_t h2_proxy_fifo_pull(h2_proxy_fifo *fifo, void **pelem) { return fifo_pull(fifo, pelem, 1); } apr_status_t h2_proxy_fifo_try_pull(h2_proxy_fifo *fifo, void **pelem) { return fifo_pull(fifo, pelem, 0); } apr_status_t h2_proxy_fifo_remove(h2_proxy_fifo *fifo, void *elem) { apr_status_t rv; if (fifo->aborted) { return APR_EOF; } if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) { int i, rc; void *e; rc = 0; for (i = 0; i < fifo->count; ++i) { e = fifo->elems[nth_index(fifo, i)]; if (e == elem) { ++rc; } else if (rc) { fifo->elems[nth_index(fifo, i-rc)] = e; } } if (rc) { fifo->count -= rc; if (fifo->count + rc == fifo->nelems) { apr_thread_cond_broadcast(fifo->not_full); } rv = APR_SUCCESS; } else { rv = APR_EAGAIN; } apr_thread_mutex_unlock(fifo->lock); } return rv; }
modules/http2/h2_proxy_util.h +51 −0 Original line number Diff line number Diff line Loading @@ -201,4 +201,55 @@ const char *h2_proxy_link_reverse_map(request_rec *r, const char *proxy_server_uri, const char *s); /******************************************************************************* * FIFO queue ******************************************************************************/ /** * A thread-safe FIFO queue with some extra bells and whistles, if you * do not need anything special, better use 'apr_queue'. */ typedef struct h2_proxy_fifo h2_proxy_fifo; /** * Create a FIFO queue that can hold up to capacity elements. Elements can * appear several times. */ apr_status_t h2_proxy_fifo_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity); /** * Create a FIFO set that can hold up to capacity elements. Elements only * appear once. Pushing an element already present does not change the * queue and is successful. */ apr_status_t h2_proxy_fifo_set_create(h2_proxy_fifo **pfifo, apr_pool_t *pool, int capacity); apr_status_t h2_proxy_fifo_term(h2_proxy_fifo *fifo); apr_status_t h2_proxy_fifo_interrupt(h2_proxy_fifo *fifo); int h2_proxy_fifo_capacity(h2_proxy_fifo *fifo); int h2_proxy_fifo_count(h2_proxy_fifo *fifo); /** * Push en element into the queue. Blocks if there is no capacity left. * * @param fifo the FIFO queue * @param elem the element to push * @return APR_SUCCESS on push, APR_EAGAIN on try_push on a full queue, * APR_EEXIST when in set mode and elem already there. */ apr_status_t h2_proxy_fifo_push(h2_proxy_fifo *fifo, void *elem); apr_status_t h2_proxy_fifo_try_push(h2_proxy_fifo *fifo, void *elem); apr_status_t h2_proxy_fifo_pull(h2_proxy_fifo *fifo, void **pelem); apr_status_t h2_proxy_fifo_try_pull(h2_proxy_fifo *fifo, void **pelem); /** * Remove the elem from the queue, will remove multiple appearances. * @param elem the element to remove * @return APR_SUCCESS iff > 0 elems were removed, APR_EAGAIN otherwise. */ apr_status_t h2_proxy_fifo_remove(h2_proxy_fifo *fifo, void *elem); #endif /* defined(__mod_h2__h2_proxy_util__) */