Reimplement callback mechanism to handle APDU response messages that we care about.
1) No sent messages will remain in the APDU queue unless they have an active timer to remove them. The dummy call reference call and global call reference call structures will not act like a memory leak to sent messages. 2) The new T-RESPONSE timer will be the generic response guard if the standards do not otherwise specify a timer for a message response. 3) The callback will be called. If it is called because of a response message, then the callback has an opportunity to indicate if more responses are expected. git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1322 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
62d35faf6b
commit
b698032e04
2
libpri.h
2
libpri.h
@ -1296,6 +1296,8 @@ enum PRI_TIMERS_AND_COUNTERS {
|
||||
PRI_TIMER_T_HOLD, /*!< Maximum time to wait for HOLD request response. */
|
||||
PRI_TIMER_T_RETRIEVE, /*!< Maximum time to wait for RETRIEVE request response. */
|
||||
|
||||
PRI_TIMER_T_RESPONSE, /*!< Maximum time to wait for a typical APDU response. */
|
||||
|
||||
/* Must be last in the enum list */
|
||||
PRI_MAX_TIMERS
|
||||
};
|
||||
|
3
pri.c
3
pri.c
@ -88,6 +88,7 @@ static const struct pri_timer_table pri_timer[] = {
|
||||
{ "T322", PRI_TIMER_T322, PRI_ALL_SWITCHES },
|
||||
{ "T-HOLD", PRI_TIMER_T_HOLD, PRI_ALL_SWITCHES },
|
||||
{ "T-RETRIEVE", PRI_TIMER_T_RETRIEVE, PRI_ALL_SWITCHES },
|
||||
{ "T-RESPONSE", PRI_TIMER_T_RESPONSE, PRI_ALL_SWITCHES },
|
||||
/* *INDENT-ON* */
|
||||
};
|
||||
|
||||
@ -157,6 +158,8 @@ static void pri_default_timers(struct pri *ctrl, int switchtype)
|
||||
ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */
|
||||
ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */
|
||||
|
||||
ctrl->timers[PRI_TIMER_T_RESPONSE] = 4 * 1000; /* Maximum time to wait for a typical APDU response. */
|
||||
|
||||
/* Set any switch specific override default values */
|
||||
switch (switchtype) {
|
||||
default:
|
||||
|
271
pri_facility.c
271
pri_facility.c
@ -1023,7 +1023,7 @@ int rose_diverting_leg_information1_encode(struct pri *ctrl, q931_call *call)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1192,7 +1192,7 @@ static int rose_diverting_leg_information2_encode(struct pri *ctrl, q931_call *c
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1314,7 +1314,7 @@ int rose_diverting_leg_information3_encode(struct pri *ctrl, q931_call *call,
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1385,7 +1385,7 @@ int rlt_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer)) {
|
||||
if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1448,7 +1448,7 @@ static int add_dms100_transfer_ability_apdu(struct pri *ctrl, q931_call *call)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1557,7 +1557,7 @@ static int add_callername_facility_ies(struct pri *ctrl, q931_call *call, int cp
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer)) {
|
||||
if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1580,7 +1580,7 @@ static int add_callername_facility_ies(struct pri *ctrl, q931_call *call, int cp
|
||||
mymessage = Q931_FACILITY;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, mymessage, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, mymessage, buffer, end - buffer, NULL);
|
||||
}
|
||||
/* End Callername */
|
||||
|
||||
@ -1714,7 +1714,7 @@ int mwi_message_send(struct pri *ctrl, q931_call *call, struct pri_sr *req, int
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
|
||||
}
|
||||
/* End MWI */
|
||||
|
||||
@ -1773,7 +1773,7 @@ int eect_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer)) {
|
||||
if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer, NULL)) {
|
||||
pri_message(ctrl, "Could not queue APDU in facility message\n");
|
||||
return -1;
|
||||
}
|
||||
@ -2094,7 +2094,7 @@ static int rose_reroute_request_encode(struct pri *ctrl, q931_call *call,
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2221,14 +2221,10 @@ static int anfpr_pathreplacement_respond(struct pri *ctrl, q931_call *call, q931
|
||||
{
|
||||
int res;
|
||||
|
||||
res = pri_call_apdu_queue_cleanup(call->bridged_call);
|
||||
if (res) {
|
||||
pri_message(ctrl, "Could not Clear queue ADPU\n");
|
||||
return -1;
|
||||
}
|
||||
pri_call_apdu_queue_cleanup(call->bridged_call);
|
||||
|
||||
/* Send message */
|
||||
res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len);
|
||||
res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL);
|
||||
if (res) {
|
||||
pri_message(ctrl, "Could not queue ADPU in facility message\n");
|
||||
return -1;
|
||||
@ -2296,7 +2292,7 @@ int anfpr_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer);
|
||||
res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer, NULL);
|
||||
if (res) {
|
||||
pri_message(ctrl, "Could not queue ADPU in facility message\n");
|
||||
return -1;
|
||||
@ -2325,7 +2321,7 @@ int anfpr_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer);
|
||||
res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer, NULL);
|
||||
if (res) {
|
||||
pri_message(ctrl, "Could not queue ADPU in facility message\n");
|
||||
return -1;
|
||||
@ -2410,7 +2406,7 @@ static int aoc_aoce_charging_unit_encode(struct pri *ctrl, q931_call *call,
|
||||
|
||||
/* Remember that if we queue a facility IE for a facility message we
|
||||
* have to explicitly send the facility message ourselves */
|
||||
if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer)
|
||||
if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
|
||||
|| q931_facility(call->pri, call)) {
|
||||
pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr);
|
||||
return -1;
|
||||
@ -2556,7 +2552,7 @@ static int rose_call_transfer_complete_encode(struct pri *ctrl, q931_call *call,
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
|
||||
@ -2624,7 +2620,7 @@ int rose_called_name_encode(struct pri *ctrl, q931_call *call, int messagetype)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2690,7 +2686,7 @@ int rose_connected_name_encode(struct pri *ctrl, q931_call *call, int messagetyp
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2700,11 +2696,18 @@ int rose_connected_name_encode(struct pri *ctrl, q931_call *call, int messagetyp
|
||||
* \param messagetype Q.931 message type.
|
||||
* \param apdu Facility ie contents buffer.
|
||||
* \param apdu_len Length of the contents buffer.
|
||||
* \param response Sender supplied information to handle APDU response messages.
|
||||
* NULL if don't care about responses.
|
||||
*
|
||||
* \note
|
||||
* Only APDU messages with an invoke component can supply a response pointer.
|
||||
* If any other APDU messages supply a response pointer then aliasing of the
|
||||
* invoke_id can occur.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len)
|
||||
int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response)
|
||||
{
|
||||
struct apdu_event *cur = NULL;
|
||||
struct apdu_event *new_event = NULL;
|
||||
@ -2731,11 +2734,16 @@ int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *a
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in the APDU event */
|
||||
new_event->message = messagetype;
|
||||
if (response) {
|
||||
new_event->response = *response;
|
||||
}
|
||||
new_event->call = call;
|
||||
new_event->apdu_len = apdu_len;
|
||||
memcpy(new_event->apdu, apdu, apdu_len);
|
||||
|
||||
/* Append APDU to the end of the list. */
|
||||
/* Append APDU event to the end of the list. */
|
||||
if (call->apdus) {
|
||||
for (cur = call->apdus; cur->next; cur = cur->next) {
|
||||
}
|
||||
@ -2747,22 +2755,85 @@ int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *a
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pri_call_apdu_queue_cleanup(q931_call *call)
|
||||
/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
|
||||
void pri_call_apdu_queue_cleanup(q931_call *call)
|
||||
{
|
||||
struct apdu_event *cur_event = NULL, *free_event = NULL;
|
||||
struct apdu_event *cur_event;
|
||||
struct apdu_event *free_event;
|
||||
|
||||
if (call && call->apdus) {
|
||||
if (call) {
|
||||
cur_event = call->apdus;
|
||||
call->apdus = NULL;
|
||||
while (cur_event) {
|
||||
/* TODO: callbacks, some way of giving return res on status of apdu */
|
||||
if (cur_event->response.callback) {
|
||||
/* Indicate to callback that the APDU is being cleaned up. */
|
||||
cur_event->response.callback(APDU_CALLBACK_REASON_CLEANUP, call->pri,
|
||||
call, cur_event, NULL);
|
||||
|
||||
/* Stop any response timeout. */
|
||||
pri_schedule_del(call->pri, cur_event->timer);
|
||||
}
|
||||
free_event = cur_event;
|
||||
cur_event = cur_event->next;
|
||||
free(free_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Find an outstanding APDU with the given invoke id.
|
||||
*
|
||||
* \param call Call to find APDU.
|
||||
* \param invoke_id Invoke id to match outstanding APDUs in queue.
|
||||
*
|
||||
* \retval apdu_event if found.
|
||||
* \retval NULL if not found.
|
||||
*/
|
||||
static struct apdu_event *pri_call_apdu_find(struct q931_call *call, int invoke_id)
|
||||
{
|
||||
struct apdu_event *apdu;
|
||||
|
||||
for (apdu = call->apdus; apdu; apdu = apdu->next) {
|
||||
/*
|
||||
* Note: The APDU cannot be sent and still in the queue without a
|
||||
* callback and timeout timer active. Therefore, an invoke_id of
|
||||
* zero is valid and not just the result of a memset().
|
||||
*/
|
||||
if (apdu->response.invoke_id == invoke_id && apdu->sent) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return apdu;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Delete the given APDU event from the given call.
|
||||
*
|
||||
* \param call Call to remove the APDU.
|
||||
* \param doomed APDU event to delete.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed)
|
||||
{
|
||||
struct apdu_event **prev;
|
||||
struct apdu_event *cur;
|
||||
|
||||
/* Find APDU in list. */
|
||||
for (prev = &call->apdus, cur = call->apdus;
|
||||
cur;
|
||||
prev = &cur->next, cur = cur->next) {
|
||||
if (cur == doomed) {
|
||||
/* Stop any response timeout. */
|
||||
pri_schedule_del(call->pri, cur->timer);
|
||||
|
||||
/* Remove APDU from list. */
|
||||
*prev = cur->next;
|
||||
free(cur);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \note Only called when sending the SETUP message. */
|
||||
@ -2948,7 +3019,7 @@ static int rose_facility_error_encode(struct pri *ctrl, q931_call *call, int inv
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -3080,7 +3151,7 @@ static int rose_result_ok_encode(struct pri *ctrl, q931_call *call, int msgtype,
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pri_call_apdu_queue(call, msgtype, buffer, end - buffer);
|
||||
return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -3163,11 +3234,39 @@ int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI
|
||||
void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
|
||||
const struct fac_extension_header *header, const struct rose_msg_reject *reject)
|
||||
{
|
||||
struct apdu_event *apdu;
|
||||
union apdu_msg_data msg;
|
||||
|
||||
/* Gripe to the user about getting rejected. */
|
||||
pri_error(ctrl, "ROSE REJECT:\n");
|
||||
if (reject->invoke_id_present) {
|
||||
pri_error(ctrl, "\tINVOKE ID: %d\n", reject->invoke_id);
|
||||
}
|
||||
pri_error(ctrl, "\tPROBLEM: %s\n", rose_reject2str(reject->code));
|
||||
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_DMS100:
|
||||
/* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reject->invoke_id_present) {
|
||||
/*
|
||||
* No invoke id to look up so we cannot match it to any outstanding APDUs.
|
||||
* This REJECT is apparently meant for someone monitoring the link.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
apdu = pri_call_apdu_find(call, reject->invoke_id);
|
||||
if (!apdu) {
|
||||
return;
|
||||
}
|
||||
msg.reject = reject;
|
||||
if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_REJECT, ctrl, call, apdu, &msg)) {
|
||||
pri_call_apdu_delete(call, apdu);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -3186,7 +3285,10 @@ void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *
|
||||
const struct fac_extension_header *header, const struct rose_msg_error *error)
|
||||
{
|
||||
const char *dms100_operation;
|
||||
struct apdu_event *apdu;
|
||||
union apdu_msg_data msg;
|
||||
|
||||
/* Gripe to the user about getting an error. */
|
||||
pri_error(ctrl, "ROSE RETURN ERROR:\n");
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_DMS100:
|
||||
@ -3211,6 +3313,23 @@ void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *
|
||||
break;
|
||||
}
|
||||
pri_error(ctrl, "\tERROR: %s\n", rose_error2str(error->code));
|
||||
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_DMS100:
|
||||
/* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
apdu = pri_call_apdu_find(call, error->invoke_id);
|
||||
if (!apdu) {
|
||||
return;
|
||||
}
|
||||
msg.error = error;
|
||||
if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_ERROR, ctrl, call, apdu, &msg)) {
|
||||
pri_call_apdu_delete(call, apdu);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -3228,8 +3347,12 @@ void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *
|
||||
void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
|
||||
const struct fac_extension_header *header, const struct rose_msg_result *result)
|
||||
{
|
||||
struct apdu_event *apdu;
|
||||
union apdu_msg_data msg;
|
||||
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_DMS100:
|
||||
/* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
|
||||
switch (result->invoke_id) {
|
||||
case ROSE_DMS100_RLT_OPERATION_IND:
|
||||
if (result->operation != ROSE_DMS100_RLT_OperationInd) {
|
||||
@ -3256,87 +3379,13 @@ void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie
|
||||
break;
|
||||
}
|
||||
|
||||
switch (result->operation) {
|
||||
case ROSE_None:
|
||||
/*
|
||||
* This is simply a positive ACK to the invoke request.
|
||||
* The invoke ID must be used to distinguish between outstanding
|
||||
* invoke requests.
|
||||
*/
|
||||
break;
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_ETSI_ActivationDiversion:
|
||||
break;
|
||||
case ROSE_ETSI_DeactivationDiversion:
|
||||
break;
|
||||
case ROSE_ETSI_InterrogationDiversion:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
case ROSE_ETSI_CallDeflection:
|
||||
/* Successfully completed call deflection. Nothing to do. */
|
||||
break;
|
||||
case ROSE_ETSI_CallRerouting:
|
||||
/* Successfully completed call rerouting. Nothing to do. */
|
||||
break;
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_ETSI_InterrogateServedUserNumbers:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_ETSI_ChargingRequest:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_ETSI_EctExecute:
|
||||
break;
|
||||
case ROSE_ETSI_ExplicitEctExecute:
|
||||
break;
|
||||
case ROSE_ETSI_EctLinkIdRequest:
|
||||
break;
|
||||
case ROSE_ETSI_EctLoopTest:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_QSIG_ChargeRequest:
|
||||
break;
|
||||
case ROSE_QSIG_AocComplete:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_QSIG_CallTransferIdentify:
|
||||
break;
|
||||
case ROSE_QSIG_CallTransferInitiate:
|
||||
break;
|
||||
case ROSE_QSIG_CallTransferSetup:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_QSIG_ActivateDiversionQ:
|
||||
break;
|
||||
case ROSE_QSIG_DeactivateDiversionQ:
|
||||
break;
|
||||
case ROSE_QSIG_InterrogateDiversionQ:
|
||||
break;
|
||||
case ROSE_QSIG_CheckRestriction:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
case ROSE_QSIG_CallRerouting:
|
||||
/* Successfully completed call rerouting. Nothing to do. */
|
||||
break;
|
||||
#if 0 /* Not handled yet */
|
||||
case ROSE_QSIG_MWIActivate:
|
||||
break;
|
||||
case ROSE_QSIG_MWIDeactivate:
|
||||
break;
|
||||
case ROSE_QSIG_MWIInterrogate:
|
||||
break;
|
||||
#endif /* Not handled yet */
|
||||
default:
|
||||
if (ctrl->debug & PRI_DEBUG_APDU) {
|
||||
pri_message(ctrl, "!! ROSE result operation not handled! %s\n",
|
||||
rose_operation2str(result->operation));
|
||||
apdu = pri_call_apdu_find(call, result->invoke_id);
|
||||
if (!apdu) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
msg.result = result;
|
||||
if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_RESULT, ctrl, call, apdu, &msg)) {
|
||||
pri_call_apdu_delete(call, apdu);
|
||||
}
|
||||
}
|
||||
|
||||
|
122
pri_facility.h
122
pri_facility.h
@ -31,6 +31,13 @@
|
||||
#define _PRI_FACILITY_H
|
||||
#include "pri_q931.h"
|
||||
|
||||
/* Forward declare some structs */
|
||||
struct fac_extension_header;
|
||||
struct rose_msg_invoke;
|
||||
struct rose_msg_result;
|
||||
struct rose_msg_error;
|
||||
struct rose_msg_reject;
|
||||
|
||||
/* Protocol Profile field */
|
||||
#define Q932_PROTOCOL_MASK 0x1F
|
||||
#define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */
|
||||
@ -65,6 +72,107 @@
|
||||
#define QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR 0x01
|
||||
#define QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR 0x02
|
||||
|
||||
/*! Reasons an APDU callback is called. */
|
||||
enum APDU_CALLBACK_REASON {
|
||||
/*!
|
||||
* \brief Send setup error. Abort and cleanup.
|
||||
* \note The message may or may not actually get sent.
|
||||
* \note The callback cannot generate an event subcmd.
|
||||
* \note The callback should not send messages. Out of order messages will result.
|
||||
*/
|
||||
APDU_CALLBACK_REASON_ERROR,
|
||||
/*!
|
||||
* \brief Abort and cleanup.
|
||||
* \note The APDU queue is being destroyed.
|
||||
* \note The callback cannot generate an event subcmd.
|
||||
* \note The callback cannot send messages as the call is likely being destroyed.
|
||||
*/
|
||||
APDU_CALLBACK_REASON_CLEANUP,
|
||||
/*!
|
||||
* \brief Timeout waiting for responses to the message.
|
||||
* \note The callback can generate an event subcmd.
|
||||
* \note The callback can send messages.
|
||||
*/
|
||||
APDU_CALLBACK_REASON_TIMEOUT,
|
||||
/*!
|
||||
* \brief Received a facility response message.
|
||||
* \note The callback can generate an event subcmd.
|
||||
* \note The callback can send messages.
|
||||
*/
|
||||
APDU_CALLBACK_REASON_MSG_RESULT,
|
||||
/*!
|
||||
* \brief Received a facility error message.
|
||||
* \note The callback can generate an event subcmd.
|
||||
* \note The callback can send messages.
|
||||
*/
|
||||
APDU_CALLBACK_REASON_MSG_ERROR,
|
||||
/*!
|
||||
* \brief Received a facility reject message.
|
||||
* \note The callback can generate an event subcmd.
|
||||
* \note The callback can send messages.
|
||||
*/
|
||||
APDU_CALLBACK_REASON_MSG_REJECT,
|
||||
};
|
||||
|
||||
union apdu_msg_data {
|
||||
const struct rose_msg_result *result;
|
||||
const struct rose_msg_error *error;
|
||||
const struct rose_msg_reject *reject;
|
||||
};
|
||||
|
||||
union apdu_callback_param {
|
||||
void *ptr;
|
||||
long value;
|
||||
char pad[8];
|
||||
};
|
||||
|
||||
struct apdu_callback_data {
|
||||
/*! APDU invoke id to match with any response messages. (Result/Error/Reject) */
|
||||
int invoke_id;
|
||||
/*!
|
||||
* \brief Time to wait for responses to APDU in ms.
|
||||
* \note Set to 0 if send the message only.
|
||||
* \note Set to less than 0 for PRI_TIMER_T_RESPONSE time.
|
||||
*/
|
||||
int timeout_time;
|
||||
/*!
|
||||
* \brief APDU callback function.
|
||||
*
|
||||
* \param reason Reason callback is called.
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg.
|
||||
* \param apdu APDU queued entry. Do not change!
|
||||
* \param msg APDU response message data. (NULL if was not the reason called.)
|
||||
*
|
||||
* \note
|
||||
* A callback must be supplied if the sender cares about any APDU_CALLBACK_REASON.
|
||||
*
|
||||
* \return TRUE if no more responses are expected.
|
||||
*/
|
||||
int (*callback)(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const union apdu_msg_data *msg);
|
||||
/*! \brief Sender data for the callback function to identify the particular APDU. */
|
||||
union apdu_callback_param user;
|
||||
};
|
||||
|
||||
struct apdu_event {
|
||||
/*! Linked list pointer */
|
||||
struct apdu_event *next;
|
||||
/*! TRUE if this APDU has been sent. */
|
||||
int sent;
|
||||
/*! What message to send the ADPU in */
|
||||
int message;
|
||||
/*! Sender supplied information to handle APDU response messages. */
|
||||
struct apdu_callback_data response;
|
||||
/*! Q.931 call leg. (Needed for the APDU timeout.) */
|
||||
struct q931_call *call;
|
||||
/*! Response timeout timer. */
|
||||
int timer;
|
||||
/*! Length of ADPU */
|
||||
int apdu_len;
|
||||
/*! ADPU to send */
|
||||
unsigned char apdu[255];
|
||||
};
|
||||
|
||||
/* Queues an MWI apdu on a the given call */
|
||||
int mwi_message_send(struct pri *pri, q931_call *call, struct pri_sr *req, int activate);
|
||||
|
||||
@ -87,23 +195,15 @@ int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int
|
||||
int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype);
|
||||
int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype);
|
||||
|
||||
int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len);
|
||||
|
||||
/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
|
||||
int pri_call_apdu_queue_cleanup(q931_call *call);
|
||||
int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response);
|
||||
void pri_call_apdu_queue_cleanup(q931_call *call);
|
||||
void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed);
|
||||
|
||||
/* Adds the "standard" APDUs to a call */
|
||||
int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
|
||||
|
||||
void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1, const unsigned char *end);
|
||||
|
||||
/* Forward declare some ROSE structures for the following prototypes */
|
||||
struct fac_extension_header;
|
||||
struct rose_msg_invoke;
|
||||
struct rose_msg_result;
|
||||
struct rose_msg_error;
|
||||
struct rose_msg_reject;
|
||||
|
||||
void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_invoke *invoke);
|
||||
void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_result *result);
|
||||
void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_error *error);
|
||||
|
@ -40,6 +40,9 @@
|
||||
#define DBGHEAD __FILE__ ":%d %s: "
|
||||
#define DBGINFO __LINE__,__PRETTY_FUNCTION__
|
||||
|
||||
/* Forward declare some structs */
|
||||
struct apdu_event;
|
||||
|
||||
struct pri_sched {
|
||||
struct timeval when;
|
||||
void (*callback)(void *data);
|
||||
@ -307,13 +310,6 @@ struct pri_sr {
|
||||
|
||||
#define Q931_MAX_TEI 8
|
||||
|
||||
struct apdu_event {
|
||||
struct apdu_event *next; /* Linked list pointer */
|
||||
int message; /* What message to send the ADPU in */
|
||||
int apdu_len; /* Length of ADPU */
|
||||
unsigned char apdu[255]; /* ADPU to send */
|
||||
};
|
||||
|
||||
/*! \brief Incoming call transfer states. */
|
||||
enum INCOMING_CT_STATE {
|
||||
/*!
|
||||
|
81
q931.c
81
q931.c
@ -2266,6 +2266,8 @@ static int receive_progress_indicator(int full_ie, struct pri *ctrl, q931_call *
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void q931_apdu_timeout(void *data);
|
||||
|
||||
static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
|
||||
{
|
||||
struct apdu_event **prev;
|
||||
@ -2275,9 +2277,7 @@ static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int
|
||||
for (prev = &call->apdus, cur = call->apdus;
|
||||
cur;
|
||||
prev = &cur->next, cur = cur->next) {
|
||||
if (cur->message == msgtype) {
|
||||
/* Remove APDU from list. */
|
||||
*prev = cur->next;
|
||||
if (!cur->sent && cur->message == msgtype) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2292,15 +2292,52 @@ static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int
|
||||
facility_decode_dump(ctrl, cur->apdu, cur->apdu_len);
|
||||
}
|
||||
|
||||
if (cur->apdu_len > 235) { /* TODO: find out how much space we can use */
|
||||
pri_message(ctrl, "Requested APDU (%d bytes) is too long\n", cur->apdu_len);
|
||||
if (len < cur->apdu_len) {
|
||||
pri_error(ctrl,
|
||||
"Could not fit facility ie in message. Size needed:%d Available space:%d\n",
|
||||
cur->apdu_len + 2, len);
|
||||
|
||||
/* Remove APDU from list. */
|
||||
*prev = cur->next;
|
||||
|
||||
if (cur->response.callback) {
|
||||
/* Indicate to callback that the APDU had a problem getting sent. */
|
||||
cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL);
|
||||
}
|
||||
|
||||
free(cur);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(ie->data, cur->apdu, cur->apdu_len);
|
||||
apdu_len = cur->apdu_len;
|
||||
cur->sent = 1;
|
||||
|
||||
if (cur->response.callback && cur->response.timeout_time) {
|
||||
int duration;
|
||||
|
||||
if (0 < cur->response.timeout_time) {
|
||||
/* Sender specified timeout duration. */
|
||||
duration = cur->response.timeout_time;
|
||||
} else {
|
||||
/* Sender wants to use the typical timeout duration. */
|
||||
duration = ctrl->timers[PRI_TIMER_T_RESPONSE];
|
||||
}
|
||||
cur->timer = pri_schedule_event(ctrl, duration, q931_apdu_timeout, cur);
|
||||
if (!cur->timer) {
|
||||
/* Remove APDU from list. */
|
||||
*prev = cur->next;
|
||||
|
||||
/* Indicate to callback that the APDU had a problem getting sent. */
|
||||
cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL);
|
||||
|
||||
free(cur);
|
||||
}
|
||||
} else if (!cur->timer) {
|
||||
/* Remove APDU from list. */
|
||||
*prev = cur->next;
|
||||
free(cur);
|
||||
}
|
||||
|
||||
return apdu_len + 2;
|
||||
}
|
||||
@ -6223,6 +6260,34 @@ static void q931_fill_facility_event(struct pri *ctrl, struct q931_call *call)
|
||||
ctrl->ev.facility.callingplan = call->remote_id.number.plan;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief APDU wait for response message timeout.
|
||||
*
|
||||
* \param data Callback data pointer.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void q931_apdu_timeout(void *data)
|
||||
{
|
||||
struct apdu_event *apdu;
|
||||
struct pri *ctrl;
|
||||
struct q931_call *call;
|
||||
|
||||
apdu = data;
|
||||
call = apdu->call;
|
||||
ctrl = call->pri;
|
||||
|
||||
q931_clr_subcommands(ctrl);
|
||||
apdu->response.callback(APDU_CALLBACK_REASON_TIMEOUT, ctrl, call, apdu, NULL);
|
||||
if (ctrl->subcmds.counter_subcmd) {
|
||||
q931_fill_facility_event(ctrl, call);
|
||||
ctrl->schedev = 1;
|
||||
}
|
||||
|
||||
pri_call_apdu_delete(call, apdu);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Find the active call given the held call.
|
||||
@ -6510,7 +6575,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
c->useruserinfo[0] = '\0';
|
||||
|
||||
for (cur = c->apdus; cur; cur = cur->next) {
|
||||
if (cur->message == Q931_FACILITY) {
|
||||
if (!cur->sent && cur->message == Q931_FACILITY) {
|
||||
q931_facility(ctrl, c);
|
||||
break;
|
||||
}
|
||||
@ -6615,7 +6680,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
ctrl->ev.proceeding.call = c->master_call;
|
||||
|
||||
for (cur = c->apdus; cur; cur = cur->next) {
|
||||
if (cur->message == Q931_FACILITY) {
|
||||
if (!cur->sent && cur->message == Q931_FACILITY) {
|
||||
q931_facility(ctrl, c);
|
||||
break;
|
||||
}
|
||||
@ -6892,7 +6957,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
ctrl->ev.setup_ack.call = c->master_call;
|
||||
|
||||
for (cur = c->apdus; cur; cur = cur->next) {
|
||||
if (cur->message == Q931_FACILITY) {
|
||||
if (!cur->sent && cur->message == Q931_FACILITY) {
|
||||
q931_facility(ctrl, c);
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user