From 47b9b750f15edd88cc81bd2dc30d61bae8df0b0e Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Sat, 28 Apr 2007 16:48:00 +0000 Subject: [PATCH] - added basic null-plci handling for chat. - moved more CAPI requests for sendf use. --- chan_capi.c | 48 ++++++++------- chan_capi.h | 15 ++++- chan_capi_chat.c | 44 ++++++++++---- chan_capi_rtp.c | 26 ++++---- chan_capi_utils.c | 150 +++++++++++++++++++++++++++++++++++++++------- chan_capi_utils.h | 4 +- 6 files changed, 213 insertions(+), 74 deletions(-) diff --git a/chan_capi.c b/chan_capi.c index 8271e50..e77b992 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -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); + } } } diff --git a/chan_capi.h b/chan_capi.h index e38b5ac..c8ecbae 100644 --- a/chan_capi.h +++ b/chan_capi.h @@ -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 diff --git a/chan_capi_chat.c b/chan_capi_chat.c index 7d860a8..cf7770e 100644 --- a/chan_capi_chat.c +++ b/chan_capi_chat.c @@ -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(¶m, "|"); + controller = strsep(¶m, "|"); 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; } diff --git a/chan_capi_rtp.c b/chan_capi_rtp.c index 58543c2..e36112c 100644 --- a/chan_capi_rtp.c +++ b/chan_capi_rtp.c @@ -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; diff --git a/chan_capi_utils.c b/chan_capi_utils.c index 2d1f2ae..77a50e2 100644 --- a/chan_capi_utils.c +++ b/chan_capi_utils.c @@ -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; diff --git a/chan_capi_utils.h b/chan_capi_utils.h index eb3ec5f..9210d47 100644 --- a/chan_capi_utils.h +++ b/chan_capi_utils.h @@ -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))