/src/haproxy/include/haproxy/chunk.h
Line | Count | Source |
1 | | /* |
2 | | * include/haproxy/chunk.h |
3 | | * Chunk management definitions, macros and inline functions. |
4 | | * |
5 | | * Copyright (C) 2000-2012 Willy Tarreau - w@1wt.eu |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation, version 2.1 |
10 | | * exclusively. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #ifndef _HAPROXY_CHUNK_H |
23 | | #define _HAPROXY_CHUNK_H |
24 | | |
25 | | #include <stdlib.h> |
26 | | #include <string.h> |
27 | | |
28 | | #include <import/ist.h> |
29 | | #include <haproxy/api.h> |
30 | | #include <haproxy/buf-t.h> |
31 | | #include <haproxy/pool.h> |
32 | | |
33 | | |
34 | | extern struct pool_head *pool_head_trash; |
35 | | extern struct pool_head *pool_head_large_trash; |
36 | | extern struct pool_head *pool_head_small_trash; |
37 | | |
38 | | /* function prototypes */ |
39 | | |
40 | | int chunk_printf(struct buffer *chk, const char *fmt, ...) |
41 | | __attribute__ ((format(printf, 2, 3))); |
42 | | |
43 | | int chunk_appendf(struct buffer *chk, const char *fmt, ...) |
44 | | __attribute__ ((format(printf, 2, 3))); |
45 | | |
46 | | int chunk_htmlencode(struct buffer *dst, struct buffer *src); |
47 | | int chunk_asciiencode(struct buffer *dst, struct buffer *src, char qc); |
48 | | int chunk_strcmp(const struct buffer *chk, const char *str); |
49 | | int chunk_strcasecmp(const struct buffer *chk, const char *str); |
50 | | struct buffer *get_trash_chunk(void); |
51 | | struct buffer *get_large_trash_chunk(void); |
52 | | struct buffer *get_small_trash_chunk(void); |
53 | | struct buffer *get_trash_chunk_sz(size_t size); |
54 | | struct buffer *get_best_trash_chunk(const struct buffer *buf, size_t size); |
55 | | struct buffer *get_larger_trash_chunk(struct buffer *chunk); |
56 | | int init_trash_buffers(int first); |
57 | | |
58 | | static inline void chunk_reset(struct buffer *chk) |
59 | 0 | { |
60 | 0 | chk->data = 0; |
61 | 0 | } |
62 | | |
63 | | static inline void chunk_init(struct buffer *chk, char *str, size_t size) |
64 | 0 | { |
65 | 0 | chk->area = str; |
66 | 0 | chk->head = 0; |
67 | 0 | chk->data = 0; |
68 | 0 | chk->size = size; |
69 | 0 | } |
70 | | |
71 | | /* report 0 in case of error, 1 if OK. */ |
72 | | static inline int chunk_initlen(struct buffer *chk, char *str, size_t size, |
73 | | int len) |
74 | 0 | { |
75 | 0 |
|
76 | 0 | if (len < 0 || (size && len > size)) |
77 | 0 | return 0; |
78 | 0 |
|
79 | 0 | chk->area = str; |
80 | 0 | chk->head = 0; |
81 | 0 | chk->data = len; |
82 | 0 | chk->size = size; |
83 | 0 |
|
84 | 0 | return 1; |
85 | 0 | } |
86 | | |
87 | | /* this is only for temporary manipulation, the chunk is read-only */ |
88 | | static inline void chunk_initstr(struct buffer *chk, const char *str) |
89 | 0 | { |
90 | 0 | chk->area = (char *)str; |
91 | 0 | chk->head = 0; |
92 | 0 | chk->data = strlen(str); |
93 | 0 | chk->size = 0; /* mark it read-only */ |
94 | 0 | } |
95 | | |
96 | | /* |
97 | | * Allocate a trash chunk from the reentrant pool. The buffer starts at the |
98 | | * end of the chunk. This chunk must be freed using free_trash_chunk(). This |
99 | | * call may fail and the caller is responsible for checking that the returned |
100 | | * pointer is not NULL. |
101 | | */ |
102 | | static forceinline struct buffer *alloc_trash_chunk(void) |
103 | 0 | { |
104 | 0 | struct buffer *chunk; |
105 | 0 |
|
106 | 0 | chunk = pool_alloc(pool_head_trash); |
107 | 0 | if (chunk) { |
108 | 0 | char *buf = (char *)chunk + sizeof(struct buffer); |
109 | 0 | *buf = 0; |
110 | 0 | chunk_init(chunk, buf, |
111 | 0 | pool_head_trash->size - sizeof(struct buffer)); |
112 | 0 | } |
113 | 0 | return chunk; |
114 | 0 | } |
115 | | |
116 | | /* |
117 | | * Allocate a large trash chunk from the reentrant pool. The buffer starts at |
118 | | * the end of the chunk. This chunk must be freed using free_trash_chunk(). This |
119 | | * call may fail and the caller is responsible for checking that the returned |
120 | | * pointer is not NULL. |
121 | | */ |
122 | | static forceinline struct buffer *alloc_large_trash_chunk(void) |
123 | 0 | { |
124 | 0 | struct buffer *chunk; |
125 | 0 |
|
126 | 0 | if (!pool_head_large_trash) |
127 | 0 | return NULL; |
128 | 0 |
|
129 | 0 | chunk = pool_alloc(pool_head_large_trash); |
130 | 0 | if (chunk) { |
131 | 0 | char *buf = (char *)chunk + sizeof(struct buffer); |
132 | 0 | *buf = 0; |
133 | 0 | chunk_init(chunk, buf, |
134 | 0 | pool_head_large_trash->size - sizeof(struct buffer)); |
135 | 0 | } |
136 | 0 | return chunk; |
137 | 0 | } |
138 | | |
139 | | /* |
140 | | * Allocate a small trash chunk from the reentrant pool. The buffer starts at |
141 | | * the end of the chunk. This chunk must be freed using free_trash_chunk(). This |
142 | | * call may fail and the caller is responsible for checking that the returned |
143 | | * pointer is not NULL. |
144 | | */ |
145 | | static forceinline struct buffer *alloc_small_trash_chunk(void) |
146 | 0 | { |
147 | 0 | struct buffer *chunk; |
148 | 0 |
|
149 | 0 | if (!pool_head_small_trash) |
150 | 0 | return NULL; |
151 | 0 |
|
152 | 0 | chunk = pool_alloc(pool_head_small_trash); |
153 | 0 | if (chunk) { |
154 | 0 | char *buf = (char *)chunk + sizeof(struct buffer); |
155 | 0 | *buf = 0; |
156 | 0 | chunk_init(chunk, buf, |
157 | 0 | pool_head_small_trash->size - sizeof(struct buffer)); |
158 | 0 | } |
159 | 0 | return chunk; |
160 | 0 | } |
161 | | |
162 | | /* |
163 | | * Allocate a trash chunk accordingly to the requested size. This chunk must be |
164 | | * freed using free_trash_chunk(). This call may fail and the caller is |
165 | | * responsible for checking that the returned pointer is not NULL. |
166 | | */ |
167 | | static forceinline struct buffer *alloc_trash_chunk_sz(size_t size) |
168 | 0 | { |
169 | 0 | if (size <= pool_head_trash->size) |
170 | 0 | return alloc_trash_chunk(); |
171 | 0 | else if (pool_head_large_trash && size <= pool_head_large_trash->size) |
172 | 0 | return alloc_large_trash_chunk(); |
173 | 0 | else |
174 | 0 | return NULL; |
175 | 0 | } |
176 | | /* Returns a trash chunk accordingly to the requested size and never larger |
177 | | * that the buffer <buf>. So if <buf> is a large buffer, |
178 | | * alloc_trash_chunk_sz() function is called. Otherwise, if the size is |
179 | | * smaller enough, a regular buffer is allocated. If <size> is too big and |
180 | | * <buf> is not a large buffer, NULL is returned. |
181 | | */ |
182 | | static forceinline struct buffer *alloc_best_trash_chunk(const struct buffer *buf, size_t size) |
183 | 0 | { |
184 | 0 | if (pool_head_large_trash && buf->size == pool_head_large_trash->size) |
185 | 0 | return alloc_trash_chunk_sz(size); |
186 | 0 | else if (size <= pool_head_trash->size) |
187 | 0 | return alloc_trash_chunk(); |
188 | 0 | else |
189 | 0 | return NULL; |
190 | 0 | } |
191 | | |
192 | | /* |
193 | | * free a trash chunk allocated by alloc_trash_chunk(). NOP on NULL. |
194 | | */ |
195 | | static forceinline void free_trash_chunk(struct buffer *chunk) |
196 | 0 | { |
197 | 0 | if (pool_head_small_trash && chunk && chunk->size == pool_head_small_trash->size - sizeof(struct buffer)) |
198 | 0 | pool_free(pool_head_small_trash, chunk); |
199 | 0 | else if (pool_head_large_trash && chunk && chunk->size == pool_head_large_trash->size - sizeof(struct buffer)) |
200 | 0 | pool_free(pool_head_large_trash, chunk); |
201 | 0 | else |
202 | 0 | pool_free(pool_head_trash, chunk); |
203 | 0 | } |
204 | | |
205 | | /* copies chunk <src> into <chk>. Returns 0 in case of failure. */ |
206 | | static inline int chunk_cpy(struct buffer *chk, const struct buffer *src) |
207 | 0 | { |
208 | 0 | if (unlikely(src->data > chk->size)) |
209 | 0 | return 0; |
210 | 0 |
|
211 | 0 | chk->data = src->data; |
212 | 0 | memcpy(chk->area, src->area, src->data); |
213 | 0 | return 1; |
214 | 0 | } |
215 | | |
216 | | /* copies memory area <src> into <chk> for <len> bytes. Returns 0 in |
217 | | * case of failure. No trailing zero is added. |
218 | | */ |
219 | | static inline int chunk_memcpy(struct buffer *chk, const char *src, |
220 | | size_t len) |
221 | 0 | { |
222 | 0 | if (unlikely(len > chk->size)) |
223 | 0 | return 0; |
224 | 0 |
|
225 | 0 | chk->data = len; |
226 | 0 | memcpy(chk->area, src, len); |
227 | 0 |
|
228 | 0 | return 1; |
229 | 0 | } |
230 | | |
231 | | /* appends memory area <src> after <chk> for <len> bytes. Returns 0 in |
232 | | * case of failure. No trailing zero is added. |
233 | | */ |
234 | | static inline int chunk_memcat(struct buffer *chk, const char *src, |
235 | | size_t len) |
236 | 0 | { |
237 | 0 | if (unlikely(chk->data + len > chk->size)) |
238 | 0 | return 0; |
239 | 0 |
|
240 | 0 | memcpy(chk->area + chk->data, src, len); |
241 | 0 | chk->data += len; |
242 | 0 | return 1; |
243 | 0 | } |
244 | | |
245 | | /* appends ist <src> after <chk>. Returns 0 in case of failure. */ |
246 | | static inline int chunk_istcat(struct buffer *chk, const struct ist src) |
247 | 0 | { |
248 | 0 | return chunk_memcat(chk, istptr(src), istlen(src)); |
249 | 0 | } |
250 | | |
251 | | /* appends chunk <src> after <chk>. Returns 0 in case of failure. */ |
252 | | static inline int chunk_cat(struct buffer *chk, const struct buffer *src) |
253 | 0 | { |
254 | 0 | return chunk_memcat(chk, src->area, src->data); |
255 | 0 | } |
256 | | |
257 | | /* copies str into <chk> followed by a trailing zero. Returns 0 in |
258 | | * case of failure. |
259 | | */ |
260 | | static inline int chunk_strcpy(struct buffer *chk, const char *str) |
261 | 0 | { |
262 | 0 | size_t len; |
263 | 0 |
|
264 | 0 | len = strlen(str); |
265 | 0 |
|
266 | 0 | if (unlikely(len >= chk->size)) |
267 | 0 | return 0; |
268 | 0 |
|
269 | 0 | chk->data = len; |
270 | 0 | memcpy(chk->area, str, len + 1); |
271 | 0 |
|
272 | 0 | return 1; |
273 | 0 | } |
274 | | |
275 | | /* copies at most <max> chars from str into <chk> followed by a trailing zero. |
276 | | * Returns 0 in case of failure. |
277 | | */ |
278 | | static inline int chunk_strncpy(struct buffer *chk, const char *str, size_t max) |
279 | 0 | { |
280 | 0 | size_t len; |
281 | 0 |
|
282 | 0 | len = strlen(str); |
283 | 0 | if (len > max) |
284 | 0 | len = max; |
285 | 0 |
|
286 | 0 | if (unlikely(len >= chk->size)) |
287 | 0 | return 0; |
288 | 0 |
|
289 | 0 | memcpy(chk->area, str, len); |
290 | 0 | chk->area[len] = 0; |
291 | 0 | chk->data = len; |
292 | 0 | return 1; |
293 | 0 | } |
294 | | |
295 | | /* appends str after <chk> followed by a trailing zero. Returns 0 in |
296 | | * case of failure. |
297 | | */ |
298 | | static inline int chunk_strcat(struct buffer *chk, const char *str) |
299 | 0 | { |
300 | 0 | size_t len; |
301 | 0 |
|
302 | 0 | len = strlen(str); |
303 | 0 |
|
304 | 0 | if (unlikely(chk->data + len >= chk->size)) |
305 | 0 | return 0; |
306 | 0 |
|
307 | 0 | memcpy(chk->area + chk->data, str, len + 1); |
308 | 0 | chk->data += len; |
309 | 0 | return 1; |
310 | 0 | } |
311 | | |
312 | | /* Adds a trailing zero to the current chunk and returns the pointer to the |
313 | | * following part. The purpose is to be able to use a chunk as a series of |
314 | | * short independent strings with chunk_* functions, which do not need to be |
315 | | * released. Returns NULL if no space is available to ensure that the new |
316 | | * string will have its own trailing zero. For example : |
317 | | * chunk_init(&trash); |
318 | | * pid = chunk_newstr(&trash); |
319 | | * chunk_appendf(&trash, "%d", getpid())); |
320 | | * name = chunk_newstr(&trash); |
321 | | * chunk_appendf(&trash, "%s", gethosname()); |
322 | | * printf("hostname=<%s>, pid=<%d>\n", name, pid); |
323 | | */ |
324 | | static inline char *chunk_newstr(struct buffer *chk) |
325 | 0 | { |
326 | 0 | if (chk->data + 1 >= chk->size) |
327 | 0 | return NULL; |
328 | | |
329 | 0 | chk->area[chk->data++] = 0; |
330 | 0 | return chk->area + chk->data; |
331 | 0 | } |
332 | | |
333 | | static inline void chunk_drop(struct buffer *chk) |
334 | 0 | { |
335 | 0 | chk->area = NULL; |
336 | 0 | chk->data = -1; |
337 | 0 | chk->size = 0; |
338 | 0 | } |
339 | | |
340 | | static inline void chunk_destroy(struct buffer *chk) |
341 | 0 | { |
342 | 0 | if (!chk->size) |
343 | 0 | return; |
344 | 0 |
|
345 | 0 | free(chk->area); |
346 | 0 | chunk_drop(chk); |
347 | 0 | } |
348 | | |
349 | | /* |
350 | | * frees the destination chunk if already allocated, allocates a new string, |
351 | | * and copies the source into it. The new chunk will have extra room for a |
352 | | * trailing zero unless the source chunk was actually full. The pointer to |
353 | | * the destination string is returned, or NULL if the allocation fails or if |
354 | | * any pointer is NULL. |
355 | | */ |
356 | | static inline char *chunk_dup(struct buffer *dst, const struct buffer *src) |
357 | 0 | { |
358 | 0 | if (!dst || !src || !src->area) |
359 | 0 | return NULL; |
360 | 0 |
|
361 | 0 | if (dst->size) |
362 | 0 | free(dst->area); |
363 | 0 | dst->head = src->head; |
364 | 0 | dst->data = src->data; |
365 | 0 | dst->size = src->data; |
366 | 0 | if (dst->size < src->size || !src->size) |
367 | 0 | dst->size++; |
368 | 0 |
|
369 | 0 | dst->area = malloc(dst->size); |
370 | 0 | if (!dst->area) { |
371 | 0 | dst->head = 0; |
372 | 0 | dst->data = 0; |
373 | 0 | dst->size = 0; |
374 | 0 | return NULL; |
375 | 0 | } |
376 | 0 |
|
377 | 0 | memcpy(dst->area, src->area, dst->data); |
378 | 0 | if (dst->data < dst->size) |
379 | 0 | dst->area[dst->data] = 0; |
380 | 0 |
|
381 | 0 | return dst->area; |
382 | 0 | } |
383 | | |
384 | | #endif /* _HAPROXY_CHUNK_H */ |
385 | | |
386 | | /* |
387 | | * Local variables: |
388 | | * c-indent-level: 8 |
389 | | * c-basic-offset: 8 |
390 | | * End: |
391 | | */ |