Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:20 2009

## Asterisk developer's documentation

# app_zapras.c File Reference

Execute an ISDN RAS. More...

`#include <sys/ioctl.h>`
`#include <sys/wait.h>`
`#include <signal.h>`
`#include <stdlib.h>`
`#include <unistd.h>`
`#include <string.h>`
`#include <errno.h>`
`#include <stdio.h>`
`#include <fcntl.h>`
`#include <zaptel.h>`
`#include "asterisk.h"`
`#include "asterisk/lock.h"`
`#include "asterisk/file.h"`
`#include "asterisk/logger.h"`
`#include "asterisk/channel.h"`
`#include "asterisk/pbx.h"`
`#include "asterisk/module.h"`
`#include "asterisk/options.h"`

Include dependency graph for app_zapras.c:

Go to the source code of this file.

## Defines

#define | PPP_EXEC "/usr/sbin/pppd"
#define | PPP_MAX_ARGS 32

## Functions

char * | description (void)
| Provides a description of the module.
char * | key ()
| Returns the ASTERISK_GPL_KEY.
int | load_module (void)
| Initialize the module.
static void | run_ras (struct ast_channel *chan, char *args)
static pid_t | spawn_ras (struct ast_channel *chan, char *args)
int | unload_module (void)
| Cleanup all module structures, sockets, etc.
int | usecount (void)
| Provides a usecount.
static int | zapras_exec (struct ast_channel *chan, void *data)

## Variables

static char * | app = "ZapRAS"
static char * | descrip
| LOCAL_USER_DECL
| STANDARD_LOCAL_USER
static char * | synopsis = "Executes Zaptel ISDN RAS application"
static char * | tdesc = "Zap RAS Application"

## Detailed Description

Execute an ISDN RAS.

Definition in file app_zapras.c.

## Define Documentation

#define PPP_EXEC "/usr/sbin/pppd"

Definition at line 79 of file app_zapras.c.

Referenced by spawn_ras().

#define PPP_MAX_ARGS 32

Definition at line 78 of file app_zapras.c.

Referenced by spawn_ras().

## Function Documentation

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 267 of file app_zapras.c.

    00268 {
    00269    return tdesc;
    00270 }

char* key | ( | void |  | ) |

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

     char *key(void) {
             return ASTERISK_GPL_KEY;
     }

Returns:
  ASTERISK_GPL_KEY

Definition at line 279 of file app_zapras.c.

References ASTERISK_GPL_KEY.

    00280 {
    00281    return ASTERISK_GPL_KEY;
    00282 }

int load_module | ( | void |  | ) |

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
  int Always 0.

TE STUFF END

Definition at line 262 of file app_zapras.c.

References ast_register_application(), and zapras_exec().

    00263 {
    00264    return ast_register_application(app, zapras_exec, synopsis, descrip);
    00265 }

static void run_ras | ( | struct ast_channel * | chan,
|  | char * | args |
| ) |  |  | `[static]`

Definition at line 145 of file app_zapras.c.

References ast_channel::_softhangup, ast_log(), ast_verbose(), ast_channel::fds, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_verbose, spawn_ras(), and VERBOSE_PREFIX_3.

Referenced by zapras_exec().

    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 }

static pid_t spawn_ras | ( | struct ast_channel * | chan,
|  | char * | args |
| ) |  |  | `[static]`

Definition at line 81 of file app_zapras.c.

References ast_set_priority(), ast_channel::fds, option_highpriority, PPP_EXEC, PPP_MAX_ARGS, and strsep().

Referenced by run_ras().

    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 }

int unload_module | ( | void |  | ) |

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
  Zero on success, or non-zero on error.

Definition at line 251 of file app_zapras.c.

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

    00252 {
    00253    int res;
    00254
    00255    res = ast_unregister_application(app);
    00256
    00257    STANDARD_HANGUP_LOCALUSERS;
    00258
    00259    return res;
    00260 }

int usecount | ( | void |  | ) |

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
  The module's usecount.

Definition at line 272 of file app_zapras.c.

References STANDARD_USECOUNT.

    00273 {
    00274    int res;
    00275    STANDARD_USECOUNT(res);
    00276    return res;
    00277 }

static int zapras_exec | ( | struct ast_channel * | chan,
|  | void * | data |
| ) |  |  | `[static]`

Definition at line 204 of file app_zapras.c.

References ast_channel::_state, ast_answer(), ast_log(), AST_STATE_UP, ast_strdupa, ast_verbose(), ast_channel::fds, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, ast_channel::name, option_verbose, run_ras(), ast_channel::type, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

Referenced by load_module().

    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 }

## Variable Documentation

char* app = "ZapRAS"`[static]`

Definition at line 63 of file app_zapras.c.

char* descrip`[static]`

Definition at line 67 of file app_zapras.c.

LOCAL_USER_DECL

Definition at line 76 of file app_zapras.c.

STANDARD_LOCAL_USER

Definition at line 74 of file app_zapras.c.

char* synopsis = "Executes Zaptel ISDN RAS application"`[static]`

Definition at line 65 of file app_zapras.c.

char* tdesc = "Zap RAS Application"`[static]`

Definition at line 61 of file app_zapras.c.