Asterisk - The Open Source Telephony Project  18.5.0
app_dahdiras.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <[email protected]>
7  *
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.
13  *
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.
17  */
18 
19 /*! \file
20  *
21  * \brief Execute an ISDN RAS
22  *
23  * \author Mark Spencer <[email protected]>
24  *
25  * \ingroup applications
26  */
27 
28 /*** MODULEINFO
29  <depend>dahdi</depend>
30  <support_level>deprecated</support_level>
31  ***/
32 
33 #include "asterisk.h"
34 
35 #include <sys/ioctl.h>
36 #include <sys/wait.h>
37 #include <signal.h>
38 #include <fcntl.h>
39 
40 #include <dahdi/user.h>
41 
42 #include "asterisk/lock.h"
43 #include "asterisk/file.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/module.h"
47 #include "asterisk/app.h"
48 
49 /*** DOCUMENTATION
50  <application name="DAHDIRAS" language="en_US">
51  <synopsis>
52  Executes DAHDI ISDN RAS application.
53  </synopsis>
54  <syntax>
55  <parameter name="args" required="true">
56  <para>A list of parameters to pass to the pppd daemon,
57  separated by <literal>,</literal> characters.</para>
58  </parameter>
59  </syntax>
60  <description>
61  <para>Executes a RAS server using pppd on the given channel.
62  The channel must be a clear channel (i.e. PRI source) and a DAHDI
63  channel to be able to use this function (No modem emulation is included).</para>
64  <para>Your pppd must be patched to be DAHDI aware.</para>
65  </description>
66  </application>
67 
68  ***/
69 
70 static const char app[] = "DAHDIRAS";
71 
72 #define PPP_MAX_ARGS 32
73 #define PPP_EXEC "/usr/sbin/pppd"
74 
75 static pid_t spawn_ras(struct ast_channel *chan, char *args)
76 {
77  pid_t pid;
78  char *c;
79 
80  char *argv[PPP_MAX_ARGS];
81  int argc = 0;
82  char *stringp=NULL;
83 
84  /* Start by forking */
85  pid = ast_safe_fork(1);
86  if (pid) {
87  return pid;
88  }
89 
90  /* Execute RAS on File handles */
91  dup2(ast_channel_fd(chan, 0), STDIN_FILENO);
92 
93  /* Drop high priority */
96 
97  /* Close other file descriptors */
98  ast_close_fds_above_n(STDERR_FILENO);
99 
100  /* Reset all arguments */
101  memset(argv, 0, sizeof(argv));
102 
103  /* First argument is executable, followed by standard
104  arguments for DAHDI PPP */
105  argv[argc++] = PPP_EXEC;
106  argv[argc++] = "nodetach";
107 
108  /* And all the other arguments */
109  stringp=args;
110  c = strsep(&stringp, ",");
111  while(c && strlen(c) && (argc < (PPP_MAX_ARGS - 4))) {
112  argv[argc++] = c;
113  c = strsep(&stringp, ",");
114  }
115 
116  if (geteuid() == 0) {
117  argv[argc++] = "plugin";
118  argv[argc++] = "dahdi.so";
119  }
120  argv[argc++] = "stdin";
121 
122  /* Finally launch PPP */
123  execv(PPP_EXEC, argv);
124  fprintf(stderr, "Failed to exec PPPD!\n");
125  exit(1);
126 }
127 
128 static void run_ras(struct ast_channel *chan, char *args)
129 {
130  pid_t pid;
131  int status;
132  int res;
133  int signalled = 0;
134  struct dahdi_bufferinfo savebi;
135  int x;
136 
137  res = ioctl(ast_channel_fd(chan, 0), DAHDI_GET_BUFINFO, &savebi);
138  if(res) {
139  ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", ast_channel_name(chan));
140  return;
141  }
142 
143  pid = spawn_ras(chan, args);
144  if (pid < 0) {
145  ast_log(LOG_WARNING, "Failed to spawn RAS\n");
146  } else {
147  for (;;) {
148  res = waitpid(pid, &status, WNOHANG);
149  if (!res) {
150  /* Check for hangup */
151  if (ast_check_hangup(chan) && !signalled) {
152  ast_debug(1, "Channel '%s' hungup. Signalling RAS at %d to die...\n", ast_channel_name(chan), pid);
153  kill(pid, SIGTERM);
154  signalled=1;
155  }
156  /* Try again */
157  sleep(1);
158  continue;
159  }
160  if (res < 0) {
161  ast_log(LOG_WARNING, "waitpid returned %d: %s\n", res, strerror(errno));
162  }
163  if (WIFEXITED(status)) {
164  ast_verb(3, "RAS on %s terminated with status %d\n", ast_channel_name(chan), WEXITSTATUS(status));
165  } else if (WIFSIGNALED(status)) {
166  ast_verb(3, "RAS on %s terminated with signal %d\n",
167  ast_channel_name(chan), WTERMSIG(status));
168  } else {
169  ast_verb(3, "RAS on %s terminated weirdly.\n", ast_channel_name(chan));
170  }
171  /* Throw back into audio mode */
172  x = 1;
173  ioctl(ast_channel_fd(chan, 0), DAHDI_AUDIOMODE, &x);
174 
175  /* Restore saved values */
176  res = ioctl(ast_channel_fd(chan, 0), DAHDI_SET_BUFINFO, &savebi);
177  if (res < 0) {
178  ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", ast_channel_name(chan));
179  }
180  break;
181  }
182  }
184 }
185 
186 static int dahdiras_exec(struct ast_channel *chan, const char *data)
187 {
188  int res=-1;
189  char *args;
190  struct dahdi_params dahdip;
191 
192  if (!data)
193  data = "";
194 
195  args = ast_strdupa(data);
196 
197  /* Answer the channel if it's not up */
198  if (ast_channel_state(chan) != AST_STATE_UP)
199  ast_answer(chan);
200  if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
201  /* If it's not a DAHDI channel, we're done. Wait a couple of
202  seconds and then hangup... */
203  ast_verb(2, "Channel %s is not a DAHDI channel\n", ast_channel_name(chan));
204  sleep(2);
205  } else {
206  memset(&dahdip, 0, sizeof(dahdip));
207  if (ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip)) {
208  ast_log(LOG_WARNING, "Unable to get DAHDI parameters\n");
209  } else if (dahdip.sigtype != DAHDI_SIG_CLEAR) {
210  ast_verb(2, "Channel %s is not a clear channel\n", ast_channel_name(chan));
211  } else {
212  /* Everything should be okay. Run PPP. */
213  ast_verb(3, "Starting RAS on %s\n", ast_channel_name(chan));
214  /* Execute RAS */
215  run_ras(chan, args);
216  }
217  }
218  return res;
219 }
220 
221 static int unload_module(void)
222 {
224 }
225 
226 static int load_module(void)
227 {
229 }
230 
231 AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server");
static const char type[]
Definition: chan_ooh323.c:109
static int dahdiras_exec(struct ast_channel *chan, const char *data)
Definition: app_dahdiras.c:186
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server")
#define LOG_WARNING
Definition: logger.h:274
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: main/app.c:3042
static pid_t spawn_ras(struct ast_channel *chan, char *args)
Definition: app_dahdiras.c:75
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static struct test_val c
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
const char * args
#define NULL
Definition: resample.c:96
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
General Asterisk PBX channel definitions.
static int load_module(void)
Definition: app_dahdiras.c:226
void ast_safe_fork_cleanup(void)
Common routine to cleanup after fork&#39;ed process is complete (if reaping was stopped) ...
Definition: main/app.c:3108
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_set_priority(int)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
Definition: asterisk.c:1799
static const char app[]
Definition: app_dahdiras.c:70
int errno
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
Definition: main/app.c:3047
static int unload_module(void)
Definition: app_dahdiras.c:221
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define PPP_MAX_ARGS
Definition: app_dahdiras.c:72
int ast_channel_fd(const struct ast_channel *chan, int which)
char * strsep(char **str, const char *delims)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
static void run_ras(struct ast_channel *chan, char *args)
Definition: app_dahdiras.c:128
#define WEXITSTATUS(status)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define WIFEXITED(status)
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
#define PPP_EXEC
Definition: app_dahdiras.c:73
jack_status_t status
Definition: app_jack.c:146
#define ast_opt_high_priority
Definition: options.h:110