Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
channelstorage.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2024, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@sangoma.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#include "asterisk.h"
20#include "asterisk/options.h"
21#include "channelstorage.h"
22
24
33
35 const char *driver_name)
36{
37 int i;
38
39 for (i = 0; i < AST_VECTOR_SIZE(&storage_drivers); i++) {
40 const struct ast_channelstorage_driver *dt =
42 if (strcasecmp(driver_name, dt->driver_name) == 0) {
43 return dt;
44 }
45 }
46 return NULL;
47}
48
50 const struct ast_channelstorage_driver *storage_driver,
51 const char *instance_name)
52{
53 struct ast_channelstorage_instance *storage_instance = NULL;
54
55 storage_instance = storage_driver->open_instance(instance_name);
56 if (!storage_instance) {
57 ast_log(LOG_ERROR, "Failed to open channel storage driver '%s'\n",
58 storage_driver->driver_name);
59 return NULL;
60 }
61
62 return storage_instance;
63};
64
66{
67 CHANNELSTORAGE_API(storage_instance, close_instance);
68};
69
70int channelstorage_exten_cb(void *obj, void *arg, void *data, int flags)
71{
72 struct ast_channel *chan = (struct ast_channel *)obj;
73 const char *context = (const char *)arg;
74 const char *exten = (const char *)data;
75 int ret = 0;
76
77 ao2_lock(chan);
78 if (strcasecmp(ast_channel_context(chan), context) == 0 &&
79 strcasecmp(ast_channel_exten(chan), exten) == 0) {
80 ret = CMP_MATCH | ((flags & OBJ_MULTIPLE) ? 0 : CMP_STOP);
81 }
82 ao2_unlock(chan);
83
84 return ret;
85}
86
88 const char *exten, const char *context, int rdlock)
89{
90 char *l_exten = (char *) exten;
91 char *l_context = (char *) context;
92
93 return CHANNELSTORAGE_API(driver, callback, channelstorage_exten_cb, l_context, l_exten, 0, rdlock);
94}
95
96int channelstorage_name_cb(void *obj, void *arg, void *data, int flags)
97{
98 struct ast_channel *chan = obj;
99 const char *name = arg;
100 size_t name_len = *(size_t *) data;
101 int ret = 0;
102
103 if (name_len == 0) {
104 if(strcasecmp(ast_channel_name(chan), name) == 0) {
105 ret = CMP_MATCH | ((flags & OBJ_MULTIPLE) ? 0 : CMP_STOP);
106 }
107 } else {
108 if (strncasecmp(ast_channel_name(chan), name, name_len) == 0) {
109 ret = CMP_MATCH | ((flags & OBJ_MULTIPLE) ? 0 : CMP_STOP);
110 }
111 }
112
113 return ret;
114}
115
117 const char *name, int rdlock)
118{
119 return CHANNELSTORAGE_API(driver, get_by_name_prefix_or_uniqueid, name, 0, rdlock);
120}
121
123 const char *name, size_t name_len, int rdlock)
124{
125 struct ast_channel *chan = NULL;
126
127 chan = CHANNELSTORAGE_API(driver, get_by_name_prefix, name, name_len, rdlock);
128 if (chan) {
129 return chan;
130 }
131
132 if (name_len == 0) {
133 chan = CHANNELSTORAGE_API(driver, get_by_uniqueid, name, rdlock);
134 }
135
136 return chan;
137}
138
139int channelstorage_uniqueid_cb(void *obj, void *arg, void *data, int flags)
140{
141 struct ast_channel *chan = obj;
142 char *uniqueid = arg;
143 int ret = 0;
144
145 if(strcasecmp(ast_channel_uniqueid(chan), uniqueid) == 0) {
146 ret = CMP_MATCH | CMP_STOP;
147 }
148
149 return ret;
150}
151
153 const char *uniqueid, int rdlock)
154{
155 return CHANNELSTORAGE_API(driver, callback, channelstorage_uniqueid_cb, (char *)uniqueid, NULL, 0, rdlock);
156}
157
158#ifdef TEST_FRAMEWORK
159#include "asterisk/test.h"
160#include "channel_private.h"
161
162static void mock_channel_destructor(void *obj)
163{
164 struct ast_channel *chan = obj;
166}
167
168struct test_info {
169 struct ast_test *test;
170 struct ast_channelstorage_instance *storage_instance;
171 enum ast_test_result_state res;
172};
173
174static void *test_storage_thread(void *data)
175{
176 struct test_info *test_info = data;
177 struct ast_test *test = test_info->test;
178 struct ast_channelstorage_instance *storage_instance = test_info->storage_instance;
179 struct ast_channel *mock_channel;
181 int i;
182 struct timeval start;
183 struct timeval end;
184 int64_t elapsed;
185 char search1[128];
186 char search2[128];
187 int rc = 0;
188 long int rand = ast_random();
189 struct ast_channel_iterator *iter;
190 int collen = 25;
191 int CHANNEL_COUNT = 500;
192 struct ast_cli_args *cli_args = ast_test_get_cli_args(test);
193 struct ast_channel **test_channels;
194
195 for (i = 0; i < cli_args->argc; i++) {
196 if (ast_begins_with(cli_args->argv[i], "channel-count=")) {
197 sscanf(cli_args->argv[i], "channel-count=%d", &CHANNEL_COUNT);
198 }
199 }
200 test_channels = ast_calloc(CHANNEL_COUNT, sizeof(*test_channels));
201 ast_test_status_update(test, "%*s: %8d\n", collen, "Channel Count", CHANNEL_COUNT);
202
203 start = ast_tvnow();
204 for (i = 0; i < CHANNEL_COUNT; i++) {
205 test_channels[i] = ao2_alloc(sizeof(*mock_channel), mock_channel_destructor);
206 ast_test_validate_cleanup(test, test_channels[i], res, done);
207 ast_string_field_init(test_channels[i], 128);
208 ast_string_field_build(test_channels[i], name, "TestChannel-%ld-%04d-something", rand, i);
209 snprintf(test_channels[i]->context, AST_MAX_CONTEXT, "TestContext-%ld-%04d", rand, i % 100);
210 snprintf(test_channels[i]->exten, AST_MAX_EXTENSION, "TestExten-%ld-%04d", rand, i % 10);
211 snprintf(test_channels[i]->uniqueid.unique_id, AST_MAX_UNIQUEID, "TestUniqueid-%ld-%04d-something", rand, i);
212 rc = CHANNELSTORAGE_API(storage_instance, insert, test_channels[i], 0, 1);
213 ast_test_validate_cleanup_custom(test, rc == 0, res, done, "Unable to insert channel %s\n", test_channels[i]->name);
214 }
215 end = ast_tvnow();
216 elapsed = ast_tvdiff_us(end, start);
217 i = CHANNELSTORAGE_API(storage_instance, active_channels, 1);
218 ast_test_status_update(test, "%*s: %8ld\n", collen, "create channels", elapsed);
219 ast_test_validate_cleanup(test, i == CHANNEL_COUNT, res, done);
220
221 start = ast_tvnow();
222 for (i = 0; i < CHANNEL_COUNT; i++) {
223 sprintf(search1, "testchannel-%ld-%04d-something", rand, i);
224 mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_name_prefix_or_uniqueid, search1, 0, 1);
225 ast_test_validate_cleanup(test, mock_channel, res, done);
226 ast_test_validate_cleanup(test, mock_channel == test_channels[i], res, done);
227 ast_test_validate_cleanup(test,
228 strcasecmp(ast_channel_name(mock_channel), search1) == 0, res, done);
229 ast_channel_unref(mock_channel);
230 }
231 end = ast_tvnow();
232 elapsed = ast_tvdiff_us(end, start);
233 ast_test_status_update(test, "%*s: %8ld\n", collen, "by name exact", elapsed);
234
235 start = ast_tvnow();
236 for (i = 0; i < CHANNEL_COUNT; i++) {
237 sprintf(search1, "TestUniqueid-%ld-%04d-something", rand, i);
238 mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_uniqueid, search1, 1);
239 ast_test_validate_cleanup(test, mock_channel, res, done);
240 ast_channel_unref(mock_channel);
241 }
242 end = ast_tvnow();
243 elapsed = ast_tvdiff_us(end, start);
244 ast_test_status_update(test, "%*s: %8ld\n", collen, "by uniqueid exact", elapsed);
245
246 start = ast_tvnow();
247 for (i = 0; i < CHANNEL_COUNT; i++) {
248 sprintf(search1, "TestUniqueid-%ld-%04d-something", rand, i);
249 mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_name_prefix_or_uniqueid, search1, 0, 1);
250 ast_test_validate_cleanup(test, mock_channel, res, done);
251 ast_channel_unref(mock_channel);
252 }
253 end = ast_tvnow();
254 elapsed = ast_tvdiff_us(end, start);
255 ast_test_status_update(test, "%*s: %8ld\n", collen, "by uniqueid via nm", elapsed);
256
257 start = ast_tvnow();
258 for (i = 0; i < CHANNEL_COUNT; i++) {
259 sprintf(search1, "TestChannel-%ld-%04d", rand, i);
260 mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_name_prefix_or_uniqueid, search1, strlen(search1), 1);
261 ast_test_validate_cleanup(test, mock_channel, res, done);
262 ast_channel_unref(mock_channel);
263 }
264 end = ast_tvnow();
265 elapsed = ast_tvdiff_us(end, start);
266 ast_test_status_update(test, "%*s: %8ld\n", collen, "by name prefix", elapsed);
267
268 /* Test negative cases - prefixes that should NOT match */
269 start = ast_tvnow();
270 for (i = 0; i < 10; i++) {
271 /* Search for non-existent prefix between existing channels
272 * e.g., "TestChannel-{rand}-0000a" falls between 0000 and 0001
273 */
274 sprintf(search1, "TestChannel-%ld-%04da", rand, i * 50);
275 mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_name_prefix_or_uniqueid, search1, strlen(search1), 1);
276 ast_test_validate_cleanup_custom(test, mock_channel == NULL, res, done,
277 "Expected NULL for non-existent prefix '%s' but got '%s'\n",
278 search1, mock_channel ? ast_channel_name(mock_channel) : "NULL");
279 if (mock_channel) {
280 ast_channel_unref(mock_channel);
281 }
282 }
283 end = ast_tvnow();
284 elapsed = ast_tvdiff_us(end, start);
285 ast_test_status_update(test, "%*s: %8ld\n", collen, "prefix no-match", elapsed);
286
287 start = ast_tvnow();
288 for (i = 0; i < CHANNEL_COUNT; i++) {
289 sprintf(search1, "TestContext-%ld-%04d", rand, i % 100);
290 sprintf(search2, "TestExten-%ld-%04d", rand, i % 10);
291 mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_exten, search2, search1, 1);
292 ast_test_validate_cleanup(test, mock_channel, res, done);
293 ast_channel_unref(mock_channel);
294 }
295 end = ast_tvnow();
296 elapsed = ast_tvdiff_us(end, start);
297 ast_test_status_update(test, "%*s: %8ld\n", collen, "by context/exten", elapsed);
298
299 i = 0;
300 start = ast_tvnow();
301 iter = CHANNELSTORAGE_API(storage_instance, iterator_all_new);
302 for (; (mock_channel = CHANNELSTORAGE_API(storage_instance, iterator_next, iter));
303 ast_channel_unref(mock_channel)) {
304 i++;
305 }
306 CHANNELSTORAGE_API(storage_instance, iterator_destroy, iter);
307 end = ast_tvnow();
308 elapsed = ast_tvdiff_us(end, start);
309 ast_test_status_update(test, "%*s: %8ld\n", collen, "iter all chan", elapsed);
310 ast_test_validate_cleanup_custom(test, i == CHANNEL_COUNT, res, done,
311 "Expected %d channels, got %d, in container: %d\n", CHANNEL_COUNT, i,
312 CHANNELSTORAGE_API(storage_instance, active_channels, 1));
313
314 i = 0;
315 start = ast_tvnow();
316 sprintf(search1, "TestChannel-%ld-%03d", rand, (CHANNEL_COUNT - 11) / 10);
317 iter = CHANNELSTORAGE_API(storage_instance, iterator_by_name_new, search1, strlen(search1));
318 ast_test_validate_cleanup(test, iter != NULL, res, done);
319 for (; (mock_channel = CHANNELSTORAGE_API(storage_instance, iterator_next, iter));
320 ast_channel_unref(mock_channel)) {
321 ast_test_validate_cleanup_custom(test, strncmp(search1,
322 ast_channel_name(mock_channel), strlen(search1)) == 0, res, done, "Expected %s got %s\n",
323 search1, ast_channel_name(mock_channel));
324 i++;
325 }
326 CHANNELSTORAGE_API(storage_instance, iterator_destroy, iter);
327 end = ast_tvnow();
328 elapsed = ast_tvdiff_us(end, start);
329 ast_test_status_update(test, "%*s: %8ld\n", collen, "iter 10 partial name", elapsed);
330 ast_test_validate_cleanup_custom(test, i == 10, res, done,
331 "Expected %d channels, got %d, in container: %d\n", 10, i,
332 CHANNELSTORAGE_API(storage_instance, active_channels, 1));
333
334 i = 0;
335 start = ast_tvnow();
336 sprintf(search1, "TestContext-%ld-%04d", rand, 50);
337 sprintf(search2, "TestExten-%ld-%04d", rand, 0);
338 iter = CHANNELSTORAGE_API(storage_instance, iterator_by_exten_new, search2, search1);
339 ast_test_validate_cleanup(test, iter != NULL, res, done);
340 for (; (mock_channel = CHANNELSTORAGE_API(storage_instance, iterator_next, iter));
341 ast_channel_unref(mock_channel)) {
342 ast_test_validate_cleanup_custom(test,
343 (strcmp(search1, mock_channel->context) == 0 &&
344 strcmp(search2, mock_channel->exten) == 0), res, done, "Expected %s-%s got %s-%s\n",
345 search1, search2, mock_channel->context, mock_channel->exten);
346 i++;
347 }
348 CHANNELSTORAGE_API(storage_instance, iterator_destroy, iter);
349 end = ast_tvnow();
350 elapsed = ast_tvdiff_us(end, start);
351 ast_test_status_update(test, "%*s: %8ld\n", collen, "iter context/exten", elapsed);
352 ast_test_validate_cleanup_custom(test, i == (CHANNEL_COUNT / 100), res, done,
353 "Expected %d channels, got %d, in container: %d\n", (CHANNEL_COUNT / 100), i,
354 CHANNEL_COUNT);
355
356done:
357 CHANNELSTORAGE_API(storage_instance, unlock);
358
359 start = ast_tvnow();
360 for (i = 0; i < CHANNEL_COUNT; i++) {
361 if (test_channels[i]) {
362 rc = CHANNELSTORAGE_API(storage_instance, remove, test_channels[i], 0);
363 ast_channel_unref(test_channels[i]);
364 test_channels[i] = NULL;
365 }
366 }
367 end = ast_tvnow();
368 elapsed = ast_tvdiff_us(end, start);
369 ast_test_status_update(test, "%*s: %8ld\n", collen, "del all channels", elapsed);
370 ast_test_validate_cleanup(test, i == CHANNEL_COUNT, res, done);
371 rc = CHANNELSTORAGE_API(storage_instance, active_channels, 1);
372 ast_test_validate_cleanup_custom(test, rc == 0, res, final,
373 "There are still %d channels in the container\n", rc);
374
375 test_info->res = res;
376 return NULL;
377
378final:
379 iter = CHANNELSTORAGE_API(storage_instance, iterator_all_new);
380 for (; (mock_channel = CHANNELSTORAGE_API(storage_instance, iterator_next, iter));
381 ast_channel_unref(mock_channel)) {
382 ast_test_status_update(test, "%p %s\n", mock_channel, ast_channel_name(mock_channel));
383 i++;
384 }
385 CHANNELSTORAGE_API(storage_instance, iterator_destroy, iter);
386
387 test_info->res = res;
388 return NULL;
389}
390
391static enum ast_test_result_state test_storage(struct ast_test_info *info,
392 enum ast_test_command cmd, struct ast_test *test,
393 const char *storage_name, const char *summary)
394{
395 const struct ast_channelstorage_driver *storage_driver;
396 struct test_info ti = {
397 .test = test,
398 .storage_instance = NULL,
399 .res = AST_TEST_PASS,
400 };
401 pthread_t thread;
402 int rc = 0;
403
404 switch (cmd) {
405 case TEST_INIT:
406 info->name = storage_name;
407 info->category = "/main/channelstorage/";
408 info->summary = summary;
409 info->description = info->summary;
410 return AST_TEST_NOT_RUN;
411 case TEST_EXECUTE:
412 break;
413 }
414
415 storage_driver = ast_channelstorage_get_driver(info->name);
416 if (!storage_driver) {
417 ast_test_status_update(test, "Storage driver %s not registered\n", info->name);
418 return AST_TEST_NOT_RUN;
419 }
420 ti.storage_instance = ast_channelstorage_open(storage_driver, "channels_test");
421 ast_test_validate(test, ti.storage_instance, res);
422
423 rc = ast_pthread_create(&thread, NULL, test_storage_thread, &ti);
424 if (rc) {
425 ast_channelstorage_close(ti.storage_instance);
426 ast_test_status_update(test, "Failed to create thread: %s\n", strerror(rc));
427 return AST_TEST_FAIL;
428 }
429 pthread_join(thread, NULL);
430 ast_channelstorage_close(ti.storage_instance);
431
432 return ti.res;
433}
434
435#define DEFINE_STORAGE_TEST(_name) \
436AST_TEST_DEFINE(_name) \
437{ \
438 return test_storage(info, cmd, test, #_name, "Channel Storage test for " #_name); \
439}
440
441DEFINE_STORAGE_TEST(ao2_legacy)
442
443DEFINE_STORAGE_TEST(cpp_map_name_id)
444
445#define REGISTER_STORAGE_TEST(_name) \
446({ \
447 if (ast_channelstorage_get_driver(#_name)) { \
448 AST_TEST_REGISTER(_name); \
449 } \
450})
451#endif
452
453static void channelstorage_shutdown(void)
454{
455#ifdef TEST_FRAMEWORK
456 /* Unregistering a test that wasn't previously registered is safe */
457 AST_TEST_UNREGISTER(cpp_map_name_id);
458 AST_TEST_UNREGISTER(ao2_legacy);
459#endif
460}
461
463{
464#ifdef TEST_FRAMEWORK
465 /* Tests run in the reverse order registered */
466 REGISTER_STORAGE_TEST(cpp_map_name_id);
467 AST_TEST_REGISTER(ao2_legacy);
468#endif
470
471 return 0;
472}
473
pthread_t thread
Definition app_sla.c:335
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_log
Definition astobj2.c:42
@ CMP_MATCH
Definition astobj2.h:1027
@ CMP_STOP
Definition astobj2.h:1028
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
@ OBJ_MULTIPLE
Definition astobj2.h:1049
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3018
#define AST_MAX_UNIQUEID
Definition channel.h:170
#define AST_MAX_CONTEXT
Definition channel.h:135
const char * ast_channel_exten(const struct ast_channel *chan)
#define AST_MAX_EXTENSION
Definition channel.h:134
struct ast_channel * channelstorage_by_exten(struct ast_channelstorage_instance *driver, const char *exten, const char *context, int rdlock)
struct ast_channelstorage_instance * ast_channelstorage_open(const struct ast_channelstorage_driver *storage_driver, const char *instance_name)
int ast_channelstorage_init(void)
int channelstorage_exten_cb(void *obj, void *arg, void *data, int flags)
struct ast_channel * channelstorage_by_name_or_uniqueid(struct ast_channelstorage_instance *driver, const char *name, int rdlock)
int channelstorage_name_cb(void *obj, void *arg, void *data, int flags)
int channelstorage_uniqueid_cb(void *obj, void *arg, void *data, int flags)
int ast_channelstorage_register_driver(const struct ast_channelstorage_driver *driver_type)
const struct ast_channelstorage_driver * ast_channelstorage_get_driver(const char *driver_name)
struct ast_channel * channelstorage_by_name_prefix_or_uniqueid(struct ast_channelstorage_instance *driver, const char *name, size_t name_len, int rdlock)
static void channelstorage_shutdown(void)
void ast_channelstorage_close(struct ast_channelstorage_instance *storage_instance)
static struct @354 storage_drivers
struct ast_channel * channelstorage_by_uniqueid(struct ast_channelstorage_instance *driver, const char *uniqueid, int rdlock)
#define CHANNELSTORAGE_API(_instance, _func,...)
static struct ast_channelstorage_driver driver_type
static struct ast_channel_iterator * iterator_by_exten_new(struct ast_channelstorage_instance *driver, const char *exten, const char *context)
static void close_instance(struct ast_channelstorage_instance *driver)
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
static struct ast_channel * iterator_next(struct ast_channelstorage_instance *driver, struct ast_channel_iterator *i)
static struct ast_channel_iterator * iterator_destroy(struct ast_channelstorage_instance *driver, struct ast_channel_iterator *i)
static struct ast_channel_iterator * iterator_by_name_new(struct ast_channelstorage_instance *driver, const char *name, size_t name_len)
static struct ast_channel * get_by_uniqueid(struct ast_channelstorage_instance *driver, const char *uniqueid, int lock)
static struct ast_channel_iterator * iterator_all_new(struct ast_channelstorage_instance *driver)
static struct ast_channel * get_by_exten(struct ast_channelstorage_instance *driver, const char *exten, const char *context, int rdlock)
static struct ast_channel * get_by_name_prefix(struct ast_channelstorage_instance *driver, const char *name, size_t name_len, int lock)
static int active_channels(struct ast_channelstorage_instance *driver, int rdlock)
returns number of active/allocated channels
char * end
Definition eagi_proxy.c:73
static const char name[]
Definition format_mp3.c:68
#define LOG_ERROR
#define remove
Options provided by main asterisk program.
#define NULL
Definition resample.c:96
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition strings.h:97
char unique_id[AST_MAX_UNIQUEID]
Main Channel structure associated with a channel.
struct ast_channel_id uniqueid
char exten[AST_MAX_EXTENSION]
const char * data
char context[AST_MAX_CONTEXT]
struct ast_flags flags
struct ast_channelstorage_instance *(* open_instance)(const char *instance_name)
const int argc
Definition cli.h:160
const char *const * argv
Definition cli.h:161
Contains all the initialization information required to store a new test definition.
Definition test.h:235
Test Framework API.
ast_test_command
Definition test.h:199
@ TEST_INIT
Definition test.h:200
@ TEST_EXECUTE
Definition test.h:201
#define AST_TEST_REGISTER(cb)
Definition test.h:127
#define ast_test_status_update(a, b, c...)
Definition test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition test.h:128
ast_test_result_state
Definition test.h:193
@ AST_TEST_PASS
Definition test.h:195
@ AST_TEST_FAIL
Definition test.h:196
@ AST_TEST_NOT_RUN
Definition test.h:194
int done
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition time.h:87
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define ast_pthread_create(a, b, c, d)
Definition utils.h:624
long int ast_random(void)
Definition utils.c:2348
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR(name, type)
Define a vector structure.
Definition vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691