2 * libpri: An implementation of Primary Rate ISDN
4 * Written by Mark Spencer <markster@linux-support.net>
6 * Copyright (C) 2001-2005, Digium, Inc.
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.
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.
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
31 * This program tests libpri call reception using a zaptel 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.
40 #include <sys/ioctl.h>
43 #include <sys/signal.h>
44 #include <sys/select.h>
46 #include <sys/resource.h>
48 #include <zaptel/zaptel.h>
52 #define PRI_DEF_NODETYPE PRI_CPE
53 #define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2
56 #define DCHANNEL_TIMESLOT 3
59 static int offset
= 0;
61 static void do_channel(ZAP
*z
)
63 /* This is the part that runs on a given channel */
64 zap_playf(z
, "raw.alaw", 0);
74 static int str2node(char *node
)
76 if (!strcasecmp(node
, "cpe"))
78 if (!strcasecmp(node
, "network"))
80 if (!strcasecmp(node
, "bri_cpe_ptmp"))
82 if (!strcasecmp(node
, "bri_network_ptmp"))
83 return BRI_NETWORK_PTMP
;
84 if (!strcasecmp(node
, "bri_cpe"))
86 if (!strcasecmp(node
, "bri_network"))
91 static void chan_ended(int sig
)
97 pid
= wait4(-1, &status
, WNOHANG
, &rusage
);
99 for (x
=0;x
<MAX_CHAN
;x
++) {
100 if (pid
== chans
[x
].pid
) {
101 printf("-- PID %d ended, channel %d\n", pid
, x
);
103 if (!chans
[x
].alreadyhungup
) {
104 /* It died, we need to hangup now */
105 chans
[x
].needhangup
= 1;
107 /* We've already been hungup, just clear it */
108 chans
[x
].alreadyhungup
= 0;
109 chans
[x
].call
= NULL
;
116 fprintf(stderr
, "--!! Unknown PID %d exited\n", pid
);
120 static int str2switch(char *swtype
)
122 if (!strcasecmp(swtype
, "ni2"))
123 return PRI_SWITCH_NI2
;
124 if (!strcasecmp(swtype
, "dms100"))
125 return PRI_SWITCH_DMS100
;
126 if (!strcasecmp(swtype
, "lucent5e"))
127 return PRI_SWITCH_LUCENT5E
;
128 if (!strcasecmp(swtype
, "att4ess"))
129 return PRI_SWITCH_ATT4ESS
;
130 if (!strcasecmp(swtype
, "euroisdn"))
131 return PRI_SWITCH_EUROISDN_E1
;
132 if (!strcasecmp(swtype
, "gr303eoc"))
133 return PRI_SWITCH_GR303_EOC
;
134 if (!strcasecmp(swtype
, "gr303tmc"))
135 return PRI_SWITCH_GR303_TMC
;
139 static void hangup_channel(int channo
)
141 if (chans
[channo
].pid
) {
144 printf("Killing channel %d (pid = %d)\n", channo
, chans
[channo
].pid
);
146 chans
[channo
].alreadyhungup
= 1;
147 kill(chans
[channo
].pid
, SIGTERM
);
148 } else if (chans
[channo
].needhangup
)
149 chans
[channo
].needhangup
= 0;
152 static void launch_channel(int channo
)
158 /* Make sure hangup state is reset */
159 chans
[channo
].needhangup
= 0;
160 chans
[channo
].alreadyhungup
= 0;
164 fprintf(stderr
, "--!! Unable to fork\n");
165 chans
[channo
].needhangup
= 1;
168 printf("-- Launching process %d to handle channel %d\n", pid
, channo
);
169 chans
[channo
].pid
= pid
;
171 sprintf(ch
, "%d", channo
+ offset
);
177 fprintf(stderr
, "--!! Unable to open channel %d\n", channo
);
184 static int get_free_channel(int channo
)
187 if((channo
>MAX_CHAN
)||(channo
<0)) {
188 fprintf(stderr
, "Invalid Bchannel RANGE <%d", channo
);
192 while(chans
[channo
].pid
) {
199 /* place here criteria for completion of destination number */
200 static int number_incommplete(char *number
)
202 return strlen(number
) < 3;
205 static void start_channel(struct pri
*pri
, pri_event
*e
)
207 int channo
= e
->ring
.channel
;
209 pri_event_ring
*ring
= &e
->ring
;
212 channo
= e
->ring
.channel
= get_free_channel(MAX_CHAN
);
214 if(channo
== DCHANNEL_TIMESLOT
)
215 channo
= e
->ring
.channel
= get_free_channel(MAX_CHAN
);
218 fprintf(stdout
, "Any channel selected: %d\n", channo
);
221 pri_release(pri
, ring
->call
, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
);
222 fprintf(stdout
, "Abort call due to no avl B channels\n");
228 /* Make sure it's a valid number */
229 if ((channo
>= MAX_CHAN
) || (channo
< 0)) {
230 fprintf(stderr
, "--!! Channel %d is out of range\n", channo
);
234 /* Make sure nothing is there */
235 if (chans
[channo
].pid
) {
236 fprintf(stderr
, "--!! Channel %d still has a call on it, ending it...\n", channo
);
237 hangup_channel(channo
);
238 /* Wait for it to die */
239 while(chans
[channo
].pid
)
243 /* Record call number */
244 chans
[channo
].call
= e
->ring
.call
;
246 /* Answer the line */
248 pri_answer(pri
, chans
[channo
].call
, channo
, 1);
250 pri_need_more_info(pri
, chans
[channo
].call
, channo
, 1);
253 /* Launch a process to handle it */
254 launch_channel(channo
);
258 static void handle_pri_event(struct pri
*pri
, pri_event
*e
)
261 case PRI_EVENT_DCHAN_UP
:
262 printf("-- D-Channel is now up! :-)\n");
264 case PRI_EVENT_DCHAN_DOWN
:
265 printf("-- D-Channel is now down! :-(\n");
267 case PRI_EVENT_RESTART
:
268 printf("-- Restarting channel %d\n", e
->restart
.channel
);
269 hangup_channel(e
->restart
.channel
);
271 case PRI_EVENT_CONFIG_ERR
:
272 printf("-- Configuration error detected: %s\n", e
->err
.err
);
275 printf("-- Ring on channel %d (from %s to %s), answering...\n", e
->ring
.channel
, e
->ring
.callingnum
, e
->ring
.callednum
);
276 start_channel(pri
, e
);
278 case PRI_EVENT_HANGUP
:
279 printf("-- Hanging up channel %d\n", e
->hangup
.channel
);
280 hangup_channel(e
->hangup
.channel
);
282 case PRI_EVENT_RINGING
:
283 case PRI_EVENT_ANSWER
:
284 fprintf(stderr
, "--!! What? We shouldn't be making any calls...\n");
286 case PRI_EVENT_HANGUP_ACK
:
289 case PRI_EVENT_INFO_RECEIVED
:
290 fprintf(stdout
, "number is: %s\n", e
->ring
.callednum
);
291 if(!number_incommplete(e
->ring
.callednum
)) {
292 fprintf(stdout
, "final number is: %s\n", e
->ring
.callednum
);
293 pri_answer(pri
, e
->ring
.call
, 0, 1);
297 case PRI_EVENT_HANGUP_REQ
:
298 printf("-- Hanging up channel %d\n", e
->hangup
.channel
);
299 hangup_channel(e
->hangup
.channel
);
302 fprintf(stderr
, "--!! Unknown PRI event %d\n", e
->e
);
306 static int run_pri(int dfd
, int swtype
, int node
)
310 struct timeval tv
= {0,0}, *next
;
314 pri
= pri_new(dfd
, node
, swtype
);
316 fprintf(stderr
, "Unable to create PRI\n");
319 pri_set_debug(pri
, -1);
322 /* Run the D-Channel */
328 if ((next
= pri_schedule_next(pri
))) {
329 gettimeofday(&tv
, NULL
);
330 tv
.tv_sec
= next
->tv_sec
- tv
.tv_sec
;
331 tv
.tv_usec
= next
->tv_usec
- tv
.tv_usec
;
332 if (tv
.tv_usec
< 0) {
333 tv
.tv_usec
+= 1000000;
341 res
= select(dfd
+ 1, &rfds
, NULL
, &efds
, next
? &tv
: NULL
);
345 e
= pri_schedule_run(pri
);
346 } else if (res
> 0) {
347 e
= pri_check_event(pri
);
348 } else if (errno
== ELAST
) {
349 res
= ioctl(dfd
, ZT_GETEVENT
, &x
);
350 printf("Got Zaptel event: %d\n", x
);
351 } else if (errno
!= EINTR
)
352 fprintf(stderr
, "Error (%d) on select: %s\n", ELAST
, strerror(errno
));
355 handle_pri_event(pri
, e
);
358 res
= ioctl(dfd
, ZT_GETEVENT
, &x
);
361 fprintf(stderr
, "Got event on PRI interface: %d\n", x
);
364 /* Check for lines that need hangups */
365 for (x
=0;x
<MAX_CHAN
;x
++)
366 if (chans
[x
].needhangup
) {
367 chans
[x
].needhangup
= 0;
368 pri_release(pri
, chans
[x
].call
, PRI_CAUSE_NORMAL_CLEARING
);
375 int main(int argc
, char *argv
[])
378 int swtype
= PRI_DEF_SWITCHTYPE
;
379 int node
= PRI_DEF_NODETYPE
;
382 fprintf(stderr
, "Usage: pritest <dchannel> [swtypetype] [nodetype]\n");
385 dfd
= open(argv
[1], O_RDWR
);
387 fprintf(stderr
, "Failed to open dchannel '%s': %s\n", argv
[1], strerror(errno
));
390 if (ioctl(dfd
, ZT_GET_PARAMS
, &p
)) {
391 fprintf(stderr
, "Unable to get parameters on '%s': %s\n", argv
[1], strerror(errno
));
394 if ((p
.sigtype
!= ZT_SIG_HDLCRAW
) && (p
.sigtype
!= ZT_SIG_HDLCFCS
)) {
395 fprintf(stderr
, "%s is in %d signalling, not FCS HDLC or RAW HDLC mode\n", argv
[1], p
.sigtype
);
400 swtype
= str2switch(argv
[2]);
402 fprintf(stderr
, "Valid switchtypes are: ni2, dms100, lucent5e, att4ess, and euroisdn\n");
408 node
= str2node(argv
[3]);
410 fprintf(stderr
, "Valid node types are: network and cpe\n");
415 signal(SIGCHLD
, chan_ended
);
417 if (run_pri(dfd
, swtype
, node
))