New version of capiconn.

This commit is contained in:
Carsten Paeth 2004-06-14 11:33:07 +00:00
parent 7f5bd829f3
commit c66178810c
3 changed files with 310 additions and 55 deletions

View File

@ -10,6 +10,9 @@
* 2 of the License, or (at your option) any later version.
*
* $Log$
* Revision 1.8 2004/01/16 15:27:13 calle
* remove several warnings.
*
* Revision 1.7 2002/05/03 11:57:49 calle
* Bugfix of Bugfix.
*
@ -34,15 +37,11 @@
* Plugin for pppd to support PPP over CAPI2.0.
*
*/
#include <stdio.h> /* snprintf */
#include <stdlib.h>
#include <string.h>
#include "capiconn.h"
static char *revision = "$Revision$";
/* xxxxxxxxxxxxxxxxxx */
static _cmsg cmdcmsg;
static _cmsg cmsg;
@ -52,6 +51,37 @@ static _cmsg cmsg;
#define CAPI_MAXDATAWINDOW 8
#endif
/* -------- util functions ------------------------------------------- */
static inline int capimsg_addu8(void *m, int off, _cbyte val)
{
((_cbyte *)m)[off] = val;
return off+1;
}
static inline int capimsg_addu16(void *m, int off, _cword val)
{
((_cbyte *)m)[off] = val & 0xff;
((_cbyte *)m)[off+1] = (val >> 8) & 0xff;
return off+2;
}
static inline int capimsg_addu32(void *m, int off, _cdword val)
{
((_cbyte *)m)[off] = val & 0xff;
((_cbyte *)m)[off+1] = (val >> 8) & 0xff;
((_cbyte *)m)[off+2] = (val >> 16) & 0xff;
((_cbyte *)m)[off+3] = (val >> 24) & 0xff;
return off+4;
}
static inline int capimsg_addcstruct(void *m, int off, _cbyte len, _cbyte *val)
{
if (len == 0 || val == 0) return capimsg_addu8(m, off, 0);
memcpy(m+off, val, len);
return off+len;
}
/* -------- type definitions ----------------------------------------- */
struct capiconn_context {
@ -105,8 +135,7 @@ struct capi_contr {
unsigned incoming:1,
disconnecting:1,
localdisconnect:1,
callednumbercomplete:1;
localdisconnect:1;
_cword disconnectreason;
_cword disconnectreason_b3;
@ -131,6 +160,7 @@ struct capi_contr {
} *ackqueue;
int ackqueuelen;
} *nccip;
void *userdata;
} *connections;
};
@ -426,15 +456,16 @@ static int set_conninfo1a(capiconn_context *ctx,
if (callednumber[0] & 0x80) {
memcpy(p->callednumber+1, callednumber, len);
p->callednumber[0] = len;
p->callednumber[len+1] = 0;
p->callednumber[len+1] = 0;
} else {
memcpy(p->callednumber+2, callednumber, len);
p->callednumber[0] = len+1;
p->callednumber[1] = 0x81;
p->callednumber[len+2] = 0;
p->callednumber[len+2] = 0;
}
} else {
p->callednumber[0] = 0;
p->callednumber[0] = 0;
p->callednumber[1] = 0;
}
if ((p->callingnumber = (*cb->malloc)(128)) == 0)
goto fail;
@ -443,10 +474,13 @@ static int set_conninfo1a(capiconn_context *ctx,
memcpy(p->callingnumber+3, callingnumber, len);
p->callingnumber[0] = len+2;
p->callingnumber[1] = 0x00;
p->callingnumber[2] = 0x80;
p->callingnumber[2] = 0x80;
p->callingnumber[len+3] = 0;
} else {
p->callingnumber[0] = 0;
p->callingnumber[0] = 2;
p->callingnumber[1] = 0x00;
p->callingnumber[2] = 0x80;
p->callingnumber[3] = 0;
}
return 0;
fail:
@ -465,21 +499,33 @@ static int set_conninfo1b(capiconn_context *ctx,
p->cipvalue = cipvalue;
if ((p->callednumber = (*cb->malloc)(128)) == 0)
if ((p->callednumber = (*cb->malloc)(128)) == 0)
goto fail;
len = callednumber[0];
memcpy(p->callednumber, callednumber, len+1);
p->callednumber[len+1] = 0;
if ((p->callingnumber = (*cb->malloc)(128)) == 0)
goto fail;
len = callingnumber[0];
memcpy(p->callingnumber, callingnumber, len+1);
p->callingnumber[len+1] = 0;
return 0;
if (callednumber && callednumber[0] >= 2) {
len = callednumber[0];
memcpy(p->callednumber, callednumber, len+1);
p->callednumber[len+1] = 0;
} else {
p->callednumber[0] = 1;
p->callednumber[1] = 0x81;
p->callednumber[2] = 0;
}
if ((p->callingnumber = (*cb->malloc)(128)) == 0)
goto fail;
if (callingnumber && callingnumber[0] >= 3) {
len = callingnumber[0];
memcpy(p->callingnumber, callingnumber, len+1);
p->callingnumber[len+1] = 0;
} else {
p->callingnumber[0] = 2;
p->callingnumber[1] = 0x00;
p->callingnumber[2] = 0x80;
p->callingnumber[3] = 0;
}
return 0;
fail:
clr_conninfo1(ctx, p);
return -1;
clr_conninfo1(ctx, p);
return -1;
}
static void extend_callednumber(capiconn_context *ctx, capi_conninfo *p,
@ -570,7 +616,7 @@ static int capi_add_ack(capi_ncci *nccip,
ncci_datahandle_queue *n, **pp;
if (nccip->ackqueuelen >= CAPI_MAXDATAWINDOW)
return 0;
return 1;
n = (ncci_datahandle_queue *)
(*cb->malloc)(sizeof(ncci_datahandle_queue));
if (!n) {
@ -603,6 +649,7 @@ static unsigned char *capi_del_ack(capi_ncci *nccip, _cword datahandle)
return data;
}
}
(*cb->errmsg)("datahandle %u not found", datahandle);
return 0;
}
@ -948,6 +995,8 @@ static void handle_controller(capiconn_context *ctx, _cmsg * cmsg)
cmsg->adr.adrController);
}
static unsigned char SendingComplete[5] = { 4, 1, 0, 0, 0 };
static void check_incoming_complete(capi_connection *plcip)
{
capi_contr *card = plcip->contr;
@ -971,12 +1020,6 @@ static void check_incoming_complete(capi_connection *plcip)
return;
}
}
if (plcip->callednumbercomplete)
return;
plcip->callednumbercomplete = 1;
if (*cb->incoming)
(*cb->incoming)(plcip,
plcip->contr->contrnr,
@ -993,7 +1036,8 @@ static void check_incoming_complete(capi_connection *plcip)
0, /* BChannelinformation */
0, /* Keypadfacility */
0, /* Useruserdata */
0 /* Facilitydataarray */
0, /* Facilitydataarray */
SendingComplete
);
plcip->msgid = cmsg.Messagenumber;
send_message(card, &cmsg);
@ -1023,8 +1067,8 @@ static void handle_incoming_call(capi_contr * card, _cmsg * cmsg)
(*cb->debugmsg)("incoming call contr=%d cip=%d %s -> %s",
card->contrnr,
cmsg->CIPValue,
plcip->conninfo.callingnumber + 3,
plcip->conninfo.callednumber + 2);
plcip->conninfo.callingnumber+2,
plcip->conninfo.callednumber+3);
if (cb->incoming == 0)
goto ignore;
@ -1120,24 +1164,17 @@ static int handle_callednumber_info(capi_connection *plcip, _cmsg *cmsg)
return 0;
}
static int handle_cause_info(capi_connection *plcip, _cmsg *cmsg)
static int handle_dtmf_info(capi_connection *plcip, _cmsg *cmsg)
{
capiconn_context *ctx = plcip->ctx;
capiconn_callbacks *cb = ctx->cb;
unsigned char *p = cmsg->InfoElement;
if (cmsg->InfoNumber == 0x0008) {
char buf[128];
char *s, *end;
int i;
s = buf; end = s + sizeof(buf)-1;
*end = 0;
for (i=0; i < p[0]; i++) {
snprintf(s, end-s, " %02x", p[i+1]);
s += strlen(s);
}
(*cb->debugmsg)("cause bytes for plci 0x%x:%s", cmsg->adr.adrPLCI, buf);
return 1;
if (cmsg->InfoNumber == 0x002c) {
if (cb->dtmf_received)
(*cb->dtmf_received)(plcip,
cmsg->InfoElement+1,
cmsg->InfoElement[0]);
return 1;
}
return 0;
}
@ -1262,7 +1299,7 @@ static void handle_plci(capiconn_context *ctx, _cmsg * cmsg)
} else if (handle_callednumber_info(plcip, cmsg)) {
capi_cmsg_answer(cmsg);
send_message(card, cmsg);
} else if (handle_cause_info(plcip, cmsg)) {
} else if (handle_dtmf_info(plcip, cmsg)) {
capi_cmsg_answer(cmsg);
send_message(card, cmsg);
} else {
@ -1276,6 +1313,16 @@ static void handle_plci(capiconn_context *ctx, _cmsg * cmsg)
case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
goto ignored;
case CAPI_FACILITY_IND: /* Controller/plci/ncci */
if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
goto notfound;
if (cmsg->FacilitySelector == 1) { /* DTMF */
(*cb->dtmf_received)(plcip,
cmsg->FacilityIndicationParameter+1,
cmsg->FacilityIndicationParameter[0]);
capi_cmsg_answer(cmsg);
send_message(card, cmsg);
break;
}
goto ignored;
case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
goto ignored;
@ -1448,8 +1495,40 @@ static void handle_ncci(capiconn_context *ctx, _cmsg * cmsg)
case CAPI_FACILITY_IND: /* Controller/plci/ncci */
goto ignored;
case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
goto ignored;
if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
goto notfound;
if (cmsg->Info) {
(*cb->infomsg)("%s info 0x%x (%s) for ncci 0x%x",
capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->Info, capi_info2str(cmsg->Info),
cmsg->adr.adrNCCI);
} else if ( cmsg->FacilitySelector == 1
&& cmsg->FacilityConfirmationParameter[0] > 0
&& cmsg->FacilityConfirmationParameter[1]) {
switch (cmsg->FacilityConfirmationParameter[1]) {
case 0:
break;
case 1:
(*cb->infomsg)("%s incorrect DTMF digit for ncci 0x%x",
capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->adr.adrNCCI);
break;
case 2:
(*cb->infomsg)("%s Unknown DTMF request for ncci 0x%x",
capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->adr.adrNCCI);
break;
default:
(*cb->infomsg)("%s DTMF errcode %d for ncci 0x%x",
capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->FacilityConfirmationParameter[1],
cmsg->adr.adrNCCI);
break;
}
}
break;
default:
(*cb->errmsg)("capidrv-%d: got %s for ncci 0x%x ???",
@ -1771,6 +1850,53 @@ int capiconn_disconnect(capi_connection *plcip, _cstruct ncpi)
static _cmsg sendcmsg;
// #define TX_STATS
#ifdef TX_STATS
static FILE *dump_open(void)
{
struct stat sb;
if (0 == stat("/var/tmp/voipd.txt", &sb)
&& sb.st_size > 60000) {
unlink("/var/tmp/voipd.txt");
}
FILE *fp = fopen("/var/tmp/voipd.txt", "a");
return fp;
}
static void ncci_dump(capi_ncci *nccip, char *header)
{
FILE *fp = dump_open();
if (fp) {
time_t t = time(0);
fprintf(fp, "\n%02u:%02u:%02u %s\n", t / (60*60), (t / 60) % 60, t % 60, header);
// txstat_dump(&nccip->txstats, fp);
// fprintf(fp, "Tx Packet Time Distribution:\n");
// timedist_dump(&nccip->txpackettdist, fp);
// fprintf(fp, "Tx DATA B3 CONF Time Distribution:\n");
// timedist_dump(&nccip->txconftdist, fp);
// fprintf(fp, "Tx Underrun Time Distribution:\n");
// timedist_dump(&nccip->txUnderruntdist, fp);
rtp_stats_display_fp(ortp_get_global_stats(), "RTP Global", fp);
// fprintf(fp, "*** Mediastraemer Fifos:\n");
// ms_fifo_dump(fp);
fclose(fp);
}
}
#endif
int capiconn_send(capi_connection *plcip,
unsigned char *data,
unsigned len)
@ -1786,6 +1912,25 @@ int capiconn_send(capi_connection *plcip,
if (!nccip || nccip->state != ST_NCCI_ACTIVE)
return CAPICONN_WRONG_STATE;
#ifdef TX_STATS
{
struct timeval tv;
struct timezone tz;
unsigned tstamp;
static unsigned next_dump_tstamp = 0;
tstamp = gettimeofday(&tv, &tz);
tstamp = tv.tv_sec * 1000 + (tv.tv_usec/1000);
// timedist_event(&nccip->txpackettdist, tstamp);
if (tstamp >= next_dump_tstamp) {
next_dump_tstamp = tstamp + 120*1000;
ncci_dump(nccip, "ncci periodic");
}
}
#endif // TX_STATS
datahandle = nccip->datahandle;
capi_fill_DATA_B3_REQ(&sendcmsg, ctx->appid, card->msgid++,
nccip->ncci, /* adr */
@ -1795,16 +1940,91 @@ int capiconn_send(capi_connection *plcip,
0 /* Flags */
);
if (capi_add_ack(nccip, datahandle, data) < 0)
if (capi_add_ack(nccip, datahandle, data) != 0)
return CAPICONN_NOT_SENT;
capi_cmsg2message(&sendcmsg, sendcmsg.buf);
(*cb->capi_put_message) (ctx->appid, sendcmsg.buf);
if((*cb->capi_put_message) (ctx->appid, sendcmsg.buf) < 0) {
capi_del_ack(nccip, datahandle);
return CAPICONN_NOT_SENT;
}
nccip->datahandle++;
ctx->nsentdatapkt++;
return CAPICONN_OK;
}
int capiconn_dtmf_setstate(capi_connection *plcip, int on)
{
_cbyte fparam[32];
int off;
capi_contr *card = plcip->contr;
capiconn_context *ctx = card->ctx;
capiconn_callbacks *cb = ctx->cb;
capi_ncci *nccip;
nccip = plcip->nccip;
if (!nccip || nccip->state != ST_NCCI_ACTIVE)
return CAPICONN_WRONG_STATE;
if (cb->dtmf_received == 0)
return CAPICONN_NOT_SUPPORTED;
capi_cmsg_header(&sendcmsg, ctx->appid,
CAPI_FACILITY, CAPI_REQ, card->msgid++, nccip->ncci);
sendcmsg.FacilitySelector = 1;
off = 1;
off = capimsg_addu16(fparam, off, on ? 1 : 2); /* Function */
off = capimsg_addu16(fparam, off, 40); /* Tone-duration */
off = capimsg_addu16(fparam, off, 40); /* Gap-dureation */
off = capimsg_addcstruct(fparam, off, 0, 0); /* DTMF-digits */
off = capimsg_addcstruct(fparam, off, 0, 0); /* DTMF-characteristics */
fparam[0] = off;
sendcmsg.FacilityRequestParameter = fparam;
capi_cmsg2message(&sendcmsg, sendcmsg.buf);
(*cb->capi_put_message) (ctx->appid, sendcmsg.buf);
return CAPICONN_OK;
}
int capiconn_dtmf_send(capi_connection *plcip, char *digits)
{
_cbyte fparam[256];
int off;
capi_contr *card = plcip->contr;
capiconn_context *ctx = card->ctx;
capiconn_callbacks *cb = ctx->cb;
capi_ncci *nccip;
nccip = plcip->nccip;
if (!nccip || nccip->state != ST_NCCI_ACTIVE)
return CAPICONN_WRONG_STATE;
capi_cmsg_header(&sendcmsg, ctx->appid,
CAPI_FACILITY, CAPI_REQ, card->msgid++, nccip->ncci);
sendcmsg.FacilitySelector = 1;
off = 1;
off = capimsg_addu16(fparam, off, 4); /* Function */
off = capimsg_addu16(fparam, off, 40); /* Tone-duration */
off = capimsg_addu16(fparam, off, 40); /* Gap-dureation */
off = capimsg_addcstruct(fparam, off, strlen(digits), digits);
off = capimsg_addcstruct(fparam, off, 0, 0); /* DTMF-characteristics */
fparam[0] = off;
sendcmsg.FacilityRequestParameter = fparam;
capi_cmsg2message(&sendcmsg, sendcmsg.buf);
(*cb->capi_put_message) (ctx->appid, sendcmsg.buf);
return CAPICONN_OK;
}
void capiconn_set_userdata(capi_connection *plcip, void *userdata)
{
plcip->userdata = userdata;
}
void *capiconn_get_userdata(capi_connection *plcip)
{
return plcip->userdata;
}
/* -------- listen handling ------------------------------------------ */
@ -1813,7 +2033,6 @@ static void send_listen(capi_contr *card)
capiconn_context *ctx = card->ctx;
card->infomask = 0;
card->infomask |= (1<<0); /* cause information */
card->infomask |= (1<<2); /* Display */
card->infomask |= (1<<6); /* Charge Info */
if (card->ddilen) card->infomask |= (1<<7); /* Called Party Number */

View File

@ -10,6 +10,11 @@
* 2 of the License, or (at your option) any later version.
*
* $Log$
* Revision 1.3 2001/01/25 14:45:41 calle
* - listen always (for info messages)
* - show versions on startup
* - wait for capifs if needed
*
* Revision 1.2 2000/10/25 10:01:47 calle
* (c) in all files
*
@ -17,7 +22,6 @@
* Plugin for pppd to support PPP over CAPI2.0.
*
*/
#ifndef __CAPICONN_H__
#define __CAPICONN_H__
@ -60,6 +64,7 @@
#define CAPICONN_OK 0
#define CAPICONN_NO_CONTROLLER -1
#define CAPICONN_NO_MEMORY -2
#define CAPICONN_NOT_SUPPORTED -3
#define CAPICONN_WRONG_STATE 1
#define CAPICONN_NOT_SENT 2
#define CAPICONN_ALREADY_DISCONNECTING 3
@ -253,10 +258,18 @@ struct capiconn_callbacks
void (*chargeinfo)(capi_connection *,
unsigned long charge,
int inunits);
/*
* DTMF received
*/
void (*dtmf_received)(capi_connection *,
unsigned char *data,
unsigned datalen);
/*
* capi functions
*/
void (*capi_put_message) (unsigned appid, unsigned char *msg);
int (*capi_put_message) (unsigned appid, unsigned char *msg);
/*
* message functions
@ -409,6 +422,12 @@ typedef struct capi_conninfo capi_conninfo;
*/
capi_conninfo *capiconn_getinfo(capi_connection *p);
/*
* userdata per connection
*/
void capiconn_set_userdata(capi_connection *plcip, void *userdata);
void *capiconn_get_userdata(capi_connection *plcip);
/*
* returncodes:
* CAPICONN_OK - Listen request sent
@ -427,4 +446,20 @@ int capiconn_listen(capiconn_context *ctx,
*/
int capiconn_listenstate(capiconn_context *ctx, unsigned contr);
/*
* returncode:
* CAPICONN_OK - request sent to CAPI
* CAPICONN_NOT_SUPPORTED - DTMF not supported
* CAPICONN_WRONG_STATE - Connection is not connected
*/
int capiconn_dtmf_setstate(capi_connection *, int on);
/*
* returncode:
* CAPICONN_OK - request sent to CAPI
* CAPICONN_NOT_SUPPORTED - DTMF not supported
* CAPICONN_WRONG_STATE - Connection is not connected
*/
int capiconn_dtmf_send(capi_connection *, char *digits);
#endif /* __CAPICONN_H__ */

View File

@ -1475,6 +1475,7 @@ capiconn_callbacks callbacks = {
received: 0,
datasent: 0,
chargeinfo: chargeinfo,
dtmf_received: 0,
capi_put_message: put_message,