static int visdn_ppp_exec(struct cw_channel *chan, int argc, char **argv) { struct visdn_chan *visdn_chan; const char **nargv; struct localuser *u; struct cw_frame *f; int res=-1; LOCAL_USER_ADD(u); if (chan->_state != CW_STATE_UP) cw_answer(chan); cw_mutex_lock(&chan->lock); if (strcmp(chan->type, "VISDN")) { cw_log(LOG_WARNING, "Only VISDN channels may be connected to" " this application\n"); cw_mutex_unlock(&chan->lock); return -1; } visdn_chan = chan->tech_pvt; if (!strlen(visdn_chan->visdn_chanid)) { cw_log(LOG_WARNING, "vISDN crossconnector channel ID not present\n"); cw_mutex_unlock(&chan->lock); return -1; } nargv = alloca((2 + argc + 3 + 1) * sizeof(nargv[0])); nargv[0] = PPP_EXEC; nargv[1] = "nodetach"; memcpy(nargv + 2, argc, argv * sizeof(argv[0])); nargv[2 + argc + 0] = "plugin"; nargv[2 + argc + 1] = "visdn.so"; nargv[2 + argc + 2] = visdn_chan->visdn_chanid; nargv[2 + argc + 3] = NULL; cw_mutex_unlock(&chan->lock); #if 0 int i; for (i=0;i<argc;i++) { cw_log(LOG_NOTICE, "Arg %d: %s\n", i, argv[i]); } #endif signal(SIGCHLD, SIG_DFL); pid_t pid = spawn_ppp(chan, nargv); if (pid < 0) { cw_log(LOG_WARNING, "Failed to spawn pppd\n"); return -1; } while(cw_waitfor(chan, -1) > -1) { f = cw_read(chan); if (!f) { cw_log(LOG_NOTICE, "Channel '%s' hungup." " Signalling PPP at %d to die...\n", chan->name, pid); kill(pid, SIGTERM); break; } cw_fr_free(f); int status; res = wait4(pid, &status, WNOHANG, NULL); if (res < 0) { cw_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno)); break; } else if (res > 0) { if (option_verbose > 2) { if (WIFEXITED(status)) { cw_verbose(VERBOSE_PREFIX_3 "PPP on %s terminated with status %d\n", chan->name, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { cw_verbose(VERBOSE_PREFIX_3 "PPP on %s terminated with signal %d\n", chan->name, WTERMSIG(status)); } else { cw_verbose(VERBOSE_PREFIX_3 "PPP on %s terminated weirdly.\n", chan->name); } } break; } } LOCAL_USER_REMOVE(u); return res; }
static int visdn_ppp_exec(struct ast_channel *chan, void *data) { int res=-1; struct ast_frame *f; if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_mutex_lock(&chan->lock); #if ASTERISK_VERSION_NUM < 010400 || (ASTERISK_VERSION_NUM >= 10200 && ASTERISK_VERSION_NUM < 10400) if (strcmp(chan->type, "VISDN")) { #else if (strcmp(chan->tech->type, "VISDN")) { #endif ast_log(LOG_WARNING, "Only VISDN channels may be connected to" " this application\n"); ast_mutex_unlock(&chan->lock); return -1; } struct visdn_chan *visdn_chan = to_visdn_chan(chan); if (!visdn_chan->node_bearer) { ast_log(LOG_WARNING, "vISDN bearer channel not present\n"); ast_mutex_unlock(&chan->lock); return -1; } const char *argv[PPP_MAX_ARGS] = { }; int argc = 0; argv[argc++] = PPP_EXEC; argv[argc++] = "nodetach"; char *stringp = strdup(data); char *arg; while((arg = strsep(&stringp, "|"))) { if (!strlen(arg)) break; if (argc >= PPP_MAX_ARGS - 4) break; argv[argc++] = arg; } char chan_id_arg[10]; snprintf(chan_id_arg, sizeof(chan_id_arg), "%06d", visdn_chan->node_bearer->id); argv[argc++] = "plugin"; argv[argc++] = "visdn.so"; argv[argc++] = chan_id_arg; ast_mutex_unlock(&chan->lock); #if 0 int i; for (i=0;i<argc;i++) { ast_log(LOG_NOTICE, "Arg %d: %s\n", i, argv[i]); } #endif signal(SIGCHLD, SIG_DFL); pid_t pid = spawn_ppp(chan, argv, argc); if (pid < 0) { ast_log(LOG_WARNING, "Failed to spawn pppd\n"); return -1; } while(ast_waitfor(chan, -1) > -1) { f = ast_read(chan); if (!f) { ast_log(LOG_NOTICE, "Channel '%s' hungup." " Signalling PPP at %d to die...\n", chan->name, pid); kill(pid, SIGTERM); break; } ast_frfree(f); int status; res = wait4(pid, &status, WNOHANG, NULL); if (res < 0) { ast_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno)); break; } else if (res > 0) { if (option_verbose > 2) { if (WIFEXITED(status)) { ast_verbose(VERBOSE_PREFIX_3 "PPP on %s terminated with " "status %d\n", chan->name, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { ast_verbose(VERBOSE_PREFIX_3 "PPP on %s terminated with " "signal %d\n", chan->name, WTERMSIG(status)); } else { ast_verbose(VERBOSE_PREFIX_3 "PPP on %s terminated " "weirdly.\n", chan->name); } } break; } } return res; } int visdn_ppp_load_module(void) { return ast_register_application( VISDN_PPP_APP_NAME, visdn_ppp_exec, "Runs pppd and connects channel to visdn-ppp gateway", descrip); } int visdn_ppp_unload_module(void) { return ast_unregister_application(VISDN_PPP_APP_NAME); }