Version 0.1.11 from FTP
[asterisk/asterisk.git] / apps / app_zapras.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Execute an ISDN RAS
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/file.h>
15 #include <asterisk/logger.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/pbx.h>
18 #include <asterisk/module.h>
19 #include <asterisk/options.h>
20 #include <sys/ioctl.h>
21 #include <sys/wait.h>
22 #include <sys/signal.h>
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include <pthread.h>
30
31 /* Need some zaptel help here */
32 #include <linux/zaptel.h>
33
34 static char *tdesc = "Zap RAS Application";
35
36 static char *app = "ZapRAS";
37
38 static char *synopsis = "Executes Zaptel ISDN RAS application";
39
40 static char *descrip =
41 "  ZapRAS(args): Executes a RAS server using pppd on the given channel.\n"
42 "The channel must be a clear channel (i.e. PRI source) and a Zaptel\n"
43 "channel to be able to use this function (No modem emulcation is included).\n"
44 "Your pppd must be patched to be zaptel aware. Arguments should be\n"
45 "separated by | characters.  Always returns -1.\n";
46
47 STANDARD_LOCAL_USER;
48
49 LOCAL_USER_DECL;
50
51 #define PPP_MAX_ARGS    32
52 #define PPP_EXEC        "/usr/sbin/pppd"
53
54 static pid_t spawn_ras(struct ast_channel *chan, char *args)
55 {
56         pid_t pid;
57         int x;  
58         char *c;
59
60         char *argv[PPP_MAX_ARGS];
61         int argc = 0;
62
63         /* Start by forking */
64         pid = fork();
65         if (pid)
66                 return pid;
67
68         /* Execute RAS on File handles */
69         dup2(chan->fds[0], STDIN_FILENO);
70
71         /* Close other file descriptors */
72         for (x=STDERR_FILENO + 1;x<1024;x++) 
73                 close(x);
74
75         /* Restore original signal handlers */
76         for (x=0;x<NSIG;x++)
77                 signal(x, SIG_DFL);
78
79         /* Reset all arguments */
80         memset(argv, 0, sizeof(argv));
81
82         /* First argument is executable, followed by standard
83            arguments for zaptel PPP */
84         argv[argc++] = PPP_EXEC;
85         argv[argc++] = "nodetach";
86
87         /* And all the other arguments */
88         c = strtok(args, "|");
89         while(c && strlen(c) && (argc < (PPP_MAX_ARGS - 4))) {
90                 argv[argc++] = c;
91                 c = strtok(NULL, "|");
92         }
93
94         argv[argc++] = "plugin";
95         argv[argc++] = "zaptel.so";
96         argv[argc++] = "stdin";
97
98 #if 0
99         for (x=0;x<argc;x++) {
100                 fprintf(stderr, "Arg %d: %s\n", x, argv[x]);
101         }
102 #endif
103
104         /* Finally launch PPP */
105         execv(PPP_EXEC, argv);
106         fprintf(stderr, "Failed to exec PPPD!\n");
107         exit(1);
108 }
109
110 static void run_ras(struct ast_channel *chan, char *args)
111 {
112         pid_t pid;
113         int status;
114         int res;
115         int signalled = 0;
116         struct zt_bufferinfo bi;
117         int x;
118
119         pid = spawn_ras(chan, args);
120         if (pid < 0) {
121                 ast_log(LOG_WARNING, "Failed to spawn RAS\n");
122         } else {
123                 for (;;) {
124                         res = wait4(pid, &status, WNOHANG, NULL);
125                         if (!res) {
126                                 /* Check for hangup */
127                                 if (chan->softhangup && !signalled) {
128                                         ast_log(LOG_DEBUG, "Channel hungup.  Signalling RAS at %d to die...\n", pid);
129                                         kill(pid, SIGTERM);
130                                         signalled=1;
131                                 }
132                                 /* Try again */
133                                 sleep(1);
134                                 continue;
135                         }
136                         if (res < 0) {
137                                 ast_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno));
138                         }
139                         if (option_verbose > 2) {
140                                 if (WIFEXITED(status)) {
141                                         ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with status %d\n", chan->name, WEXITSTATUS(status));
142                                 } else if (WIFSIGNALED(status)) {
143                                         ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with signal %d\n", 
144                                                  chan->name, WTERMSIG(status));
145                                 } else {
146                                         ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated weirdly.\n", chan->name);
147                                 }
148                         }
149                         /* Throw back into audio mode */
150                         x = 0;
151                         ioctl(chan->fds[0], ZT_AUDIOMODE, &x);
152
153                         /* Double check buffering too */
154                         res = ioctl(chan->fds[0], ZT_GET_BUFINFO, &bi);
155                         if (!res) {
156                                 /* XXX This is ZAP_BLOCKSIZE XXX */
157                                 bi.bufsize = 204;
158                                 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
159                                 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
160                                 bi.numbufs = 4;
161                                 res = ioctl(chan->fds[0], ZT_SET_BUFINFO, &bi);
162                                 if (res < 0) {
163                                         ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", chan->name);
164                                 }
165                         } else
166                                 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", chan->name);
167                         break;
168                 }
169         }
170 }
171
172 static int zapras_exec(struct ast_channel *chan, void *data)
173 {
174         int res=-1;
175         char args[256];
176         struct localuser *u;
177         ZT_PARAMS ztp;
178
179         if (!data) 
180                 data = "";
181         LOCAL_USER_ADD(u);
182         strncpy(args, data, sizeof(args) - 1);
183         /* Answer the channel if it's not up */
184         if (chan->state != AST_STATE_UP)
185                 ast_answer(chan);
186         if (strcasecmp(chan->type, "Zap")) {
187                 /* If it's not a zap channel, we're done.  Wait a couple of
188                    seconds and then hangup... */
189                 if (option_verbose > 1)
190                         ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a Zap channel\n", chan->name);
191                 sleep(2);
192         } else {
193                 memset(&ztp, 0, sizeof(ztp));
194                 if (ioctl(chan->fds[0], ZT_GET_PARAMS, &ztp)) {
195                         ast_log(LOG_WARNING, "Unable to get zaptel parameters\n");
196                 } else if (ztp.sigtype != ZT_SIG_CLEAR) {
197                         if (option_verbose > 1)
198                                 ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a clear channel\n", chan->name);
199                 } else {
200                         /* Everything should be okay.  Run PPP. */
201                         if (option_verbose > 2)
202                                 ast_verbose(VERBOSE_PREFIX_3 "Starting RAS on %s\n", chan->name);
203                         /* Execute RAS */
204                         run_ras(chan, args);
205                 }
206         }
207         LOCAL_USER_REMOVE(u);
208         return res;
209 }
210
211 int unload_module(void)
212 {
213         STANDARD_HANGUP_LOCALUSERS;
214         return ast_unregister_application(app);
215 }
216
217 int load_module(void)
218 {
219         return ast_register_application(app, zapras_exec, synopsis, descrip);
220 }
221
222 char *description(void)
223 {
224         return tdesc;
225 }
226
227 int usecount(void)
228 {
229         int res;
230         STANDARD_USECOUNT(res);
231         return res;
232 }
233
234 char *key()
235 {
236         return ASTERISK_GPL_KEY;
237 }