Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:49 2009

## Asterisk developer's documentation

# app_zapras.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 /*! \file
    00020  *
    00021  * \brief Execute an ISDN RAS
    00022  *
    00023  * \ingroup applications
    00024  */
    00025
    00026 #include <sys/ioctl.h>
    00027 #include <sys/wait.h>
    00028 #ifdef __linux__
    00029 #include <sys/signal.h>
    00030 #else
    00031 #include <signal.h>
    00032 #endif /* __linux__ */
    00033
    00034 #include <stdlib.h>
    00035 #include <unistd.h>
    00036 #include <string.h>
    00037 #include <stdlib.h>
    00038 #include <errno.h>
    00039 #include <stdio.h>
    00040 #include <fcntl.h>
    00041
    00042 /* Need some zaptel help here */
    00043 #ifdef __linux__
    00044 #include <linux/zaptel.h>
    00045 #else
    00046 #include <zaptel.h>
    00047 #endif /* __linux__ */
    00048
    00049 #include "asterisk.h"
    00050
    00051 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 48374 $")
    00052
    00053 #include "asterisk/lock.h"
    00054 #include "asterisk/file.h"
    00055 #include "asterisk/logger.h"
    00056 #include "asterisk/channel.h"
    00057 #include "asterisk/pbx.h"
    00058 #include "asterisk/module.h"
    00059 #include "asterisk/options.h"
    00060
    00061 static char *tdesc = "Zap RAS Application";
    00062
    00063 static char *app = "ZapRAS";
    00064
    00065 static char *synopsis = "Executes Zaptel ISDN RAS application";
    00066
    00067 static char *descrip =
    00068 "  ZapRAS(args): Executes a RAS server using pppd on the given channel.\n"
    00069 "The channel must be a clear channel (i.e. PRI source) and a Zaptel\n"
    00070 "channel to be able to use this function (No modem emulation is included).\n"
    00071 "Your pppd must be patched to be zaptel aware. Arguments should be\n"
    00072 "separated by | characters.\n";
    00073
    00074 STANDARD_LOCAL_USER;
    00075
    00076 LOCAL_USER_DECL;
    00077
    00078 #define PPP_MAX_ARGS 32
    00079 #define PPP_EXEC  "/usr/sbin/pppd"
    00080
    00081 static pid_t spawn_ras(struct ast_channel *chan, char *args)
    00082 {
    00083    pid_t pid;
    00084    int x;
    00085    char *c;
    00086
    00087    char *argv[PPP_MAX_ARGS];
    00088    int argc = 0;
    00089    char *stringp=NULL;
    00090    sigset_t fullset, oldset;
    00091
    00092    sigfillset(&fullset);
    00093    pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
    00094
    00095    /* Start by forking */
    00096    pid = fork();
    00097    if (pid) {
    00098       pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    00099       return pid;
    00100    }
    00101
    00102    /* Restore original signal handlers */
    00103    for (x=0;x<NSIG;x++)
    00104       signal(x, SIG_DFL);
    00105
    00106    pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
    00107
    00108    /* Execute RAS on File handles */
    00109    dup2(chan->fds[0], STDIN_FILENO);
    00110
    00111    /* Drop high priority */
    00112    if (option_highpriority)
    00113       ast_set_priority(0);
    00114
    00115    /* Close other file descriptors */
    00116    for (x=STDERR_FILENO + 1;x<1024;x++)
    00117       close(x);
    00118
    00119    /* Reset all arguments */
    00120    memset(argv, 0, sizeof(argv));
    00121
    00122    /* First argument is executable, followed by standard
    00123       arguments for zaptel PPP */
    00124    argv[argc++] = PPP_EXEC;
    00125    argv[argc++] = "nodetach";
    00126
    00127    /* And all the other arguments */
    00128    stringp=args;
    00129    c = strsep(&stringp, "|");
    00130    while(c && strlen(c) && (argc < (PPP_MAX_ARGS - 4))) {
    00131       argv[argc++] = c;
    00132       c = strsep(&stringp, "|");
    00133    }
    00134
    00135    argv[argc++] = "plugin";
    00136    argv[argc++] = "zaptel.so";
    00137    argv[argc++] = "stdin";
    00138
    00139    /* Finally launch PPP */
    00140    execv(PPP_EXEC, argv);
    00141    fprintf(stderr, "Failed to exec PPPD!\n");
    00142    exit(1);
    00143 }
    00144
    00145 static void run_ras(struct ast_channel *chan, char *args)
    00146 {
    00147    pid_t pid;
    00148    int status;
    00149    int res;
    00150    int signalled = 0;
    00151    struct zt_bufferinfo savebi;
    00152    int x;
    00153
    00154    res = ioctl(chan->fds[0], ZT_GET_BUFINFO, &savebi);
    00155    if(res) {
    00156       ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", chan->name);
    00157       return;
    00158    }
    00159
    00160    pid = spawn_ras(chan, args);
    00161    if (pid < 0) {
    00162       ast_log(LOG_WARNING, "Failed to spawn RAS\n");
    00163    } else {
    00164       for (;;) {
    00165          res = wait4(pid, &status, WNOHANG, NULL);
    00166          if (!res) {
    00167             /* Check for hangup */
    00168             if (chan->_softhangup && !signalled) {
    00169                ast_log(LOG_DEBUG, "Channel '%s' hungup.  Signalling RAS at %d to die...\n", chan->name, pid);
    00170                kill(pid, SIGTERM);
    00171                signalled=1;
    00172             }
    00173             /* Try again */
    00174             sleep(1);
    00175             continue;
    00176          }
    00177          if (res < 0) {
    00178             ast_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno));
    00179          }
    00180          if (option_verbose > 2) {
    00181             if (WIFEXITED(status)) {
    00182                ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with status %d\n", chan->name, WEXITSTATUS(status));
    00183             } else if (WIFSIGNALED(status)) {
    00184                ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with signal %d\n",
    00185                    chan->name, WTERMSIG(status));
    00186             } else {
    00187                ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated weirdly.\n", chan->name);
    00188             }
    00189          }
    00190          /* Throw back into audio mode */
    00191          x = 1;
    00192          ioctl(chan->fds[0], ZT_AUDIOMODE, &x);
    00193
    00194          /* Restore saved values */
    00195          res = ioctl(chan->fds[0], ZT_SET_BUFINFO, &savebi);
    00196          if (res < 0) {
    00197             ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", chan->name);
    00198          }
    00199          break;
    00200       }
    00201    }
    00202 }
    00203
    00204 static int zapras_exec(struct ast_channel *chan, void *data)
    00205 {
    00206    int res=-1;
    00207    char *args;
    00208    struct localuser *u;
    00209    ZT_PARAMS ztp;
    00210
    00211    if (!data)
    00212       data = "";
    00213
    00214    LOCAL_USER_ADD(u);
    00215
    00216    args = ast_strdupa(data);
    00217    if (!args) {
    00218       ast_log(LOG_ERROR, "Out of memory\n");
    00219       LOCAL_USER_REMOVE(u);
    00220       return -1;
    00221    }
    00222
    00223    /* Answer the channel if it's not up */
    00224    if (chan->_state != AST_STATE_UP)
    00225       ast_answer(chan);
    00226    if (strcasecmp(chan->type, "Zap")) {
    00227       /* If it's not a zap channel, we're done.  Wait a couple of
    00228          seconds and then hangup... */
    00229       if (option_verbose > 1)
    00230          ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a Zap channel\n", chan->name);
    00231       sleep(2);
    00232    } else {
    00233       memset(&ztp, 0, sizeof(ztp));
    00234       if (ioctl(chan->fds[0], ZT_GET_PARAMS, &ztp)) {
    00235          ast_log(LOG_WARNING, "Unable to get zaptel parameters\n");
    00236       } else if (ztp.sigtype != ZT_SIG_CLEAR) {
    00237          if (option_verbose > 1)
    00238             ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a clear channel\n", chan->name);
    00239       } else {
    00240          /* Everything should be okay.  Run PPP. */
    00241          if (option_verbose > 2)
    00242             ast_verbose(VERBOSE_PREFIX_3 "Starting RAS on %s\n", chan->name);
    00243          /* Execute RAS */
    00244          run_ras(chan, args);
    00245       }
    00246    }
    00247    LOCAL_USER_REMOVE(u);
    00248    return res;
    00249 }
    00250
    00251 int unload_module(void)
    00252 {
    00253    int res;
    00254
    00255    res = ast_unregister_application(app);
    00256
    00257    STANDARD_HANGUP_LOCALUSERS;
    00258
    00259    return res;
    00260 }
    00261
    00262 int load_module(void)
    00263 {
    00264    return ast_register_application(app, zapras_exec, synopsis, descrip);
    00265 }
    00266
    00267 char *description(void)
    00268 {
    00269    return tdesc;
    00270 }
    00271
    00272 int usecount(void)
    00273 {
    00274    int res;
    00275    STANDARD_USECOUNT(res);
    00276    return res;
    00277 }
    00278
    00279 char *key()
    00280 {
    00281    return ASTERISK_GPL_KEY;
    00282 }