Add test program for windowing, implement proper windowing
git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@79 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
d00abddee3
commit
91b4a60c1f
9
Makefile
9
Makefile
@ -28,6 +28,7 @@
|
|||||||
#LIBPRI_COUNTERS=-DLIBPRI_COUNTERS
|
#LIBPRI_COUNTERS=-DLIBPRI_COUNTERS
|
||||||
|
|
||||||
TOBJS=testpri.o
|
TOBJS=testpri.o
|
||||||
|
T2OBJS=testprilib.o
|
||||||
STATIC_LIBRARY=libpri.a
|
STATIC_LIBRARY=libpri.a
|
||||||
DYNAMIC_LIBRARY=libpri.so.1.0
|
DYNAMIC_LIBRARY=libpri.so.1.0
|
||||||
STATIC_OBJS=pri.o q921.o prisched.o q931.o
|
STATIC_OBJS=pri.o q921.o prisched.o q931.o
|
||||||
@ -60,6 +61,12 @@ uninstall:
|
|||||||
pritest: pritest.o
|
pritest: pritest.o
|
||||||
$(CC) -o pritest pritest.o -L. -lpri -lzap
|
$(CC) -o pritest pritest.o -L. -lpri -lzap
|
||||||
|
|
||||||
|
testprilib.o: testprilib.c
|
||||||
|
$(CC) $(CFLAGS) -D_REENTRANT -D_GNU_SOURCE -o $@ -c $<
|
||||||
|
|
||||||
|
testprilib: testprilib.o
|
||||||
|
$(CC) -o testprilib testprilib.o -L. -lpri -lpthread
|
||||||
|
|
||||||
pridump: pridump.o
|
pridump: pridump.o
|
||||||
$(CC) -o pridump pridump.o -L. -lpri -lzap
|
$(CC) -o pridump pridump.o -L. -lpri -lzap
|
||||||
|
|
||||||
@ -77,5 +84,5 @@ $(DYNAMIC_LIBRARY): $(DYNAMIC_OBJS)
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.so *.lo *.so.1 *.so.1.0
|
rm -f *.o *.so *.lo *.so.1 *.so.1.0
|
||||||
rm -f testpri $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY)
|
rm -f testpri testprilib $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY)
|
||||||
rm -f pritest pridump
|
rm -f pritest pridump
|
||||||
|
3
libpri.h
3
libpri.h
@ -390,4 +390,7 @@ extern void pri_set_overlapdial(struct pri *pri,int state);
|
|||||||
#define PRI_DUMP_INFO
|
#define PRI_DUMP_INFO
|
||||||
extern void pri_dump_info(struct pri *pri);
|
extern void pri_dump_info(struct pri *pri);
|
||||||
|
|
||||||
|
/* Get file descriptor */
|
||||||
|
extern int pri_fd(struct pri *pri);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
9
pri.c
9
pri.c
@ -72,8 +72,8 @@ struct pri *pri_new(int fd, int node, int switchtype)
|
|||||||
p->q931_rxcount = 0;
|
p->q931_rxcount = 0;
|
||||||
p->q931_txcount = 0;
|
p->q931_txcount = 0;
|
||||||
#endif
|
#endif
|
||||||
/* Start Q.921 layer */
|
/* Start Q.921 layer, Wait if we're the network */
|
||||||
q921_start(p, 1);
|
q921_start(p, p->localtype == PRI_CPE);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -338,6 +338,11 @@ void pri_set_overlapdial(struct pri *pri,int state)
|
|||||||
pri->overlapdial = state;
|
pri->overlapdial = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pri_fd(struct pri *pri)
|
||||||
|
{
|
||||||
|
return pri->fd;
|
||||||
|
}
|
||||||
|
|
||||||
void pri_dump_info(struct pri *pri)
|
void pri_dump_info(struct pri *pri)
|
||||||
{
|
{
|
||||||
#ifdef LIBPRI_COUNTERS
|
#ifdef LIBPRI_COUNTERS
|
||||||
|
@ -52,6 +52,7 @@ struct pri {
|
|||||||
/* Q.921 State */
|
/* Q.921 State */
|
||||||
int q921_state;
|
int q921_state;
|
||||||
int window; /* Max window size */
|
int window; /* Max window size */
|
||||||
|
int windowlen; /* Fullness of window */
|
||||||
int v_s; /* Next N(S) for transmission */
|
int v_s; /* Next N(S) for transmission */
|
||||||
int v_a; /* Last acknowledged frame */
|
int v_a; /* Last acknowledged frame */
|
||||||
int v_r; /* Next frame expected to be received */
|
int v_r; /* Next frame expected to be received */
|
||||||
|
@ -134,6 +134,7 @@ typedef union {
|
|||||||
typedef struct q921_frame {
|
typedef struct q921_frame {
|
||||||
struct q921_frame *next; /* Next in list */
|
struct q921_frame *next; /* Next in list */
|
||||||
int len; /* Length of header + body */
|
int len; /* Length of header + body */
|
||||||
|
int transmitted; /* Have we been transmitted */
|
||||||
q921_i h;
|
q921_i h;
|
||||||
} q921_frame;
|
} q921_frame;
|
||||||
|
|
||||||
|
43
q921.c
43
q921.c
@ -170,6 +170,22 @@ static int q921_ack_packet(struct pri *pri, int num)
|
|||||||
free(f);
|
free(f);
|
||||||
/* Reset retransmission counter if we actually acked something */
|
/* Reset retransmission counter if we actually acked something */
|
||||||
pri->retrans = 0;
|
pri->retrans = 0;
|
||||||
|
/* Decrement window size */
|
||||||
|
pri->windowlen--;
|
||||||
|
/* Search for something to send */
|
||||||
|
f = pri->txqueue;
|
||||||
|
while(f) {
|
||||||
|
if (!f->transmitted) {
|
||||||
|
/* Send it now... */
|
||||||
|
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
||||||
|
pri_message("-- Finally transmitting %d, since window opened up\n", f->h.n_s);
|
||||||
|
f->transmitted++;
|
||||||
|
pri->windowlen++;
|
||||||
|
q921_transmit(pri, (q921_h *)(&f->h), f->len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
prev = f;
|
prev = f;
|
||||||
@ -319,8 +335,11 @@ static void t200_expire(void *vpri)
|
|||||||
pri_message("-- Retransmitting %d bytes\n", pri->txqueue->len);
|
pri_message("-- Retransmitting %d bytes\n", pri->txqueue->len);
|
||||||
if (pri->busy)
|
if (pri->busy)
|
||||||
q921_rr(pri, 1, 0);
|
q921_rr(pri, 1, 0);
|
||||||
else
|
else {
|
||||||
|
if (!pri->txqueue->transmitted)
|
||||||
|
pri_error("!! Not good - head of queue has not been transmitted yet\n");
|
||||||
q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len);
|
q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len);
|
||||||
|
}
|
||||||
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
||||||
pri_message("-- Rescheduling retransmission (%d)\n", pri->retrans);
|
pri_message("-- Rescheduling retransmission (%d)\n", pri->retrans);
|
||||||
pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri);
|
pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri);
|
||||||
@ -362,6 +381,7 @@ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
f->next = NULL;
|
f->next = NULL;
|
||||||
|
f->transmitted = 0;
|
||||||
f->len = len + 4;
|
f->len = len + 4;
|
||||||
memcpy(f->h.data, buf, len);
|
memcpy(f->h.data, buf, len);
|
||||||
f->h.n_s = pri->v_s;
|
f->h.n_s = pri->v_s;
|
||||||
@ -374,9 +394,18 @@ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
|
|||||||
prev->next = f;
|
prev->next = f;
|
||||||
else
|
else
|
||||||
pri->txqueue = f;
|
pri->txqueue = f;
|
||||||
/* Immediately transmit unless we're in a recovery state */
|
/* Immediately transmit unless we're in a recovery state, or the window
|
||||||
|
size is too big */
|
||||||
if (!pri->retrans && !pri->busy) {
|
if (!pri->retrans && !pri->busy) {
|
||||||
q921_transmit(pri, (q921_h *)(&f->h), f->len);
|
if (pri->windowlen < pri->window) {
|
||||||
|
pri->windowlen++;
|
||||||
|
q921_transmit(pri, (q921_h *)(&f->h), f->len);
|
||||||
|
f->transmitted++;
|
||||||
|
} else {
|
||||||
|
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
||||||
|
pri_message("Delaying transmission of %d, window is %d/%d long\n",
|
||||||
|
f->h.n_s, pri->windowlen, pri->window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (pri->t203_timer) {
|
if (pri->t203_timer) {
|
||||||
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
||||||
@ -468,7 +497,7 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx)
|
|||||||
pri_message("\n%c [", direction_tag);
|
pri_message("\n%c [", direction_tag);
|
||||||
for (x=0;x<len;x++)
|
for (x=0;x<len;x++)
|
||||||
pri_message("%02x ",h->raw[x]);
|
pri_message("%02x ",h->raw[x]);
|
||||||
pri_message("]");
|
pri_message("]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (h->h.data[0] & Q921_FRAMETYPE_MASK) {
|
switch (h->h.data[0] & Q921_FRAMETYPE_MASK) {
|
||||||
@ -627,6 +656,7 @@ void q921_reset(struct pri *pri)
|
|||||||
pri->v_r = 0;
|
pri->v_r = 0;
|
||||||
pri->v_na = 0;
|
pri->v_na = 0;
|
||||||
pri->window = 7;
|
pri->window = 7;
|
||||||
|
pri->windowlen = 0;
|
||||||
pri_schedule_del(pri, pri->sabme_timer);
|
pri_schedule_del(pri, pri->sabme_timer);
|
||||||
pri_schedule_del(pri, pri->t203_timer);
|
pri_schedule_del(pri, pri->t203_timer);
|
||||||
pri_schedule_del(pri, pri->t200_timer);
|
pri_schedule_del(pri, pri->t200_timer);
|
||||||
@ -731,8 +761,9 @@ static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
|
|||||||
sendnow = 0;
|
sendnow = 0;
|
||||||
/* Resend the proper I-frame */
|
/* Resend the proper I-frame */
|
||||||
for(f=pri->txqueue;f;f=f->next) {
|
for(f=pri->txqueue;f;f=f->next) {
|
||||||
if (sendnow || (f->h.n_s == h->s.n_r)) {
|
if ((sendnow || (f->h.n_s == h->s.n_r)) && f->transmitted) {
|
||||||
/* Matches the request, or follows in our window */
|
/* Matches the request, or follows in our window, and has
|
||||||
|
already been transmitted. */
|
||||||
sendnow = 1;
|
sendnow = 1;
|
||||||
pri_error("!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s);
|
pri_error("!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s);
|
||||||
f->h.n_r = pri->v_r;
|
f->h.n_r = pri->v_r;
|
||||||
|
234
testprilib.c
Executable file
234
testprilib.c
Executable file
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* libpri: An implementation of Primary Rate ISDN
|
||||||
|
*
|
||||||
|
* Written by Mark Spencer <markster@linux-support.net>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001, Linux Support Services, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This program tests libpri call reception using a zaptel interface.
|
||||||
|
* Its state machines are setup for RECEIVING CALLS ONLY, so if you
|
||||||
|
* are trying to both place and receive calls you have to a bit more.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/signal.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/zaptel.h>
|
||||||
|
#include <zap.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include "libpri.h"
|
||||||
|
|
||||||
|
#define DEBUG_LEVEL PRI_DEBUG_ALL
|
||||||
|
|
||||||
|
#define PRI_DEF_NODETYPE PRI_CPE
|
||||||
|
#define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2
|
||||||
|
|
||||||
|
static struct pri *first, *cur;
|
||||||
|
|
||||||
|
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
#define TEST_CALLS 32
|
||||||
|
|
||||||
|
static void event1(struct pri *pri, pri_event *e)
|
||||||
|
{
|
||||||
|
/* Network */
|
||||||
|
int x;
|
||||||
|
static q931_call *calls[TEST_CALLS];
|
||||||
|
char name[256], num[256], dest[256];
|
||||||
|
switch(e->gen.e) {
|
||||||
|
case PRI_EVENT_DCHAN_UP:
|
||||||
|
printf("Network is up. Sending blast of calls!\n");
|
||||||
|
for (x=0;x<TEST_CALLS;x++) {
|
||||||
|
sprintf(name, "Caller %d", x + 1);
|
||||||
|
sprintf(num, "25642860%02d", x+1);
|
||||||
|
sprintf(dest, "60%02d", x + 1);
|
||||||
|
if (!(calls[x] = pri_new_call(pri))) {
|
||||||
|
perror("pri_new_call");
|
||||||
|
} else if (pri_call(pri, calls[x], PRI_TRANS_CAP_DIGITAL, x + 1, 1, 1, num,
|
||||||
|
PRI_NATIONAL_ISDN, name, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN,
|
||||||
|
dest, PRI_NATIONAL_ISDN, PRI_LAYER_1_ULAW)) {
|
||||||
|
perror("pri_call");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Setup %d calls!\n", TEST_CALLS);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("PRI 1: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void event2(struct pri *pri, pri_event *e)
|
||||||
|
{
|
||||||
|
/* CPE */
|
||||||
|
switch(e->gen.e) {
|
||||||
|
case PRI_EVENT_DCHAN_UP:
|
||||||
|
default:
|
||||||
|
printf("PRI 2: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testmsg(char *s)
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
static int keeplast = 0;
|
||||||
|
do {
|
||||||
|
c = strchr(s, '\n');
|
||||||
|
if (c) {
|
||||||
|
*c = '\0';
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
if (keeplast)
|
||||||
|
printf("%s", s);
|
||||||
|
else if (cur == first)
|
||||||
|
printf("-1 %s", s);
|
||||||
|
else
|
||||||
|
printf("-2 %s", s);
|
||||||
|
if (c)
|
||||||
|
printf("\n");
|
||||||
|
s = c;
|
||||||
|
} while(c && *c);
|
||||||
|
if (!c)
|
||||||
|
keeplast = 1;
|
||||||
|
else
|
||||||
|
keeplast = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testerr(char *s)
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
static int keeplast = 0;
|
||||||
|
do {
|
||||||
|
c = strchr(s, '\n');
|
||||||
|
if (c) {
|
||||||
|
*c = '\0';
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
if (keeplast)
|
||||||
|
printf("%s", s);
|
||||||
|
else if (cur == first)
|
||||||
|
printf("=1 %s", s);
|
||||||
|
else
|
||||||
|
printf("=2 %s", s);
|
||||||
|
if (c)
|
||||||
|
printf("\n");
|
||||||
|
s = c;
|
||||||
|
} while(c && *c);
|
||||||
|
if (!c)
|
||||||
|
keeplast = 1;
|
||||||
|
else
|
||||||
|
keeplast = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *dchan(void *data)
|
||||||
|
{
|
||||||
|
/* Joint D-channel */
|
||||||
|
struct pri *pri = data;
|
||||||
|
struct timeval *next, tv;
|
||||||
|
pri_event *e;
|
||||||
|
fd_set fds;
|
||||||
|
int res;
|
||||||
|
for(;;) {
|
||||||
|
if (next == pri_schedule_next(pri)) {
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
tv.tv_sec = next->tv_sec - tv.tv_sec;
|
||||||
|
tv.tv_usec = next->tv_usec - tv.tv_usec;
|
||||||
|
if (tv.tv_usec < 0) {
|
||||||
|
tv.tv_usec += 1000000;
|
||||||
|
tv.tv_sec -= 1;
|
||||||
|
}
|
||||||
|
if (tv.tv_sec < 0) {
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(pri_fd(pri), &fds);
|
||||||
|
res = select(pri_fd(pri) + 1, &fds, NULL, NULL, next ? &tv : NULL);
|
||||||
|
pthread_mutex_lock(&lock);
|
||||||
|
cur = pri;
|
||||||
|
if (res < 0) {
|
||||||
|
perror("select");
|
||||||
|
} else if (!res) {
|
||||||
|
e = pri_schedule_run(pri);
|
||||||
|
} else {
|
||||||
|
e = pri_check_event(pri);
|
||||||
|
}
|
||||||
|
if (e) {
|
||||||
|
if (first == pri) {
|
||||||
|
event1(pri, e);
|
||||||
|
} else {
|
||||||
|
event2(pri, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int pair[2];
|
||||||
|
pthread_t tmp;
|
||||||
|
struct pri *pri;
|
||||||
|
pri_set_message(testmsg);
|
||||||
|
pri_set_error(testerr);
|
||||||
|
if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, pair)) {
|
||||||
|
perror("socketpair");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!(pri = pri_new(pair[0], PRI_NETWORK, PRI_DEF_SWITCHTYPE))) {
|
||||||
|
perror("pri(0)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
first = pri;
|
||||||
|
pri_set_debug(pri, DEBUG_LEVEL);
|
||||||
|
if (pthread_create(&tmp, NULL, dchan, pri)) {
|
||||||
|
perror("thread(0)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!(pri = pri_new(pair[1], PRI_CPE, PRI_DEF_SWITCHTYPE))) {
|
||||||
|
perror("pri(1)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pri_set_debug(pri, DEBUG_LEVEL);
|
||||||
|
if (pthread_create(&tmp, NULL, dchan, pri)) {
|
||||||
|
perror("thread(1)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* Wait for things to run */
|
||||||
|
sleep(5);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user