summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pppd/accel-ppp.conf.514
-rw-r--r--accel-pppd/extra/metrics.c59
2 files changed, 71 insertions, 2 deletions
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index feb9214e..076f7137 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -1328,6 +1328,20 @@ When the option is missing or empty, all peers are allowed. Peers
that do not match a CIDR have their connection closed immediately
after
.BR accept (2).
+.TP
+.BI "read_timeout=" seconds
+Maximum time a client may take to deliver a complete HTTP request.
+Connections that have not produced a terminating
+.BR \(dq\\r\\n\\r\\n\(dq
+within this deadline are closed. Defaults to 5 seconds. Set to
+.B 0
+to disable the deadline.
+.TP
+.BI "max_clients=" n
+Maximum number of in-flight HTTP clients. Excess connections are
+accepted then immediately closed. Defaults to 64. Set to
+.B 0
+to disable the cap.
.SH [connlimit]
.br
This module limits connection rate from single source.
diff --git a/accel-pppd/extra/metrics.c b/accel-pppd/extra/metrics.c
index d0fbe6e5..78774dd0 100644
--- a/accel-pppd/extra/metrics.c
+++ b/accel-pppd/extra/metrics.c
@@ -45,10 +45,13 @@ enum metrics_format {
};
#define METRICS_RECV_BUF_SIZE 2048
+#define METRICS_DEFAULT_READ_TIMEOUT 5 /* seconds */
+#define METRICS_DEFAULT_MAX_CLIENTS 64
struct metrics_client_t {
struct list_head entry;
struct triton_md_handler_t hnd;
+ struct triton_timer_t timer;
struct sockaddr_in addr;
char *recv_buf;
int recv_pos;
@@ -64,10 +67,15 @@ struct metrics_acl_t {
static enum metrics_format conf_format = METRICS_FORMAT_PROMETHEUS;
static char *conf_address;
static LIST_HEAD(conf_allowed);
+static int conf_read_timeout = METRICS_DEFAULT_READ_TIMEOUT;
+static int conf_max_clients = METRICS_DEFAULT_MAX_CLIENTS;
+
+#define METRICS_ACCEPT_BATCH 16 /* max accept()s per serv_read tick */
static struct triton_context_t serv_ctx;
static struct triton_md_handler_t serv_hnd;
static LIST_HEAD(clients);
+static unsigned int client_count;
static int serv_running;
static int parse_format(const char *opt, enum metrics_format *out)
@@ -304,6 +312,18 @@ static int load_config(void)
free_acl(&conf_allowed);
list_replace_init(&new_allowed, &conf_allowed);
+ opt = conf_get_opt("metrics", "read_timeout");
+ if (opt) {
+ int n = atoi(opt);
+ conf_read_timeout = n > 0 ? n : 0;
+ }
+
+ opt = conf_get_opt("metrics", "max_clients");
+ if (opt) {
+ int n = atoi(opt);
+ conf_max_clients = n > 0 ? n : 0;
+ }
+
return 0;
}
@@ -717,15 +737,27 @@ out:
strbuf_free(&sb);
}
+static void client_timeout(struct triton_timer_t *t);
+
static void disconnect_client(struct metrics_client_t *cln)
{
+ if (cln->timer.tpd)
+ triton_timer_del(&cln->timer);
list_del(&cln->entry);
+ client_count--;
triton_md_unregister_handler(&cln->hnd, 1);
if (cln->recv_buf)
_free(cln->recv_buf);
_free(cln);
}
+static void client_timeout(struct triton_timer_t *t)
+{
+ struct metrics_client_t *cln = container_of(t, typeof(*cln), timer);
+
+ disconnect_client(cln);
+}
+
static void handle_request(struct metrics_client_t *cln)
{
char *line_end, *space1, *space2;
@@ -807,8 +839,19 @@ static int serv_read(struct triton_md_handler_t *h)
socklen_t size = sizeof(addr);
int sock;
struct metrics_client_t *cln;
-
- while (1) {
+ int batch;
+
+ /* Cap the number of accepts handled per dispatch. Without this, an
+ * overflow burst (peers exceeding max_clients or denied by
+ * allowed_ips) keeps us in this loop accept()ing and immediately
+ * closing sockets, never yielding back to the triton dispatcher.
+ * Since the per-client read-timeout timers share serv_ctx, that
+ * would delay client_timeout() and let stalled clients live past
+ * read_timeout. Return after METRICS_ACCEPT_BATCH iterations; if
+ * the listening fd is still readable triton will dispatch us again
+ * on the next loop after timers have had a chance to fire.
+ */
+ for (batch = 0; batch < METRICS_ACCEPT_BATCH; batch++) {
sock = accept(h->fd, (struct sockaddr *)&addr, &size);
if (sock < 0) {
if (errno == EAGAIN)
@@ -822,6 +865,11 @@ static int serv_read(struct triton_md_handler_t *h)
continue;
}
+ if (conf_max_clients && client_count >= (unsigned int)conf_max_clients) {
+ close(sock);
+ continue;
+ }
+
if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
log_error("metrics: failed to set nonblocking mode: %s\n", strerror(errno));
close(sock);
@@ -845,8 +893,15 @@ static int serv_read(struct triton_md_handler_t *h)
}
list_add_tail(&cln->entry, &clients);
+ client_count++;
triton_md_register_handler(&serv_ctx, &cln->hnd);
triton_md_enable_handler(&cln->hnd, MD_MODE_READ);
+
+ if (conf_read_timeout > 0) {
+ cln->timer.expire = client_timeout;
+ cln->timer.expire_tv.tv_sec = conf_read_timeout;
+ triton_timer_add(&serv_ctx, &cln->timer, 0);
+ }
}
return 0;