[MEDIUM] the stats dump FSM was buggy and looped on dispatch instances.

It has been rewritten and now supports an initialization state. It now also
prevents from dumping stopped(disabled) listeners and it is possible to
specify a scope with a list of proxies that are allowed to be dumped from
the one being configured ('.' meaning "this one"). The 'stats' entry can
be configured from the 'defaults' instance and it is correctly flushed
from proxies which redefine it.
This commit is contained in:
willy tarreau 2006-05-21 14:46:15 +02:00
parent fac1a86495
commit 1f431b5851
4 changed files with 225 additions and 88 deletions

14
ROADMAP
View File

@ -1,4 +1,4 @@
'+' = done, '-' = todo '+' = done, '-' = todo, '*' = done except doc
1.2.12 : 1.2.12 :
+ weighted RR/SH + weighted RR/SH
@ -8,7 +8,15 @@
+ queueing + queueing
1.2.14 : 1.2.14 :
- HTML status page * HTML status page
stats enable
stats uri /?stats
stats realm w.ods.org\ statistics
stats auth user1:pass1
stats auth user2:pass2
stats auth user3:pass3
stats scope <px_id> | '.'
- separate timeout controls - separate timeout controls
@ -25,6 +33,8 @@
srv->effective_maxconn = srv->effective_maxconn =
max(srv->maxconn * px->nbsess / px->maxconn, srv->minconn) max(srv->maxconn * px->nbsess / px->maxconn, srv->minconn)
- allow server-less proxies (for stats)
1.3 : 1.3 :
- handle half-closed connections better (cli/srv would not distinguish - handle half-closed connections better (cli/srv would not distinguish
DATA/SHUTR/SHUTW, it would be a session flag which would tell shutr/shutw). DATA/SHUTR/SHUTW, it would be a session flag which would tell shutr/shutw).

246
haproxy.c
View File

@ -442,6 +442,10 @@ char *ultoa(unsigned long n) {
#define DATA_SRC_NONE 0 #define DATA_SRC_NONE 0
#define DATA_SRC_STATS 1 #define DATA_SRC_STATS 1
/* data transmission states for the responses */
#define DATA_ST_INIT 0
#define DATA_ST_DATA 1
/* different possible states for the client side */ /* different possible states for the client side */
#define CL_STHEADERS 0 #define CL_STHEADERS 0
#define CL_STDATA 1 #define CL_STDATA 1
@ -641,11 +645,13 @@ struct session {
int status; /* HTTP status from the server, negative if from proxy */ int status; /* HTTP status from the server, negative if from proxy */
long long bytes; /* number of bytes transferred from the server */ long long bytes; /* number of bytes transferred from the server */
} logs; } logs;
int data_source; /* where to get the data we generate ourselves */ short int data_source; /* where to get the data we generate ourselves */
short int data_state; /* where to get the data we generate ourselves */
union { union {
struct { struct {
struct proxy *px; struct proxy *px;
struct server *sv; struct server *sv;
short px_st, sv_st; /* DATA_ST_INIT or DATA_ST_DATA */
} stats; } stats;
} data_ctx; } data_ctx;
unsigned int uniq_id; /* unique ID used for the traces */ unsigned int uniq_id; /* unique ID used for the traces */
@ -2981,6 +2987,7 @@ int buffer_realign(struct buffer *buf) {
/* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of /* writes <len> bytes from message <msg> to buffer <buf>. Returns 0 in case of
* success, or the number of bytes available otherwise. * success, or the number of bytes available otherwise.
* FIXME-20060521: handle unaligned data.
*/ */
int buffer_write(struct buffer *buf, const char *msg, int len) { int buffer_write(struct buffer *buf, const char *msg, int len) {
int max; int max;
@ -3042,19 +3049,21 @@ int produce_content(struct session *s) {
struct proxy *px; struct proxy *px;
struct server *sv; struct server *sv;
int msglen; int msglen;
unsigned int up;
int failed_checks, down_trans;
if (s->data_source == DATA_SRC_NONE) { if (s->data_source == DATA_SRC_NONE) {
s->flags &= ~SN_SELF_GEN; s->flags &= ~SN_SELF_GEN;
return 1; return 1;
} }
else if (s->data_source == DATA_SRC_STATS) { else if (s->data_source == DATA_SRC_STATS) {
if (s->data_ctx.stats.px == NULL) { /* initialized to NULL at session creation */ msglen = 0;
/* the proxy was not known, the function had not been called yet */
if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
unsigned int up;
s->flags |= SN_SELF_GEN; // more data will follow s->flags |= SN_SELF_GEN; // more data will follow
msglen = sprintf(trash,
/* send the start of the HTTP response */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"HTTP/1.0 200 OK\r\n" "HTTP/1.0 200 OK\r\n"
"Cache-Control: no-cache\r\n" "Cache-Control: no-cache\r\n"
"Connection: close\r\n" "Connection: close\r\n"
@ -3062,13 +3071,15 @@ int produce_content(struct session *s) {
s->logs.status = 200; s->logs.status = 200;
client_retnclose(s, msglen, trash); // send the start of the response. client_retnclose(s, msglen, trash); // send the start of the response.
msglen = 0;
if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
if (!(s->flags & SN_FINST_MASK)) if (!(s->flags & SN_FINST_MASK))
s->flags |= SN_FINST_R; s->flags |= SN_FINST_R;
/* WARNING! This must fit in the first buffer !!! */ /* WARNING! This must fit in the first buffer !!! */
msglen = snprintf(trash, sizeof(trash), msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n" "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
"<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n" "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
"<style type=\"text/css\"><!--\n" "<style type=\"text/css\"><!--\n"
@ -3124,11 +3135,12 @@ int produce_content(struct session *s) {
if (buffer_write(rep, trash, msglen) != 0) if (buffer_write(rep, trash, msglen) != 0)
return 0; return 0;
msglen = 0;
up = (now.tv_sec - start_date.tv_sec); up = (now.tv_sec - start_date.tv_sec);
/* WARNING! this has to fit the first packet too */ /* WARNING! this has to fit the first packet too */
msglen = snprintf(trash, sizeof(trash), msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<body><h1>" PRODUCT_NAME "</h1>\n" "<body><h1>" PRODUCT_NAME "</h1>\n"
"<h2>Statistics Report for pid %d</h2>\n" "<h2>Statistics Report for pid %d</h2>\n"
"<hr width=\"100%%\" class=\"hr\">\n" "<hr width=\"100%%\" class=\"hr\">\n"
@ -3166,18 +3178,52 @@ int produce_content(struct session *s) {
if (buffer_write(rep, trash, msglen) != 0) if (buffer_write(rep, trash, msglen) != 0)
return 0; return 0;
msglen = 0;
s->data_state = DATA_ST_DATA;
memset(&s->data_ctx, 0, sizeof(s->data_ctx));
px = s->data_ctx.stats.px = proxy; px = s->data_ctx.stats.px = proxy;
s->data_ctx.stats.px_st = DATA_ST_INIT;
} }
while (s->data_ctx.stats.px) { while (s->data_ctx.stats.px) {
int dispatch_sess, dispatch_cum; int dispatch_sess, dispatch_cum;
int failed_checks, down_trans;
/* if sv == NULL, this is because we are on a new proxy : if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
* initialized to NULL at session creation /* we are on a new proxy */
*/
while (s->data_ctx.stats.sv == NULL) {
px = s->data_ctx.stats.px; px = s->data_ctx.stats.px;
msglen = snprintf(trash, sizeof(trash),
/* skip the disabled proxies */
if (px->state == PR_STSTOPPED)
goto next_proxy;
if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
/* we have a limited scope, we have to check the proxy name */
struct stat_scope *scope;
int len;
len = strlen(px->id);
scope = s->proxy->uri_auth->scope;
while (scope) {
/* match exact proxy name */
if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
break;
/* match '.' which means 'self' proxy */
if (!strcmp(scope->px_id, ".") && px == s->proxy)
break;
scope = scope->next;
}
/* proxy name not found */
if (scope == NULL)
goto next_proxy;
}
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<h3>&gt; Proxy instance %s : " "<h3>&gt; Proxy instance %s : "
"%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n" "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
"", "",
@ -3199,29 +3245,23 @@ int produce_content(struct session *s) {
if (buffer_write(rep, trash, msglen) != 0) if (buffer_write(rep, trash, msglen) != 0)
return 0; return 0;
msglen = 0;
s->data_ctx.stats.sv = px->srv; s->data_ctx.stats.sv = px->srv;
s->data_ctx.stats.px_st = DATA_ST_DATA;
} }
px = s->data_ctx.stats.px; px = s->data_ctx.stats.px;
dispatch_sess = px->nbconn; /* stats.sv has been initialized above */
dispatch_cum = px->cum_conn;
failed_checks = down_trans = 0;
while (s->data_ctx.stats.sv != NULL) { while (s->data_ctx.stats.sv != NULL) {
static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" }; static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" }; static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" }; static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */ int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
px = s->data_ctx.stats.px;
sv = s->data_ctx.stats.sv; sv = s->data_ctx.stats.sv;
dispatch_sess -= sv->cur_sess;
dispatch_cum -= sv->cum_sess;
failed_checks += sv->failed_checks;
down_trans += sv->down_trans;
/* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */ /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
if (!(sv->state & SRV_CHECKED)) if (!(sv->state & SRV_CHECKED))
sv_state = 4; sv_state = 4;
@ -3237,7 +3277,7 @@ int produce_content(struct session *s) {
sv_state = 0; /* DOWN */ sv_state = 0; /* DOWN */
/* name, weight */ /* name, weight */
msglen = snprintf(trash, sizeof(trash), msglen += snprintf(trash, sizeof(trash),
"<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>", "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
(sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state], (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
sv->id, sv->uweight+1); sv->id, sv->uweight+1);
@ -3271,66 +3311,88 @@ int produce_content(struct session *s) {
msglen += snprintf(trash + msglen, sizeof(trash) - msglen, msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>-</td><td align=right>-</td></tr>\n"); "<td align=right>-</td><td align=right>-</td></tr>\n");
sv = sv->next;
if (!sv) {
/* first, write informations about the dispatcher */
/* name, weight, status, act, bck */
msglen += snprintf(trash + msglen, sizeof(trash),
"<tr align=center bgcolor=\"#e8e8d0\">"
"<td>Dispatcher</td><td>-</td>"
"<td>%s</td><td>-</td><td>-</td>",
px->state == PR_STRUN ? "UP" : "DOWN");
/* queue : current, max */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>%d</td><td align=right>%d</td>",
px->nbpend, px->nbpend_max);
/* sessions : current, max, limit, cumul */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
/* failures : unique, fatal */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>-</td><td align=right>-</td></tr>\n");
/* now the summary for the proxy */
/* name, weight, status, act, bck */
msglen += snprintf(trash + msglen, sizeof(trash),
"<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
"<td><b>Total</b></td><td>-</td>"
"<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
(px->state == PR_STRUN && (px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
px->srv_act, px->srv_bck);
/* queue : current, max */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
px->totpend, px->nbpend_max);
/* sessions : current, max, limit, cumul */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
/* failures : unique, fatal */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>%d</td><td align=right>%d</td></tr>\n",
failed_checks, down_trans);
msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
px = px->next;
/* the server loop will automatically detect the NULL */
}
if (buffer_write(rep, trash, msglen) != 0) if (buffer_write(rep, trash, msglen) != 0)
return 0; return 0;
s->data_ctx.stats.sv = sv; msglen = 0;
s->data_ctx.stats.px = px;
} /* server loop */ s->data_ctx.stats.sv = sv->next;
} /* while sv */
/* now we are past the last server, we'll dump information about the dispatcher */
/* We have to count down from the proxy to the servers to tell how
* many sessions are on the dispatcher, and how many checks have
* failed. We cannot count this during the servers dump because it
* might be interrupted multiple times.
*/
dispatch_sess = px->nbconn;
dispatch_cum = px->cum_conn;
failed_checks = down_trans = 0;
sv = px->srv;
while (sv) {
dispatch_sess -= sv->cur_sess;
dispatch_cum -= sv->cum_sess;
failed_checks += sv->failed_checks;
down_trans += sv->down_trans;
sv = sv->next;
}
/* name, weight, status, act, bck */
msglen += snprintf(trash + msglen, sizeof(trash),
"<tr align=center bgcolor=\"#e8e8d0\">"
"<td>Dispatcher</td><td>-</td>"
"<td>%s</td><td>-</td><td>-</td>",
px->state == PR_STRUN ? "UP" : "DOWN");
/* queue : current, max */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>%d</td><td align=right>%d</td>",
px->nbpend, px->nbpend_max);
/* sessions : current, max, limit, cumul. */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
/* failures : unique, fatal */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>-</td><td align=right>-</td></tr>\n");
/* now the summary for the whole proxy */
/* name, weight, status, act, bck */
msglen += snprintf(trash + msglen, sizeof(trash),
"<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
"<td><b>Total</b></td><td>-</td>"
"<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
(px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
px->srv_act, px->srv_bck);
/* queue : current, max */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
px->totpend, px->nbpend_max);
/* sessions : current, max, limit, cumul */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
/* failures : unique, fatal */
msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
"<td align=right>%d</td><td align=right>%d</td></tr>\n",
failed_checks, down_trans);
msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
if (buffer_write(rep, trash, msglen) != 0)
return 0;
msglen = 0;
s->data_ctx.stats.px_st = DATA_ST_INIT;
next_proxy:
s->data_ctx.stats.px = px->next;
} /* proxy loop */ } /* proxy loop */
/* here, we just have reached the sv == NULL and px == NULL */ /* here, we just have reached the sv == NULL and px == NULL */
s->flags &= ~SN_SELF_GEN; s->flags &= ~SN_SELF_GEN;
@ -3611,7 +3673,6 @@ int event_accept(int fd) {
s->logs.srv_queue_size = 0; /* we will get this number soon */ s->logs.srv_queue_size = 0; /* we will get this number soon */
s->data_source = DATA_SRC_NONE; s->data_source = DATA_SRC_NONE;
memset(&s->data_ctx, 0, sizeof(s->data_ctx));
s->uniq_id = totalconn; s->uniq_id = totalconn;
p->cum_conn++; p->cum_conn++;
@ -4193,6 +4254,7 @@ int process_cli(struct session *t) {
req->rlim = req->data + BUFSIZE; /* no more rewrite needed */ req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
t->data_source = DATA_SRC_STATS; t->data_source = DATA_SRC_STATS;
t->data_state = DATA_ST_INIT;
produce_content(t); produce_content(t);
return 1; return 1;
} }
@ -7827,6 +7889,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
curproxy->loglev2 = defproxy.loglev2; curproxy->loglev2 = defproxy.loglev2;
curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR; curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
curproxy->grace = defproxy.grace; curproxy->grace = defproxy.grace;
curproxy->uri_auth = defproxy.uri_auth;
curproxy->source_addr = defproxy.source_addr; curproxy->source_addr = defproxy.source_addr;
curproxy->mon_net = defproxy.mon_net; curproxy->mon_net = defproxy.mon_net;
curproxy->mon_mask = defproxy.mon_mask; curproxy->mon_mask = defproxy.mon_mask;
@ -7844,7 +7907,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502); if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503); if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504); if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
/* we cannot free uri_auth because it might already be used */
init_default_instance(); init_default_instance();
curproxy = &defproxy; curproxy = &defproxy;
return 0; return 0;
@ -8112,8 +8175,11 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
curproxy->conn_retries = atol(args[1]); curproxy->conn_retries = atol(args[1]);
} }
else if (!strcmp(args[0], "stats")) { else if (!strcmp(args[0], "stats")) {
if (curproxy != &defproxy && curproxy->uri_auth == defproxy.uri_auth)
curproxy->uri_auth = NULL; /* we must detach from the default config */
if (*(args[1]) == 0) { if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth' or 'enable'.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
return -1; return -1;
} else if (!strcmp(args[1], "uri")) { } else if (!strcmp(args[1], "uri")) {
if (*(args[2]) == 0) { if (*(args[2]) == 0) {
@ -8139,6 +8205,14 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum); Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
return -1; return -1;
} }
} else if (!strcmp(args[1], "scope")) {
if (*(args[2]) == 0) {
Alert("parsing [%s:%d] : 'scope' needs a proxy name.\n", file, linenum);
return -1;
} else if (!stats_add_scope(&curproxy->uri_auth, args[2])) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
return -1;
}
} else if (!strcmp(args[1], "enable")) { } else if (!strcmp(args[1], "enable")) {
if (!stats_check_init_uri_auth(&curproxy->uri_auth)) { if (!stats_check_init_uri_auth(&curproxy->uri_auth)) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum); Alert("parsing [%s:%d] : out of memory.\n", file, linenum);

View File

@ -19,12 +19,22 @@ struct user_auth {
char *user_pwd; /* auth as base64("user":"passwd") (see RFC2617) */ char *user_pwd; /* auth as base64("user":"passwd") (see RFC2617) */
}; };
/* This is a list of proxies we are allowed to see. Later, it should go in the
* user list, but before this we need to support de/re-authentication.
*/
struct stat_scope {
struct stat_scope *next; /* next entry, NULL if none */
int px_len; /* proxy name length */
char *px_id; /* proxy id */
};
/* later we may link them to support multiple URI matching */ /* later we may link them to support multiple URI matching */
struct uri_auth { struct uri_auth {
int uri_len; /* the prefix length */ int uri_len; /* the prefix length */
char *uri_prefix; /* the prefix we want to match */ char *uri_prefix; /* the prefix we want to match */
char *auth_realm; /* the realm reported to the client */ char *auth_realm; /* the realm reported to the client */
struct user_auth *users; /* linked list of valid user:passwd couples */ struct user_auth *users; /* linked list of valid user:passwd couples */
struct stat_scope *scope; /* linked list of authorized proxies */
}; };
/* This is the default statistics URI */ /* This is the default statistics URI */
@ -53,5 +63,6 @@ struct uri_auth *stats_check_init_uri_auth(struct uri_auth **root);
struct uri_auth *stats_set_uri(struct uri_auth **root, char *uri); struct uri_auth *stats_set_uri(struct uri_auth **root, char *uri);
struct uri_auth *stats_set_realm(struct uri_auth **root, char *realm); struct uri_auth *stats_set_realm(struct uri_auth **root, char *realm);
struct uri_auth *stats_add_auth(struct uri_auth **root, char *user); struct uri_auth *stats_add_auth(struct uri_auth **root, char *user);
struct uri_auth *stats_add_scope(struct uri_auth **root, char *scope);
#endif /* URI_AUTH_H */ #endif /* URI_AUTH_H */

View File

@ -160,3 +160,45 @@ struct uri_auth *stats_add_auth(struct uri_auth **root, char *auth)
return NULL; return NULL;
} }
/*
* Returns a default uri_auth with a <scope> entry added to the list of
* allowed scopes. If a matching entry is found, no update will be performed.
* Uses the pointer provided if not NULL and not initialized.
*/
struct uri_auth *stats_add_scope(struct uri_auth **root, char *scope)
{
struct uri_auth *u;
char *new_name;
struct stat_scope *old_scope, **scope_list;
if ((u = stats_check_init_uri_auth(root)) == NULL)
goto out;
scope_list = &u->scope;
while ((old_scope = *scope_list)) {
if (!strcmp(old_scope->px_id, scope))
break;
scope_list = &old_scope->next;
}
if (!old_scope) {
if ((new_name = strdup(scope)) == NULL)
goto out_u;
if ((old_scope = (struct stat_scope *)calloc(1, sizeof(*old_scope))) == NULL)
goto out_name;
old_scope->px_id = new_name;
old_scope->px_len = strlen(new_name);
*scope_list = old_scope;
}
return u;
out_name:
free(new_name);
out_u:
free(u);
out:
return NULL;
}