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