1 /*
2 * libpri: An implementation of Primary Rate ISDN
3 *
4 * Written by Mark Spencer <markster@digium.com>
5 *
6 * Copyright (C) 2001-2005, Digium, Inc.
7 * All Rights Reserved.
8 */
9
10 /*
11 * See http://www.asterisk.org for more information about
12 * the Asterisk project. Please do not directly contact
13 * any of the maintainers of this project for assistance;
14 * the project provides a web site, mailing lists and IRC
15 * channels for your use.
16 *
17 * This program is free software, distributed under the terms of
18 * the GNU General Public License Version 2 as published by the
19 * Free Software Foundation. See the LICENSE file included with
20 * this program for more details.
21 *
22 * In addition, when this program is distributed with Asterisk in
23 * any form that would qualify as a 'combined work' or as a
24 * 'derivative work' (but not mere aggregation), you can redistribute
25 * and/or modify the combination under the terms of the license
26 * provided with that copy of Asterisk, instead of the license
27 * terms granted here.
28 */
29
30 /*
31 * This program tests libpri call reception using a dahdi interface.
32 * Its state machines are setup for RECEIVING CALLS ONLY, so if you
33 * are trying to both place and receive calls you have to a bit more.
34 */
35
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <sys/ioctl.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <sys/signal.h>
45 #include <sys/select.h>
46 #include <sys/wait.h>
47 #include <sys/resource.h>
48 #include <sys/time.h>
49 #include <dahdi/user.h>
50 #include <dahdi/tonezone.h>
51 #include "libpri.h"
52
53 #define PRI_DEF_NODETYPE PRI_CPE
54 #define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2
55
56 #define MAX_CHAN 32
57 #define DCHANNEL_TIMESLOT 16
58
59 #define READ_SIZE 160
60
61 static int offset = 0;
62
do_channel(int fd)63 static void do_channel(int fd)
64 {
65 /* This is the part that runs on a given channel */
66 char buf[READ_SIZE];
67 int res;
68 int i=0;
69
70 while ((res = read(fd, buf, READ_SIZE)) > 0 && (i++ < 1000)) {
71 if (write(fd, buf, res) == -1) {
72 fprintf(stderr, "--!! Failed write: %d\n", errno);
73 break;
74 }
75 }
76 }
77
78 struct pri_chan {
79 pid_t pid;
80 int needhangup;
81 int alreadyhungup;
82 q931_call *call;
83 } chans[MAX_CHAN];
84
str2node(char * node)85 static int str2node(char *node)
86 {
87 if (!strcasecmp(node, "cpe"))
88 return PRI_CPE;
89 if (!strcasecmp(node, "network"))
90 return PRI_NETWORK;
91 return -1;
92 }
93
chan_ended(int sig)94 static void chan_ended(int sig)
95 {
96 int status;
97 int x;
98 struct rusage rusage;
99 pid_t pid;
100 pid = wait4(-1, &status, WNOHANG, &rusage);
101
102 for (x=0;x<MAX_CHAN;x++) {
103 if (pid == chans[x].pid) {
104 printf("-- PID %d ended, channel %d\n", pid, x);
105 chans[x].pid = 0;
106 if (!chans[x].alreadyhungup) {
107 /* It died, we need to hangup now */
108 chans[x].needhangup = 1;
109 } else {
110 /* We've already been hungup, just clear it */
111 chans[x].alreadyhungup = 0;
112 chans[x].call = NULL;
113 }
114 return;
115 }
116 }
117
118 if (pid > -1) {
119 fprintf(stderr, "--!! Unknown PID %d exited\n", pid);
120 return;
121 }
122 }
str2switch(char * swtype)123 static int str2switch(char *swtype)
124 {
125 if (!strcasecmp(swtype, "ni2"))
126 return PRI_SWITCH_NI2;
127 if (!strcasecmp(swtype, "dms100"))
128 return PRI_SWITCH_DMS100;
129 if (!strcasecmp(swtype, "lucent5e"))
130 return PRI_SWITCH_LUCENT5E;
131 if (!strcasecmp(swtype, "att4ess"))
132 return PRI_SWITCH_ATT4ESS;
133 if (!strcasecmp(swtype, "euroisdn"))
134 return PRI_SWITCH_EUROISDN_E1;
135 if (!strcasecmp(swtype, "gr303eoc"))
136 return PRI_SWITCH_GR303_EOC;
137 if (!strcasecmp(swtype, "gr303tmc"))
138 return PRI_SWITCH_GR303_TMC;
139 return -1;
140 }
141
hangup_channel(int channo)142 static void hangup_channel(int channo)
143 {
144 if (chans[channo].pid) {
145
146 #if 0
147 printf("Killing channel %d (pid = %d)\n", channo, chans[channo].pid);
148 #endif
149 chans[channo].alreadyhungup = 1;
150 kill(chans[channo].pid, SIGTERM);
151 } else if (chans[channo].needhangup)
152 chans[channo].needhangup = 0;
153 }
154
dahdi_open(char * fn)155 static int dahdi_open(char *fn)
156 {
157 int fd;
158 int isnum;
159 int chan = 0;
160 int bs;
161 int x;
162
163 fprintf(stderr, "dahdi open %s\n", fn);
164
165 isnum = 1;
166 for (x = 0; x < strlen(fn); x++) {
167 if (!isdigit(fn[x])) {
168 isnum = 0;
169 break;
170 }
171 }
172 if (isnum) {
173 chan = atoi(fn);
174 if (chan < 1) {
175 printf("Invalid channel number '%s'\n", fn);
176 exit(1);
177 }
178 fn = "/dev/dahdi/channel";
179 }
180 fd = open(fn, O_RDWR /* | O_NONBLOCK */);
181 if (fd < 0) {
182 printf("Unable to open '%s': %s\n", fn, strerror(errno));
183 exit(1);
184 }
185 if (chan) {
186 if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
187 x = errno;
188 close(fd);
189 errno = x;
190 printf("Unable to specify channel %d: %s\n", chan, strerror(errno));
191 exit(1);
192 }
193 }
194 bs = READ_SIZE;
195 if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
196 printf("Unable to set blocksize '%d': %s\n", bs, strerror(errno));
197 exit(1);
198 }
199 return fd;
200 }
201
launch_channel(int channo)202 static void launch_channel(int channo)
203 {
204 pid_t pid;
205 int z;
206 char ch[80];
207
208 /* Make sure hangup state is reset */
209 chans[channo].needhangup = 0;
210 chans[channo].alreadyhungup = 0;
211
212 pid = fork();
213 if (pid < 0) {
214 fprintf(stderr, "--!! Unable to fork\n");
215 chans[channo].needhangup = 1;
216 }
217 if (pid) {
218 printf("-- Launching process %d to handle channel %d\n", pid, channo);
219 chans[channo].pid = pid;
220 } else {
221 sprintf(ch, "%d", channo + offset);
222 z = dahdi_open(ch);
223 if (z) {
224 do_channel(z);
225 exit(0);
226 } else {
227 fprintf(stderr, "--!! Unable to open channel %d\n", channo);
228 exit(1);
229 }
230 }
231
232 }
233
get_free_channel(int channo)234 static int get_free_channel(int channo)
235 {
236 channo--;
237 if((channo>MAX_CHAN)||(channo<0)) {
238 fprintf(stderr, "Invalid Bchannel RANGE <%d", channo);
239 return 0;
240 };
241
242 while(chans[channo].pid) {
243 channo--;
244 }
245
246 return channo;
247 }
248
249 /* place here criteria for completion of destination number */
number_incommplete(char * number)250 static int number_incommplete(char *number)
251 {
252 return strlen(number) < 3;
253 }
254
start_channel(struct pri * pri,pri_event * e)255 static void start_channel(struct pri *pri, pri_event *e)
256 {
257 int channo = e->ring.channel;
258 int flag = 1;
259 pri_event_ring *ring = &e->ring;
260
261 if(channo == -1) {
262 channo = e->ring.channel = get_free_channel(MAX_CHAN);
263
264 if(channo == DCHANNEL_TIMESLOT)
265 channo = e->ring.channel = get_free_channel(MAX_CHAN);
266
267
268 fprintf(stdout, "Any channel selected: %d\n", channo);
269
270 if(!channo) {
271 pri_release(pri, ring->call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
272 fprintf(stdout, "Abort call due to no avl B channels\n");
273 return;
274 }
275
276 flag = 0;
277 }
278 /* Make sure it's a valid number */
279 if ((channo >= MAX_CHAN) || (channo < 0)) {
280 fprintf(stderr, "--!! Channel %d is out of range\n", channo);
281 return;
282 }
283
284 /* Make sure nothing is there */
285 if (chans[channo].pid) {
286 fprintf(stderr, "--!! Channel %d still has a call on it, ending it...\n", channo);
287 hangup_channel(channo);
288 /* Wait for it to die */
289 while(chans[channo].pid)
290 usleep(100);
291 }
292
293 /* Record call number */
294 chans[channo].call = e->ring.call;
295
296 /* Answer the line */
297 if(flag) {
298 pri_answer(pri, chans[channo].call, channo, 1);
299 } else {
300 pri_need_more_info(pri, chans[channo].call, channo, 1);
301 }
302
303 /* Launch a process to handle it */
304 launch_channel(channo);
305
306 }
307
handle_pri_event(struct pri * pri,pri_event * e)308 static void handle_pri_event(struct pri *pri, pri_event *e)
309 {
310 switch(e->e) {
311 case PRI_EVENT_DCHAN_UP:
312 printf("-- D-Channel is now up! :-)\n");
313 break;
314 case PRI_EVENT_DCHAN_DOWN:
315 printf("-- D-Channel is now down! :-(\n");
316 break;
317 case PRI_EVENT_RESTART:
318 printf("-- Restarting channel %d\n", e->restart.channel);
319 hangup_channel(e->restart.channel);
320 break;
321 case PRI_EVENT_CONFIG_ERR:
322 printf("-- Configuration error detected: %s\n", e->err.err);
323 break;
324 case PRI_EVENT_RING:
325 printf("-- Ring on channel %d (from %s to %s), answering...\n", e->ring.channel, e->ring.callingnum, e->ring.callednum);
326 start_channel(pri, e);
327 break;
328 case PRI_EVENT_HANGUP:
329 printf("-- Hanging up channel %d\n", e->hangup.channel);
330 hangup_channel(e->hangup.channel);
331 break;
332 case PRI_EVENT_RINGING:
333 case PRI_EVENT_ANSWER:
334 fprintf(stderr, "--!! What? We shouldn't be making any calls...\n");
335 break;
336 case PRI_EVENT_HANGUP_ACK:
337 /* Ignore */
338 break;
339 case PRI_EVENT_INFO_RECEIVED:
340 fprintf(stdout, "number is: %s\n", e->ring.callednum);
341 if(!number_incommplete(e->ring.callednum)) {
342 fprintf(stdout, "final number is: %s\n", e->ring.callednum);
343 pri_answer(pri, e->ring.call, 0, 1);
344 }
345
346 break;
347 default:
348 fprintf(stderr, "--!! Unknown PRI event %d\n", e->e);
349 }
350 }
351
run_pri(int dfd,int swtype,int node)352 static int run_pri(int dfd, int swtype, int node)
353 {
354 struct pri *pri;
355 pri_event *e;
356 struct timeval tv = {0,0}, *next;
357 fd_set rfds, efds;
358 int res,x;
359
360 pri = pri_new(dfd, node, swtype);
361 if (!pri) {
362 fprintf(stderr, "Unable to create PRI\n");
363 return -1;
364 }
365 pri_set_debug(pri, -1);
366 for (;;) {
367
368 /* Run the D-Channel */
369 FD_ZERO(&rfds);
370 FD_ZERO(&efds);
371 FD_SET(dfd, &rfds);
372 FD_SET(dfd, &efds);
373
374 if ((next = pri_schedule_next(pri))) {
375 gettimeofday(&tv, NULL);
376 tv.tv_sec = next->tv_sec - tv.tv_sec;
377 tv.tv_usec = next->tv_usec - tv.tv_usec;
378 if (tv.tv_usec < 0) {
379 tv.tv_usec += 1000000;
380 tv.tv_sec -= 1;
381 }
382 if (tv.tv_sec < 0) {
383 tv.tv_sec = 0;
384 tv.tv_usec = 0;
385 }
386 }
387 res = select(dfd + 1, &rfds, NULL, &efds, next ? &tv : NULL);
388 e = NULL;
389
390 if (!res) {
391 e = pri_schedule_run(pri);
392 } else if (res > 0) {
393 e = pri_check_event(pri);
394 } else if (errno == ELAST) {
395 res = ioctl(dfd, DAHDI_GETEVENT, &x);
396 printf("Got DAHDI event: %d\n", x);
397 } else if (errno != EINTR)
398 fprintf(stderr, "Error (%d) on select: %s\n", ELAST, strerror(errno));
399
400 if (e) {
401 handle_pri_event(pri, e);
402 }
403
404 res = ioctl(dfd, DAHDI_GETEVENT, &x);
405
406 if (!res && x) {
407 fprintf(stderr, "Got event on PRI interface: %d\n", x);
408 }
409
410 /* Check for lines that need hangups */
411 for (x=0;x<MAX_CHAN;x++)
412 if (chans[x].needhangup) {
413 chans[x].needhangup = 0;
414 pri_release(pri, chans[x].call, PRI_CAUSE_NORMAL_CLEARING);
415 }
416
417 }
418 return 0;
419 }
420
main(int argc,char * argv[])421 int main(int argc, char *argv[])
422 {
423 int dfd;
424 int swtype = PRI_DEF_SWITCHTYPE;
425 int node = PRI_DEF_NODETYPE;
426 struct dahdi_params p;
427 if (argc < 2) {
428 fprintf(stderr, "Usage: pritest <dchannel> [swtypetype] [nodetype]\n");
429 exit(1);
430 }
431 dfd = open(argv[1], O_RDWR);
432 if (dfd < 0) {
433 fprintf(stderr, "Failed to open dchannel '%s': %s\n", argv[1], strerror(errno));
434 exit(1);
435 }
436 if (ioctl(dfd, DAHDI_GET_PARAMS, &p)) {
437 fprintf(stderr, "Unable to get parameters on '%s': %s\n", argv[1], strerror(errno));
438 exit(1);
439 }
440 if ((p.sigtype != DAHDI_SIG_HDLCRAW) && (p.sigtype != DAHDI_SIG_HDLCFCS)) {
441 fprintf(stderr, "%s is in %d signalling, not FCS HDLC or RAW HDLC mode\n", argv[1], p.sigtype);
442 exit(1);
443 }
444
445 if (argc > 2) {
446 swtype = str2switch(argv[2]);
447 if (swtype < 0) {
448 fprintf(stderr, "Valid switchtypes are: ni2, dms100, lucent5e, att4ess, and euroisdn\n");
449 exit(1);
450 }
451 }
452
453 if (argc > 3) {
454 node = str2node(argv[3]);
455 if (node < 0) {
456 fprintf(stderr, "Valid node types are: network and cpe\n");
457 exit(1);
458 }
459 }
460
461 signal(SIGCHLD, chan_ended);
462
463 if (run_pri(dfd, swtype, node))
464 exit(1);
465 exit(0);
466
467 return 0;
468 }
469