CHANNEL(callid): Give dialplan access to the callid.
[asterisk/asterisk.git] / main / stringfields.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Digium, Inc.
5  *
6  * Kevin P. Fleming <kpfleming@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief String fields
22  *
23  * \author Kevin P. Fleming <kpfleming@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 #include "asterisk/stringfields.h"
29 #include "asterisk/utils.h"
30
31 /* this is a little complex... string fields are stored with their
32    allocated size in the bytes preceding the string; even the
33    constant 'empty' string has to be this way, so the code that
34    checks to see if there is enough room for a new string doesn't
35    have to have any special case checks
36 */
37
38 static const struct {
39         ast_string_field_allocation allocation;
40         char string[1];
41 } __ast_string_field_empty_buffer;
42
43 ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string;
44
45 #define ALLOCATOR_OVERHEAD 48
46
47 static size_t optimal_alloc_size(size_t size)
48 {
49         unsigned int count;
50
51         size += ALLOCATOR_OVERHEAD;
52
53         for (count = 1; size; size >>= 1, count++);
54
55         return (1 << count) - ALLOCATOR_OVERHEAD;
56 }
57
58 static void *calloc_wrapper(unsigned int num_structs, size_t struct_size,
59         const char *file, int lineno, const char *func)
60 {
61         return __ast_calloc(num_structs, struct_size, file, lineno, func);
62 }
63
64 /*! \brief add a new block to the pool.
65  * We can only allocate from the topmost pool, so the
66  * fields in *mgr reflect the size of that only.
67  */
68 static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
69         size_t size, const char *file, int lineno, const char *func)
70 {
71         struct ast_string_field_pool *pool;
72         size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
73
74         if (!(pool = calloc_wrapper(1, alloc_size, file, lineno, func))) {
75                 return -1;
76         }
77
78         pool->prev = *pool_head;
79         pool->size = alloc_size - sizeof(*pool);
80         *pool_head = pool;
81         mgr->last_alloc = NULL;
82
83         return 0;
84 }
85
86 static void reset_field(const char **p)
87 {
88         *p = __ast_string_field_empty;
89 }
90
91 /*!
92  * \brief Internal cleanup function
93  * \internal
94  * \param mgr
95  * \param pool_head
96  * \param cleanup_type
97  *           0: Reset all string fields and free all pools except the last or embedded pool.
98  *              Keep the internal management structures so the structure can be reused.
99  *          -1: Reset all string fields and free all pools except the embedded pool.
100  *              Free the internal management structures.
101  * \param file
102  * \param lineno
103  * \param func
104  *
105  * \retval 0 Success
106  * \retval -1 Failure
107  */
108 int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr,
109         struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type,
110         const char *file, int lineno, const char *func)
111 {
112         struct ast_string_field_pool *cur = NULL;
113         struct ast_string_field_pool *preserve = NULL;
114
115         /* reset all the fields regardless of cleanup type */
116         AST_VECTOR_CALLBACK_VOID(&mgr->string_fields, reset_field);
117
118         switch (cleanup_type) {
119         case AST_STRINGFIELD_DESTROY:
120                 AST_VECTOR_FREE(&mgr->string_fields);
121
122                 if (mgr->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */
123                         preserve = mgr->embedded_pool;
124                         preserve->used = preserve->active = 0;
125                 }
126
127                 break;
128         case AST_STRINGFIELD_RESET:
129                 /* Preserve the embedded pool if there is one, otherwise the last pool */
130                 if (mgr->embedded_pool) {
131                         preserve = mgr->embedded_pool;
132                 } else {
133                         if (*pool_head == NULL) {
134                                 ast_log(LOG_WARNING, "trying to reset empty pool\n");
135                                 return -1;
136                         }
137                         preserve = *pool_head;
138                 }
139                 preserve->used = preserve->active = 0;
140                 break;
141         default:
142                 return -1;
143         }
144
145         cur = *pool_head;
146         while (cur) {
147                 struct ast_string_field_pool *prev = cur->prev;
148
149                 if (cur != preserve) {
150                         ast_free(cur);
151                 }
152                 cur = prev;
153         }
154
155         *pool_head = preserve;
156         if (preserve) {
157                 preserve->prev = NULL;
158         }
159
160         return 0;
161 }
162
163 /*!
164  * \brief Internal initialization function
165  * \internal
166  * \param mgr
167  * \param pool_head
168  * \param needed
169  * \param file
170  * \param lineno
171  * \param func
172  *
173  * \retval 0 Success
174  * \retval -1 Failure
175  */
176 int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
177         int needed, const char *file, int lineno, const char *func)
178 {
179         const char **p = (const char **) pool_head + 1;
180         size_t initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
181
182         if (needed <= 0) {
183                 return __ast_string_field_free_memory(mgr, pool_head, needed, file, lineno, func);
184         }
185
186         mgr->last_alloc = NULL;
187 #if defined(__AST_DEBUG_MALLOC)
188         mgr->owner_file = file;
189         mgr->owner_func = func;
190         mgr->owner_line = lineno;
191 #endif
192
193         if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) {
194                 return -1;
195         }
196
197         while ((struct ast_string_field_mgr *) p != mgr) {
198                 AST_VECTOR_APPEND(&mgr->string_fields, p);
199                 *p++ = __ast_string_field_empty;
200         }
201
202         *pool_head = NULL;
203         mgr->embedded_pool = NULL;
204         if (add_string_pool(mgr, pool_head, needed, file, lineno, func)) {
205                 AST_VECTOR_FREE(&mgr->string_fields);
206                 return -1;
207         }
208
209         return 0;
210 }
211
212 ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
213         struct ast_string_field_pool **pool_head, size_t needed)
214 {
215         char *result = NULL;
216         size_t space = (*pool_head)->size - (*pool_head)->used;
217         size_t to_alloc;
218
219         /* Make room for ast_string_field_allocation and make it a multiple of that. */
220         to_alloc = ast_make_room_for(needed, ast_string_field_allocation);
221         ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0);
222
223         if (__builtin_expect(to_alloc > space, 0)) {
224                 size_t new_size = (*pool_head)->size;
225
226                 while (new_size < to_alloc) {
227                         new_size *= 2;
228                 }
229
230 #if defined(__AST_DEBUG_MALLOC)
231                 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
232                         return NULL;
233 #else
234                 if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
235                         return NULL;
236 #endif
237         }
238
239         /* pool->base is always aligned (gcc aligned attribute). We ensure that
240          * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation)
241          * causing result to always be aligned as well; which in turn fixes that
242          * AST_STRING_FIELD_ALLOCATION(result) is aligned. */
243         result = (*pool_head)->base + (*pool_head)->used;
244         (*pool_head)->used += to_alloc;
245         (*pool_head)->active += needed;
246         result += ast_alignof(ast_string_field_allocation);
247         AST_STRING_FIELD_ALLOCATION(result) = needed;
248         mgr->last_alloc = result;
249
250         return result;
251 }
252
253 int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
254         struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr)
255 {
256         ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr);
257         size_t space = (*pool_head)->size - (*pool_head)->used;
258
259         if (*ptr != mgr->last_alloc) {
260                 return 1;
261         }
262
263         if (space < grow) {
264                 return 1;
265         }
266
267         (*pool_head)->used += grow;
268         (*pool_head)->active += grow;
269         AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
270
271         return 0;
272 }
273
274 void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
275         const ast_string_field ptr)
276 {
277         struct ast_string_field_pool *pool, *prev;
278
279         if (ptr == __ast_string_field_empty) {
280                 return;
281         }
282
283         for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) {
284                 if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) {
285                         pool->active -= AST_STRING_FIELD_ALLOCATION(ptr);
286                         if (pool->active == 0) {
287                                 if (prev) {
288                                         prev->prev = pool->prev;
289                                         ast_free(pool);
290                                 } else {
291                                         pool->used = 0;
292                                 }
293                         }
294                         break;
295                 }
296         }
297 }
298
299 void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
300         struct ast_string_field_pool **pool_head, ast_string_field *ptr,
301         const char *format, va_list ap)
302 {
303         size_t needed;
304         size_t available;
305         size_t space = (*pool_head)->size - (*pool_head)->used;
306         int res;
307         ssize_t grow;
308         char *target;
309         va_list ap2;
310
311         /* if the field already has space allocated, try to reuse it;
312            otherwise, try to use the empty space at the end of the current
313            pool
314         */
315         if (*ptr != __ast_string_field_empty) {
316                 target = (char *) *ptr;
317                 available = AST_STRING_FIELD_ALLOCATION(*ptr);
318                 if (*ptr == mgr->last_alloc) {
319                         available += space;
320                 }
321         } else {
322                 /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation)
323                  * so we don't need to re-align anything here.
324                  */
325                 target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation);
326                 if (space > ast_alignof(ast_string_field_allocation)) {
327                         available = space - ast_alignof(ast_string_field_allocation);
328                 } else {
329                         available = 0;
330                 }
331         }
332
333         va_copy(ap2, ap);
334         res = vsnprintf(target, available, format, ap2);
335         va_end(ap2);
336
337         if (res < 0) {
338                 /* Are we out of memory? */
339                 return;
340         }
341         if (res == 0) {
342                 __ast_string_field_release_active(*pool_head, *ptr);
343                 *ptr = __ast_string_field_empty;
344                 return;
345         }
346         needed = (size_t)res + 1; /* NUL byte */
347
348         if (needed > available) {
349                 /* the allocation could not be satisfied using the field's current allocation
350                    (if it has one), or the space available in the pool (if it does not). allocate
351                    space for it, adding a new string pool if necessary.
352                 */
353                 if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) {
354                         return;
355                 }
356                 vsprintf(target, format, ap);
357                 va_end(ap); /* XXX va_end without va_start? */
358                 __ast_string_field_release_active(*pool_head, *ptr);
359                 *ptr = target;
360         } else if (*ptr != target) {
361                 /* the allocation was satisfied using available space in the pool, but not
362                    using the space already allocated to the field
363                 */
364                 __ast_string_field_release_active(*pool_head, *ptr);
365                 mgr->last_alloc = *ptr = target;
366                 ast_assert(needed < (ast_string_field_allocation)-1);
367                 AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed;
368                 (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation);
369                 (*pool_head)->active += needed;
370         } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {
371                 /* the allocation was satisfied by using available space in the pool *and*
372                    the field was the last allocated field from the pool, so it grew
373                 */
374                 AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
375                 (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation);
376                 (*pool_head)->active += grow;
377         }
378 }
379
380 void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
381         struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, ...)
382 {
383         va_list ap;
384
385         va_start(ap, format);
386         __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap);
387         va_end(ap);
388 }
389
390 void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size,
391         size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, const char *file,
392         int lineno, const char *func)
393 {
394         struct ast_string_field_mgr *mgr;
395         struct ast_string_field_pool *pool;
396         struct ast_string_field_pool **pool_head;
397         size_t pool_size_needed = sizeof(*pool) + pool_size;
398         size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed);
399         void *allocation;
400         const char **p;
401         size_t initial_vector_size;
402
403         ast_assert(num_structs == 1);
404
405         if (!(allocation = calloc_wrapper(num_structs, size_to_alloc, file, lineno, func))) {
406                 return NULL;
407         }
408
409         mgr = allocation + field_mgr_offset;
410
411         pool = allocation + struct_size;
412         pool_head = allocation + field_mgr_pool_offset;
413         p = (const char **) pool_head + 1;
414         initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p);
415
416         if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) {
417                 ast_free(allocation);
418                 return NULL;
419         }
420
421         while ((struct ast_string_field_mgr *) p != mgr) {
422                 AST_VECTOR_APPEND(&mgr->string_fields, p);
423                 *p++ = __ast_string_field_empty;
424         }
425
426         mgr->embedded_pool = pool;
427         *pool_head = pool;
428         pool->size = size_to_alloc - struct_size - sizeof(*pool);
429 #if defined(__AST_DEBUG_MALLOC)
430                 mgr->owner_file = file;
431                 mgr->owner_func = func;
432                 mgr->owner_line = lineno;
433 #endif
434
435         return allocation;
436 }
437
438 int __ast_string_fields_cmp(struct ast_string_field_vector *left,
439         struct ast_string_field_vector *right)
440 {
441         int i;
442         int res = 0;
443
444         ast_assert(AST_VECTOR_SIZE(left) == AST_VECTOR_SIZE(right));
445
446         for (i = 0; i < AST_VECTOR_SIZE(left); i++) {
447                 if ((res = strcmp(*AST_VECTOR_GET(left, i), *AST_VECTOR_GET(right, i)))) {
448                         return res;
449                 }
450         }
451
452         return res;
453 }
454
455 int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool,
456         struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr)
457 {
458         int i;
459         struct ast_string_field_vector *dest = &(copy_mgr->string_fields);
460         struct ast_string_field_vector *src = &(orig_mgr->string_fields);
461
462         ast_assert(AST_VECTOR_SIZE(dest) == AST_VECTOR_SIZE(src));
463
464         for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
465                 __ast_string_field_release_active(copy_pool, *AST_VECTOR_GET(dest, i));
466                 *AST_VECTOR_GET(dest, i) = __ast_string_field_empty;
467         }
468
469         for (i = 0; i < AST_VECTOR_SIZE(dest); i++) {
470                 if (ast_string_field_ptr_set_by_fields(copy_pool, *copy_mgr, AST_VECTOR_GET(dest, i),
471                         *AST_VECTOR_GET(src, i))) {
472                         return -1;
473                 }
474         }
475
476         return 0;
477 }