app_dahdiras.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  * \author Mark Spencer <markster@digium.com>
00024  * 
00025  * \ingroup applications
00026  */
00027 
00028 /*** MODULEINFO
00029    <depend>dahdi</depend>
00030    <support_level>extended</support_level>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419592 $")
00036 
00037 #include <sys/ioctl.h>
00038 #include <sys/wait.h>
00039 #ifdef __linux__
00040 #include <sys/signal.h>
00041 #else
00042 #include <signal.h>
00043 #endif /* __linux__ */
00044 
00045 #include <fcntl.h>
00046 
00047 #include <dahdi/user.h>
00048 
00049 #include "asterisk/lock.h"
00050 #include "asterisk/file.h"
00051 #include "asterisk/channel.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/app.h"
00055 
00056 /*** DOCUMENTATION
00057    <application name="DAHDIRAS" language="en_US">
00058       <synopsis>
00059          Executes DAHDI ISDN RAS application.
00060       </synopsis>
00061       <syntax>
00062          <parameter name="args" required="true">
00063             <para>A list of parameters to pass to the pppd daemon,
00064             separated by <literal>,</literal> characters.</para>
00065          </parameter>
00066       </syntax>
00067       <description>
00068          <para>Executes a RAS server using pppd on the given channel.
00069          The channel must be a clear channel (i.e. PRI source) and a DAHDI
00070          channel to be able to use this function (No modem emulation is included).</para>
00071          <para>Your pppd must be patched to be DAHDI aware.</para>
00072       </description>
00073    </application>
00074 
00075  ***/
00076 
00077 static const char app[] = "DAHDIRAS";
00078 
00079 #define PPP_MAX_ARGS 32
00080 #define PPP_EXEC  "/usr/sbin/pppd"
00081 
00082 static pid_t spawn_ras(struct ast_channel *chan, char *args)
00083 {
00084    pid_t pid;
00085    char *c;
00086 
00087    char *argv[PPP_MAX_ARGS];
00088    int argc = 0;
00089    char *stringp=NULL;
00090 
00091    /* Start by forking */
00092    pid = ast_safe_fork(1);
00093    if (pid) {
00094       return pid;
00095    }
00096 
00097    /* Execute RAS on File handles */
00098    dup2(ast_channel_fd(chan, 0), STDIN_FILENO);
00099 
00100    /* Drop high priority */
00101    if (ast_opt_high_priority)
00102       ast_set_priority(0);
00103 
00104    /* Close other file descriptors */
00105    ast_close_fds_above_n(STDERR_FILENO);
00106 
00107    /* Reset all arguments */
00108    memset(argv, 0, sizeof(argv));
00109 
00110    /* First argument is executable, followed by standard
00111       arguments for DAHDI PPP */
00112    argv[argc++] = PPP_EXEC;
00113    argv[argc++] = "nodetach";
00114 
00115    /* And all the other arguments */
00116    stringp=args;
00117    c = strsep(&stringp, ",");
00118    while(c && strlen(c) && (argc < (PPP_MAX_ARGS - 4))) {
00119       argv[argc++] = c;
00120       c = strsep(&stringp, ",");
00121    }
00122 
00123    argv[argc++] = "plugin";
00124    argv[argc++] = "dahdi.so";
00125    argv[argc++] = "stdin";
00126 
00127    /* Finally launch PPP */
00128    execv(PPP_EXEC, argv);
00129    fprintf(stderr, "Failed to exec PPPD!\n");
00130    exit(1);
00131 }
00132 
00133 static void run_ras(struct ast_channel *chan, char *args)
00134 {
00135    pid_t pid;
00136    int status;
00137    int res;
00138    int signalled = 0;
00139    struct dahdi_bufferinfo savebi;
00140    int x;
00141    
00142    res = ioctl(ast_channel_fd(chan, 0), DAHDI_GET_BUFINFO, &savebi);
00143    if(res) {
00144       ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", ast_channel_name(chan));
00145       return;
00146    }
00147 
00148    pid = spawn_ras(chan, args);
00149    if (pid < 0) {
00150       ast_log(LOG_WARNING, "Failed to spawn RAS\n");
00151    } else {
00152       for (;;) {
00153          res = waitpid(pid, &status, WNOHANG);
00154          if (!res) {
00155             /* Check for hangup */
00156             if (ast_check_hangup(chan) && !signalled) {
00157                ast_debug(1, "Channel '%s' hungup.  Signalling RAS at %d to die...\n", ast_channel_name(chan), pid);
00158                kill(pid, SIGTERM);
00159                signalled=1;
00160             }
00161             /* Try again */
00162             sleep(1);
00163             continue;
00164          }
00165          if (res < 0) {
00166             ast_log(LOG_WARNING, "waitpid returned %d: %s\n", res, strerror(errno));
00167          }
00168          if (WIFEXITED(status)) {
00169             ast_verb(3, "RAS on %s terminated with status %d\n", ast_channel_name(chan), WEXITSTATUS(status));
00170          } else if (WIFSIGNALED(status)) {
00171             ast_verb(3, "RAS on %s terminated with signal %d\n", 
00172                 ast_channel_name(chan), WTERMSIG(status));
00173          } else {
00174             ast_verb(3, "RAS on %s terminated weirdly.\n", ast_channel_name(chan));
00175          }
00176          /* Throw back into audio mode */
00177          x = 1;
00178          ioctl(ast_channel_fd(chan, 0), DAHDI_AUDIOMODE, &x);
00179 
00180          /* Restore saved values */
00181          res = ioctl(ast_channel_fd(chan, 0), DAHDI_SET_BUFINFO, &savebi);
00182          if (res < 0) {
00183             ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", ast_channel_name(chan));
00184          }
00185          break;
00186       }
00187    }
00188    ast_safe_fork_cleanup();
00189 }
00190 
00191 static int dahdiras_exec(struct ast_channel *chan, const char *data)
00192 {
00193    int res=-1;
00194    char *args;
00195    struct dahdi_params dahdip;
00196 
00197    if (!data) 
00198       data = "";
00199 
00200    args = ast_strdupa(data);
00201    
00202    /* Answer the channel if it's not up */
00203    if (ast_channel_state(chan) != AST_STATE_UP)
00204       ast_answer(chan);
00205    if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
00206       /* If it's not a DAHDI channel, we're done.  Wait a couple of
00207          seconds and then hangup... */
00208       ast_verb(2, "Channel %s is not a DAHDI channel\n", ast_channel_name(chan));
00209       sleep(2);
00210    } else {
00211       memset(&dahdip, 0, sizeof(dahdip));
00212       if (ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip)) {
00213          ast_log(LOG_WARNING, "Unable to get DAHDI parameters\n");
00214       } else if (dahdip.sigtype != DAHDI_SIG_CLEAR) {
00215          ast_verb(2, "Channel %s is not a clear channel\n", ast_channel_name(chan));
00216       } else {
00217          /* Everything should be okay.  Run PPP. */
00218          ast_verb(3, "Starting RAS on %s\n", ast_channel_name(chan));
00219          /* Execute RAS */
00220          run_ras(chan, args);
00221       }
00222    }
00223    return res;
00224 }
00225 
00226 static int unload_module(void) 
00227 {
00228    return ast_unregister_application(app);
00229 }
00230 
00231 static int load_module(void)
00232 {
00233    return ((ast_register_application_xml(app, dahdiras_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
00234 }
00235 
00236 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server");
00237 
00238 

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