Newer
Older
memmove(e - 1, e, strlen(e) + 1);
work = e;
}
}
return s;
}
int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
{
int result;
if (!buffer || !*buffer || !space || !*space)
return -1;
result = vsnprintf(*buffer, *space, fmt, ap);
if (result < 0)
return -1;
else if (result > *space)
result = *space;
*buffer += result;
*space -= result;
return 0;
}
int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
result = ast_build_string_va(buffer, space, fmt, ap);
va_end(ap);
return result;
}
int ast_true(const char *s)
{
if (ast_strlen_zero(s))
return 0;
/* Determine if this is a true value */
if (!strcasecmp(s, "yes") ||
!strcasecmp(s, "true") ||
!strcasecmp(s, "y") ||
!strcasecmp(s, "t") ||
!strcasecmp(s, "1") ||
!strcasecmp(s, "on"))
return -1;
return 0;
}
int ast_false(const char *s)
{
if (ast_strlen_zero(s))
return 0;
/* Determine if this is a false value */
if (!strcasecmp(s, "no") ||
!strcasecmp(s, "false") ||
!strcasecmp(s, "n") ||
!strcasecmp(s, "f") ||
!strcasecmp(s, "0") ||
!strcasecmp(s, "off"))
return -1;
return 0;
}
Kevin P. Fleming
committed
#define ONE_MILLION 1000000
/*
* put timeval in a valid range. usec is 0..999999
* negative values are not allowed and truncated.
*/
static struct timeval tvfix(struct timeval a)
{
if (a.tv_usec >= ONE_MILLION) {
ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
a.tv_sec += a.tv_usec / ONE_MILLION;
Kevin P. Fleming
committed
a.tv_usec %= ONE_MILLION;
} else if (a.tv_usec < 0) {
ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
a.tv_sec, (long int) a.tv_usec);
Kevin P. Fleming
committed
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
a.tv_usec = 0;
}
return a;
}
struct timeval ast_tvadd(struct timeval a, struct timeval b)
{
/* consistency checks to guarantee usec in 0..999999 */
a = tvfix(a);
b = tvfix(b);
a.tv_sec += b.tv_sec;
a.tv_usec += b.tv_usec;
if (a.tv_usec >= ONE_MILLION) {
a.tv_sec++;
a.tv_usec -= ONE_MILLION;
}
return a;
}
struct timeval ast_tvsub(struct timeval a, struct timeval b)
{
/* consistency checks to guarantee usec in 0..999999 */
a = tvfix(a);
b = tvfix(b);
a.tv_sec -= b.tv_sec;
a.tv_usec -= b.tv_usec;
if (a.tv_usec < 0) {
a.tv_sec-- ;
a.tv_usec += ONE_MILLION;
}
return a;
}
#undef ONE_MILLION
/*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
Joshua Colp
committed
#ifndef linux
Joshua Colp
committed
#endif
long int ast_random(void)
{
long int res;
Joshua Colp
committed
#ifdef HAVE_DEV_URANDOM
if (dev_urandom_fd >= 0) {
int read_res = read(dev_urandom_fd, &res, sizeof(res));
if (read_res > 0)
return labs(res);
Joshua Colp
committed
}
#endif
#ifdef linux
res = random();
#else
ast_mutex_lock(&randomlock);
res = random();
ast_mutex_unlock(&randomlock);
Joshua Colp
committed
#endif
Russell Bryant
committed
char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
{
char *dataPut = start;
int inEscape = 0;
int inQuotes = 0;
for (; *start; start++) {
if (inEscape) {
*dataPut++ = *start; /* Always goes verbatim */
inEscape = 0;
Russell Bryant
committed
if (*start == '\\') {
inEscape = 1; /* Do not copy \ into the data */
} else if (*start == '\'') {
inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
Russell Bryant
committed
} else {
/* Replace , with |, unless in quotes */
*dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
Russell Bryant
committed
}
}
}
if (start != dataPut)
*dataPut = 0;
return dataPut;
}
Russell Bryant
committed
void ast_join(char *s, size_t len, char * const w[])
Russell Bryant
committed
{
int x, ofs = 0;
const char *src;
/* Join words into a string */
if (!s)
return;
Russell Bryant
committed
if (x > 0)
s[ofs++] = ' ';
for (src = w[x]; *src && ofs < len; src++)
s[ofs++] = *src;
}
if (ofs == len)
ofs--;
s[ofs] = '\0';
}
const char __ast_string_field_empty[] = "";
static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size)
{
struct ast_string_field_pool *pool;
if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
return -1;
pool->prev = mgr->pool;
mgr->pool = pool;
mgr->size = size;
mgr->space = size;
mgr->used = 0;
return 0;
}
int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
ast_string_field *fields, int num_fields)
{
int index;
if (add_string_pool(mgr, size))
return -1;
for (index = 0; index < num_fields; index++)
fields[index] = __ast_string_field_empty;
return 0;
ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
Kevin P. Fleming
committed
ast_string_field *fields, int num_fields)
{
char *result = NULL;
if (__builtin_expect(needed > mgr->space, 0)) {
size_t new_size = mgr->size * 2;
new_size *= 2;
if (add_string_pool(mgr, new_size))
return NULL;
}
result = mgr->pool->base + mgr->used;
mgr->used += needed;
mgr->space -= needed;
return result;
}
Kevin P. Fleming
committed
void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
Kevin P. Fleming
committed
ast_string_field *fields, int num_fields,
int index, const char *format, va_list ap1, va_list ap2)
Kevin P. Fleming
committed
{
size_t needed;
needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1;
Kevin P. Fleming
committed
va_end(ap1);
if (needed > mgr->space) {
size_t new_size = mgr->size * 2;
while (new_size < needed)
new_size *= 2;
if (add_string_pool(mgr, new_size))
return;
vsprintf(mgr->pool->base + mgr->used, format, ap2);
}
fields[index] = mgr->pool->base + mgr->used;
mgr->used += needed;
mgr->space -= needed;
}
void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
ast_string_field *fields, int num_fields,
int index, const char *format, ...)
{
va_list ap1, ap2;
Kevin P. Fleming
committed
va_start(ap1, format);
va_start(ap2, format); /* va_copy does not exist on FreeBSD */
__ast_string_field_index_build_va(mgr, fields, num_fields, index, format, ap1, ap2);
va_end(ap1);
Kevin P. Fleming
committed
va_end(ap2);
}
AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
{
int ret;
ast_mutex_lock(&fetchadd_m);
ret = *p;
*p += v;
ast_mutex_unlock(&fetchadd_m);
return ret;
}
Tilghman Lesher
committed
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
/*! \brief
* get values from config variables.
*/
int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed)
{
long double dtv = 0.0;
int scanned;
if (dst == NULL)
return -1;
*dst = _default;
if (ast_strlen_zero(src))
return -1;
/* only integer at the moment, but one day we could accept more formats */
if (sscanf(src, "%Lf%n", &dtv, &scanned) > 0) {
dst->tv_sec = dtv;
dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0;
if (consumed)
*consumed = scanned;
return 0;
} else
return -1;
}
* get values from config variables.
*/
Kevin P. Fleming
committed
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
{
long t;
Kevin P. Fleming
committed
int scanned;
if (dst == NULL)
return -1;
*dst = _default;
if (ast_strlen_zero(src))
return -1;
/* only integer at the moment, but one day we could accept more formats */
Kevin P. Fleming
committed
if (sscanf(src, "%ld%n", &t, &scanned) == 1) {
*dst = t;
Kevin P. Fleming
committed
if (consumed)
*consumed = scanned;
return 0;
} else
return -1;
}
/*!
* core handler for dynamic strings.
* This is not meant to be called directly, but rather through the
* various wrapper macros
* ast_str_set(...)
* ast_str_append(...)
* ast_str_set_va(...)
* ast_str_append_va(...)
int __ast_str_helper(struct ast_str **buf, size_t max_len,
int append, const char *fmt, va_list ap)
int offset = (append && (*buf)->len) ? (*buf)->used : 0;
if (max_len < 0)
max_len = (*buf)->len; /* don't exceed the allocated space */
/*
* Ask vsnprintf how much space we need. Remember that vsnprintf
* does not count the final '\0' so we must add 1.
*/
res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap);
/*
* If there is not enough space and we are below the max length,
* reallocate the buffer and return a message telling to retry.
*/
if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) {
if (max_len && max_len < need) /* truncate as needed */
else if (max_len == 0) /* if unbounded, give more room for next time */
need += 16 + need/4;
if (0) /* debugging */
ast_verbose("extend from %d to %d\n", (int)(*buf)->len, need);
if (ast_str_make_space(buf, need)) {
ast_verbose("failed to extend from %d to %d\n", (int)(*buf)->len, need);
return AST_DYNSTR_BUILD_FAILED;
(*buf)->str[offset] = '\0'; /* Truncate the partial write. */
Russell Bryant
committed
/* va_end() and va_start() must be done before calling
* vsnprintf() again. */
return AST_DYNSTR_BUILD_RETRY;
}
/* update space used, keep in mind the truncation */
(*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset;
void ast_enable_packet_fragmentation(int sock)
{
#if defined(HAVE_IP_MTU_DISCOVER)
int val = IP_PMTUDISC_DONT;
if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
#endif /* HAVE_IP_MTU_DISCOVER */
Tilghman Lesher
committed
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
int ast_mkdir(const char *path, int mode)
{
char *ptr;
int len = strlen(path), count = 0, x, piececount = 0;
char *tmp = ast_strdupa(path);
char **pieces;
char *fullpath = alloca(len + 1);
int res = 0;
for (ptr = tmp; *ptr; ptr++) {
if (*ptr == '/')
count++;
}
/* Count the components to the directory path */
pieces = alloca(count * sizeof(*pieces));
for (ptr = tmp; *ptr; ptr++) {
if (*ptr == '/') {
*ptr = '\0';
pieces[piececount++] = ptr + 1;
}
}
*fullpath = '\0';
for (x = 0; x < piececount; x++) {
/* This looks funky, but the buffer is always ideally-sized, so it's fine. */
strcat(fullpath, "/");
strcat(fullpath, pieces[x]);
res = mkdir(fullpath, mode);
if (res && errno != EEXIST)
return errno;
}
return 0;
}
int ast_utils_init(void)
{
#ifdef HAVE_DEV_URANDOM
dev_urandom_fd = open("/dev/urandom", O_RDONLY);
#endif
base64_init();
#ifdef DEBUG_THREADS
ast_cli_register_multiple(utils_cli, sizeof(utils_cli) / sizeof(utils_cli[0]));
#endif
return 0;
}