- added basic null-plci handling for chat.

- moved more CAPI requests for sendf use.
This commit is contained in:
MelwareDE 2007-04-28 16:48:00 +00:00
parent 0c80e2361f
commit 47b9b750f1
6 changed files with 213 additions and 74 deletions

View File

@ -275,9 +275,10 @@ static const char * capi_command_to_string(unsigned short wCmd)
/*
* wait for B3 up
*/
void capi_wait_for_b3_up(struct capi_pvt *i)
int capi_wait_for_b3_up(struct capi_pvt *i)
{
struct timespec abstime;
int ret = 0;
cc_mutex_lock(&i->lock);
if (!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) {
@ -292,9 +293,12 @@ void capi_wait_for_b3_up(struct capi_pvt *i)
} else {
cc_verbose(4, 1, "%s: cond signal received for b3 up.\n",
i->vname);
ret = 1;
}
}
cc_mutex_unlock(&i->lock);
return ret;
}
/*
@ -456,16 +460,6 @@ static void capi_channel_task(struct ast_channel *c, int task)
* Echo cancellation is for cards w/ integrated echo cancellation only
* (i.e. Eicon active cards support it)
*/
#define EC_FUNCTION_ENABLE 1
#define EC_FUNCTION_DISABLE 2
#define EC_FUNCTION_FREEZE 3
#define EC_FUNCTION_RESUME 4
#define EC_FUNCTION_RESET 5
#define EC_OPTION_DISABLE_NEVER 0
#define EC_OPTION_DISABLE_G165 (1<<2)
#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2)
#define EC_DEFAULT_TAIL 0 /* maximum */
static void capi_echo_canceller(struct ast_channel *c, int function)
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
@ -801,6 +795,10 @@ static void interface_cleanup(struct capi_pvt *i)
i->writerfd = -1;
}
if (capi_remove_nullif(i)) {
return;
}
i->isdnstate = 0;
i->cause = 0;
@ -946,20 +944,22 @@ static void capi_send_disconnect(unsigned int PLCI, struct capi_pvt *i)
* hangup a line (CAPI messages)
* (this must be called with i->lock held)
*/
static void capi_activehangup(struct ast_channel *c, int state)
void capi_activehangup(struct capi_pvt *i, int state)
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
struct ast_channel *c = i->owner;
_cmsg CMSG;
const char *cause;
i->cause = c->hangupcause;
if ((cause = pbx_builtin_getvar_helper(c, "PRI_CAUSE"))) {
i->cause = atoi(cause);
}
if (c) {
i->cause = c->hangupcause;
if ((cause = pbx_builtin_getvar_helper(c, "PRI_CAUSE"))) {
i->cause = atoi(cause);
}
if ((i->isdnstate & CAPI_ISDN_STATE_ECT)) {
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: activehangup ECT call\n",
i->vname);
if ((i->isdnstate & CAPI_ISDN_STATE_ECT)) {
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: activehangup ECT call\n",
i->vname);
}
}
cc_verbose(2, 1, VERBOSE_PREFIX_3 "%s: activehangingup (cause=%d) for PLCI=%#x\n",
@ -1045,7 +1045,7 @@ static int pbx_capi_hangup(struct ast_channel *c)
interface_cleanup(i);
} else {
/* not disconnected yet, we must actively do it */
capi_activehangup(c, state);
capi_activehangup(i, state);
}
i->owner = NULL;
@ -3766,7 +3766,7 @@ void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI,
}
*i = find_interface_by_msgnum(wMsgNum);
ii = *i;
if ((ii == NULL) || (!ii->owner)) {
if (ii == NULL) {
return;
}
cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: received CONNECT_CONF PLCI = %#x\n",
@ -3777,7 +3777,9 @@ void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI,
} else {
/* error in connect, so set correct state and signal busy */
ii->state = CAPI_STATE_DISCONNECTED;
local_queue_frame(ii, &fr);
if (ii->owner) {
local_queue_frame(ii, &fr);
}
}
}

View File

@ -175,6 +175,16 @@ typedef struct fax3proto3 B3_PROTO_FAXG3;
#define FACILITYSELECTOR_FAX_OVER_IP 0x00fd
#define FACILITYSELECTOR_VOICE_OVER_IP 0x00fe
#define EC_FUNCTION_ENABLE 1
#define EC_FUNCTION_DISABLE 2
#define EC_FUNCTION_FREEZE 3
#define EC_FUNCTION_RESUME 4
#define EC_FUNCTION_RESET 5
#define EC_OPTION_DISABLE_NEVER 0
#define EC_OPTION_DISABLE_G165 (1<<2)
#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2)
#define EC_DEFAULT_TAIL 0 /* maximum */
#define CC_HOLDTYPE_LOCAL 0
#define CC_HOLDTYPE_HOLD 1
#define CC_HOLDTYPE_NOTIFY 2
@ -243,7 +253,7 @@ struct cc_capi_gains {
#define CAPI_CHANNELTYPE_B 0
#define CAPI_CHANNELTYPE_D 1
#define CAPI_CHANNELTYPE_NONE 2
#define CAPI_CHANNELTYPE_NULL 2
/* the lower word is reserved for capi commands */
#define CAPI_WAITEVENT_B3_UP 0x00010000
@ -570,6 +580,7 @@ extern void queue_cause_control(struct capi_pvt *i, int control);
extern void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI,
unsigned short wInfo, unsigned short wMsgNum);
extern void capi_wait_for_answered(struct capi_pvt *i);
extern void capi_wait_for_b3_up(struct capi_pvt *i);
extern int capi_wait_for_b3_up(struct capi_pvt *i);
extern void capi_activehangup(struct capi_pvt *i, int state);
#endif

View File

@ -187,16 +187,14 @@ static struct capichat_s *add_chat_member(char *roomname,
int pbx_capi_chat(struct ast_channel *c, char *param)
{
struct capi_pvt *i = NULL;
char *roomname, *options;
char *roomname, *controller, *options;
struct capichat_s *room;
struct ast_frame *f;
if (c->tech == &capi_tech) {
i = CC_CHANNEL_PVT(c);
} else
return -1;
int state;
unsigned int contr = 1;
roomname = strsep(&param, "|");
controller = strsep(&param, "|");
options = param;
if (!roomname) {
@ -204,15 +202,30 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
return -1;
}
cc_verbose(3, 1, VERBOSE_PREFIX_3 "capi chat: %s: roomname=%s options=%s\n",
c->name, roomname, options);
cc_verbose(3, 1, VERBOSE_PREFIX_3 "capi chat: %s: roomname=%s "
"controller=%s options=%s\n",
c->name, roomname, controller, options);
if (controller) {
contr = (unsigned int)strtoul(controller, NULL, 0);
}
if (c->tech == &capi_tech) {
i = CC_CHANNEL_PVT(c);
} else {
/* virtual CAPI channel */
i = mknullif(contr);
if (!i) {
return -1;
}
}
if (c->_state != AST_STATE_UP)
ast_answer(c);
if (i) {
capi_wait_for_answered(i);
capi_wait_for_b3_up(i);
capi_wait_for_answered(i);
if (!(capi_wait_for_b3_up(i))) {
goto out;
}
room = add_chat_member(roomname, c, i);
@ -233,6 +246,15 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
del_chat_member(room);
out:
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
cc_mutex_lock(&i->lock);
state = i->state;
i->state = CAPI_STATE_DISCONNECTING;
capi_activehangup(i, state);
cc_mutex_unlock(&i->lock);
}
return 0;
}

View File

@ -191,7 +191,6 @@ int capi_alloc_rtp(struct capi_pvt *i)
int capi_write_rtp(struct ast_channel *c, struct ast_frame *f)
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
_cmsg CMSG;
struct sockaddr_in us;
int len;
socklen_t uslen;
@ -244,14 +243,13 @@ int capi_write_rtp(struct ast_channel *c, struct ast_frame *f)
i->vname, i->NCCI, len, f->datalen, ast_getformatname(f->subclass),
i->timestamp);
DATA_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
DATA_B3_REQ_NCCI(&CMSG) = i->NCCI;
DATA_B3_REQ_FLAGS(&CMSG) = 0;
DATA_B3_REQ_DATAHANDLE(&CMSG) = i->send_buffer_handle;
DATA_B3_REQ_DATALENGTH(&CMSG) = len;
DATA_B3_REQ_DATA(&CMSG) = (buf);
_capi_put_cmsg(&CMSG);
capi_sendf (NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(),
"dwww",
buf,
len,
i->send_buffer_handle,
0
);
}
return 0;
@ -315,11 +313,11 @@ void voice_over_ip_profile(struct cc_capi_controller *cp)
unsigned short info = 0;
unsigned int payload1, payload2;
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
FACILITY_REQ_CONTROLLER(&CMSG) = cp->controller;
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_VOICE_OVER_IP;
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac;
_capi_put_cmsg(&CMSG);
capi_sendf (NULL, 0, CAPI_FACILITY_REQ, cp->controller, get_capi_MessageNumber(),
"ws",
FACILITYSELECTOR_VOICE_OVER_IP,
&fac
);
tv.tv_sec = 1;
tv.tv_usec = 0;

View File

@ -27,9 +27,12 @@ AST_MUTEX_DEFINE_STATIC(verbose_lock);
AST_MUTEX_DEFINE_STATIC(messagenumber_lock);
AST_MUTEX_DEFINE_STATIC(capi_put_lock);
AST_MUTEX_DEFINE_STATIC(peerlink_lock);
AST_MUTEX_DEFINE_STATIC(nullif_lock);
static _cword capi_MessageNumber;
static struct capi_pvt *nulliflist = NULL;
#define CAPI_MAX_PEERLINKCHANNELS 32
static struct peerlink_s {
struct ast_channel *channel;
@ -57,6 +60,86 @@ void cc_verbose(int o_v, int c_d, char *text, ...)
}
}
/*
* hangup and remove null-interface
*/
int capi_remove_nullif(struct capi_pvt *i)
{
struct capi_pvt *ii;
struct capi_pvt *tmp = NULL;
if (i->channeltype != CAPI_CHANNELTYPE_NULL) {
return 0;
}
cc_mutex_lock(&nullif_lock);
ii = nulliflist;
while (ii) {
if (ii == i) {
if (!tmp) {
nulliflist = ii->next;
} else {
tmp->next = ii->next;
}
free(i);
break;
}
tmp = ii;
ii = ii->next;
}
cc_mutex_unlock(&nullif_lock);
return 1;
}
/*
* create new null-interface
*/
struct capi_pvt *mknullif(unsigned int controller)
{
struct capi_pvt *tmp;
tmp = malloc(sizeof(struct capi_pvt));
if (!tmp) {
return NULL;
}
memset(tmp, 0, sizeof(struct capi_pvt));
tmp->readerfd = -1;
tmp->writerfd = -1;
cc_mutex_init(&tmp->lock);
ast_cond_init(&tmp->event_trigger, NULL);
snprintf(tmp->name, sizeof(tmp->name) - 1, "CAPI-NULL-PLCI");
snprintf(tmp->vname, sizeof(tmp->vname) - 1, "%s", tmp->name);
tmp->channeltype = CAPI_CHANNELTYPE_NULL;
tmp->controller = controller;
tmp->doEC = 1;
tmp->doEC_global = 1;
tmp->ecOption = EC_OPTION_DISABLE_NEVER;
tmp->ecTail = EC_DEFAULT_TAIL;
tmp->isdnmode = CAPI_ISDNMODE_MSN;
tmp->ecSelector = FACILITYSELECTOR_ECHO_CANCEL;
cc_mutex_lock(&nullif_lock);
tmp->next = nulliflist; /* prepend */
nulliflist = tmp;
cc_mutex_unlock(&nullif_lock);
tmp->outgoing = 1;
tmp->state = CAPI_STATE_CONNECTPENDING;
tmp->MessageNumber = get_capi_MessageNumber();
capi_sendf (NULL, 0, CAPI_CONNECT_REQ, controller, tmp->MessageNumber,
"w()()()()(www()()()())()()()((wwbbb)()()())",
0, 1,1,0, 3,0,0,0,0);
return tmp;
}
/*
* get a new capi message number automically
*/
@ -90,9 +173,16 @@ struct capi_pvt *find_interface_by_plci(unsigned int plci)
return NULL;
for (i = iflist; i; i = i->next) {
if (i->PLCI == plci)
return i;
}
cc_mutex_lock(&nullif_lock);
for (i = nulliflist; i; i = i->next) {
if (i->PLCI == plci)
break;
}
cc_mutex_unlock(&nullif_lock);
return i;
}
@ -108,9 +198,16 @@ struct capi_pvt *find_interface_by_msgnum(unsigned short msgnum)
return NULL;
for (i = iflist; i; i = i->next) {
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
return i;
}
cc_mutex_lock(&nullif_lock);
for (i = nulliflist; i; i = i->next) {
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
break;
}
cc_mutex_unlock(&nullif_lock);
return i;
}
@ -143,24 +240,30 @@ MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd)
}
/*
* log verbose a capi message
* log an error in sending capi message
*/
static void log_capi_message(MESSAGE_EXCHANGE_ERROR err, _cmsg *CMSG)
static void log_capi_error_message(MESSAGE_EXCHANGE_ERROR err, _cmsg *CMSG)
{
unsigned short wCmd;
if (err) {
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
err, capi_info_string((unsigned int)err));
}
}
/*
* log verbose a capi message
*/
static void log_capi_message(_cmsg *CMSG)
{
unsigned short wCmd;
wCmd = HEADER_CMD(CMSG);
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
(wCmd == CAPI_P_RESP(DATA_B3))) {
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
} else {
wCmd = HEADER_CMD(CMSG);
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
(wCmd == CAPI_P_RESP(DATA_B3))) {
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
} else {
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
}
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
}
}
@ -177,13 +280,14 @@ MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG)
}
error = capi_put_cmsg(CMSG);
log_capi_message(CMSG);
if (cc_mutex_unlock(&capi_put_lock)) {
cc_log(LOG_WARNING, "Unable to unlock capi put!\n");
return -1;
}
log_capi_message(error, CMSG);
log_capi_error_message(error, CMSG);
return error;
}
@ -202,6 +306,7 @@ MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
}
capi_message2cmsg(&CMSG, msg);
log_capi_message(&CMSG);
error = capi20_put_message(capi_ApplID, msg);
@ -210,7 +315,7 @@ MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
return -1;
}
log_capi_message(error, &CMSG);
log_capi_error_message(error, &CMSG);
return error;
}
@ -744,19 +849,18 @@ void show_capi_info(struct capi_pvt *i, _cword info)
/*
* send Listen to specified controller
*/
unsigned ListenOnController(unsigned long CIPmask, unsigned controller)
unsigned ListenOnController(unsigned int CIPmask, unsigned controller)
{
MESSAGE_EXCHANGE_ERROR error;
_cmsg CMSG;
int waitcount = 50;
_cmsg CMSG;
LISTEN_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), controller);
LISTEN_REQ_INFOMASK(&CMSG) = 0xffff; /* lots of info ;) + early B3 connect */
/* 0x00ff if no early B3 should be done */
LISTEN_REQ_CIPMASK(&CMSG) = CIPmask;
error = _capi_put_cmsg(&CMSG);
error = capi_sendf (NULL, 0, CAPI_LISTEN_REQ, controller, get_capi_MessageNumber(),
"ddd()()",
0x0000ffff,
CIPmask,
0
);
if (error)
goto done;

View File

@ -30,11 +30,13 @@ extern MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG);
extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg_wait_conf(struct capi_pvt *i, _cmsg *CMSG);
extern char *capi_info_string(unsigned int info);
extern void show_capi_info(struct capi_pvt *i, _cword info);
extern unsigned ListenOnController(unsigned long CIPmask, unsigned controller);
extern unsigned ListenOnController(unsigned int CIPmask, unsigned controller);
extern void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid);
extern char *capi_number_func(unsigned char *data, unsigned int strip, char *buf);
extern int cc_add_peer_link_id(struct ast_channel *c);
extern struct ast_channel *cc_get_peer_link_id(const char *p);
extern int capi_remove_nullif(struct capi_pvt *i);
extern struct capi_pvt *mknullif(unsigned int controller);
#define capi_number(data, strip) \
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))