Make it build with the bristuffed libpri
[asterisk-bristuff.git] / apps / app_dahdiras.c
blob4ac5daa3d33ed6d0956825c4f4c71c0c6cb219a9
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief Execute an ISDN RAS
23 * \author Mark Spencer <markster@digium.com>
25 * \ingroup applications
28 /*** MODULEINFO
29 <depend>dahdi</depend>
30 ***/
32 #include "asterisk.h"
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36 #include <sys/ioctl.h>
37 #include <sys/wait.h>
38 #ifdef __linux__
39 #include <sys/signal.h>
40 #else
41 #include <signal.h>
42 #endif /* __linux__ */
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <fcntl.h>
52 #include "asterisk/lock.h"
53 #include "asterisk/file.h"
54 #include "asterisk/logger.h"
55 #include "asterisk/channel.h"
56 #include "asterisk/pbx.h"
57 #include "asterisk/module.h"
58 #include "asterisk/options.h"
60 #include "asterisk/dahdi_compat.h"
62 static char *dahdi_app = "DAHDIRAS";
63 static char *zap_app = "ZapRAS";
65 static char *dahdi_synopsis = "Executes DAHDI ISDN RAS application";
66 static char *zap_synopsis = "Executes Zaptel ISDN RAS application";
68 static char *dahdi_descrip =
69 " DAHDIRAS(args): Executes a RAS server using pppd on the given channel.\n"
70 "The channel must be a clear channel (i.e. PRI source) and a DAHDI\n"
71 "channel to be able to use this function (no modem emulation is included).\n"
72 "Your pppd must have the DAHDI plugin available. Arguments should be\n"
73 "separated by | characters.\n";
75 static char *zap_descrip =
76 " ZapRAS(args): Executes a RAS server using pppd on the given channel.\n"
77 "The channel must be a clear channel (i.e. PRI source) and a Zaptel\n"
78 "channel to be able to use this function (no modem emulation is included).\n"
79 "Your pppd must have the Zaptel plugin available. Arguments should be\n"
80 "separated by | characters.\n";
82 #define PPP_MAX_ARGS 32
83 #define PPP_EXEC "/usr/sbin/pppd"
85 static pid_t spawn_ras(struct ast_channel *chan, char *args)
87 pid_t pid;
88 int x;
89 char *c;
91 char *argv[PPP_MAX_ARGS];
92 int argc = 0;
93 char *stringp=NULL;
94 sigset_t fullset, oldset;
96 sigfillset(&fullset);
97 pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
99 /* Start by forking */
100 pid = fork();
101 if (pid) {
102 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
103 return pid;
106 /* Restore original signal handlers */
107 for (x=0;x<NSIG;x++)
108 signal(x, SIG_DFL);
110 pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
112 /* Execute RAS on File handles */
113 dup2(chan->fds[0], STDIN_FILENO);
115 /* Drop high priority */
116 if (ast_opt_high_priority)
117 ast_set_priority(0);
119 /* Close other file descriptors */
120 for (x=STDERR_FILENO + 1;x<1024;x++)
121 close(x);
123 /* Reset all arguments */
124 memset(argv, 0, sizeof(argv));
126 /* First argument is executable, followed by standard
127 arguments for DAHDI PPP */
128 argv[argc++] = PPP_EXEC;
129 argv[argc++] = "nodetach";
131 /* And all the other arguments */
132 stringp=args;
133 c = strsep(&stringp, "|");
134 while(c && strlen(c) && (argc < (PPP_MAX_ARGS - 4))) {
135 argv[argc++] = c;
136 c = strsep(&stringp, "|");
139 argv[argc++] = "plugin";
140 #ifdef HAVE_ZAPTEL
141 argv[argc++] = "zaptel.so";
142 #else
143 argv[argc++] = "dahdi.so";
144 #endif
145 argv[argc++] = "stdin";
147 /* Finally launch PPP */
148 execv(PPP_EXEC, argv);
149 fprintf(stderr, "Failed to exec PPPD!\n");
150 exit(1);
153 static void run_ras(struct ast_channel *chan, char *args)
155 pid_t pid;
156 int status;
157 int res;
158 int signalled = 0;
159 struct dahdi_bufferinfo savebi;
160 int x;
162 res = ioctl(chan->fds[0], DAHDI_GET_BUFINFO, &savebi);
163 if(res) {
164 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", chan->name);
165 return;
168 pid = spawn_ras(chan, args);
169 if (pid < 0) {
170 ast_log(LOG_WARNING, "Failed to spawn RAS\n");
171 } else {
172 for (;;) {
173 res = wait4(pid, &status, WNOHANG, NULL);
174 if (!res) {
175 /* Check for hangup */
176 if (chan->_softhangup && !signalled) {
177 ast_log(LOG_DEBUG, "Channel '%s' hungup. Signalling RAS at %d to die...\n", chan->name, pid);
178 kill(pid, SIGTERM);
179 signalled=1;
181 /* Try again */
182 sleep(1);
183 continue;
185 if (res < 0) {
186 ast_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno));
188 if (option_verbose > 2) {
189 if (WIFEXITED(status)) {
190 ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with status %d\n", chan->name, WEXITSTATUS(status));
191 } else if (WIFSIGNALED(status)) {
192 ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with signal %d\n",
193 chan->name, WTERMSIG(status));
194 } else {
195 ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated weirdly.\n", chan->name);
198 /* Throw back into audio mode */
199 x = 1;
200 ioctl(chan->fds[0], DAHDI_AUDIOMODE, &x);
202 /* Restore saved values */
203 res = ioctl(chan->fds[0], DAHDI_SET_BUFINFO, &savebi);
204 if (res < 0) {
205 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", chan->name);
207 break;
212 static int exec(struct ast_channel *chan, void *data)
214 int res=-1;
215 char *args;
216 struct ast_module_user *u;
217 struct dahdi_params ztp;
219 if (!data)
220 data = "";
222 u = ast_module_user_add(chan);
224 args = ast_strdupa(data);
226 /* Answer the channel if it's not up */
227 if (chan->_state != AST_STATE_UP)
228 ast_answer(chan);
229 if (strcasecmp(chan->tech->type, dahdi_chan_name)) {
230 if (option_verbose > 1)
231 ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a %s channel\n", chan->name, dahdi_chan_name);
232 sleep(2);
233 } else {
234 memset(&ztp, 0, sizeof(ztp));
235 if (ioctl(chan->fds[0], DAHDI_GET_PARAMS, &ztp)) {
236 ast_log(LOG_WARNING, "Unable to get parameters\n");
237 } else if (ztp.sigtype != DAHDI_SIG_CLEAR) {
238 if (option_verbose > 1)
239 ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a clear channel\n", chan->name);
240 } else {
241 /* Everything should be okay. Run PPP. */
242 if (option_verbose > 2)
243 ast_verbose(VERBOSE_PREFIX_3 "Starting RAS on %s\n", chan->name);
244 /* Execute RAS */
245 run_ras(chan, args);
248 ast_module_user_remove(u);
249 return res;
252 static int exec_warn(struct ast_channel *chan, void *data)
254 ast_log(LOG_WARNING, "Use of the command %s is deprecated, please use %s instead.\n", zap_app, dahdi_app);
256 return exec(chan, data);
259 static int unload_module(void)
261 int res = 0;
263 if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
264 res |= ast_unregister_application(dahdi_app);
267 res |= ast_unregister_application(zap_app);
269 ast_module_user_hangup_all();
271 return res;
274 static int load_module(void)
276 int res = 0;
278 if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
279 res |= ast_register_application(dahdi_app, exec, dahdi_synopsis, dahdi_descrip);
282 res |= ast_register_application(zap_app, exec_warn, zap_synopsis, zap_descrip);
284 return res;
287 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI RAS Application");