From d70150d0470f76ea769da623ac8f50e828609b61 Mon Sep 17 00:00:00 2001 From: Super User Date: Mon, 28 Apr 2008 19:29:06 +0200 Subject: [PATCH] work on chan_lcr: call instance and asterisk channel instance creation and destruction process please read the comments on the top of chan_lcr. modified: apppbx.cpp modified: chan_lcr.c modified: chan_lcr.h modified: message.h --- apppbx.cpp | 1 + chan_lcr.c | 393 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- chan_lcr.h | 61 +++++++++- message.h | 2 +- 4 files changed, 423 insertions(+), 34 deletions(-) diff --git a/apppbx.cpp b/apppbx.cpp index a0a14d0..691a519 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -3437,6 +3437,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un join_mISDNsignal(portlist, message_type, param); break; +was ist hiermit #if 0 /* JOIN requests bchannel */ case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */ diff --git a/chan_lcr.c b/chan_lcr.c index e31882a..382025b 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -11,23 +11,80 @@ /* -How does it work: +Registering to LCR: -To connect, open a socket and send a MESSAGE_HELLO to admin socket with +To connect, open an LCR socket and send a MESSAGE_HELLO to socket with the application name. This name is unique an can be used for routing calls. +Now the channel driver is linked to LCR and can receive and make calls. -To make a call, send a MESSAGE_NEWREF and a new reference is received. -When receiving a call, a new reference is received. -The reference is received with MESSAGE_NEWREF. -Make a MESSAGE_SETUP or receive a MESSAGE_SETUP with the reference. +Call is initiated by LCR: -To release call and reference, send or receive MESSAGE_RELEASE. -From that point on, the ref is not valid, so no other message may be sent -with that reference. +If a call is received from LCR, a MESSAGE_NEWREF is received first. +A new chan_call instance is created. The call reference (ref) is given by +MESSAGE_NEWREF. The state is CHAN_LCR_STATE_IN_PREPARE. +After receiving MESSAGE_SETUP from LCR, the ast_channel instance is created +using ast_channel_alloc(1). The setup information is given to asterisk. +The new Asterisk instance pointer (ast) is stored to chan_call structure. +The state changes to CHAN_LCR_STATE_IN_SETUP. + + +Call is initiated by Asterisk: + +If a call is reveiced from Asterisk, a new chan_call instance is created. +The new Asterisk instance pointer (ast) is stored to chan_call structure. +A MESSASGE_NEWREF is sent to LCR requesting a new call reference (ref). +The current call ref is set to 0, the state is CHAN_LCR_STATE_OUT_PREPARE. +Further dialing information is queued. +After the new callref is received by special MESSAGE_NEWREF reply, new ref +is stored in the chan_call structure. +The setup information is sent to LCR using MESSAGE_SETUP. +The state changes to CHAN_LCR_STATE_OUT_SETUP. + + +Call is in process: + +During call process, messages are received and sent. +The state changes accordingly. +Any message is allowed to be sent to LCR at any time except MESSAGE_RELEASE. +If a MESSAGE_OVERLAP is received, further dialing is required. +Queued dialing information, if any, is sent to LCR using MESSAGE_DIALING. +In this case, the state changes to CHAN_LCR_STATE_OUT_DIALING. + + +Call is released by LCR: + +A MESSAGE_RELEASE is received with the call reference (ref) to be released. +The current ref is set to 0, to indicate released reference. +The state changes to CHAN_LCR_STATE_RELEASE. +ast_queue_hangup() is called, if asterisk instance (ast) exists, if not, +the chan_call instance is destroyed. +After lcr_hangup() is called-back by Asterisk, the chan_call instance +is destroyed, because the current ref is set to 0 and the state equals +CHAN_LCR_STATE_RELEASE. +If the ref is 0 and the state is not CHAN_LCR_STATE_RELEASE, see the proceedure +"Call is released by Asterisk". + + +Call is released by Asterisk: + +lcr_hangup() is called-back by Asterisk. If the call reference (ref) is set, +a MESSAGE_RELEASE is sent to LCR and the chan_call instance is destroyed. +If the ref is 0 and the state is not CHAN_LCR_STATE_RELEASE, the new state is +set to CHAN_LCR_STATE_RELEASE. +Later, if the MESSAGE_NEWREF reply is received, a MESSAGE_RELEASE is sent to +LCR and the chan_call instance is destroyed. +If the ref is 0 and the state is CHAN_LCR_STATE_RELEASE, see the proceedure +"Call is released by LCR". */ +locking asterisk process and handler +reconnect after socket closed, release all calls. +debug of call handling +denke an alle info-elements in jeder message (from asterisk & from lcr) + + #include #include #include @@ -73,6 +130,8 @@ with that reference. #include #include +CHAN_LCR_STATE // state description structure + int lcr_debug=1; int mISDN_created=1; @@ -123,6 +182,8 @@ struct chan_call *alloc_call(void) callp = &((*callp)->next); *callp = (struct chan_call *)malloc(sizeof(struct chan_call)); + if (*callp) + memset(*callp, 0, sizeof(struct chan_call)); return(*callp); } @@ -197,6 +258,145 @@ int send_message(int message_type, unsigned long ref, union parameter *param) } /* + * incoming setup from LCR + */ +static void lcr_in_setup(struct chan_call *call, int message_type, union parameter *param) +{ + struct ast_channel *ast; + union parameter newparam; + + /* create asterisk channel instrance */ + ast = ast_channel_alloc(1); + if (!ast) + { + /* release */ + memset(&newparam, 0, sizeof(union parameter)); + newparam.disconnectinfo.cause = CAUSE_RESSOURCEUNAVAIL; + newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + send_message(MESSAGE_RELEASE, call->ref, &newparam); + /* remove call */ + free_call(call); + return; + } + /* set ast pointer */ + call->ast = ast; + + /* fill setup information */ +#warning todo: setup-info reinschreiben + + /* send setup to asterisk */ +#warning todo: setup bei der asterisk triggern + + /* change state */ + call->state = CHAN_LCR_STATE_IN_SETUP; +} + +/* + * incoming setup acknowledge from LCR + */ +static void lcr_in_overlap(struct chan_call *call, int message_type, union parameter *param) +{ + /* send pending digits in dialque */ + if (call->dialque) + send_dialing_to_lcr(call); + /* change to overlap state */ + call->state = CHAN_LCR_STATE_OUT_DIALING; +} + +/* + * incoming proceeding from LCR + */ +static void lcr_in_proceeding(struct chan_call *call, int message_type, union parameter *param) +{ + /* change state */ + call->state = CHAN_LCR_STATE_OUT_PROCEEDING; + /* send event to asterisk */ + ast_queue_... todo +} + +/* + * incoming alerting from LCR + */ +static void lcr_in_alerting(struct chan_call *call, int message_type, union parameter *param) +{ + /* change state */ + call->state = CHAN_LCR_STATE_OUT_ALERTING; + /* send event to asterisk */ + ast_queue_... todo +} + +/* + * incoming connect from LCR + */ +static void lcr_in_connect(struct chan_call *call, int message_type, union parameter *param) +{ + /* change state */ + call->state = CHAN_LCR_STATE_CONNECT; + /* copy connectinfo */ + todo + /* send event to asterisk */ + ast_queue_... todo +} + +/* + * incoming disconnect from LCR + */ +static void lcr_in_disconnect(struct chan_call *call, int message_type, union parameter *param) +{ + /* change state */ + call->state = CHAN_LCR_STATE_IN_DISCONNECT; + /* copy disconnect info */ + todo + /* send event to asterisk */ + ast_queue_... todo +} + +/* + * incoming setup acknowledge from LCR + */ +static void lcr_in_release(struct chan_call *call, int message_type, union parameter *param) +{ + /* release ref */ + call->ref = NULL; + /* change to release state */ + call->state = CHAN_LCR_STATE_RELEASE; + /* copy release info */ + todo + /* if we have an asterisk instance, send hangup, else we are done */ + if (call->ast) + { + ast_queue_hangup(call->ast); + } else + { + free_call(call); + } + +} + +/* + * incoming information from LCR + */ +static void lcr_in_information(struct chan_call *call, int message_type, union parameter *param) +{ + /* copy digits */ + todo and write them, maybe queue them for asterisk + /* send event to asterisk */ + ast_queue_... todo +} + +/* + * incoming information from LCR + */ +static void lcr_in_facility(struct chan_call *call, int message_type, union parameter *param) +{ + /* copy progress info */ + todo and write them, maybe queue them for asterisk + /* send event to asterisk */ + ast_queue_... todo + or maybe use bride info to forward facility. +} + +/* * message received from LCR */ int receive_message(int message_type, unsigned long ref, union parameter *param) @@ -298,8 +498,13 @@ int receive_message(int message_type, unsigned long ref, union parameter *param) fprintf(stderr, "illegal new ref %d received\n", ref); return(-1); } + /* allocate new call instance */ call = alloc_call(); + /* new state */ + call->state = CHAN_LCR_STATE_IN_PREPARE; + /* set ref */ call->ref = ref; + /* wait for setup (or release from asterisk) */ } else { /* new ref, as requested from this remote application */ @@ -312,8 +517,22 @@ int receive_message(int message_type, unsigned long ref, union parameter *param) send_message(MESSAGE_RELEASE, ref, &newparam); return(0); } + /* store new ref */ call->ref = ref; -#warning process call (send setup, if pending) + /* send pending setup info */ + if (call->state == CHAN_LCR_STATE_OUT_PREPARE) + send_setup_to_lcr(call); + /* release if asterisk has signed off */ + else if (call->state == CHAN_LCR_STATE_RELEASE) + { + /* send release */ + newparam.disconnectinfo.cause = todo + newparam.disconnectinfo.location = todo + send_message(MESSAGE_RELEASE, ref, &newparam); + /* free call */ + free_call(call); + return(0); + } } return(0); } @@ -335,40 +554,39 @@ int receive_message(int message_type, unsigned long ref, union parameter *param) switch(message_type) { case MESSAGE_SETUP: -#warning todo + lcr_in_setup(call, message_type, param); break; case MESSAGE_OVERLAP: -#warning todo + lcr_in_overlap(call, message_type, param); break; case MESSAGE_PROCEEDING: -#warning todo + lcr_in_proceeding(call, message_type, param); break; case MESSAGE_ALERTING: -#warning todo + lcr_in_alerting(call, message_type, param); break; case MESSAGE_CONNECT: -#warning todo + lcr_in_connect(call, message_type, param); break; case MESSAGE_DISCONNECT: -#warning todo + lcr_in_disconnect(call, message_type, param); break; case MESSAGE_RELEASE: -#warning todo - free_call(call); - return(0); + lcr_in_release(call, message_type, param); + break; case MESSAGE_INFORMATION: -#warning todo + lcr_in_disconnect(call, message_type, param); break; case MESSAGE_FACILITY: -#warning todo + lcr_in_disconnect(call, message_type, param); break; case MESSAGE_PATTERN: @@ -526,6 +744,8 @@ void close_socket(int sock) } +hander thread muss noch +socket muss per timer fuer das öffnen checken void lcr_thread(void) { int work; @@ -551,13 +771,74 @@ void lcr_thread(void) } } -static struct ast_channel *lcr_request(const char *type, int format, void *data, int *cause) +/* + * send setup info to LCR + * this function is called, when asterisk call is received and ref is received + */ +static void send_setup_to_lcr(struct chan_call *call) { + if (!ast || !call->ref) + return; + /* send setup message to LCR */ + memset(&newparam, 0, sizeof(union parameter)); + newparam.setup.xxxxxx = + send_message(MESSAGE_SETUP, call->ref, &newparam); + /* change to outgoing setup state */ + call->state = CHAN_LCR_STATE_OUT_SETUP; } +/* + * send dialing info to LCR + * this function is called, when setup acknowledge is received and dialing + * info is available. + */ +static void send_dialing_to_lcr(struct chan_call *call) +{ + if (!ast || !call->ref || !call->dialque) + return; + + /* send setup message to LCR */ + memset(&newparam, 0, sizeof(union parameter)); + strncpy(newparam.dialinginfo.id, call->dialque, sizeof(newparam.dialinginfo.id)-1); + call->dialque[0] = '\0'; + send_message(MESSAGE_INFORMATION, call->ref, &newparam); +} -/* call from asterisk (new instance) */ +/* + * new asterisk instance + */ +static struct ast_channel *lcr_request(const char *type, int format, void *data, int *cause) +{ + /* create call instance */ + call = alloc_call(); + if (!call) + { + /* failed to create instance */ + return NULL; + } + /* create asterisk channel instrance */ + ast = ast_channel_alloc(1); + if (!ast) + { + free_call(call); + /* failed to create instance */ + return NULL; + } + /* link together */ + ast->tech_pvt = call; + call->ast = ast; + /* send MESSAGE_NEWREF */ + memset(&newparam, 0, sizeof(union parameter)); + newparam.direction = 0; /* request from app */ + send_message(MESSAGE_NEWREF, 0, &newparam); + /* set state */ + call->state = CHAN_LCR_STATE_OUT_PREPARE; +} + +/* + * call from asterisk + */ static int lcr_call(struct ast_channel *ast, char *dest, int timeout) { struct lcr_pvt *lcr=ast->tech_pvt; @@ -567,11 +848,16 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout) char buf[128]; char *port_str, *dad, *p; + hier muss noch ast_copy_string(buf, dest, sizeof(buf)-1); p=buf; port_str=strsep(&p, "/"); dad=strsep(&p, "/"); + /* send setup message, if we already have a callref */ + if (call->ref) + send_setup_to_lcr(call); + if (lcr_debug) ast_verbose("Call: ext:%s dest:(%s) -> dad(%s) \n", ast->exten,dest, dad); @@ -579,18 +865,67 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout) return 0; } +static int lcr_digit(struct ast_channel *ast, char digit) +{ + char buf[]="x"; + + /* only pass IA5 number space */ + if (digit > 126 || digit < 32) + return 0; + + /* send information or queue them */ + if (call->ref && call->state == CHAN_LCR_STATE_OUT_DIALING) + { + send_dialing_to_lcr(call); + } else + if (!call->ref + && (call->state == CHAN_LCR_STATE_OUT_PREPARE || call->state == CHAN_LCR_STATE_OUT_SETUP)); + { + *buf = digit; + strncat(call->dialque, buf, strlen(char->dialque)-1); + } else + { +digits kommen, koennen aber nicht verwendet werden. + sollen wir sie als info senden (im connect zb.) + } +} + static int lcr_answer(struct ast_channel *c) { struct lcr_pvt *lcr=c->tech_pvt; return 0; } -static int lcr_hangup(struct ast_channel *c) +static int lcr_hangup(struct ast_channel *ast) { - struct lcr_pvt *lcr=c->tech_pvt; - c->tech_pvt=NULL; -} + struct chan_call *call = ast->tech_pvt; + /* disconnect asterisk, maybe not required */ + ast->tech_pvt = NULL; + if (ref) + { + /* release */ + memset(&newparam, 0, sizeof(union parameter)); + newparam.disconnectinfo.cause = CAUSE_RESSOURCEUNAVAIL; + newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + send_message(MESSAGE_RELEASE, call->ref, &newparam); + /* remove call */ + free_call(call); + return; + } else + { + /* ref is not set, due to prepare setup or release */ + if (call->state == CHAN_LCR_STATE_RELEASE) + { + /* we get the response to our release */ + free_call(call); + } else + { + /* during prepare, we change to release state */ + call->state = CHAN_LCR_STATE_RELEASE; + } + } +} static int lcr_write(struct ast_channel *c, struct ast_frame *f) { @@ -640,7 +975,7 @@ static struct ast_channel_tech lcr_tech = { .description="Channel driver for connecting to Linux-Call-Router", .capabilities=AST_FORMAT_ALAW, .requester=lcr_request, -// .send_digit=lcr_digit, + .send_digit=lcr_digit, .call=lcr_call, // .bridge=lcr_bridge, .hangup=lcr_hangup, @@ -853,7 +1188,7 @@ char *key(void) #define AST_MODULE "chan_lcr" AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, - "Channel driver for lcr", + "Channel driver for LCR", .load = load_module, .unload = unload_module, .reload = reload_module, diff --git a/chan_lcr.h b/chan_lcr.h index 8633d3a..45a5a94 100644 --- a/chan_lcr.h +++ b/chan_lcr.h @@ -11,11 +11,64 @@ /* structure for all calls */ struct chan_call { - struct chan_call *next; - unsigned long ref; /* callref, is 0, if not yet set */ - unsigned long bchannel_handle; /* reference to bchannel, if set */ - + struct chan_call *next; /* link to next call instance */ + int state; /* current call state CHAN_LCR_STATE */ + unsigned long ref; /* callref for this channel */ + struct ast_channel *ast; /* current asterisk channel */ + unsigned long bchannel_handle; + /* reference to bchannel, if set */ unsigned short bridge_id; /* 0 = off, equal ids are bridged */ }; +enum { + CHAN_LCR_STATE_IN_PREPARE = 0, + CHAN_LCR_STATE_IN_SETUP, + CHAN_LCR_STATE_IN_DIALING, + CHAN_LCR_STATE_IN_PROCEEDING, + CHAN_LCR_STATE_IN_ALERTING, + CHAN_LCR_STATE_OUT_PREPARE, + CHAN_LCR_STATE_OUT_SETUP, + CHAN_LCR_STATE_OUT_DIALING, + CHAN_LCR_STATE_OUT_PROCEEDING, + CHAN_LCR_STATE_OUT_ALERTING, + CHAN_LCR_STATE_CONNECT, + CHAN_LCR_STATE_IN_DISCONNECT, + CHAN_LCR_STATE_OUT_DISCONNECT, + CHAN_LCR_STATE_RELEASE, +}; + +#define CHAN_LCR_STATE static const struct chan_lcr_state { \ + char name, \ + char meaning, \ +} chan_lcr_state[] = { \ + { "IN_PREPARE", \ + "New call from ISDN is waiting for setup." }, \ + { "IN_SETUP", \ + "Call from ISDN is currently set up." }, \ + { "IN_DIALING", \ + "Call from ISDN is currently waiting for digits to be dialed." }, \ + { "IN_PROCEEDING", \ + "Call from ISDN is complete and proceeds to ring." }, \ + { "IN_ALERTING", \ + "Call from ISDN is ringing." }, \ + { "OUT_PREPARE", \ + "New call to ISDN is wating for setup." }, \ + { "OUT_SETUP", \ + "Call to ISDN is currently set up." }, \ + { "OUT_DIALING", \ + "Call to ISDN is currently waiting for digits to be dialed." }, \ + { "OUT_PROCEEDING", \ + "Call to ISDN is complete and proceeds to ring." }, \ + { "OUT_ALERTING", \ + "Call to ISDN is ringing." }, \ + { "CONNECT", \ + "Call has been answered." }, \ + { "IN_DISCONNECT", \ + "Call has been hung up on ISDN side." }, \ + { "OUT_DISCONNECT", \ + "Call has been hung up on Asterisk side." }, \ + { "RELEASE", \ + "Call is waiting for complete release." }, \ +}; + diff --git a/message.h b/message.h index 8283aaf..7712cd1 100644 --- a/message.h +++ b/message.h @@ -19,7 +19,7 @@ enum { /* interface types */ }; enum { /* number types */ - INFO_NTYPE_UNKNOWN, + INFO_NTYPE_UNKNOWN = 0, INFO_NTYPE_SUBSCRIBER, INFO_NTYPE_NATIONAL, INFO_NTYPE_INTERNATIONAL, -- 2.13.6