quark

quark web server
git clone git://git.suckless.org/quark
Log | Files | Refs | LICENSE

commit 2920ba56d92b461c39f3c7c9c5a264f38b899fd7
parent 6d7c7b6ff701fafc2a649b21a66a92a9ab626221
Author: Laslo Hunhold <dev@frign.de>
Date:   Sat, 13 Feb 2021 11:46:59 +0100

Further refine dropout-candidates over response-type and progress

There might not only be scenarios where the server is under attack
by a single entity, but possibly a botnet of hundreds of computers with
a few connections each.
An honest client connecting to the server with a few connections that
might include a long-running download might end up as the client with
the most simultaneous connections (e.g. 6 over the respective 5
of each botnet-member).

If we end up dropping one of the honest client's connections, we don't
want it to be the long-running-download, but lower-priority things
(directory listings, error responses, not-far-advanced downloads; in
increasing order of importance). Among similar types, we drop those
that are not as far advanced in absolute terms. The reasoning behind
this (and against relative progress) is that it's worse to drop a
download at 50% when the requested file is 300MB compared to
dropping another connection at 75% when the requested file is merely
a few kB large.

Signed-off-by: Laslo Hunhold <dev@frign.de>

Diffstat:
Mdata.c | 2+-
Mhttp.h | 2+-
Mmain.c | 48+++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/data.c b/data.c @@ -13,9 +13,9 @@ enum status (* const data_fct[])(const struct response *, struct buffer *, size_t *) = { + [RESTYPE_DIRLISTING] = data_prepare_dirlisting_buf, [RESTYPE_ERROR] = data_prepare_error_buf, [RESTYPE_FILE] = data_prepare_file_buf, - [RESTYPE_DIRLISTING] = data_prepare_dirlisting_buf, }; static int diff --git a/http.h b/http.h @@ -65,9 +65,9 @@ enum res_field { extern const char *res_field_str[]; enum res_type { + RESTYPE_DIRLISTING, RESTYPE_ERROR, RESTYPE_FILE, - RESTYPE_DIRLISTING, NUM_RES_TYPES, }; diff --git a/main.c b/main.c @@ -181,8 +181,12 @@ get_connection_drop_candidate(struct connection *connection, size_t nslots) */ for (i = 0, minc = NULL, maxcnt = 0; i < nslots; i++) { /* - * the c is used to minimize in regard to importance - * within the same-address-group + * we determine how many connections have the same + * in-address as connection[i], but also minimize over + * that set with other criteria, yielding a general + * minimizer c. We first set it to connection[i] and + * update it, if a better candidate shows up, in the inner + * loop */ c = &connection[i]; @@ -193,16 +197,46 @@ get_connection_drop_candidate(struct connection *connection, size_t nslots) } cnt++; + /* minimize over state */ if (connection[j].state < c->state) { - /* - * we have found a connection with an - * even lower state and thus lower - * importance - */ c = &connection[j]; + } else if (connection[j].state == c->state) { + /* minimize over progress */ + if (c->state == C_SEND_BODY && + connection[i].res.type != c->res.type) { + /* + * mixed response types; progress + * is not comparable + * + * the res-type-enum is ordered as + * DIRLISTING, ERROR, FILE, i.e. + * in rising priority, because a + * file transfer is most important, + * followed by error-messages. + * Dirlistings as an "interactive" + * feature (that take up lots of + * resources) have the lowest + * priority + */ + if (connection[i].res.type < + c->res.type) { + c = &connection[j]; + } + } else if (connection[j].progress < + c->progress) { + /* + * for C_SEND_BODY with same response + * type, C_RECV_HEADER and C_SEND_BODY + * it is sufficient to compare the + * raw progress + */ + c = &connection[j]; + } } } + if (cnt > maxcnt) { + /* this run yielded an even greedier in-address */ minc = c; maxcnt = cnt; }