app_dahdiras.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  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. /*! \file
  19. *
  20. * \brief Execute an ISDN RAS
  21. *
  22. * \author Mark Spencer <markster@digium.com>
  23. *
  24. * \ingroup applications
  25. */
  26. /*** MODULEINFO
  27. <depend>dahdi</depend>
  28. <support_level>extended</support_level>
  29. ***/
  30. #include "asterisk.h"
  31. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  32. #include <sys/ioctl.h>
  33. #include <sys/wait.h>
  34. #ifdef __linux__
  35. #include <sys/signal.h>
  36. #else
  37. #include <signal.h>
  38. #endif /* __linux__ */
  39. #include <fcntl.h>
  40. #include <dahdi/user.h>
  41. #include "asterisk/lock.h"
  42. #include "asterisk/file.h"
  43. #include "asterisk/channel.h"
  44. #include "asterisk/pbx.h"
  45. #include "asterisk/module.h"
  46. #include "asterisk/app.h"
  47. /*** DOCUMENTATION
  48. <application name="DAHDIRAS" language="en_US">
  49. <synopsis>
  50. Executes DAHDI ISDN RAS application.
  51. </synopsis>
  52. <syntax>
  53. <parameter name="args" required="true">
  54. <para>A list of parameters to pass to the pppd daemon,
  55. separated by <literal>,</literal> characters.</para>
  56. </parameter>
  57. </syntax>
  58. <description>
  59. <para>Executes a RAS server using pppd on the given channel.
  60. The channel must be a clear channel (i.e. PRI source) and a DAHDI
  61. channel to be able to use this function (No modem emulation is included).</para>
  62. <para>Your pppd must be patched to be DAHDI aware.</para>
  63. </description>
  64. </application>
  65. ***/
  66. static const char app[] = "DAHDIRAS";
  67. #define PPP_MAX_ARGS 32
  68. #define PPP_EXEC "/usr/sbin/pppd"
  69. static pid_t spawn_ras(struct ast_channel *chan, char *args)
  70. {
  71. pid_t pid;
  72. char *c;
  73. char *argv[PPP_MAX_ARGS];
  74. int argc = 0;
  75. char *stringp=NULL;
  76. /* Start by forking */
  77. pid = ast_safe_fork(1);
  78. if (pid) {
  79. return pid;
  80. }
  81. /* Execute RAS on File handles */
  82. dup2(ast_channel_fd(chan, 0), STDIN_FILENO);
  83. /* Drop high priority */
  84. if (ast_opt_high_priority)
  85. ast_set_priority(0);
  86. /* Close other file descriptors */
  87. ast_close_fds_above_n(STDERR_FILENO);
  88. /* Reset all arguments */
  89. memset(argv, 0, sizeof(argv));
  90. /* First argument is executable, followed by standard
  91. arguments for DAHDI PPP */
  92. argv[argc++] = PPP_EXEC;
  93. argv[argc++] = "nodetach";
  94. /* And all the other arguments */
  95. stringp=args;
  96. c = strsep(&stringp, ",");
  97. while(c && strlen(c) && (argc < (PPP_MAX_ARGS - 4))) {
  98. argv[argc++] = c;
  99. c = strsep(&stringp, ",");
  100. }
  101. argv[argc++] = "plugin";
  102. argv[argc++] = "dahdi.so";
  103. argv[argc++] = "stdin";
  104. /* Finally launch PPP */
  105. execv(PPP_EXEC, argv);
  106. fprintf(stderr, "Failed to exec PPPD!\n");
  107. exit(1);
  108. }
  109. static void run_ras(struct ast_channel *chan, char *args)
  110. {
  111. pid_t pid;
  112. int status;
  113. int res;
  114. int signalled = 0;
  115. struct dahdi_bufferinfo savebi;
  116. int x;
  117. res = ioctl(ast_channel_fd(chan, 0), DAHDI_GET_BUFINFO, &savebi);
  118. if(res) {
  119. ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", ast_channel_name(chan));
  120. return;
  121. }
  122. pid = spawn_ras(chan, args);
  123. if (pid < 0) {
  124. ast_log(LOG_WARNING, "Failed to spawn RAS\n");
  125. } else {
  126. for (;;) {
  127. res = waitpid(pid, &status, WNOHANG);
  128. if (!res) {
  129. /* Check for hangup */
  130. if (ast_check_hangup(chan) && !signalled) {
  131. ast_debug(1, "Channel '%s' hungup. Signalling RAS at %d to die...\n", ast_channel_name(chan), pid);
  132. kill(pid, SIGTERM);
  133. signalled=1;
  134. }
  135. /* Try again */
  136. sleep(1);
  137. continue;
  138. }
  139. if (res < 0) {
  140. ast_log(LOG_WARNING, "waitpid returned %d: %s\n", res, strerror(errno));
  141. }
  142. if (WIFEXITED(status)) {
  143. ast_verb(3, "RAS on %s terminated with status %d\n", ast_channel_name(chan), WEXITSTATUS(status));
  144. } else if (WIFSIGNALED(status)) {
  145. ast_verb(3, "RAS on %s terminated with signal %d\n",
  146. ast_channel_name(chan), WTERMSIG(status));
  147. } else {
  148. ast_verb(3, "RAS on %s terminated weirdly.\n", ast_channel_name(chan));
  149. }
  150. /* Throw back into audio mode */
  151. x = 1;
  152. ioctl(ast_channel_fd(chan, 0), DAHDI_AUDIOMODE, &x);
  153. /* Restore saved values */
  154. res = ioctl(ast_channel_fd(chan, 0), DAHDI_SET_BUFINFO, &savebi);
  155. if (res < 0) {
  156. ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", ast_channel_name(chan));
  157. }
  158. break;
  159. }
  160. }
  161. ast_safe_fork_cleanup();
  162. }
  163. static int dahdiras_exec(struct ast_channel *chan, const char *data)
  164. {
  165. int res=-1;
  166. char *args;
  167. struct dahdi_params dahdip;
  168. if (!data)
  169. data = "";
  170. args = ast_strdupa(data);
  171. /* Answer the channel if it's not up */
  172. if (ast_channel_state(chan) != AST_STATE_UP)
  173. ast_answer(chan);
  174. if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
  175. /* If it's not a DAHDI channel, we're done. Wait a couple of
  176. seconds and then hangup... */
  177. ast_verb(2, "Channel %s is not a DAHDI channel\n", ast_channel_name(chan));
  178. sleep(2);
  179. } else {
  180. memset(&dahdip, 0, sizeof(dahdip));
  181. if (ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip)) {
  182. ast_log(LOG_WARNING, "Unable to get DAHDI parameters\n");
  183. } else if (dahdip.sigtype != DAHDI_SIG_CLEAR) {
  184. ast_verb(2, "Channel %s is not a clear channel\n", ast_channel_name(chan));
  185. } else {
  186. /* Everything should be okay. Run PPP. */
  187. ast_verb(3, "Starting RAS on %s\n", ast_channel_name(chan));
  188. /* Execute RAS */
  189. run_ras(chan, args);
  190. }
  191. }
  192. return res;
  193. }
  194. static int unload_module(void)
  195. {
  196. return ast_unregister_application(app);
  197. }
  198. static int load_module(void)
  199. {
  200. return ((ast_register_application_xml(app, dahdiras_exec)) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS);
  201. }
  202. AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server");