From 78abe618a87df1f63f7a6b439c72173f4bee5b85 Mon Sep 17 00:00:00 2001 From: Krzysztof Piotr Oledzki Date: Sun, 27 Sep 2009 13:23:20 +0200 Subject: [PATCH] [MAJOR] struct chunk rework Add size to struct chunk and simplify the code as there is no longer required to pass sizeof in chunk_printf(). --- include/proto/buffers.h | 61 ++++++++++++- include/types/buffers.h | 3 +- src/buffers.c | 11 ++- src/cfgparse.c | 18 ++-- src/checks.c | 46 +++++----- src/client.c | 8 +- src/dumpstats.c | 187 +++++++++++++++++++--------------------- src/haproxy.c | 2 +- src/proto_http.c | 18 ++-- 9 files changed, 200 insertions(+), 154 deletions(-) diff --git a/include/proto/buffers.h b/include/proto/buffers.h index 3a4367894f..a20ae8ba14 100644 --- a/include/proto/buffers.h +++ b/include/proto/buffers.h @@ -409,8 +409,6 @@ int buffer_si_peekline(struct buffer *buf, char *str, int len); int buffer_replace(struct buffer *b, char *pos, char *end, const char *str); int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len); int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len); -int chunk_printf(struct chunk *chk, int size, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); void buffer_dump(FILE *o, struct buffer *b, int from, int to); @@ -448,6 +446,65 @@ static inline int buffer_feed_chunk(struct buffer *buf, struct chunk *chunk) return ret; } +static inline void chunk_init(struct chunk *chk, char *str, size_t size) { + chk->str = str; + chk->len = 0; + chk->size = size; +} + +/* report 0 in case of error, 1 if OK. */ +static inline int chunk_initlen(struct chunk *chk, char *str, size_t size, size_t len) { + + if (len > size) + return 0; + + chk->str = str; + chk->len = len; + chk->size = size; + + return 1; +} + +static inline void chunk_initstr(struct chunk *chk, char *str) { + chk->str = str; + chk->len = strlen(str); + chk->size = 0; /* mark it read-only */ +} + +static inline int chunk_strcpy(struct chunk *chk, const char *str) { + size_t len; + + len = strlen(str); + + if (unlikely(len > chk->size)) + return 0; + + chk->len = len; + memcpy(chk->str, str, len); + + return 1; +} + +int chunk_printf(struct chunk *chk, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); + +static inline void chunk_reset(struct chunk *chk) { + chk->str = NULL; + chk->len = -1; + chk->size = 0; +} + +static inline void chunk_destroy(struct chunk *chk) { + + if (!chk->size) + return; + + if (chk->str) + free(chk->str); + + chunk_reset(chk); +} + /* * frees the destination chunk if already allocated, allocates a new string, * and copies the source into it. The pointer to the destination string is diff --git a/include/types/buffers.h b/include/types/buffers.h index c7ac91b52c..133285f4c3 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -148,7 +148,8 @@ /* describes a chunk of string */ struct chunk { char *str; /* beginning of the string itself. Might not be 0-terminated */ - int len; /* size of the string from first to last char. <0 = uninit. */ + size_t size; /* total size of the buffer, 0 if the *str is read-only */ + size_t len; /* current size of the string from first to last char. <0 = uninit. */ }; /* needed for a declaration below */ diff --git a/src/buffers.c b/src/buffers.c index 724400f02e..ee00f1c8f0 100644 --- a/src/buffers.c +++ b/src/buffers.c @@ -302,17 +302,20 @@ int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len) /* * Does an snprintf() at the end of chunk , respecting the limit of - * at most chars. If the size is over, nothing is added. Returns + * at most chk->size chars. If the chk->len is over, nothing is added. Returns * the new chunk size. */ -int chunk_printf(struct chunk *chk, int size, const char *fmt, ...) +int chunk_printf(struct chunk *chk, const char *fmt, ...) { va_list argp; int ret; + if (!chk->str || !chk->size) + return 0; + va_start(argp, fmt); - ret = vsnprintf(chk->str + chk->len, size - chk->len, fmt, argp); - if (ret >= size - chk->len) + ret = vsnprintf(chk->str + chk->len, chk->size - chk->len, fmt, argp); + if (ret >= chk->size - chk->len) /* do not copy anything in case of truncation */ chk->str[chk->len] = 0; else diff --git a/src/cfgparse.c b/src/cfgparse.c index b36470bd03..69fd00f4c6 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -873,10 +873,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->fe_sps_lim = defproxy.fe_sps_lim; /* initialize error relocations */ - for (rc = 0; rc < HTTP_ERR_SIZE; rc++) { - if (defproxy.errmsg[rc].str) - chunk_dup(&curproxy->errmsg[rc], &defproxy.errmsg[rc]); - } + for (rc = 0; rc < HTTP_ERR_SIZE; rc++) + chunk_dup(&curproxy->errmsg[rc], &defproxy.errmsg[rc]); curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR; } @@ -975,7 +973,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) defproxy.fwdfor_hdr_len = 0; for (rc = 0; rc < HTTP_ERR_SIZE; rc++) - free(defproxy.errmsg[rc].str); + chunk_destroy(&defproxy.errmsg[rc]); /* we cannot free uri_auth because it might already be used */ init_default_instance(); @@ -3467,9 +3465,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) for (rc = 0; rc < HTTP_ERR_SIZE; rc++) { if (http_err_codes[rc] == errnum) { - free(curproxy->errmsg[rc].str); - curproxy->errmsg[rc].str = err; - curproxy->errmsg[rc].len = errlen; + chunk_destroy(&curproxy->errmsg[rc]); + chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen); break; } } @@ -3528,9 +3525,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) errnum = atol(args[1]); for (rc = 0; rc < HTTP_ERR_SIZE; rc++) { if (http_err_codes[rc] == errnum) { - free(curproxy->errmsg[rc].str); - curproxy->errmsg[rc].str = err; - curproxy->errmsg[rc].len = errlen; + chunk_destroy(&curproxy->errmsg[rc]); + chunk_initlen(&curproxy->errmsg[rc], err, errlen, errlen); break; } } diff --git a/src/checks.c b/src/checks.c index 278f0c1c2a..3ee08081fe 100644 --- a/src/checks.c +++ b/src/checks.c @@ -232,24 +232,23 @@ static void set_server_down(struct server *s) */ xferred = redistribute_pending(s); - msg.len = 0; - msg.str = trash; + chunk_init(&msg, trash, sizeof(trash)); - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, "%sServer %s/%s is DOWN", s->state & SRV_BACKUP ? "Backup " : "", s->proxy->id, s->id); if (s->tracked) - chunk_printf(&msg, sizeof(trash), " via %s/%s", + chunk_printf(&msg, " via %s/%s", s->tracked->proxy->id, s->tracked->id); - chunk_printf(&msg, sizeof(trash), ", reason: %s", get_check_status_description(s->check_status)); + chunk_printf(&msg, ", reason: %s", get_check_status_description(s->check_status)); if (s->check_status >= HCHK_STATUS_L57DATA) - chunk_printf(&msg, sizeof(trash), ", code: %d", s->check_code); + chunk_printf(&msg, ", code: %d", s->check_code); - chunk_printf(&msg, sizeof(trash), ", check duration: %lums", s->check_duration); + chunk_printf(&msg, ", check duration: %lums", s->check_duration); - chunk_printf(&msg, sizeof(trash), ". %d active and %d backup servers left.%s" + chunk_printf(&msg, ". %d active and %d backup servers left.%s" " %d sessions active, %d requeued, %d remaining in queue.\n", s->proxy->srv_act, s->proxy->srv_bck, (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "", @@ -313,22 +312,21 @@ static void set_server_up(struct server *s) { */ xferred = check_for_pending(s); - msg.len = 0; - msg.str = trash; + chunk_init(&msg, trash, sizeof(trash)); - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, "%sServer %s/%s is UP", s->state & SRV_BACKUP ? "Backup " : "", s->proxy->id, s->id); if (s->tracked) - chunk_printf(&msg, sizeof(trash), " via %s/%s", + chunk_printf(&msg, " via %s/%s", s->tracked->proxy->id, s->tracked->id); - chunk_printf(&msg, sizeof(trash), ", reason: %s", get_check_status_description(s->check_status)); + chunk_printf(&msg, ", reason: %s", get_check_status_description(s->check_status)); if (s->check_status >= HCHK_STATUS_L57DATA) - chunk_printf(&msg, sizeof(trash), ", code: %d", s->check_code); + chunk_printf(&msg, ", code: %d", s->check_code); - chunk_printf(&msg, sizeof(trash), ". %d active and %d backup servers online.%s" + chunk_printf(&msg, ". %d active and %d backup servers online.%s" " %d sessions requeued, %d total in queue.\n", s->proxy->srv_act, s->proxy->srv_bck, (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "", @@ -362,20 +360,19 @@ static void set_server_disabled(struct server *s) { */ xferred = redistribute_pending(s); - msg.len = 0; - msg.str = trash; + chunk_init(&msg, trash, sizeof(trash)); - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, "Load-balancing on %sServer %s/%s is disabled", s->state & SRV_BACKUP ? "Backup " : "", s->proxy->id, s->id); if (s->tracked) - chunk_printf(&msg, sizeof(trash), " via %s/%s", + chunk_printf(&msg, " via %s/%s", s->tracked->proxy->id, s->tracked->id); - chunk_printf(&msg, sizeof(trash),". %d active and %d backup servers online.%s" + chunk_printf(&msg,". %d active and %d backup servers online.%s" " %d sessions requeued, %d total in queue.\n", s->proxy->srv_act, s->proxy->srv_bck, (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "", @@ -407,19 +404,18 @@ static void set_server_enabled(struct server *s) { */ xferred = check_for_pending(s); - msg.len = 0; - msg.str = trash; + chunk_init(&msg, trash, sizeof(trash)); - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, "Load-balancing on %sServer %s/%s is enabled again", s->state & SRV_BACKUP ? "Backup " : "", s->proxy->id, s->id); if (s->tracked) - chunk_printf(&msg, sizeof(trash), " via %s/%s", + chunk_printf(&msg, " via %s/%s", s->tracked->proxy->id, s->tracked->id); - chunk_printf(&msg, sizeof(trash), ". %d active and %d backup servers online.%s" + chunk_printf(&msg, ". %d active and %d backup servers online.%s" " %d sessions requeued, %d total in queue.\n", s->proxy->srv_act, s->proxy->srv_bck, (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "", diff --git a/src/client.c b/src/client.c index 88c11312f9..63c5bd29e6 100644 --- a/src/client.c +++ b/src/client.c @@ -279,7 +279,7 @@ int event_accept(int fd) { txn->rsp.sol = txn->rsp.eol = NULL; txn->rsp.som = txn->rsp.eoh = 0; /* relative to the buffer */ txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */ - txn->auth_hdr.len = -1; + chunk_reset(&txn->auth_hdr); if (p->options2 & PR_O2_REQBUG_OK) txn->req.err_pos = -1; /* let buggy requests pass */ @@ -455,13 +455,15 @@ int event_accept(int fd) { * or we're in health check mode with the 'httpchk' option enabled. In * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit. */ - struct chunk msg = { .str = "HTTP/1.0 200 OK\r\n\r\n", .len = 19 }; + struct chunk msg; + chunk_initstr(&msg, "HTTP/1.0 200 OK\r\n\r\n"); stream_int_retnclose(&s->si[0], &msg); /* forge a 200 response */ s->req->analysers = 0; t->expire = s->rep->wex; } else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */ - struct chunk msg = { .str = "OK\n", .len = 3 }; + struct chunk msg; + chunk_initstr(&msg, "OK\n"); stream_int_retnclose(&s->si[0], &msg); /* forge an "OK" response */ s->req->analysers = 0; t->expire = s->rep->wex; diff --git a/src/dumpstats.c b/src/dumpstats.c index 390f853c58..86ce23e86e 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -213,9 +213,9 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx return 0; } -int print_csv_header(struct chunk *msg, int size) +int print_csv_header(struct chunk *msg) { - return chunk_printf(msg, size, + return chunk_printf(msg, "# pxname,svname," "qcur,qmax," "scur,smax,slim,stot," @@ -532,8 +532,7 @@ int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri) struct chunk msg; unsigned int up; - msg.len = 0; - msg.str = trash; + chunk_init(&msg, trash, sizeof(trash)); switch (s->data_state) { case DATA_ST_INIT: @@ -545,7 +544,7 @@ int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri) case DATA_ST_HEAD: if (s->data_ctx.stats.flags & STAT_SHOW_STAT) { - print_csv_header(&msg, sizeof(trash)); + print_csv_header(&msg); if (buffer_write_chunk(rep, &msg) >= 0) return 0; } @@ -556,7 +555,7 @@ int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri) case DATA_ST_INFO: up = (now.tv_sec - start_date.tv_sec); if (s->data_ctx.stats.flags & STAT_SHOW_INFO) { - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, "Name: " PRODUCT_NAME "\n" "Version: " HAPROXY_VERSION "\n" "Release_date: " HAPROXY_DATE "\n" @@ -667,12 +666,11 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) struct chunk msg; unsigned int up; - msg.len = 0; - msg.str = trash; + chunk_init(&msg, trash, sizeof(trash)); switch (s->data_state) { case DATA_ST_INIT: - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, "HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n" "Connection: close\r\n" @@ -680,10 +678,10 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) (s->data_ctx.stats.flags & STAT_FMT_CSV) ? "text/plain" : "text/html"); if (uri->refresh > 0 && !(s->data_ctx.stats.flags & STAT_NO_REFRESH)) - chunk_printf(&msg, sizeof(trash), "Refresh: %d\r\n", + chunk_printf(&msg, "Refresh: %d\r\n", uri->refresh); - chunk_printf(&msg, sizeof(trash), "\r\n"); + chunk_printf(&msg, "\r\n"); s->txn.status = 200; if (buffer_write_chunk(rep, &msg) >= 0) @@ -709,7 +707,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) case DATA_ST_HEAD: if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) { /* WARNING! This must fit in the first buffer !!! */ - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, "Statistics Report for " PRODUCT_NAME "%s%s\n" "\n" "