astfd.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2009, Digium, Inc.
00005  *
00006  * Tilghman Lesher <tlesher@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Debugging routines for file descriptor leaks
00022  *
00023  * \author Tilghman Lesher \verbatim <tlesher@digium.com> \endverbatim
00024  */
00025 
00026 /*** MODULEINFO
00027    <support_level>core</support_level>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 #ifdef DEBUG_FD_LEAKS
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 433498 $")
00035 
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <stddef.h>
00039 #include <time.h>
00040 #include <sys/time.h>
00041 #include <sys/resource.h>
00042 
00043 #include "asterisk/cli.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/lock.h"
00047 #include "asterisk/strings.h"
00048 #include "asterisk/unaligned.h"
00049 
00050 static struct fdleaks {
00051    char file[40];
00052    int line;
00053    char function[25];
00054    char callname[10];
00055    char callargs[60];
00056    unsigned int isopen:1;
00057 } fdleaks[1024] = { { "", }, };
00058 
00059 #define  COPY(dst, src)                                             \
00060    do {                                                           \
00061       int dlen = sizeof(dst), slen = strlen(src);                \
00062       if (slen + 1 > dlen) {                                     \
00063          char *slash = strrchr(src, '/');                       \
00064          if (slash) {                                           \
00065             ast_copy_string(dst, slash + 1, dlen);             \
00066          } else {                                               \
00067             ast_copy_string(dst, src + slen - dlen + 1, dlen); \
00068          }                                                      \
00069       } else {                                                   \
00070          ast_copy_string(dst, src, dlen);                       \
00071       }                                                          \
00072    } while (0)
00073 
00074 #define STORE_COMMON(offset, name, ...)     \
00075    COPY(fdleaks[offset].file, file);       \
00076    fdleaks[offset].line = line;            \
00077    COPY(fdleaks[offset].function, func);   \
00078    strcpy(fdleaks[offset].callname, name); \
00079    snprintf(fdleaks[offset].callargs, sizeof(fdleaks[offset].callargs), __VA_ARGS__); \
00080    fdleaks[offset].isopen = 1;
00081 
00082 #undef open
00083 int __ast_fdleak_open(const char *file, int line, const char *func, const char *path, int flags, ...)
00084 {
00085    int res;
00086    va_list ap;
00087    int mode;
00088 
00089    if (flags & O_CREAT) {
00090       va_start(ap, flags);
00091       mode = va_arg(ap, int);
00092       va_end(ap);
00093       res = open(path, flags, mode);
00094       if (res > -1 && res < (sizeof(fdleaks) / sizeof(fdleaks[0]))) {
00095          char sflags[80];
00096          snprintf(sflags, sizeof(sflags), "O_CREAT%s%s%s%s%s%s%s%s",
00097             flags & O_APPEND ? "|O_APPEND" : "",
00098             flags & O_EXCL ? "|O_EXCL" : "",
00099             flags & O_NONBLOCK ? "|O_NONBLOCK" : "",
00100             flags & O_TRUNC ? "|O_TRUNC" : "",
00101             flags & O_RDWR ? "|O_RDWR" : "",
00102 #if O_RDONLY == 0
00103             !(flags & (O_WRONLY | O_RDWR)) ? "|O_RDONLY" : "",
00104 #else
00105             flags & O_RDONLY ? "|O_RDONLY" : "",
00106 #endif
00107             flags & O_WRONLY ? "|O_WRONLY" : "",
00108             "");
00109          flags &= ~(O_CREAT | O_APPEND | O_EXCL | O_NONBLOCK | O_TRUNC | O_RDWR | O_RDONLY | O_WRONLY);
00110          if (flags) {
00111             STORE_COMMON(res, "open", "\"%s\",%s|%d,%04o", path, sflags, flags, mode);
00112          } else {
00113             STORE_COMMON(res, "open", "\"%s\",%s,%04o", path, sflags, mode);
00114          }
00115       }
00116    } else {
00117       res = open(path, flags);
00118       if (res > -1 && res < (sizeof(fdleaks) / sizeof(fdleaks[0]))) {
00119          STORE_COMMON(res, "open", "\"%s\",%d", path, flags);
00120       }
00121    }
00122    return res;
00123 }
00124 
00125 #undef pipe
00126 int __ast_fdleak_pipe(int *fds, const char *file, int line, const char *func)
00127 {
00128    int i, res = pipe(fds);
00129    if (res) {
00130       return res;
00131    }
00132    for (i = 0; i < 2; i++) {
00133       STORE_COMMON(fds[i], "pipe", "{%d,%d}", fds[0], fds[1]);
00134    }
00135    return 0;
00136 }
00137 
00138 #undef socket
00139 int __ast_fdleak_socket(int domain, int type, int protocol, const char *file, int line, const char *func)
00140 {
00141    char sdomain[20], stype[20], *sproto = NULL;
00142    struct protoent *pe;
00143    int res = socket(domain, type, protocol);
00144    if (res < 0 || res > 1023) {
00145       return res;
00146    }
00147 
00148    if ((pe = getprotobynumber(protocol))) {
00149       sproto = pe->p_name;
00150    }
00151 
00152    if (domain == PF_UNIX) {
00153       ast_copy_string(sdomain, "PF_UNIX", sizeof(sdomain));
00154    } else if (domain == PF_INET) {
00155       ast_copy_string(sdomain, "PF_INET", sizeof(sdomain));
00156    } else {
00157       snprintf(sdomain, sizeof(sdomain), "%d", domain);
00158    }
00159 
00160    if (type == SOCK_DGRAM) {
00161       ast_copy_string(stype, "SOCK_DGRAM", sizeof(stype));
00162       if (protocol == 0) {
00163          sproto = "udp";
00164       }
00165    } else if (type == SOCK_STREAM) {
00166       ast_copy_string(stype, "SOCK_STREAM", sizeof(stype));
00167       if (protocol == 0) {
00168          sproto = "tcp";
00169       }
00170    } else {
00171       snprintf(stype, sizeof(stype), "%d", type);
00172    }
00173 
00174    if (sproto) {
00175       STORE_COMMON(res, "socket", "%s,%s,\"%s\"", sdomain, stype, sproto);
00176    } else {
00177       STORE_COMMON(res, "socket", "%s,%s,\"%d\"", sdomain, stype, protocol);
00178    }
00179    return res;
00180 }
00181 
00182 #undef close
00183 int __ast_fdleak_close(int fd)
00184 {
00185    int res = close(fd);
00186    if (!res && fd > -1 && fd < 1024) {
00187       fdleaks[fd].isopen = 0;
00188    }
00189    return res;
00190 }
00191 
00192 #undef fopen
00193 FILE *__ast_fdleak_fopen(const char *path, const char *mode, const char *file, int line, const char *func)
00194 {
00195    FILE *res = fopen(path, mode);
00196    int fd;
00197    if (!res) {
00198       return res;
00199    }
00200    fd = fileno(res);
00201    STORE_COMMON(fd, "fopen", "\"%s\",\"%s\"", path, mode);
00202    return res;
00203 }
00204 
00205 #undef fclose
00206 int __ast_fdleak_fclose(FILE *ptr)
00207 {
00208    int fd, res;
00209    if (!ptr) {
00210       return fclose(ptr);
00211    }
00212 
00213    fd = fileno(ptr);
00214    if ((res = fclose(ptr)) || fd < 0 || fd > 1023) {
00215       return res;
00216    }
00217    fdleaks[fd].isopen = 0;
00218    return res;
00219 }
00220 
00221 #undef dup2
00222 int __ast_fdleak_dup2(int oldfd, int newfd, const char *file, int line, const char *func)
00223 {
00224    int res = dup2(oldfd, newfd);
00225    if (res < 0 || res > 1023) {
00226       return res;
00227    }
00228    STORE_COMMON(res, "dup2", "%d,%d", oldfd, newfd);
00229    return res;
00230 }
00231 
00232 #undef dup
00233 int __ast_fdleak_dup(int oldfd, const char *file, int line, const char *func)
00234 {
00235    int res = dup(oldfd);
00236    if (res < 0 || res > 1023) {
00237       return res;
00238    }
00239    STORE_COMMON(res, "dup2", "%d", oldfd);
00240    return res;
00241 }
00242 
00243 static char *handle_show_fd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00244 {
00245    int i;
00246    char line[24];
00247    struct rlimit rl;
00248    switch (cmd) {
00249    case CLI_INIT:
00250       e->command = "core show fd";
00251       e->usage =
00252          "Usage: core show fd\n"
00253          "       List all file descriptors currently in use and where\n"
00254          "       each was opened, and with what command.\n";
00255       return NULL;
00256    case CLI_GENERATE:
00257       return NULL;
00258    }
00259    getrlimit(RLIMIT_FSIZE, &rl);
00260    if (rl.rlim_cur == RLIM_INFINITY || rl.rlim_max == RLIM_INFINITY) {
00261       ast_copy_string(line, "unlimited", sizeof(line));
00262    } else {
00263       snprintf(line, sizeof(line), "%d/%d", (int) rl.rlim_cur, (int) rl.rlim_max);
00264    }
00265    ast_cli(a->fd, "Current maxfiles: %s\n", line);
00266    for (i = 0; i < 1024; i++) {
00267       if (fdleaks[i].isopen) {
00268          snprintf(line, sizeof(line), "%d", fdleaks[i].line);
00269          ast_cli(a->fd, "%5d %15s:%-7.7s (%-25s): %s(%s)\n", i, fdleaks[i].file, line, fdleaks[i].function, fdleaks[i].callname, fdleaks[i].callargs);
00270       }
00271    }
00272    return CLI_SUCCESS;
00273 }
00274 
00275 static struct ast_cli_entry cli_show_fd = AST_CLI_DEFINE(handle_show_fd, "Show open file descriptors");
00276 
00277 static void fd_shutdown(void)
00278 {
00279    ast_cli_unregister(&cli_show_fd);
00280 }
00281 
00282 int ast_fd_init(void)
00283 {
00284    ast_register_cleanup(fd_shutdown);
00285    return ast_cli_register(&cli_show_fd);
00286 }
00287 
00288 #else  /* !defined(DEBUG_FD_LEAKS) */
00289 int ast_fd_init(void)
00290 {
00291    return 0;
00292 }
00293 #endif /* defined(DEBUG_FD_LEAKS) */
00294 

Generated on Thu Apr 16 06:27:14 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6