[MEDIUM] fix stats socket limitation to 16 kB
Due to the way the stats socket work, it was not possible to
maintain the information related to the command entered, so
after filling a whole buffer, the request was lost and it was
considered that there was nothing to write anymore.
The major reason was that some flags were passed directly
during the first call to stats_dump_raw() instead of being
stored persistently in the session.
To definitely fix this problem, flags were added to the stats
member of the session structure.
A second problem appeared. When the stats were produced, a first
call to client_retnclose() was performed, then one or multiple
subsequent calls to buffer_write_chunks() were done. But once the
stats buffer was full and a reschedule operated, the buffer was
flushed, the write flag cleared from the buffer and nothing was
done to re-arm it.
For this reason, a check was added in the proto_uxst_stats()
function in order to re-call the client FSM when data were added
by stats_dump_raw(). Finally, the whole unix stats dump FSM was
rewritten to avoid all the magics it depended on. It is now
simpler and looks more like the HTTP one.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 99ac770..a9fb84d 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -177,12 +177,12 @@
/*
* Produces statistics data for the session <s>. Expects to be called with
- * s->cli_state == CL_STSHUTR. It *may* make use of informations from <uri>
- * and <flags>.
+ * s->cli_state == CL_STSHUTR. It *may* make use of informations from <uri>.
+ * s->data_ctx must have been zeroed first, and the flags properly set.
* It returns 0 if it had to stop writing data and an I/O is needed, 1 if the
* dump is finished and the session must be closed, or -1 in case of any error.
*/
-int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags)
+int stats_dump_raw(struct session *s, struct uri_auth *uri)
{
struct buffer *rep = s->rep;
struct proxy *px;
@@ -202,7 +202,7 @@
/* fall through */
case DATA_ST_HEAD:
- if (flags & STAT_SHOW_STAT) {
+ if (s->data_ctx.stats.flags & STAT_SHOW_STAT) {
print_csv_header(&msg, sizeof(trash));
if (buffer_write_chunk(rep, &msg) != 0)
return 0;
@@ -213,8 +213,7 @@
case DATA_ST_INFO:
up = (now.tv_sec - start_date.tv_sec);
-
- if (flags & STAT_SHOW_INFO) {
+ if (s->data_ctx.stats.flags & STAT_SHOW_INFO) {
chunk_printf(&msg, sizeof(trash),
"Name: " PRODUCT_NAME "\n"
"Version: " HAPROXY_VERSION "\n"
@@ -256,13 +255,13 @@
case DATA_ST_LIST:
/* dump proxies */
- if (flags & STAT_SHOW_STAT) {
+ if (s->data_ctx.stats.flags & STAT_SHOW_STAT) {
while (s->data_ctx.stats.px) {
px = s->data_ctx.stats.px;
/* skip the disabled proxies and non-networked ones */
if (px->state != PR_STSTOPPED &&
(px->cap & (PR_CAP_FE | PR_CAP_BE)))
- if (stats_dump_proxy(s, px, NULL, 0) == 0)
+ if (stats_dump_proxy(s, px, NULL) == 0)
return 0;
s->data_ctx.stats.px = px->next;
@@ -293,10 +292,11 @@
* s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
* flag from the session, which it uses to keep on being called when there is
* free space in the buffer, of simply by letting an empty buffer upon return.
+ * s->data_ctx must have been zeroed before the first call, and the flags set.
* It returns 0 if it had to stop writing data and an I/O is needed, 1 if the
* dump is finished and the session must be closed, or -1 in case of any error.
*/
-int stats_dump_http(struct session *s, struct uri_auth *uri, int flags)
+int stats_dump_http(struct session *s, struct uri_auth *uri)
{
struct buffer *rep = s->rep;
struct proxy *px;
@@ -316,9 +316,9 @@
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Content-Type: %s\r\n",
- (flags & STAT_FMT_HTML) ? "text/html" : "text/plain");
+ (s->data_ctx.stats.flags & STAT_FMT_CSV) ? "text/plain" : "text/html");
- if (uri->refresh > 0 && !(s->flags & SN_STAT_NORFRSH))
+ if (uri->refresh > 0 && !(s->data_ctx.stats.flags & STAT_NO_REFRESH))
chunk_printf(&msg, sizeof(trash), "Refresh: %d\r\n",
uri->refresh);
@@ -344,7 +344,7 @@
/* fall through */
case DATA_ST_HEAD:
- if (flags & STAT_FMT_HTML) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
/* WARNING! This must fit in the first buffer !!! */
chunk_printf(&msg, sizeof(trash),
"<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
@@ -435,7 +435,7 @@
* We are around 3.5 kB, add adding entries will
* become tricky if we want to support 4kB buffers !
*/
- if (flags & STAT_FMT_HTML) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, sizeof(trash),
"<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
PRODUCT_NAME "%s</a></h1>\n"
@@ -480,39 +480,39 @@
actconn
);
- if (s->flags & SN_STAT_HIDEDWN)
+ if (s->data_ctx.stats.flags & STAT_HIDE_DOWN)
chunk_printf(&msg, sizeof(trash),
"<li><a href=\"%s%s%s\">Show all servers</a><br>\n",
uri->uri_prefix,
"",
- (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : "");
+ (s->data_ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "");
else
chunk_printf(&msg, sizeof(trash),
"<li><a href=\"%s%s%s\">Hide 'DOWN' servers</a><br>\n",
uri->uri_prefix,
";up",
- (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : "");
+ (s->data_ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "");
if (uri->refresh > 0) {
- if (s->flags & SN_STAT_NORFRSH)
+ if (s->data_ctx.stats.flags & STAT_NO_REFRESH)
chunk_printf(&msg, sizeof(trash),
"<li><a href=\"%s%s%s\">Enable refresh</a><br>\n",
uri->uri_prefix,
- (s->flags & SN_STAT_HIDEDWN) ? ";up" : "",
+ (s->data_ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
"");
else
chunk_printf(&msg, sizeof(trash),
"<li><a href=\"%s%s%s\">Disable refresh</a><br>\n",
uri->uri_prefix,
- (s->flags & SN_STAT_HIDEDWN) ? ";up" : "",
+ (s->data_ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
";norefresh");
}
chunk_printf(&msg, sizeof(trash),
"<li><a href=\"%s%s%s\">Refresh now</a><br>\n",
uri->uri_prefix,
- (s->flags & SN_STAT_HIDEDWN) ? ";up" : "",
- (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : "");
+ (s->data_ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
+ (s->data_ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "");
chunk_printf(&msg, sizeof(trash),
"<li><a href=\"%s;csv%s\">CSV export</a><br>\n",
@@ -536,8 +536,6 @@
return 0;
}
- memset(&s->data_ctx, 0, sizeof(s->data_ctx));
-
s->data_ctx.stats.px = proxy;
s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
s->data_state = DATA_ST_LIST;
@@ -549,7 +547,7 @@
px = s->data_ctx.stats.px;
/* skip the disabled proxies and non-networked ones */
if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
- if (stats_dump_proxy(s, px, uri, flags) == 0)
+ if (stats_dump_proxy(s, px, uri) == 0)
return 0;
s->data_ctx.stats.px = px->next;
@@ -561,7 +559,7 @@
/* fall through */
case DATA_ST_END:
- if (flags & STAT_FMT_HTML) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, sizeof(trash), "</body></html>\n");
if (buffer_write_chunk(rep, &msg) != 0)
return 0;
@@ -587,7 +585,7 @@
* Returns 0 if it had to stop dumping data because of lack of buffer space,
* ot non-zero if everything completed.
*/
-int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, int flags)
+int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
{
struct buffer *rep = s->rep;
struct server *sv, *svs; /* server and server-state, server-state=server or server->tracked */
@@ -624,7 +622,7 @@
return 1;
}
- if ((s->flags & SN_STAT_BOUND) && (s->data_ctx.stats.iid != -1) &&
+ if ((s->data_ctx.stats.flags & STAT_BOUND) && (s->data_ctx.stats.iid != -1) &&
(px->uuid != s->data_ctx.stats.iid))
return 1;
@@ -632,7 +630,7 @@
/* fall through */
case DATA_ST_PX_TH:
- if (flags & STAT_FMT_HTML) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
/* print a new table */
chunk_printf(&msg, sizeof(trash),
"<table cols=\"26\" class=\"tbl\" width=\"100%%\">\n"
@@ -667,8 +665,9 @@
case DATA_ST_PX_FE:
/* print the frontend */
- if ((px->cap & PR_CAP_FE) && (!(s->flags & SN_STAT_BOUND) || (s->data_ctx.stats.type & (1 << STATS_TYPE_FE)))) {
- if (flags & STAT_FMT_HTML) {
+ if ((px->cap & PR_CAP_FE) &&
+ (!(s->data_ctx.stats.flags & STAT_BOUND) || (s->data_ctx.stats.type & (1 << STATS_TYPE_FE)))) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, sizeof(trash),
/* name, queue */
"<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=3></td>"
@@ -742,7 +741,7 @@
sv = s->data_ctx.stats.sv;
- if (s->flags & SN_STAT_BOUND) {
+ if (s->data_ctx.stats.flags & STAT_BOUND) {
if (!(s->data_ctx.stats.type & (1 << STATS_TYPE_SV)))
break;
@@ -773,13 +772,13 @@
else
sv_state = 0; /* DOWN */
- if ((sv_state == 0) && (s->flags & SN_STAT_HIDEDWN)) {
+ if ((sv_state == 0) && (s->data_ctx.stats.flags & STAT_HIDE_DOWN)) {
/* do not report servers which are DOWN */
s->data_ctx.stats.sv = sv->next;
continue;
}
- if (flags & STAT_FMT_HTML) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
static char *srv_hlt_st[7] = { "DOWN", "DN %d/%d ↑",
"UP %d/%d ↓", "UP",
"NOLB %d/%d ↓", "NOLB",
@@ -952,8 +951,9 @@
case DATA_ST_PX_BE:
/* print the backend */
- if ((px->cap & PR_CAP_BE) && (!(s->flags & SN_STAT_BOUND) || (s->data_ctx.stats.type & (1 << STATS_TYPE_BE)))) {
- if (flags & STAT_FMT_HTML) {
+ if ((px->cap & PR_CAP_BE) &&
+ (!(s->data_ctx.stats.flags & STAT_BOUND) || (s->data_ctx.stats.type & (1 << STATS_TYPE_BE)))) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, sizeof(trash),
/* name */
"<tr align=center class=\"backend\"><td>Backend</td>"
@@ -1047,7 +1047,7 @@
/* fall through */
case DATA_ST_PX_END:
- if (flags & STAT_FMT_HTML) {
+ if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, sizeof(trash), "</table><p>\n");
if (buffer_write_chunk(rep, &msg) != 0)