Skip to content
Snippets Groups Projects
utils.c 36.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			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;
    }
    
    
    		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)
    {
    
    		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;
    }
    
    
    #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, (long int) a.tv_usec);
    
    		a.tv_sec += a.tv_usec / ONE_MILLION;
    
    		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);
    
    		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
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
    
     * BSD libc (and others) do not. */
    
    AST_MUTEX_DEFINE_STATIC(randomlock);
    
    long int ast_random(void)
    {
    	long int res;
    
    #ifdef HAVE_DEV_URANDOM
    	if (dev_urandom_fd >= 0) {
    		int read_res = read(dev_urandom_fd, &res, sizeof(res));
    		if (read_res > 0)
    
    	ast_mutex_lock(&randomlock);
    	res = random();
    	ast_mutex_unlock(&randomlock);
    
    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;
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		} else {
    
    			if (*start == '\\') {
    				inEscape = 1;      /* Do not copy \ into the data */
    			} else if (*start == '\'') {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    				inQuotes = 1 - inQuotes;   /* Do not copy ' into the data */
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    				*dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
    
    void ast_join(char *s, size_t len, char * const w[])
    
    {
    	int x, ofs = 0;
    	const char *src;
    
    	/* Join words into a string */
    	if (!s)
    		return;
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	for (x = 0; ofs < len && w[x]; x++) {
    
    		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,
    
    						ast_string_field *fields, int num_fields)
    
    	if (__builtin_expect(needed > mgr->space, 0)) {
    		size_t new_size = mgr->size * 2;
    
    		while (new_size < needed)
    
    		if (add_string_pool(mgr, new_size))
    
    	result = mgr->pool->base + mgr->used;
    	mgr->used += needed;
    	mgr->space -= needed;
    
    void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr,
    
    				    ast_string_field *fields, int num_fields,
    
    				    int index, const char *format, va_list ap1, va_list ap2)
    
    	needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1;
    
    	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;
    
    	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);
    
    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;
    }
    
    /*! \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;
    }
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief
    
    int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
    
    
    	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, "%ld%n", &t, &scanned) == 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)
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	int res, need;
    
    	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);
    
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	need = res + offset + 1;
    
    	/*
    	 * If there is not enough space and we are below the max length,
    	 * reallocate the buffer and return a message telling to retry.
    	 */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) {
    
    		if (max_len && max_len < need)	/* truncate as needed */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    			need = max_len;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		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;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		}
    
    		(*buf)->str[offset] = '\0';	/* Truncate the partial write. */
    
    		/* 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 */
    
    
    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;
    }