Newer
Older
/* Not enough room left for the escape sequence. */
break;
}
*p++ = '\\';
*p = escape_sequences_map[c - escape_sequences];
} else {
*p = *s;
}
}
*p = '\0';
return dest;
}
static char *escape_alloc(const char *s, size_t *size)
{
return NULL;
}
/*
* The result string needs to be twice the size of the given
* string just in case every character in it needs to be escaped.
*/
*size = strlen(s) * 2 + 1;
return ast_malloc(*size);
}
char *ast_escape_alloc(const char *s, const char *to_escape)
{
size_t size = 0;
char *dest = escape_alloc(s, &size);
return ast_escape(dest, s, size, to_escape);
}
char *ast_escape_c_alloc(const char *s)
{
size_t size = 0;
char *dest = escape_alloc(s, &size);
return ast_escape_c(dest, s, size);
}
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_regex_string_to_regex_pattern(const char *regex_string, struct ast_str **regex_pattern)
{
int regex_len = strlen(regex_string);
int ret = 3;
/* Chop off the leading / if there is one */
if ((regex_len >= 1) && (regex_string[0] == '/')) {
ast_str_set(regex_pattern, 0, "%s", regex_string + 1);
ret -= 2;
}
/* Chop off the ending / if there is one */
if ((regex_len > 1) && (regex_string[regex_len - 1] == '/')) {
ast_str_truncate(*regex_pattern, -1);
ret -= 1;
}
return ret;
}
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",
(long)a.tv_sec, (long int) a.tv_usec);
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",
(long)a.tv_sec, (long int) a.tv_usec);
Kevin P. Fleming
committed
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
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;
}
int ast_remaining_ms(struct timeval start, int max_ms)
{
int ms;
if (max_ms < 0) {
ms = max_ms;
} else {
ms = max_ms - ast_tvdiff_ms(ast_tvnow(), start);
if (ms < 0) {
ms = 0;
}
}
return ms;
}
void ast_format_duration_hh_mm_ss(int duration, char *buf, size_t length)
{
int durh, durm, durs;
durh = duration / 3600;
durm = (duration % 3600) / 60;
durs = duration % 60;
snprintf(buf, length, "%02d:%02d:%02d", durh, durm, durs);
}
Kevin P. Fleming
committed
#undef ONE_MILLION
Joshua Colp
committed
#ifndef linux
Joshua Colp
committed
#endif
long int ast_random(void)
{
long int res;
Joshua Colp
committed
if (dev_urandom_fd >= 0) {
int read_res = read(dev_urandom_fd, &res, sizeof(res));
Joshua Colp
committed
if (read_res > 0) {
Joshua Colp
committed
long int rm = RAND_MAX;
Joshua Colp
committed
res = res < 0 ? ~res : res;
Joshua Colp
committed
rm++;
return res % rm;
Joshua Colp
committed
}
Joshua Colp
committed
}
/* XXX - Thread safety really depends on the libc, not the OS.
*
* But... popular Linux libc's (uClibc, glibc, eglibc), all have a
* somewhat thread safe random(3) (results are random, but not
* reproducible). The libc's for other systems (BSD, et al.), not so
* much.
*/
Joshua Colp
committed
#ifdef linux
res = random();
#else
ast_mutex_lock(&randomlock);
res = random();
ast_mutex_unlock(&randomlock);
Joshua Colp
committed
#endif
void ast_replace_subargument_delimiter(char *s)
{
for (; *s; s++) {
if (*s == '^') {
*s = ',';
}
}
}
Russell Bryant
committed
char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
{
Russell Bryant
committed
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_delim(char *s, size_t len, const char * const w[], unsigned int size, char delim)
Russell Bryant
committed
{
int x, ofs = 0;
const char *src;
/* Join words into a string */
if (!s)
return;
for (x = 0; ofs < len && x < size && w[x] ; x++) {
Russell Bryant
committed
if (x > 0)
Russell Bryant
committed
for (src = w[x]; *src && ofs < len; src++)
s[ofs++] = *src;
}
if (ofs == len)
ofs--;
s[ofs] = '\0';
}
char *ast_to_camel_case_delim(const char *s, const char *delim)
{
char *res = ast_strdup(s);
char *front, *back, *buf = res;
int size;
front = strtok_r(buf, delim, &back);
while (front) {
size = strlen(front);
*front = toupper(*front);
ast_copy_string(buf, front, size + 1);
buf += size;
front = strtok_r(NULL, delim, &back);
}
return res;
}
Tilghman Lesher
committed
/*! \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 */
Tilghman Lesher
committed
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 */
*dst = t;
Kevin P. Fleming
committed
if (consumed)
*consumed = scanned;
return 0;
} else
return -1;
}
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
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 = ast_alloca(len + 1);
Tilghman Lesher
committed
int res = 0;
for (ptr = tmp; *ptr; ptr++) {
if (*ptr == '/')
count++;
}
/* Count the components to the directory path */
pieces = ast_alloca(count * sizeof(*pieces));
Tilghman Lesher
committed
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;
}
static int safe_mkdir(const char *base_path, char *path, int mode)
{
RAII_VAR(char *, absolute_path, NULL, ast_std_free);
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
absolute_path = realpath(path, NULL);
if (absolute_path) {
/* Path exists, but is it in the right place? */
if (!ast_begins_with(absolute_path, base_path)) {
return EPERM;
}
/* It is in the right place! */
return 0;
} else {
/* Path doesn't exist. */
/* The slash terminating the subpath we're checking */
char *path_term = strchr(path, '/');
/* True indicates the parent path is within base_path */
int parent_is_safe = 0;
int res;
while (path_term) {
RAII_VAR(char *, absolute_subpath, NULL, ast_std_free);
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
/* Truncate the path one past the slash */
char c = *(path_term + 1);
*(path_term + 1) = '\0';
absolute_subpath = realpath(path, NULL);
if (absolute_subpath) {
/* Subpath exists, but is it safe? */
parent_is_safe = ast_begins_with(
absolute_subpath, base_path);
} else if (parent_is_safe) {
/* Subpath does not exist, but parent is safe
* Create it */
res = mkdir(path, mode);
if (res != 0) {
ast_assert(errno != EEXIST);
return errno;
}
} else {
/* Subpath did not exist, parent was not safe
* Fail! */
errno = EPERM;
return errno;
}
/* Restore the path */
*(path_term + 1) = c;
/* Move on to the next slash */
path_term = strchr(path_term + 1, '/');
}
/* Now to build the final path, but only if it's safe */
if (!parent_is_safe) {
errno = EPERM;
return errno;
}
res = mkdir(path, mode);
if (res != 0 && errno != EEXIST) {
return errno;
}
return 0;
}
}
int ast_safe_mkdir(const char *base_path, const char *path, int mode)
{
RAII_VAR(char *, absolute_base_path, NULL, ast_std_free);
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
RAII_VAR(char *, p, NULL, ast_free);
if (base_path == NULL || path == NULL) {
errno = EFAULT;
return errno;
}
p = ast_strdup(path);
if (p == NULL) {
errno = ENOMEM;
return errno;
}
absolute_base_path = realpath(base_path, NULL);
if (absolute_base_path == NULL) {
return errno;
}
return safe_mkdir(absolute_base_path, p, mode);
}
Jonathan Rose
committed
static void utils_shutdown(void)
{
close(dev_urandom_fd);
dev_urandom_fd = -1;
#if defined(DEBUG_THREADS) && !defined(LOW_MEMORY)
ast_cli_unregister_multiple(utils_cli, ARRAY_LEN(utils_cli));
#endif
}
int ast_utils_init(void)
{
dev_urandom_fd = open("/dev/urandom", O_RDONLY);
base64_init();
#ifdef DEBUG_THREADS
ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli));
ast_register_cleanup(utils_shutdown);
/*!
*\brief Parse digest authorization header.
*\return Returns -1 if we have no auth or something wrong with digest.
*\note This function may be used for Digest request and responce header.
* request arg is set to nonzero, if we parse Digest Request.
* pedantic arg can be set to nonzero if we need to do addition Digest check.
*/
int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic) {
struct ast_str *str = ast_str_create(16);
/* table of recognised keywords, and places where they should be copied */
const struct x {
const char *key;
const ast_string_field *field;
} *i, keys[] = {
{ "username=", &d->username },
{ "realm=", &d->realm },
{ "nonce=", &d->nonce },
{ "uri=", &d->uri },
{ "domain=", &d->domain },
{ "response=", &d->response },
{ "cnonce=", &d->cnonce },
{ "opaque=", &d->opaque },
/* Special cases that cannot be directly copied */
{ "algorithm=", NULL },
{ "qop=", NULL },
{ "nc=", NULL },
{ NULL, 0 },
};
if (ast_strlen_zero(digest) || !d || !str) {
ast_free(str);
return -1;
}
ast_str_set(&str, 0, "%s", digest);
c = ast_skip_blanks(ast_str_buffer(str));
if (strncasecmp(c, "Digest ", strlen("Digest "))) {
ast_log(LOG_WARNING, "Missing Digest.\n");
ast_free(str);
return -1;
}
c += strlen("Digest ");
/* lookup for keys/value pair */
while (c && *c && *(c = ast_skip_blanks(c))) {
/* find key */
for (i = keys; i->key != NULL; i++) {
char *src, *separator;
int unescape = 0;
if (strncasecmp(c, i->key, strlen(i->key)) != 0) {
continue;
}
/* Found. Skip keyword, take text in quotes or up to the separator. */
c += strlen(i->key);
if (*c == '"') {
src = ++c;
separator = "\"";
unescape = 1;
} else {
src = c;
separator = ",";
strsep(&c, separator); /* clear separator and move ptr */
if (unescape) {
ast_unescape_c(src);
}
if (i->field) {
ast_string_field_ptr_set(d, i->field, src);
} else {
/* Special cases that require additional processing */
if (!strcasecmp(i->key, "algorithm=")) {
if (strcasecmp(src, "MD5")) {
ast_log(LOG_WARNING, "Digest algorithm: \"%s\" not supported.\n", src);
ast_free(str);
return -1;
}
} else if (!strcasecmp(i->key, "qop=") && !strcasecmp(src, "auth")) {
d->qop = 1;
} else if (!strcasecmp(i->key, "nc=")) {
unsigned long u;
if (sscanf(src, "%30lx", &u) != 1) {
ast_log(LOG_WARNING, "Incorrect Digest nc value: \"%s\".\n", src);
ast_free(str);
return -1;
}
ast_string_field_set(d, nc, src);
}
break;
}
if (i->key == NULL) { /* not found, try ',' */
strsep(&c, ",");
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
}
}
ast_free(str);
/* Digest checkout */
if (ast_strlen_zero(d->realm) || ast_strlen_zero(d->nonce)) {
/* "realm" and "nonce" MUST be always exist */
return -1;
}
if (!request) {
/* Additional check for Digest response */
if (ast_strlen_zero(d->username) || ast_strlen_zero(d->uri) || ast_strlen_zero(d->response)) {
return -1;
}
if (pedantic && d->qop && (ast_strlen_zero(d->cnonce) || ast_strlen_zero(d->nc))) {
return -1;
}
}
return 0;
}
int ast_get_tid(void)
{
int ret = -1;
#if defined (__linux) && defined(SYS_gettid)
ret = syscall(SYS_gettid); /* available since Linux 1.4.11 */
#elif defined(__sun)
ret = pthread_self();
#elif defined(__APPLE__)
ret = mach_thread_self();
mach_port_deallocate(mach_task_self(), ret);
#elif defined(__FreeBSD__) && defined(HAVE_SYS_THR_H)
long lwpid;
thr_self(&lwpid); /* available since sys/thr.h creation 2003 */
ret = lwpid;
#elif defined(__NetBSD__)
ret = _lwp_self();
#endif
return ret;
}
char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
{
const char *envPATH = getenv("PATH");
char *tpath, *path;
struct stat unused;
if (!envPATH) {
return NULL;
}
tpath = ast_strdupa(envPATH);
while ((path = strsep(&tpath, ":"))) {
snprintf(fullpath, fullpath_size, "%s/%s", path, binary);
if (!stat(fullpath, &unused)) {
return fullpath;
}
}
return NULL;
}
int ast_check_ipv6(void)
{
int udp6_socket = socket(AF_INET6, SOCK_DGRAM, 0);
if (udp6_socket < 0) {
return 0;
}
close(udp6_socket);
return 1;
}
void DO_CRASH_NORETURN ast_do_crash(void)
{
#if defined(DO_CRASH)
abort();
/*
* Just in case abort() doesn't work or something else super
* silly, and for Qwell's amusement.
*/
*((int *) 0) = 0;
#endif /* defined(DO_CRASH) */
}
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
{
/*
* Attempt to put it into the logger, but hope that at least
* someone saw the message on stderr ...
*/
fprintf(stderr, "FRACK!, Failed assertion %s (%d) at line %d in %s of %s\n",
condition_str, condition, line, function, file);
ast_log(__LOG_ERROR, file, line, function, "FRACK!, Failed assertion %s (%d)\n",
condition_str, condition);
/* Generate a backtrace for the assert */
ast_log_backtrace();
/*
* Give the logger a chance to get the message out, just in case
* we abort(), or Asterisk crashes due to whatever problem just
* happened after we exit ast_assert().
*/
usleep(1);
ast_do_crash();
}
char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
{
int x;
char *os = s;
if (maxlen < 18) {
if (s && (maxlen > 0)) {
*s = '\0';
}
} else {
for (x = 0; x < 5; x++) {
sprintf(s, "%02hhx:", eid->eid[x]);
s += 3;
}
sprintf(s, "%02hhx", eid->eid[5]);
}
return os;
}
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__Darwin__)
#include <ifaddrs.h>
#include <net/if_dl.h>
void ast_set_default_eid(struct ast_eid *eid)
{
struct ifaddrs *ifap, *ifaphead;
int rtnerr;
const struct sockaddr_dl *sdl;
int alen;
caddr_t ap;
char eid_str[20];
unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
rtnerr = getifaddrs(&ifaphead);
if (rtnerr) {
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
"You will have to set it manually.\n");
return;
}
if (!ifaphead) {
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
"You will have to set it manually.\n");
return;
}
for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
if (ifap->ifa_addr->sa_family != AF_LINK) {
continue;
sdl = (const struct sockaddr_dl *) ifap->ifa_addr;
ap = ((caddr_t) ((sdl)->sdl_data + (sdl)->sdl_nlen));
alen = sdl->sdl_alen;
if (alen != 6 || !(memcmp(ap, &empty_mac, 6) && memcmp(ap, &full_mac, 6))) {
continue;
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
memcpy(eid, ap, sizeof(*eid));
ast_debug(1, "Seeding global EID '%s'\n",
ast_eid_to_str(eid_str, sizeof(eid_str), eid));
freeifaddrs(ifaphead);
return;
}
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
"You will have to set it manually.\n");
freeifaddrs(ifaphead);
return;
}
#elif defined(SOLARIS)
#include <sys/sockio.h>
#include <net/if_arp.h>
void ast_set_default_eid(struct ast_eid *eid)
{
int s;
int x;
struct lifreq *ifr = NULL;
struct lifnum ifn;
struct lifconf ifc;
struct arpreq ar;
struct sockaddr_in *sa, *sa2;
char *buf = NULL;
char eid_str[20];
int bufsz;
unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
s = socket(AF_INET, SOCK_STREAM, 0);
if (s <= 0) {
ast_log(LOG_WARNING, "Unable to open a socket for seeding global EID. "
" You will have to set it manually.\n");
return;
}
/* Get a count of interfaces on the machine */
ifn.lifn_family = AF_UNSPEC;
ifn.lifn_flags = 0;
ifn.lifn_count = 0;
if (ioctl(s, SIOCGLIFNUM, &ifn) < 0) {
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
" You will have to set it manually.\n");
close(s);
return;
}
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
bufsz = ifn.lifn_count * sizeof(struct lifreq);
if (!(buf = ast_malloc(bufsz))) {
ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. "
"You will have to set it manually.\n");
close(s);
return;
}
memset(buf, 0, bufsz);
/* Get a list of interfaces on the machine */
ifc.lifc_len = bufsz;
ifc.lifc_buf = buf;
ifc.lifc_family = AF_UNSPEC;
ifc.lifc_flags = 0;
if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) {
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
"You will have to set it manually.\n");
ast_free(buf);
close(s);
return;
}
for (ifr = (struct lifreq *)buf, x = 0; x < ifn.lifn_count; ifr++, x++) {
unsigned char *p;
sa = (struct sockaddr_in *)&(ifr->lifr_addr);
sa2 = (struct sockaddr_in *)&(ar.arp_pa);
*sa2 = *sa;
if(ioctl(s, SIOCGARP, &ar) >= 0) {
p = (unsigned char *)&(ar.arp_ha.sa_data);
if (!(memcmp(p, &empty_mac, 6) && memcmp(p, &full_mac, 6))) {
continue;
}
memcpy(eid, p, sizeof(*eid));
ast_debug(1, "Seeding global EID '%s'\n",
ast_eid_to_str(eid_str, sizeof(eid_str), eid));
ast_free(buf);
close(s);
return;
}
}
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
"You will have to set it manually.\n");
ast_free(buf);
return;
}
void ast_set_default_eid(struct ast_eid *eid)
{
int s;
int i;
struct ifreq *ifr;
struct ifreq *ifrp;
struct ifconf ifc;
char *buf = NULL;
char eid_str[20];
int bufsz, num_interfaces;
unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
s = socket(AF_INET, SOCK_STREAM, 0);
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
ast_log(LOG_WARNING, "Unable to open socket for seeding global EID. "
"You will have to set it manually.\n");
return;
}
ifc.ifc_len = 0;
ifc.ifc_buf = NULL;
if (ioctl(s, SIOCGIFCONF, &ifc) || ifc.ifc_len <= 0) {
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
"You will have to set it manually.\n");
close(s);
return;
}
bufsz = ifc.ifc_len;
if (!(buf = ast_malloc(bufsz))) {
ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. "
"You will have to set it manually.\n");
close(s);
return;
}
ifc.ifc_buf = buf;
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
ast_log(LOG_WARNING, "Unable to retrieve ethernet interfaces for seeding global EID. "
"You will have to set it manually.\n");
ast_free(buf);
close(s);
return;
}
ifrp = ifc.ifc_req;
num_interfaces = ifc.ifc_len / sizeof(*ifr);
for (i = 0; i < num_interfaces; i++) {
ifr = &ifrp[i];
if (!ioctl(s, SIOCGIFHWADDR, ifr)) {
unsigned char *hwaddr = (unsigned char *) ifr->ifr_hwaddr.sa_data;
if (!(memcmp(hwaddr, &empty_mac, 6) && memcmp(hwaddr, &full_mac, 6))) {
continue;
memcpy(eid, hwaddr, sizeof(*eid));
ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n",
ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr->ifr_name);
ast_free(buf);
close(s);
return;
ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
"You will have to set it manually.\n");
ast_free(buf);
close(s);
return;
#endif /* LINUX */
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
int ast_str_to_eid(struct ast_eid *eid, const char *s)
{
unsigned int eid_int[6];
int x;
if (sscanf(s, "%2x:%2x:%2x:%2x:%2x:%2x", &eid_int[0], &eid_int[1], &eid_int[2],
&eid_int[3], &eid_int[4], &eid_int[5]) != 6) {
return -1;
}
for (x = 0; x < 6; x++) {
eid->eid[x] = eid_int[x];
}
return 0;
}
int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
{
return memcmp(eid1, eid2, sizeof(*eid1));
}
int ast_eid_is_empty(const struct ast_eid *eid)
{
struct ast_eid empty_eid;
memset(&empty_eid, 0, sizeof(empty_eid));
return memcmp(eid, &empty_eid, sizeof(empty_eid)) ? 0 : 1;