Thu Oct 9 06:44:48 2008

Asterisk developer's documentation


asterisk.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@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 
00020 /* Doxygenified Copyright Header */
00021 
00022 /*!
00023  * \mainpage Asterisk -- An Open Source Telephony Toolkit
00024  *
00025  * \par Developer Documentation for Asterisk
00026  * This is the main developer documentation for Asterisk. It is 
00027  * generated by running "make progdocs".
00028  * \par Additional documentation
00029  * \arg \ref DevDoc 
00030  * \arg \ref ConfigFiles
00031  *
00032  * \section copyright Copyright and author
00033  *
00034  * Copyright (C) 1999 - 2005, Digium, Inc.
00035  * Asterisk is a trade mark registered by Digium, Inc.
00036  *
00037  * \author Mark Spencer <markster@digium.com>
00038  * Also see \ref AstCREDITS
00039  *
00040  * \section license License
00041  * See http://www.asterisk.org for more information about
00042  * the Asterisk project. Please do not directly contact
00043  * any of the maintainers of this project for assistance;
00044  * the project provides a web site, mailing lists and IRC
00045  * channels for your use.
00046  *
00047  * This program is free software, distributed under the terms of
00048  * the GNU General Public License Version 2. See the LICENSE file
00049  * at the top of the source tree.
00050  *
00051  * \verbinclude LICENSE
00052  *
00053  */
00054 
00055 /*! \file
00056   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
00057   of PBX core functions and CLI interface.
00058   
00059  */
00060 
00061 #include <unistd.h>
00062 #include <stdlib.h>
00063 #include <sys/time.h>
00064 #include <fcntl.h>
00065 #include <stdio.h>
00066 #include <signal.h>
00067 #include <sched.h>
00068 #include <sys/socket.h>
00069 #include <sys/un.h>
00070 #include <sys/wait.h>
00071 #include <string.h>
00072 #include <errno.h>
00073 #include <ctype.h>
00074 #include <sys/resource.h>
00075 #include <grp.h>
00076 #include <pwd.h>
00077 #include <sys/stat.h>
00078 #include <regex.h>
00079 
00080 #ifdef linux
00081 #include <sys/prctl.h>
00082 #endif 
00083 
00084 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
00085 #include <netdb.h>
00086 #if defined(SOLARIS)
00087 extern int daemon(int, int);  /* defined in libresolv of all places */
00088 #endif
00089 #endif
00090 
00091 #include "asterisk.h"
00092 
00093 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 72373 $")
00094 
00095 #include "asterisk/logger.h"
00096 #include "asterisk/options.h"
00097 #include "asterisk/cli.h"
00098 #include "asterisk/channel.h"
00099 #include "asterisk/ulaw.h"
00100 #include "asterisk/alaw.h"
00101 #include "asterisk/callerid.h"
00102 #include "asterisk/module.h"
00103 #include "asterisk/image.h"
00104 #include "asterisk/tdd.h"
00105 #include "asterisk/term.h"
00106 #include "asterisk/manager.h"
00107 #include "asterisk/cdr.h"
00108 #include "asterisk/pbx.h"
00109 #include "asterisk/enum.h"
00110 #include "asterisk/rtp.h"
00111 #include "asterisk/app.h"
00112 #include "asterisk/lock.h"
00113 #include "asterisk/utils.h"
00114 #include "asterisk/file.h"
00115 #include "asterisk/io.h"
00116 #include "asterisk/lock.h"
00117 #include "editline/histedit.h"
00118 #include "asterisk/config.h"
00119 #include "asterisk/version.h"
00120 #include "asterisk/linkedlists.h"
00121 #include "asterisk/devicestate.h"
00122 #include "asterisk/compat.h"
00123 
00124 #include "asterisk/doxyref.h"    /* Doxygen documentation */
00125 
00126 #include "defaults.h"
00127 
00128 #ifndef AF_LOCAL
00129 #define AF_LOCAL AF_UNIX
00130 #define PF_LOCAL PF_UNIX
00131 #endif
00132 
00133 #define AST_MAX_CONNECTS 128
00134 #define NUM_MSGS 64
00135 
00136 /*! \brief Welcome message when starting a CLI interface */
00137 #define WELCOME_MESSAGE \
00138    ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2007 Digium, Inc. and others.\n"); \
00139    ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
00140    ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
00141    ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
00142    ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
00143    ast_verbose("certain conditions. Type 'show license' for details.\n"); \
00144    ast_verbose("=========================================================================\n")
00145 
00146 /*! \defgroup main_options 
00147  \brief Main configuration options from \ref Config_ast "asterisk.conf" or 
00148   the operating system command line when starting Asterisk 
00149   Some of them can be changed in the CLI 
00150  */
00151 /*! @{ */
00152 int option_verbose=0;         /*!< Verbosity level */
00153 int option_debug=0;        /*!< Debug level */
00154 int option_exec_includes=0;      /*!< Allow \#exec in config files? */
00155 int option_nofork=0;       /*!< Do not fork */
00156 int option_quiet=0;        /*!< Keep quiet */
00157 int option_console=0;         /*!< Console mode, no background */
00158 int option_highpriority=0;    /*!< Run in realtime Linux priority */
00159 int option_remote=0;       /*!< Remote CLI */
00160 int option_exec=0;         /*!< */
00161 int option_initcrypto=0;      /*!< Initialize crypto keys for RSA auth */
00162 int option_nocolor;        /*!< Don't use termcap colors */
00163 int option_dumpcore = 0;         /*!< Dump core when failing */
00164 int option_cache_record_files = 0;     /*!< Cache sound files */
00165 int option_timestamp = 0;        /*!< Timestamp in logging */
00166 int option_overrideconfig = 0;         /*!< */
00167 int option_reconnect = 0;        /*!< */
00168 int option_transcode_slin = 1;         /*!< */
00169 int option_maxcalls = 0;         /*!< */
00170 double option_maxload = 0.0;        /*!< Max load avg on system */
00171 int option_dontwarn = 0;         /*!< */
00172 int option_priority_jumping = 1;    /*!< Enable priority jumping as result value for apps */
00173 int option_transmit_silence_during_record = 0;  /*!< Transmit silence during record() app */
00174 
00175 /*! @} */
00176 
00177 int fully_booted = 0;
00178 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
00179 char debug_filename[AST_FILENAME_MAX] = "";
00180 
00181 static int ast_socket = -1;      /*!< UNIX Socket for allowing remote control */
00182 static int ast_consock = -1;     /*!< UNIX Socket for controlling another asterisk */
00183 int ast_mainpid;
00184 struct console {
00185    int fd;           /*!< File descriptor */
00186    int p[2];         /*!< Pipe */
00187    pthread_t t;         /*!< Thread of handler */
00188 };
00189 
00190 static struct ast_atexit {
00191    void (*func)(void);
00192    struct ast_atexit *next;
00193 } *atexits = NULL;
00194 
00195 AST_MUTEX_DEFINE_STATIC(atexitslock);
00196 
00197 time_t ast_startuptime;
00198 time_t ast_lastreloadtime;
00199 
00200 static History *el_hist = NULL;
00201 static EditLine *el = NULL;
00202 static char *remotehostname;
00203 
00204 struct console consoles[AST_MAX_CONNECTS];
00205 
00206 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00207 
00208 static int ast_el_add_history(char *);
00209 static int ast_el_read_history(char *);
00210 static int ast_el_write_history(char *);
00211 
00212 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
00213 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
00214 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
00215 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
00216 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
00217 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
00218 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
00219 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
00220 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
00221 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
00222 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
00223 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
00224 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
00225 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
00226 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
00227 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
00228 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
00229 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
00230 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
00231 
00232 static char *_argv[256];
00233 static int shuttingdown = 0;
00234 static int restartnow = 0;
00235 static pthread_t consolethread = AST_PTHREADT_NULL;
00236 
00237 static int sig_alert_pipe[2] = { -1, -1 };
00238 static struct {
00239     unsigned int need_reload:1;
00240     unsigned int need_quit:1;
00241 } sig_flags;
00242 
00243 #if !defined(LOW_MEMORY)
00244 struct file_version {
00245    AST_LIST_ENTRY(file_version) list;
00246    const char *file;
00247    char *version;
00248 };
00249 
00250 static AST_LIST_HEAD_STATIC(file_versions, file_version);
00251 
00252 void ast_register_file_version(const char *file, const char *version)
00253 {
00254    struct file_version *new;
00255    char *work;
00256    size_t version_length;
00257 
00258    work = ast_strdupa(version);
00259    work = ast_strip(ast_strip_quoted(work, "$", "$"));
00260    version_length = strlen(work) + 1;
00261 
00262    new = calloc(1, sizeof(*new) + version_length);
00263    if (!new)
00264       return;
00265 
00266    new->file = file;
00267    new->version = (char *) new + sizeof(*new);
00268    memcpy(new->version, work, version_length);
00269    AST_LIST_LOCK(&file_versions);
00270    AST_LIST_INSERT_HEAD(&file_versions, new, list);
00271    AST_LIST_UNLOCK(&file_versions);
00272 }
00273 
00274 void ast_unregister_file_version(const char *file)
00275 {
00276    struct file_version *find;
00277 
00278    AST_LIST_LOCK(&file_versions);
00279    AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00280       if (!strcasecmp(find->file, file)) {
00281          AST_LIST_REMOVE_CURRENT(&file_versions, list);
00282          break;
00283       }
00284    }
00285    AST_LIST_TRAVERSE_SAFE_END;
00286    AST_LIST_UNLOCK(&file_versions);
00287    if (find)
00288       free(find);
00289 }
00290 
00291 static char show_version_files_help[] = 
00292 "Usage: show version files [like <pattern>]\n"
00293 "       Shows the revision numbers of the files used to build this copy of Asterisk.\n"
00294 "       Optional regular expression pattern is used to filter the file list.\n";
00295 
00296 /*! CLI command to list module versions */
00297 static int handle_show_version_files(int fd, int argc, char *argv[])
00298 {
00299 #define FORMAT "%-25.25s %-40.40s\n"
00300    struct file_version *iterator;
00301    regex_t regexbuf;
00302    int havepattern = 0;
00303    int havename = 0;
00304    int count_files = 0;
00305 
00306    switch (argc) {
00307    case 5:
00308       if (!strcasecmp(argv[3], "like")) {
00309          if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
00310             return RESULT_SHOWUSAGE;
00311          havepattern = 1;
00312       } else
00313          return RESULT_SHOWUSAGE;
00314       break;
00315    case 4:
00316       havename = 1;
00317       break;
00318    case 3:
00319       break;
00320    default:
00321       return RESULT_SHOWUSAGE;
00322    }
00323 
00324    ast_cli(fd, FORMAT, "File", "Revision");
00325    ast_cli(fd, FORMAT, "----", "--------");
00326    AST_LIST_LOCK(&file_versions);
00327    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00328       if (havename && strcasecmp(iterator->file, argv[3]))
00329          continue;
00330 
00331       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
00332          continue;
00333 
00334       ast_cli(fd, FORMAT, iterator->file, iterator->version);
00335       count_files++;
00336       if (havename)
00337          break;
00338    }
00339    AST_LIST_UNLOCK(&file_versions);
00340    if (!havename) {
00341       ast_cli(fd, "%d files listed.\n", count_files);
00342    }
00343 
00344    if (havepattern)
00345       regfree(&regexbuf);
00346 
00347    return RESULT_SUCCESS;
00348 #undef FORMAT
00349 }
00350 
00351 static char *complete_show_version_files(char *line, char *word, int pos, int state)
00352 {
00353    struct file_version *find;
00354    int which = 0;
00355    char *ret = NULL;
00356    int matchlen = strlen(word);
00357 
00358    if (pos != 3)
00359       return NULL;
00360 
00361    AST_LIST_LOCK(&file_versions);
00362    AST_LIST_TRAVERSE(&file_versions, find, list) {
00363       if (!strncasecmp(word, find->file, matchlen)) {
00364          if (++which > state) {
00365             ret = strdup(find->file);
00366             break;
00367          }
00368       }
00369    }
00370    AST_LIST_UNLOCK(&file_versions);
00371 
00372    return ret;
00373 }
00374 #endif /* ! LOW_MEMORY */
00375 
00376 int ast_register_atexit(void (*func)(void))
00377 {
00378    int res = -1;
00379    struct ast_atexit *ae;
00380    ast_unregister_atexit(func);
00381    ae = malloc(sizeof(struct ast_atexit));
00382    ast_mutex_lock(&atexitslock);
00383    if (ae) {
00384       memset(ae, 0, sizeof(struct ast_atexit));
00385       ae->next = atexits;
00386       ae->func = func;
00387       atexits = ae;
00388       res = 0;
00389    }
00390    ast_mutex_unlock(&atexitslock);
00391    return res;
00392 }
00393 
00394 void ast_unregister_atexit(void (*func)(void))
00395 {
00396    struct ast_atexit *ae, *prev = NULL;
00397    ast_mutex_lock(&atexitslock);
00398    ae = atexits;
00399    while(ae) {
00400       if (ae->func == func) {
00401          if (prev)
00402             prev->next = ae->next;
00403          else
00404             atexits = ae->next;
00405          break;
00406       }
00407       prev = ae;
00408       ae = ae->next;
00409    }
00410    ast_mutex_unlock(&atexitslock);
00411 }
00412 
00413 static int fdprint(int fd, const char *s)
00414 {
00415    return write(fd, s, strlen(s) + 1);
00416 }
00417 
00418 /*! NULL handler so we can collect the child exit status */
00419 static void null_sig_handler(int signal)
00420 {
00421 
00422 }
00423 
00424 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
00425 static unsigned int safe_system_level = 0;
00426 static void *safe_system_prev_handler;
00427 
00428 int ast_safe_system(const char *s)
00429 {
00430    pid_t pid;
00431    int x;
00432    int res;
00433    struct rusage rusage;
00434    int status;
00435    unsigned int level;
00436 
00437    /* keep track of how many ast_safe_system() functions
00438       are running at this moment
00439    */
00440    ast_mutex_lock(&safe_system_lock);
00441    level = safe_system_level++;
00442 
00443    /* only replace the handler if it has not already been done */
00444    if (level == 0)
00445       safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
00446 
00447    ast_mutex_unlock(&safe_system_lock);
00448 
00449    pid = fork();
00450 
00451    if (pid == 0) {
00452       if (option_highpriority)
00453          ast_set_priority(0);
00454       /* Close file descriptors and launch system command */
00455       for (x = STDERR_FILENO + 1; x < 4096; x++)
00456          close(x);
00457       execl("/bin/sh", "/bin/sh", "-c", s, NULL);
00458       _exit(1);
00459    } else if (pid > 0) {
00460       for(;;) {
00461          res = wait4(pid, &status, 0, &rusage);
00462          if (res > -1) {
00463             res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00464             break;
00465          } else if (errno != EINTR) 
00466             break;
00467       }
00468    } else {
00469       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00470       res = -1;
00471    }
00472 
00473    ast_mutex_lock(&safe_system_lock);
00474    level = --safe_system_level;
00475 
00476    /* only restore the handler if we are the last one */
00477    if (level == 0)
00478       signal(SIGCHLD, safe_system_prev_handler);
00479 
00480    ast_mutex_unlock(&safe_system_lock);
00481 
00482    return res;
00483 }
00484 
00485 /*!
00486  * write the string to all attached console clients
00487  */
00488 static void ast_network_puts(const char *string)
00489 {
00490    int x;
00491    for (x=0;x<AST_MAX_CONNECTS; x++) {
00492       if (consoles[x].fd > -1) 
00493          fdprint(consoles[x].p[1], string);
00494    }
00495 }
00496 
00497 /*!
00498  * write the string to the console, and all attached
00499  * console clients
00500  */
00501 void ast_console_puts(const char *string)
00502 {
00503    fputs(string, stdout);
00504    fflush(stdout);
00505    ast_network_puts(string);
00506 }
00507 
00508 static void network_verboser(const char *s, int pos, int replace, int complete)
00509    /* ARGUSED */
00510 {
00511    if (replace) {
00512       char *t = alloca(strlen(s) + 2);
00513       if (t) {
00514          sprintf(t, "\r%s", s);
00515          if (complete)
00516             ast_network_puts(t);
00517       } else {
00518          ast_log(LOG_ERROR, "Out of memory\n");
00519          ast_network_puts(s);
00520       }
00521    } else {
00522       if (complete)
00523          ast_network_puts(s);
00524    }
00525 }
00526 
00527 static pthread_t lthread;
00528 
00529 static void *netconsole(void *vconsole)
00530 {
00531    struct console *con = vconsole;
00532    char hostname[MAXHOSTNAMELEN]="";
00533    char tmp[512];
00534    int res;
00535    struct pollfd fds[2];
00536    
00537    if (gethostname(hostname, sizeof(hostname)-1))
00538       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
00539    snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
00540    fdprint(con->fd, tmp);
00541    for(;;) {
00542       fds[0].fd = con->fd;
00543       fds[0].events = POLLIN;
00544       fds[0].revents = 0;
00545       fds[1].fd = con->p[0];
00546       fds[1].events = POLLIN;
00547       fds[1].revents = 0;
00548 
00549       res = poll(fds, 2, -1);
00550       if (res < 0) {
00551          if (errno != EINTR)
00552             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
00553          continue;
00554       }
00555       if (fds[0].revents) {
00556          res = read(con->fd, tmp, sizeof(tmp));
00557          if (res < 1) {
00558             break;
00559          }
00560          tmp[res] = 0;
00561          ast_cli_command(con->fd, tmp);
00562       }
00563       if (fds[1].revents) {
00564          res = read(con->p[0], tmp, sizeof(tmp));
00565          if (res < 1) {
00566             ast_log(LOG_ERROR, "read returned %d\n", res);
00567             break;
00568          }
00569          res = write(con->fd, tmp, res);
00570          if (res < 1)
00571             break;
00572       }
00573    }
00574    if (option_verbose > 2) 
00575       ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
00576    close(con->fd);
00577    close(con->p[0]);
00578    close(con->p[1]);
00579    con->fd = -1;
00580    
00581    return NULL;
00582 }
00583 
00584 static void *listener(void *unused)
00585 {
00586    struct sockaddr_un sunaddr;
00587    int s;
00588    socklen_t len;
00589    int x;
00590    int flags;
00591    struct pollfd fds[1];
00592    pthread_attr_t attr;
00593    pthread_attr_init(&attr);
00594    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00595    for(;;) {
00596       if (ast_socket < 0)
00597          return NULL;
00598       fds[0].fd = ast_socket;
00599       fds[0].events= POLLIN;
00600       s = poll(fds, 1, -1);
00601       pthread_testcancel();
00602       if (s < 0) {
00603          if (errno != EINTR)
00604             ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
00605          continue;
00606       }
00607       len = sizeof(sunaddr);
00608       s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
00609       if (s < 0) {
00610          if (errno != EINTR)
00611             ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
00612       } else {
00613          for (x=0;x<AST_MAX_CONNECTS;x++) {
00614             if (consoles[x].fd < 0) {
00615                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
00616                   ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
00617                   consoles[x].fd = -1;
00618                   fdprint(s, "Server failed to create pipe\n");
00619                   close(s);
00620                   break;
00621                }
00622                flags = fcntl(consoles[x].p[1], F_GETFL);
00623                fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
00624                consoles[x].fd = s;
00625                if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
00626                   ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
00627                   close(consoles[x].p[0]);
00628                   close(consoles[x].p[1]);
00629                   consoles[x].fd = -1;
00630                   fdprint(s, "Server failed to spawn thread\n");
00631                   close(s);
00632                }
00633                break;
00634             }
00635          }
00636          if (x >= AST_MAX_CONNECTS) {
00637             fdprint(s, "No more connections allowed\n");
00638             ast_log(LOG_WARNING, "No more connections allowed\n");
00639             close(s);
00640          } else if (consoles[x].fd > -1) {
00641             if (option_verbose > 2) 
00642                ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
00643          }
00644       }
00645    }
00646    return NULL;
00647 }
00648 
00649 static int ast_makesocket(void)
00650 {
00651    struct sockaddr_un sunaddr;
00652    int res;
00653    int x;
00654    uid_t uid = -1;
00655    gid_t gid = -1;
00656 
00657    for (x = 0; x < AST_MAX_CONNECTS; x++) 
00658       consoles[x].fd = -1;
00659    unlink(ast_config_AST_SOCKET);
00660    ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
00661    if (ast_socket < 0) {
00662       ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
00663       return -1;
00664    }     
00665    memset(&sunaddr, 0, sizeof(sunaddr));
00666    sunaddr.sun_family = AF_LOCAL;
00667    ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
00668    res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
00669    if (res) {
00670       ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00671       close(ast_socket);
00672       ast_socket = -1;
00673       return -1;
00674    }
00675    res = listen(ast_socket, 2);
00676    if (res < 0) {
00677       ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00678       close(ast_socket);
00679       ast_socket = -1;
00680       return -1;
00681    }
00682    ast_register_verbose(network_verboser);
00683    ast_pthread_create(&lthread, NULL, listener, NULL);
00684 
00685    if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
00686       struct passwd *pw;
00687       if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
00688          ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
00689       } else {
00690          uid = pw->pw_uid;
00691       }
00692    }
00693       
00694    if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
00695       struct group *grp;
00696       if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
00697          ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
00698       } else {
00699          gid = grp->gr_gid;
00700       }
00701    }
00702 
00703    if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
00704       ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00705 
00706    if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
00707       int p1;
00708       mode_t p;
00709       sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
00710       p = p1;
00711       if ((chmod(ast_config_AST_SOCKET, p)) < 0)
00712          ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00713    }
00714 
00715    return 0;
00716 }
00717 
00718 static int ast_tryconnect(void)
00719 {
00720    struct sockaddr_un sunaddr;
00721    int res;
00722    ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
00723    if (ast_consock < 0) {
00724       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
00725       return 0;
00726    }
00727    memset(&sunaddr, 0, sizeof(sunaddr));
00728    sunaddr.sun_family = AF_LOCAL;
00729    ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
00730    res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
00731    if (res) {
00732       close(ast_consock);
00733       ast_consock = -1;
00734       return 0;
00735    } else
00736       return 1;
00737 }
00738 
00739 /*! Urgent handler
00740  Called by soft_hangup to interrupt the poll, read, or other
00741  system call.  We don't actually need to do anything though.  
00742  Remember: Cannot EVER ast_log from within a signal handler 
00743  */
00744 static void urg_handler(int num)
00745 {
00746    signal(num, urg_handler);
00747    return;
00748 }
00749 
00750 static void hup_handler(int num)
00751 {
00752    int a = 0;
00753    if (option_verbose > 1) 
00754       printf("Received HUP signal -- Reloading configs\n");
00755    if (restartnow)
00756       execvp(_argv[0], _argv);
00757    sig_flags.need_reload = 1;
00758    if (sig_alert_pipe[1] != -1)
00759       write(sig_alert_pipe[1], &a, sizeof(a));
00760    signal(num, hup_handler);
00761 }
00762 
00763 static void child_handler(int sig)
00764 {
00765    /* Must not ever ast_log or ast_verbose within signal handler */
00766    int n, status;
00767 
00768    /*
00769     * Reap all dead children -- not just one
00770     */
00771    for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
00772       ;
00773    if (n == 0 && option_debug)   
00774       printf("Huh?  Child handler, but nobody there?\n");
00775    signal(sig, child_handler);
00776 }
00777 
00778 /*! Set an X-term or screen title */
00779 static void set_title(char *text)
00780 {
00781    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
00782       fprintf(stdout, "\033]2;%s\007", text);
00783 }
00784 
00785 static void set_icon(char *text)
00786 {
00787    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
00788       fprintf(stdout, "\033]1;%s\007", text);
00789 }
00790 
00791 /*! We set ourselves to a high priority, that we might pre-empt everything
00792    else.  If your PBX has heavy activity on it, this is a good thing.  */
00793 int ast_set_priority(int pri)
00794 {
00795    struct sched_param sched;
00796    memset(&sched, 0, sizeof(sched));
00797 #ifdef __linux__
00798 #undef sched_setscheduler
00799    if (pri) {  
00800       sched.sched_priority = 10;
00801       if (sched_setscheduler(0, SCHED_RR, &sched)) {
00802          ast_log(LOG_WARNING, "Unable to set high priority\n");
00803          return -1;
00804       } else
00805          if (option_verbose)
00806             ast_verbose("Set to realtime thread\n");
00807    } else {
00808       sched.sched_priority = 0;
00809       /* According to the manpage, this can never fail, with these parameters. */
00810       sched_setscheduler(0, SCHED_OTHER, &sched);
00811    }
00812 #else
00813 #undef setpriority
00814    if (pri) {
00815       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
00816          ast_log(LOG_WARNING, "Unable to set high priority\n");
00817          return -1;
00818       } else
00819          if (option_verbose)
00820             ast_verbose("Set to high priority\n");
00821    } else {
00822       /* According to the manpage, this can never fail, with these parameters. */
00823       setpriority(PRIO_PROCESS, 0, 0);
00824    }
00825 #endif
00826    return 0;
00827 }
00828 
00829 static void ast_run_atexits(void)
00830 {
00831    struct ast_atexit *ae;
00832    ast_mutex_lock(&atexitslock);
00833    ae = atexits;
00834    while(ae) {
00835       if (ae->func) 
00836          ae->func();
00837       ae = ae->next;
00838    }
00839    ast_mutex_unlock(&atexitslock);
00840 }
00841 
00842 static void quit_handler(int num, int nice, int safeshutdown, int restart)
00843 {
00844    char filename[80] = "";
00845    time_t s,e;
00846    int x;
00847    /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
00848    ast_cdr_engine_term();
00849    if (safeshutdown) {
00850       shuttingdown = 1;
00851       if (!nice) {
00852          /* Begin shutdown routine, hanging up active channels */
00853          ast_begin_shutdown(1);
00854          if (option_verbose && option_console)
00855             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
00856          time(&s);
00857          for(;;) {
00858             time(&e);
00859             /* Wait up to 15 seconds for all channels to go away */
00860             if ((e - s) > 15)
00861                break;
00862             if (!ast_active_channels())
00863                break;
00864             if (!shuttingdown)
00865                break;
00866             /* Sleep 1/10 of a second */
00867             usleep(100000);
00868          }
00869       } else {
00870          if (nice < 2)
00871             ast_begin_shutdown(0);
00872          if (option_verbose && option_console)
00873             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
00874          for(;;) {
00875             if (!ast_active_channels())
00876                break;
00877             if (!shuttingdown)
00878                break;
00879             sleep(1);
00880          }
00881       }
00882 
00883       if (!shuttingdown) {
00884          if (option_verbose && option_console)
00885             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
00886          return;
00887       }
00888    }
00889    if (option_console || option_remote) {
00890       if (getenv("HOME")) 
00891          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
00892       if (!ast_strlen_zero(filename))
00893          ast_el_write_history(filename);
00894       if (el != NULL)
00895          el_end(el);
00896       if (el_hist != NULL)
00897          history_end(el_hist);
00898    }
00899    if (option_verbose)
00900       ast_verbose("Executing last minute cleanups\n");
00901    ast_run_atexits();
00902    /* Called on exit */
00903    if (option_verbose && option_console)
00904       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
00905    if (option_debug)
00906       ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
00907    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
00908    if (ast_socket > -1) {
00909       pthread_cancel(lthread);
00910       close(ast_socket);
00911       ast_socket = -1;
00912       unlink(ast_config_AST_SOCKET);
00913    }
00914    if (ast_consock > -1)
00915       close(ast_consock);
00916    if (!option_remote) unlink((char *)ast_config_AST_PID);
00917    printf(term_quit());
00918    if (restart) {
00919       if (option_verbose || option_console)
00920          ast_verbose("Preparing for Asterisk restart...\n");
00921       /* Mark all FD's for closing on exec */
00922       for (x=3;x<32768;x++) {
00923          fcntl(x, F_SETFD, FD_CLOEXEC);
00924       }
00925       if (option_verbose || option_console)
00926          ast_verbose("Restarting Asterisk NOW...\n");
00927       restartnow = 1;
00928 
00929       /* close logger */
00930       close_logger();
00931 
00932       /* If there is a consolethread running send it a SIGHUP 
00933          so it can execvp, otherwise we can do it ourselves */
00934       if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
00935          pthread_kill(consolethread, SIGHUP);
00936          /* Give the signal handler some time to complete */
00937          sleep(2);
00938       } else
00939          execvp(_argv[0], _argv);
00940    
00941    } else {
00942       /* close logger */
00943       close_logger();
00944    }
00945    exit(0);
00946 }
00947 
00948 static void __quit_handler(int num)
00949 {
00950    int a = 0;
00951    sig_flags.need_quit = 1;
00952    if (sig_alert_pipe[1] != -1)
00953       write(sig_alert_pipe[1], &a, sizeof(a));
00954    /* There is no need to restore the signal handler here, since the app
00955     * is going to exit */
00956 }
00957 
00958 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
00959 {
00960    const char *c;
00961    if (!strncmp(s, cmp, strlen(cmp))) {
00962       c = s + strlen(cmp);
00963       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
00964       return c;
00965    }
00966    return NULL;
00967 }
00968 
00969 static void console_verboser(const char *s, int pos, int replace, int complete)
00970 {
00971    char tmp[80];
00972    const char *c=NULL;
00973    /* Return to the beginning of the line */
00974    if (!pos) {
00975       fprintf(stdout, "\r");
00976       if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
00977          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
00978          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
00979          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
00980          fputs(tmp, stdout);
00981    }
00982    if (c)
00983       fputs(c + pos,stdout);
00984    else
00985       fputs(s + pos,stdout);
00986    fflush(stdout);
00987    if (complete) {
00988       /* Wake up a poll()ing console */
00989       if (option_console && consolethread != AST_PTHREADT_NULL)
00990          pthread_kill(consolethread, SIGURG);
00991    }
00992 }
00993 
00994 static int ast_all_zeros(char *s)
00995 {
00996    while(*s) {
00997       if (*s > 32)
00998          return 0;
00999       s++;  
01000    }
01001    return 1;
01002 }
01003 
01004 static void consolehandler(char *s)
01005 {
01006    printf(term_end());
01007    fflush(stdout);
01008 
01009    /* Called when readline data is available */
01010    if (!ast_all_zeros(s))
01011       ast_el_add_history(s);
01012    /* The real handler for bang */
01013    if (s[0] == '!') {
01014       if (s[1])
01015          ast_safe_system(s+1);
01016       else
01017          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01018    } else 
01019       ast_cli_command(STDOUT_FILENO, s);
01020 }
01021 
01022 static int remoteconsolehandler(char *s)
01023 {
01024    int ret = 0;
01025 
01026    /* Called when readline data is available */
01027    if (!ast_all_zeros(s))
01028       ast_el_add_history(s);
01029    /* The real handler for bang */
01030    if (s[0] == '!') {
01031       if (s[1])
01032          ast_safe_system(s+1);
01033       else
01034          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01035       ret = 1;
01036    }
01037    if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01038        (s[4] == '\0' || isspace(s[4]))) {
01039       quit_handler(0, 0, 0, 0);
01040       ret = 1;
01041    }
01042 
01043    return ret;
01044 }
01045 
01046 static char abort_halt_help[] = 
01047 "Usage: abort shutdown\n"
01048 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01049 "       call operations.\n";
01050 
01051 static char shutdown_now_help[] = 
01052 "Usage: stop now\n"
01053 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01054 
01055 static char shutdown_gracefully_help[] = 
01056 "Usage: stop gracefully\n"
01057 "       Causes Asterisk to not accept new calls, and exit when all\n"
01058 "       active calls have terminated normally.\n";
01059 
01060 static char shutdown_when_convenient_help[] = 
01061 "Usage: stop when convenient\n"
01062 "       Causes Asterisk to perform