BuildSystem: Remove unused variables.
[asterisk/asterisk.git] / main / utils.c
index 0983975..85228c1 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "asterisk.h"
 
-ASTERISK_REGISTER_FILE()
-
 #include <ctype.h>
 #include <fcntl.h>
 #include <sys/stat.h>
@@ -69,6 +67,9 @@ ASTERISK_REGISTER_FILE()
 #define AST_API_MODULE
 #include "asterisk/config.h"
 
+#define AST_API_MODULE
+#include "asterisk/alertpipe.h"
+
 static char base64[64];
 static char b2a[256];
 
@@ -614,10 +615,9 @@ static int dev_urandom_fd = -1;
 #undef pthread_create /* For ast_pthread_create function only */
 #endif /* !__linux__ */
 
-#if !defined(LOW_MEMORY)
-
 #ifdef DEBUG_THREADS
 
+#if !defined(LOW_MEMORY)
 /*! \brief A reasonable maximum number of locks a thread would be holding ... */
 #define AST_MAX_LOCKS 64
 
@@ -720,14 +720,12 @@ static void lock_info_destroy(void *data)
  * \brief The thread storage key for per-thread lock info
  */
 AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy);
-#ifdef HAVE_BKTR
+#endif /* ! LOW_MEMORY */
+
 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
        int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
-#else
-void ast_store_lock_info(enum ast_lock_type type, const char *filename,
-       int line_num, const char *func, const char *lock_name, void *lock_addr)
-#endif
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
        int i;
 
@@ -778,10 +776,12 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename,
        lock_info->num_locks++;
 
        pthread_mutex_unlock(&lock_info->lock);
+#endif /* ! LOW_MEMORY */
 }
 
 void ast_mark_lock_acquired(void *lock_addr)
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
 
        if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
@@ -792,10 +792,12 @@ void ast_mark_lock_acquired(void *lock_addr)
                lock_info->locks[lock_info->num_locks - 1].pending = 0;
        }
        pthread_mutex_unlock(&lock_info->lock);
+#endif /* ! LOW_MEMORY */
 }
 
 void ast_mark_lock_failed(void *lock_addr)
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
 
        if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
@@ -807,10 +809,12 @@ void ast_mark_lock_failed(void *lock_addr)
                lock_info->locks[lock_info->num_locks - 1].times_locked--;
        }
        pthread_mutex_unlock(&lock_info->lock);
+#endif /* ! LOW_MEMORY */
 }
 
 int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size)
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
        int i = 0;
 
@@ -838,10 +842,14 @@ int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, in
        pthread_mutex_unlock(&lock_info->lock);
 
        return 0;
+#else /* if defined(LOW_MEMORY) */
+       return -1;
+#endif
 }
 
 void ast_suspend_lock_info(void *lock_addr)
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
        int i = 0;
 
@@ -865,10 +873,12 @@ void ast_suspend_lock_info(void *lock_addr)
        lock_info->locks[i].suspended = 1;
 
        pthread_mutex_unlock(&lock_info->lock);
+#endif /* ! LOW_MEMORY */
 }
 
 void ast_restore_lock_info(void *lock_addr)
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
        int i = 0;
 
@@ -891,15 +901,13 @@ void ast_restore_lock_info(void *lock_addr)
        lock_info->locks[i].suspended = 0;
 
        pthread_mutex_unlock(&lock_info->lock);
+#endif /* ! LOW_MEMORY */
 }
 
 
-#ifdef HAVE_BKTR
 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
-#else
-void ast_remove_lock_info(void *lock_addr)
-#endif
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
        int i = 0;
 
@@ -937,8 +945,10 @@ void ast_remove_lock_info(void *lock_addr)
        lock_info->num_locks--;
 
        pthread_mutex_unlock(&lock_info->lock);
+#endif /* ! LOW_MEMORY */
 }
 
+#if !defined(LOW_MEMORY)
 static const char *locktype2str(enum ast_lock_type type)
 {
        switch (type) {
@@ -1017,7 +1027,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
        }
        ast_reentrancy_unlock(lt);
 }
-
+#endif /* ! LOW_MEMORY */
 
 /*! This function can help you find highly temporal locks; locks that happen for a
     short time, but at unexpected times, usually at times that create a deadlock,
@@ -1040,6 +1050,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
 */
 void ast_log_show_lock(void *this_lock_addr)
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
        struct ast_str *str;
 
@@ -1066,11 +1077,13 @@ void ast_log_show_lock(void *this_lock_addr)
        }
        pthread_mutex_unlock(&lock_infos_lock.mutex);
        ast_free(str);
+#endif /* ! LOW_MEMORY */
 }
 
 
 struct ast_str *ast_dump_locks(void)
 {
+#if !defined(LOW_MEMORY)
        struct thr_lock_info *lock_info;
        struct ast_str *str;
 
@@ -1137,8 +1150,12 @@ struct ast_str *ast_dump_locks(void)
                       "\n");
 
        return str;
+#else /* if defined(LOW_MEMORY) */
+       return NULL;
+#endif
 }
 
+#if !defined(LOW_MEMORY)
 static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct ast_str *str;
@@ -1172,9 +1189,10 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_
 static struct ast_cli_entry utils_cli[] = {
        AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"),
 };
-
+#endif /* ! LOW_MEMORY */
 #endif /* DEBUG_THREADS */
 
+#if !defined(LOW_MEMORY)
 /*
  * support for 'show threads'. The start routine is wrapped by
  * dummy_start(), so that ast_register_thread() and
@@ -1236,6 +1254,15 @@ static void *dummy_start(void *data)
 
 #endif /* !LOW_MEMORY */
 
+int ast_background_stacksize(void)
+{
+#if !defined(LOW_MEMORY)
+       return AST_STACKSIZE;
+#else
+       return AST_STACKSIZE_LOW;
+#endif
+}
+
 int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
                             void *data, size_t stacksize, const char *file, const char *caller,
                             int line, const char *start_fn)
@@ -1429,68 +1456,6 @@ int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
        return res;
 }
 
-int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms)
-{
-       struct timeval start = ast_tvnow();
-       int n = 0;
-       int elapsed = 0;
-
-       while (len) {
-               if (wait_for_output(fd, timeoutms - elapsed)) {
-                       /* poll returned a fatal error, so bail out immediately. */
-                       return -1;
-               }
-
-               /* Clear any errors from a previous write */
-               clearerr(f);
-
-               n = fwrite(src, 1, len, f);
-
-               if (ferror(f) && errno != EINTR && errno != EAGAIN) {
-                       /* fatal error from fwrite() */
-                       if (!feof(f)) {
-                               /* Don't spam the logs if it was just that the connection is closed. */
-                               ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno));
-                       }
-                       n = -1;
-                       break;
-               }
-
-               /* Update for data already written to the socket */
-               len -= n;
-               src += n;
-
-               elapsed = ast_tvdiff_ms(ast_tvnow(), start);
-               if (elapsed >= timeoutms) {
-                       /* We've taken too long to write
-                        * This is only an error condition if we haven't finished writing. */
-                       n = len ? -1 : 0;
-                       break;
-               }
-       }
-
-       errno = 0;
-       while (fflush(f)) {
-               if (errno == EAGAIN || errno == EINTR) {
-                       /* fflush() does not appear to reset errno if it flushes
-                        * and reaches EOF at the same time. It returns EOF with
-                        * the last seen value of errno, causing a possible loop.
-                        * Also usleep() to reduce CPU eating if it does loop */
-                       errno = 0;
-                       usleep(1);
-                       continue;
-               }
-               if (errno && !feof(f)) {
-                       /* Don't spam the logs if it was just that the connection is closed. */
-                       ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
-               }
-               n = -1;
-               break;
-       }
-
-       return n < 0 ? -1 : 0;
-}
-
 char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
 {
        char *e;
@@ -1516,7 +1481,7 @@ char *ast_strsep(char **iss, const char sep, uint32_t flags)
        int found = 0;
        char stack[8];
 
-       if (iss == NULL || *iss == '\0') {
+       if (ast_strlen_zero(st)) {
                return NULL;
        }
 
@@ -2369,13 +2334,19 @@ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request,
 }
 
 #ifndef __AST_DEBUG_MALLOC
-int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
+int __ast_asprintf(const char *file, int lineno, const char *func, char **ret, const char *fmt, ...)
 {
        int res;
        va_list ap;
 
        va_start(ap, fmt);
-       if ((res = vasprintf(ret, fmt, ap)) == -1) {
+       res = vasprintf(ret, fmt, ap);
+       if (res < 0) {
+               /*
+                * *ret is undefined so set to NULL to ensure it is
+                * initialized to something useful.
+                */
+               *ret = NULL;
                MALLOC_FAILURE_MSG;
        }
        va_end(ap);
@@ -2420,7 +2391,19 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
        return NULL;
 }
 
-void ast_do_crash(void)
+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();
@@ -2432,17 +2415,16 @@ void ast_do_crash(void)
 #endif /* defined(DO_CRASH) */
 }
 
-#if defined(AST_DEVMODE)
-void __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
+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 ...
         */
-       ast_log(__LOG_ERROR, file, line, function, "FRACK!, Failed assertion %s (%d)\n",
-               condition_str, condition);
        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();
@@ -2455,7 +2437,6 @@ void __ast_assert_failed(int condition, const char *condition_str, const char *f
        usleep(1);
        ast_do_crash();
 }
-#endif /* defined(AST_DEVMODE) */
 
 char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
 {
@@ -2475,72 +2456,226 @@ char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
        return os;
 }
 
+#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__)
+#include <ifaddrs.h>
+#include <net/if_dl.h>
+
 void ast_set_default_eid(struct ast_eid *eid)
 {
-#if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR)
-       int s, x = 0;
+       struct ifaddrs *ifap, *ifaphead;
+       int rtnerr;
+       const struct sockaddr_dl *sdl;
+       int alen;
+       caddr_t ap;
        char eid_str[20];
-       struct ifreq ifr;
-       static const unsigned int MAXIF = 10;
+       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) {
+       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;
        }
-       for (x = 0; x < MAXIF; x++) {
-               static const char *prefixes[] = { "eth", "em" };
-               unsigned int i;
 
-               for (i = 0; i < ARRAY_LEN(prefixes); i++) {
-                       memset(&ifr, 0, sizeof(ifr));
-                       snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", prefixes[i], x);
-                       if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-                               break;
-                       }
+       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;
                }
 
-               if (i == ARRAY_LEN(prefixes)) {
-                       /* Try pciX#[1..N] */
-                       for (i = 0; i < MAXIF; i++) {
-                               memset(&ifr, 0, sizeof(ifr));
-                               snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "pci%d#%u", x, i);
-                               if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-                                       break;
-                               }
-                       }
-                       if (i == MAXIF) {
-                               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;
                }
 
-               memcpy(eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, 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);
+               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;
+       int res = 0;
+       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;
+       }
+
+       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);
        close(s);
+
+       return;
+}
+
 #else
-#if defined(ifa_broadaddr) && !defined(SOLARIS)
+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];
-       struct ifaddrs *ifap;
-
-       if (getifaddrs(&ifap) == 0) {
-               struct ifaddrs *p;
-               for (p = ifap; p; p = p->ifa_next) {
-                       if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
-                               struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
-                               memcpy(&(eid->eid), sdp->sdl_data + sdp->sdl_nlen, 6);
-                               ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), p->ifa_name);
-                               freeifaddrs(ifap);
-                               return;
+       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);
+       if (s < 0) {
+               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;
                }
-               freeifaddrs(ifap);
        }
-#endif
-#endif
-       ast_debug(1, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
+
+       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 */
 
 int ast_str_to_eid(struct ast_eid *eid, const char *s)
 {
@@ -2564,6 +2699,14 @@ 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;
+}
+
 int ast_file_is_readable(const char *filename)
 {
 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
@@ -2606,3 +2749,37 @@ int ast_compare_versions(const char *version1, const char *version2)
        }
        return extra[0] - extra[1];
 }
+
+int __ast_fd_set_flags(int fd, int flags, enum ast_fd_flag_operation op,
+       const char *file, int lineno, const char *function)
+{
+       int f;
+
+       f = fcntl(fd, F_GETFL);
+       if (f == -1) {
+               ast_log(__LOG_ERROR, file, lineno, function,
+                       "Failed to get fcntl() flags for file descriptor: %s\n", strerror(errno));
+               return -1;
+       }
+
+       switch (op) {
+       case AST_FD_FLAG_SET:
+               f |= flags;
+               break;
+       case AST_FD_FLAG_CLEAR:
+               f &= ~flags;
+               break;
+       default:
+               ast_assert(0);
+               break;
+       }
+
+       f = fcntl(fd, F_SETFL, f);
+       if (f == -1) {
+               ast_log(__LOG_ERROR, file, lineno, function,
+                       "Failed to set fcntl() flags for file descriptor: %s\n", strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}