- better handling of the different connections. All connections are

now in a list with the current state.
- not completly tested.
This commit is contained in:
Carsten Paeth 2001-05-15 09:23:11 +00:00
parent 6ed19ab980
commit 9db340586a
1 changed files with 260 additions and 54 deletions

View File

@ -50,10 +50,11 @@ char pppd_version[] = VERSION;
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
static void handlemessages(void) ;
/* -------------------------------------------------------------------- */
static capiconn_context *ctx; static capiconn_context *ctx;
static capi_connection *conn = 0;
static int isconnected = 0;
static int connectinprogress = 0;
static unsigned applid; static unsigned applid;
#define CM(x) (1<<(x)) #define CM(x) (1<<(x))
#define CIPMASK_ALL 0x1FFF03FF #define CIPMASK_ALL 0x1FFF03FF
@ -240,6 +241,179 @@ static STRINGLIST *stringlist_split(char *tosplit, char *seps)
return p; return p;
} }
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
typedef struct conn {
struct conn *next;
capi_connection *conn;
int type;
#define CONNTYPE_OUTGOING 0
#define CONNTYPE_INCOMING 1
#define CONNTYPE_IGNORE 2
#define CONNTYPE_REJECT 3
#define CONNTYPE_FOR_CALLBACK 4
int inprogress;
int isconnected;
} CONN;
static CONN *connections;
/* -------------------------------------------------------------------- */
static CONN *conn_remember(capi_connection *conn, int type)
{
CONN *p, **pp;
for (pp = &connections; *pp; pp = &(*pp)->next) ;
if ((p = (CONN *)malloc(sizeof(CONN))) == 0) {
int serrno = errno;
fatal("capiplugin: malloc failed - %s (%d)",
strerror(serrno), serrno);
return 0;
}
memset(p, 0, sizeof(CONN));
p->conn = conn;
p->type = type;
p->next = 0;
switch (type) {
case CONNTYPE_OUTGOING:
case CONNTYPE_INCOMING:
case CONNTYPE_FOR_CALLBACK:
p->inprogress = 1;
p->isconnected = 0;
break;
default:
break;
}
*pp = p;
return p;
}
static int conn_forget(capi_connection *conn)
{
CONN **pp, *p;
for (pp = &connections; *pp && (*pp)->conn != conn; pp = &(*pp)->next) ;
if (*pp) {
p = *pp;
*pp = (*pp)->next;
free(p);
return 0;
}
return -1;
}
static CONN *conn_find(capi_connection *cp)
{
CONN *p;
for (p = connections; p; p = p->next) {
if (p->conn == cp)
return p;
}
return 0;
}
/* -------------------------------------------------------------------- */
static int conn_connected(capi_connection *conn)
{
CONN *p;
for (p = connections; p; p = p->next) {
if (p->conn == conn) {
p->isconnected = 1;
p->inprogress = 0;
return 0;
}
}
fatal("capiplugin: connected connection not found ??");
return -1;
}
/* -------------------------------------------------------------------- */
static int conn_incoming_inprogress(void)
{
CONN *p;
for (p = connections; p; p = p->next) {
if (p->type == CONNTYPE_INCOMING)
return p->inprogress;
}
return 0;
}
static int conn_incoming_connected(void)
{
CONN *p;
for (p = connections; p; p = p->next) {
if (p->type == CONNTYPE_INCOMING)
return p->isconnected;
}
return 0;
}
static int conn_incoming_exists(void)
{
CONN *p;
for (p = connections; p; p = p->next) {
if (p->type == CONNTYPE_INCOMING)
return p->isconnected || p->inprogress;
}
return 0;
}
/* -------------------------------------------------------------------- */
static int conn_inprogress(capi_connection *cp)
{
CONN *p;
for (p = connections; p; p = p->next) {
if (p->conn == cp)
return p->inprogress;
}
return 0;
}
static int conn_isconnected(capi_connection *cp)
{
CONN *p;
if (cp) {
for (p = connections; p; p = p->next) {
if (p->conn == cp)
return p->isconnected;
}
} else {
for (p = connections; p; p = p->next) {
if (p->isconnected)
return 1;
}
}
return 0;
}
/* -------------------------------------------------------------------- */
static void disconnectall(void)
{
time_t t;
CONN *p;
(void) capiconn_listen(ctx, controller, 0, 0);
for (p = connections; p; p = p->next) {
if (p->inprogress || p->isconnected) {
p->isconnected = p->inprogress = 0;
capiconn_disconnect(p->conn, 0);
}
}
t = time(0)+10;
do {
handlemessages();
} while (connections && time(0) < t);
if (connections)
fatal("capiplugin: disconnectall failed");
}
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
static int timeoutrunning = 0; static int timeoutrunning = 0;
@ -381,20 +555,25 @@ static void handlemessages(void)
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
static void dodisconnect(void) static void dodisconnect(capi_connection *cp)
{ {
CONN *conn;
time_t t; time_t t;
if (!conn)
if ((conn = conn_find(cp)) == 0)
return; return;
(void)capiconn_disconnect(conn, 0); (void)capiconn_disconnect(cp, 0);
conn->isconnected = conn->inprogress = 0;
t = time(0)+10; t = time(0)+10;
while (conn && time(0) < t) do {
handlemessages(); handlemessages();
if (conn) } while (conn_find(cp) && time(0) < t);
if (conn_find(cp))
fatal("capiplugin: timeout while waiting for disconnect"); fatal("capiplugin: timeout while waiting for disconnect");
} }
static void init_capiconn(void) static void init_capiconn(void)
{ {
static int init = 0; static int init = 0;
@ -716,14 +895,23 @@ static void disconnected(capi_connection *cp,
unsigned reason, unsigned reason,
unsigned reason_b3) unsigned reason_b3)
{ {
if (conn != cp) { CONN *p;
dbglog("capiplugin: ignored/rejected call disconnected");
if ((p = conn_find(cp)) == 0)
return; return;
} conn_forget(cp);
conn = 0; switch (p->type) {
connectinprogress = 0; case CONNTYPE_OUTGOING:
isconnected = 0; case CONNTYPE_INCOMING:
break;
case CONNTYPE_IGNORE:
case CONNTYPE_REJECT:
return;
case CONNTYPE_FOR_CALLBACK:
dreason = reason; dreason = reason;
break;
}
if (reason != 0x3304 || debug) /* Another Applikation got the call */ if (reason != 0x3304 || debug) /* Another Applikation got the call */
info("capiplugin: disconnect(%s): %s 0x%04x (0x%04x) - %s", info("capiplugin: disconnect(%s): %s 0x%04x (0x%04x) - %s",
localdisconnect ? "local" : "remote", localdisconnect ? "local" : "remote",
@ -744,8 +932,9 @@ static void incoming(capi_connection *cp,
info("capiplugin: incoming call: %s (0x%x)", conninfo(cp), cipvalue); info("capiplugin: incoming call: %s (0x%x)", conninfo(cp), cipvalue);
if (conn) { if (conn_incoming_exists()) {
info("capiplugin: ignoring call, conn != NULL"); info("capiplugin: ignoring call, incoming connection exists");
conn_remember(cp, CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
return; return;
} }
@ -759,6 +948,7 @@ static void incoming(capi_connection *cp,
if (!p) { if (!p) {
info("capiplugin: ignoring call, msn %s not in \"%s\"", info("capiplugin: ignoring call, msn %s not in \"%s\"",
callednumber, opt_inmsn); callednumber, opt_inmsn);
conn_remember(cp, CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
return; return;
} }
@ -767,6 +957,7 @@ static void incoming(capi_connection *cp,
|| strcmp(s, opt_msn) != 0) { || strcmp(s, opt_msn) != 0) {
info("capiplugin: ignoring call, msn mismatch (%s != %s)", info("capiplugin: ignoring call, msn mismatch (%s != %s)",
opt_msn, callednumber); opt_msn, callednumber);
conn_remember(cp, CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
return; return;
} }
@ -781,6 +972,7 @@ static void incoming(capi_connection *cp,
if (!p) { if (!p) {
info("capiplugin: ignoring call, cli mismatch (%s != %s)", info("capiplugin: ignoring call, cli mismatch (%s != %s)",
opt_cli, callingnumber); opt_cli, callingnumber);
conn_remember(cp, CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
return; return;
} }
@ -793,6 +985,7 @@ static void incoming(capi_connection *cp,
if (!p) { if (!p) {
info("capiplugin: ignoring call, number mismatch (%s != %s)", info("capiplugin: ignoring call, number mismatch (%s != %s)",
opt_number, callingnumber); opt_number, callingnumber);
conn_remember(cp, CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
return; return;
} }
@ -820,6 +1013,7 @@ static void incoming(capi_connection *cp,
} else { } else {
info("capiplugin: ignoring speech call from %s", info("capiplugin: ignoring speech call from %s",
callingnumber); callingnumber);
conn_remember(cp,CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
} }
break; break;
@ -840,17 +1034,20 @@ static void incoming(capi_connection *cp,
} else { } else {
info("capiplugin: ignoring digital call from %s", info("capiplugin: ignoring digital call from %s",
callingnumber); callingnumber);
conn_remember(cp,CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
} }
break; break;
case 17: /* Group 2/3 facsimile */ case 17: /* Group 2/3 facsimile */
info("capiplugin: ignoring fax call from %s", info("capiplugin: ignoring fax call from %s",
callingnumber); callingnumber);
conn_remember(cp,CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
break; break;
default: default:
info("capiplugin: ignoring type %d call from %s", info("capiplugin: ignoring type %d call from %s",
cipvalue, callingnumber); cipvalue, callingnumber);
conn_remember(cp,CONNTYPE_IGNORE);
(void) capiconn_ignore(cp); (void) capiconn_ignore(cp);
break; break;
} }
@ -859,12 +1056,14 @@ static void incoming(capi_connection *cp,
callback: callback:
(void) capiconn_listen(ctx, controller, 0, 0); (void) capiconn_listen(ctx, controller, 0, 0);
dbglog("capiplugin: rejecting call: %s (0x%x)", conninfo(cp), cipvalue); dbglog("capiplugin: rejecting call: %s (0x%x)", conninfo(cp), cipvalue);
conn_remember(cp, CONNTYPE_REJECT);
capiconn_reject(cp); capiconn_reject(cp);
makecallback(); makecallback();
return; return;
wakeupdemand: wakeupdemand:
dbglog("capiplugin: rejecting call: %s (0x%x)", conninfo(cp), cipvalue); dbglog("capiplugin: rejecting call: %s (0x%x)", conninfo(cp), cipvalue);
conn_remember(cp, CONNTYPE_REJECT);
capiconn_reject(cp); capiconn_reject(cp);
wakeupdemand(); wakeupdemand();
return; return;
@ -887,8 +1086,7 @@ accept:
} else { /* hdlc */ } else { /* hdlc */
(void) capiconn_accept(cp, 0, 1, 0, 0, 0, 0, 0); (void) capiconn_accept(cp, 0, 1, 0, 0, 0, 0, 0);
} }
conn = cp; conn_remember(cp, CONNTYPE_INCOMING);
connectinprogress = 1;
(void) capiconn_listen(ctx, controller, 0, 0); (void) capiconn_listen(ctx, controller, 0, 0);
return; return;
} }
@ -939,8 +1137,7 @@ static void connected(capi_connection *cp, _cstruct NCPI)
sprintf(buf, "%d", p->b2proto); _script_setenv("B2PROTOCOL", buf); sprintf(buf, "%d", p->b2proto); _script_setenv("B2PROTOCOL", buf);
sprintf(buf, "%d", p->b3proto); _script_setenv("B3PROTOCOL", buf); sprintf(buf, "%d", p->b3proto); _script_setenv("B3PROTOCOL", buf);
isconnected = 1; conn_connected(cp);
connectinprogress = 0;
if (wakeupneeded) if (wakeupneeded)
wakeupdemand(); wakeupdemand();
} }
@ -984,15 +1181,16 @@ capiconn_callbacks callbacks = {
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
static void setupconnection(char *num, int awaitingreject) static capi_connection *setupconnection(char *num, int awaitingreject)
{ {
struct capi_connection *cp;
char number[256]; char number[256];
snprintf(number, sizeof(number), "%s%s", snprintf(number, sizeof(number), "%s%s",
opt_numberprefix ? opt_numberprefix : "", num); opt_numberprefix ? opt_numberprefix : "", num);
if (proto == PROTO_HDLC) { if (proto == PROTO_HDLC) {
conn = capiconn_connect(ctx, cp = capiconn_connect(ctx,
controller, /* contr */ controller, /* contr */
2, /* cipvalue */ 2, /* cipvalue */
opt_channels ? 0 : number, opt_channels ? 0 : number,
@ -1002,7 +1200,7 @@ static void setupconnection(char *num, int awaitingreject)
opt_channels ? AdditionalInfo : 0, opt_channels ? AdditionalInfo : 0,
0); 0);
} else if (proto == PROTO_X75) { } else if (proto == PROTO_X75) {
conn = capiconn_connect(ctx, cp = capiconn_connect(ctx,
controller, /* contr */ controller, /* contr */
2, /* cipvalue */ 2, /* cipvalue */
opt_channels ? 0 : number, opt_channels ? 0 : number,
@ -1012,7 +1210,7 @@ static void setupconnection(char *num, int awaitingreject)
opt_channels ? AdditionalInfo : 0, opt_channels ? AdditionalInfo : 0,
0); 0);
} else if (proto == PROTO_V42BIS) { } else if (proto == PROTO_V42BIS) {
conn = capiconn_connect(ctx, cp = capiconn_connect(ctx,
controller, /* contr */ controller, /* contr */
2, /* cipvalue */ 2, /* cipvalue */
opt_channels ? 0 : number, opt_channels ? 0 : number,
@ -1022,7 +1220,7 @@ static void setupconnection(char *num, int awaitingreject)
opt_channels ? AdditionalInfo : 0, opt_channels ? AdditionalInfo : 0,
0); 0);
} else if (proto == PROTO_MODEM) { } else if (proto == PROTO_MODEM) {
conn = capiconn_connect(ctx, cp = capiconn_connect(ctx,
controller, /* contr */ controller, /* contr */
1, /* cipvalue */ 1, /* cipvalue */
opt_channels ? 0 : number, opt_channels ? 0 : number,
@ -1033,7 +1231,7 @@ static void setupconnection(char *num, int awaitingreject)
0); 0);
} else { } else {
fatal("capiplugin: unknown protocol \"%s\"", opt_proto); fatal("capiplugin: unknown protocol \"%s\"", opt_proto);
return; return 0;
} }
if (opt_channels) { if (opt_channels) {
info("capiplugin: leased line (%s)", info("capiplugin: leased line (%s)",
@ -1044,26 +1242,31 @@ static void setupconnection(char *num, int awaitingreject)
info("capiplugin: dialing %s (%s)", info("capiplugin: dialing %s (%s)",
number, opt_proto ? opt_proto : "hdlc"); number, opt_proto ? opt_proto : "hdlc");
} }
connectinprogress = 1; if (awaitingreject)
conn_remember(cp, CONNTYPE_FOR_CALLBACK);
else
conn_remember(cp, CONNTYPE_OUTGOING);
return cp;
} }
static void makeleasedline(void) static void makeleasedline(void)
{ {
capi_connection *cp;
time_t t; time_t t;
setupconnection("", 0); cp = setupconnection("", 0);
t = time(0)+opt_dialtimeout; t = time(0)+opt_dialtimeout;
do { do {
handlemessages(); handlemessages();
if (status != EXIT_OK && conn) if (status != EXIT_OK && conn_find(cp))
dodisconnect(); dodisconnect(cp);
} while (time(0) < t && conn && !isconnected); } while (time(0) < t && conn_inprogress(cp));
if (status != EXIT_OK) if (status != EXIT_OK)
die(status); die(status);
if (conn && isconnected) { if (conn_isconnected(cp)) {
t = time(0)+opt_connectdelay; t = time(0)+opt_connectdelay;
do { do {
handlemessages(); handlemessages();
@ -1073,12 +1276,13 @@ static void makeleasedline(void)
if (status != EXIT_OK) if (status != EXIT_OK)
die(status); die(status);
if (!conn) if (!conn_isconnected(cp))
fatal("capiplugin: couldn't make connection"); fatal("capiplugin: couldn't make connection");
} }
static void makeconnection(STRINGLIST *numbers) static void makeconnection(STRINGLIST *numbers)
{ {
capi_connection *cp = 0;
time_t t; time_t t;
STRINGLIST *p; STRINGLIST *p;
int retry = 0; int retry = 0;
@ -1094,37 +1298,39 @@ static void makeconnection(STRINGLIST *numbers)
} while (time(0) < t); } while (time(0) < t);
} }
setupconnection(p->s, 0); cp = setupconnection(p->s, 0);
t = time(0)+opt_dialtimeout; t = time(0)+opt_dialtimeout;
do { do {
handlemessages(); handlemessages();
if (status != EXIT_OK && conn) if (status != EXIT_OK && conn_find(cp))
dodisconnect(); dodisconnect(cp);
} while (time(0) < t && conn && !isconnected); } while (time(0) < t && conn_inprogress(cp));
if (conn && isconnected) if (conn_isconnected(cp))
goto connected; goto connected;
if (status != EXIT_OK) if (status != EXIT_OK)
die(status); die(status);
} }
} while (++retry < opt_dialmax); } while (++retry < opt_dialmax);
connected: connected:
if (conn && isconnected) { if (conn_isconnected(cp)) {
t = time(0)+opt_connectdelay; t = time(0)+opt_connectdelay;
do { do {
handlemessages(); handlemessages();
} while (time(0) < t); } while (time(0) < t);
} }
if (!conn) if (!conn_isconnected(cp))
fatal("capiplugin: couldn't make connection after %d retries", fatal("capiplugin: couldn't make connection after %d retries",
retry); retry);
} }
static void makeconnection_with_callback(void) static void makeconnection_with_callback(void)
{ {
capi_connection *cp;
STRINGLIST *p; STRINGLIST *p;
time_t t; time_t t;
int retry = 0; int retry = 0;
@ -1142,7 +1348,7 @@ again:
} while (time(0) < t); } while (time(0) < t);
} }
setupconnection(p->s, 1); cp = setupconnection(p->s, 1);
/* Wait specific time for the server rejecting the call */ /* Wait specific time for the server rejecting the call */
t = time(0)+opt_dialtimeout; t = time(0)+opt_dialtimeout;
@ -1150,10 +1356,10 @@ again:
handlemessages(); handlemessages();
if (status != EXIT_OK) if (status != EXIT_OK)
die(status); die(status);
} while (time(0) < t && conn && !isconnected); } while (time(0) < t && conn_inprogress(cp));
if (conn) { if (conn_isconnected(cp)) {
dodisconnect(); dodisconnect(cp);
fatal("capiplugin: callback failed - other side answers the call (no reject)"); fatal("capiplugin: callback failed - other side answers the call (no reject)");
} else if (was_no_reject()) { } else if (was_no_reject()) {
goto again; goto again;
@ -1169,9 +1375,9 @@ again:
(void) capiconn_listen(ctx, controller, 0, 0); (void) capiconn_listen(ctx, controller, 0, 0);
die(status); die(status);
} }
} while (!isconnected && time(0) < t); } while (!conn_incoming_connected() && time(0) < t);
if (isconnected) { if (conn_incoming_connected()) {
add_fd(capi20_fileno(applid)); add_fd(capi20_fileno(applid));
setup_timeout(); setup_timeout();
return; return;
@ -1212,17 +1418,17 @@ static void waitforcall(void)
(void) capiconn_listen(ctx, controller, 0, 0); (void) capiconn_listen(ctx, controller, 0, 0);
die(status); die(status);
} }
if (connectinprogress) try=1; if (conn_incoming_inprogress()) try=1;
if (try && !connectinprogress) { if (try && !conn_incoming_inprogress()) {
try = 0; try = 0;
if (!isconnected) { if (!conn_incoming_connected()) {
(void) capiconn_listen(ctx, controller, cipmask, 0); (void) capiconn_listen(ctx, controller, cipmask, 0);
info("capiplugin: waiting for incoming call ..."); info("capiplugin: waiting for incoming call ...");
} }
} }
} while (!isconnected); } while (!conn_incoming_connected());
if (conn && isconnected) { if (conn_incoming_connected()) {
time_t t = time(0)+opt_connectdelay; time_t t = time(0)+opt_connectdelay;
do { do {
handlemessages(); handlemessages();
@ -1244,7 +1450,7 @@ static int capi_new_phase_hook(int phase)
if ((fd = capi20_fileno(applid)) >= 0) if ((fd = capi20_fileno(applid)) >= 0)
remove_fd(fd); remove_fd(fd);
unsetup_timeout(); unsetup_timeout();
dodisconnect(); disconnectall();
break; break;
case PHASE_INITIALIZE: case PHASE_INITIALIZE:
info("capiplugin: phase initialize"); info("capiplugin: phase initialize");
@ -1260,7 +1466,7 @@ static int capi_new_phase_hook(int phase)
case PHASE_SERIALCONN: case PHASE_SERIALCONN:
info("capiplugin: phase serialconn%s", info("capiplugin: phase serialconn%s",
opt_cbflag ? " (callback)" : ""); opt_cbflag ? " (callback)" : "");
if (isconnected) if (conn_isconnected(0))
break; break;
plugin_check_options(); plugin_check_options();
init_capiconn(); init_capiconn();