mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-14 07:24:32 +00:00
b686afd568
The trash buffers are becoming increasingly complex to deal with due to the code's modularity allowing some functions to be chained and causing the same chunk buffers to be used multiple times along the chain, possibly corrupting each other. In fact the trash were designed from scratch for explicitly not surviving a function call but string manipulation makes this impossible most of the time while not fullfilling the need for reliable temporary chunks. Here we introduce the ability to allocate a temporary trash chunk which is reserved, so that it will not conflict with the trash chunks other functions use, and will even support reentrant calls (eg: build_logline). For this, we create a new pool which is exactly the size of a usual chunk buffer plus the size of the chunk struct so that these chunks when allocated are exactly the same size as the ones returned by get_trash_buffer(). These chunks may fail so the caller must check them, and the caller is also responsible for freeing them. The code focuses on minimal changes and ease of reliable backporting because it will be needed in stable versions in order to support next patch.
227 lines
5.6 KiB
C
227 lines
5.6 KiB
C
/*
|
|
* include/common/chunk.h
|
|
* Chunk management definitions, macros and inline functions.
|
|
*
|
|
* Copyright (C) 2000-2012 Willy Tarreau - w@1wt.eu
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation, version 2.1
|
|
* exclusively.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef _TYPES_CHUNK_H
|
|
#define _TYPES_CHUNK_H
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <common/config.h>
|
|
#include <common/memory.h>
|
|
|
|
|
|
/* describes a chunk of string */
|
|
struct chunk {
|
|
char *str; /* beginning of the string itself. Might not be 0-terminated */
|
|
int size; /* total size of the buffer, 0 if the *str is read-only */
|
|
int len; /* current size of the string from first to last char. <0 = uninit. */
|
|
};
|
|
|
|
struct pool_head *pool2_trash;
|
|
|
|
/* function prototypes */
|
|
|
|
int chunk_printf(struct chunk *chk, const char *fmt, ...)
|
|
__attribute__ ((format(printf, 2, 3)));
|
|
|
|
int chunk_appendf(struct chunk *chk, const char *fmt, ...)
|
|
__attribute__ ((format(printf, 2, 3)));
|
|
|
|
int chunk_htmlencode(struct chunk *dst, struct chunk *src);
|
|
int chunk_asciiencode(struct chunk *dst, struct chunk *src, char qc);
|
|
int chunk_strcmp(const struct chunk *chk, const char *str);
|
|
int chunk_strcasecmp(const struct chunk *chk, const char *str);
|
|
int alloc_trash_buffers(int bufsize);
|
|
void free_trash_buffers(void);
|
|
struct chunk *get_trash_chunk(void);
|
|
struct chunk *alloc_trash_chunk(void);
|
|
|
|
/*
|
|
* free a trash chunk allocated by alloc_trash_chunk(). NOP on NULL.
|
|
*/
|
|
static inline void free_trash_chunk(struct chunk *chunk)
|
|
{
|
|
pool_free2(pool2_trash, chunk);
|
|
}
|
|
|
|
|
|
static inline void chunk_reset(struct chunk *chk)
|
|
{
|
|
chk->len = 0;
|
|
}
|
|
|
|
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, int len)
|
|
{
|
|
|
|
if (len < 0 || (size && len > size))
|
|
return 0;
|
|
|
|
chk->str = str;
|
|
chk->len = len;
|
|
chk->size = size;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* this is only for temporary manipulation, the chunk is read-only */
|
|
static inline void chunk_initstr(struct chunk *chk, const char *str)
|
|
{
|
|
chk->str = (char *)str;
|
|
chk->len = strlen(str);
|
|
chk->size = 0; /* mark it read-only */
|
|
}
|
|
|
|
/* copies str into <chk> followed by a trailing zero. Returns 0 in
|
|
* case of failure.
|
|
*/
|
|
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 + 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* appends str after <chk> followed by a trailing zero. Returns 0 in
|
|
* case of failure.
|
|
*/
|
|
static inline int chunk_strcat(struct chunk *chk, const char *str)
|
|
{
|
|
size_t len;
|
|
|
|
len = strlen(str);
|
|
|
|
if (unlikely(chk->len < 0 || chk->len + len >= chk->size))
|
|
return 0;
|
|
|
|
memcpy(chk->str + chk->len, str, len + 1);
|
|
chk->len += len;
|
|
return 1;
|
|
}
|
|
|
|
/* appends <nb> characters from str after <chk>.
|
|
* Returns 0 in case of failure.
|
|
*/
|
|
static inline int chunk_strncat(struct chunk *chk, const char *str, int nb)
|
|
{
|
|
if (unlikely(chk->len < 0 || chk->len + nb >= chk->size))
|
|
return 0;
|
|
|
|
memcpy(chk->str + chk->len, str, nb);
|
|
chk->len += nb;
|
|
return 1;
|
|
}
|
|
|
|
/* Adds a trailing zero to the current chunk and returns the pointer to the
|
|
* following part. The purpose is to be able to use a chunk as a series of
|
|
* short independant strings with chunk_* functions, which do not need to be
|
|
* released. Returns NULL if no space is available to ensure that the new
|
|
* string will have its own trailing zero. For example :
|
|
* chunk_init(&trash);
|
|
* pid = chunk_newstr(&trash);
|
|
* chunk_appendf(&trash, "%d", getpid()));
|
|
* name = chunk_newstr(&trash);
|
|
* chunk_appendf(&trash, "%s", gethosname());
|
|
* printf("hostname=<%s>, pid=<%d>\n", name, pid);
|
|
*/
|
|
static inline char *chunk_newstr(struct chunk *chk)
|
|
{
|
|
if (chk->len < 0 || chk->len + 1 >= chk->size)
|
|
return NULL;
|
|
|
|
chk->str[chk->len++] = 0;
|
|
return chk->str + chk->len;
|
|
}
|
|
|
|
static inline void chunk_drop(struct chunk *chk)
|
|
{
|
|
chk->str = NULL;
|
|
chk->len = -1;
|
|
chk->size = 0;
|
|
}
|
|
|
|
static inline void chunk_destroy(struct chunk *chk)
|
|
{
|
|
if (!chk->size)
|
|
return;
|
|
|
|
free(chk->str);
|
|
chunk_drop(chk);
|
|
}
|
|
|
|
/*
|
|
* frees the destination chunk if already allocated, allocates a new string,
|
|
* and copies the source into it. The new chunk will have extra room for a
|
|
* trailing zero unless the source chunk was actually full. The pointer to
|
|
* the destination string is returned, or NULL if the allocation fails or if
|
|
* any pointer is NULL.
|
|
*/
|
|
static inline char *chunk_dup(struct chunk *dst, const struct chunk *src)
|
|
{
|
|
if (!dst || !src || src->len < 0 || !src->str)
|
|
return NULL;
|
|
|
|
if (dst->size)
|
|
free(dst->str);
|
|
dst->len = src->len;
|
|
dst->size = src->len;
|
|
if (dst->size < src->size || !src->size)
|
|
dst->size++;
|
|
|
|
dst->str = (char *)malloc(dst->size);
|
|
if (!dst->str) {
|
|
dst->len = 0;
|
|
dst->size = 0;
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(dst->str, src->str, dst->len);
|
|
if (dst->len < dst->size)
|
|
dst->str[dst->len] = 0;
|
|
|
|
return dst->str;
|
|
}
|
|
|
|
#endif /* _TYPES_CHUNK_H */
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 8
|
|
* c-basic-offset: 8
|
|
* End:
|
|
*/
|