l4isup.c
来自「asterisk1.4.6版本下 7#信令驱动 源码」· C语言 代码 · 共 2,056 行 · 第 1/5 页
C
2,056 行
}
/* This should be called with pvt->lock held. */
static void t22_start(struct ss7_chan *pvt) {
t22_clear(pvt);
pvt->t22 = start_timer(30000, t22_timeout, pvt);
}
/* This should be called with pvt->lock held. */
static void t23_clear(struct ss7_chan *pvt) {
if(pvt->t23 != -1) {
stop_timer(pvt->t23);
pvt->t23 = -1;
}
}
static int t23_timeout(void *arg) {
struct ss7_chan *pvt = arg;
/* For the long T23 timeout, alert maintenance using LOG_WARNING. */
ast_log(LOG_WARNING, "T23 timeout (No \"circuit group reset acknowledge\" from peer) CIC=%d.\n", pvt->cic);
t22_clear(pvt);
isup_send_grs(pvt, pvt->grs_count, 0);
return 1; /* Run us again the next period */
}
/* This should be called with pvt->lock held. */
static void t23_start(struct ss7_chan *pvt) {
t23_clear(pvt);
pvt->t23 = start_timer(10*60*1000, t23_timeout, pvt);
}
static int t35_timeout(void *arg) {
struct ss7_chan *pvt = arg;
pvt->t35 = -1;
if (pvt->link->linkset->t35_action) {
pvt->iam.dni.complete = 1;
handle_complete_address(pvt);
return 0; /* Remove us from sched */
}
ast_log(LOG_NOTICE, "T35 timeout (waiting for end-of-pulsing) CIC=%d.\n", pvt->cic);
initiate_release_circuit(pvt, AST_CAUSE_INVALID_NUMBER_FORMAT);
return 0; /* Remove us from sched */
}
/* This should be called with pvt->lock held. */
static void t35_clear(struct ss7_chan *pvt) {
if(pvt->t35 != -1) {
stop_timer(pvt->t35);
pvt->t35 = -1;
}
}
/* This should be called with pvt->lock held. */
static void t35_start(struct ss7_chan* pvt)
{
t35_clear(pvt);
pvt->t35 = start_timer(pvt->link->linkset->t35_value, t35_timeout, pvt);
}
static int t36_timeout(void *arg) {
struct ss7_chan *pvt = arg;
ast_log(LOG_NOTICE, "T36 timeout (waiting for COT or REL) CIC=%d.\n", pvt->cic);
initiate_release_circuit(pvt, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
ast_mutex_lock(&continuity_check_lock);
continuity_check_changes = 1;
ast_mutex_unlock(&continuity_check_lock);
pvt->t36 = -1;
return 0; /* Remove us from sched */
}
/* This should be called with pvt->lock held. */
static void t36_clear(struct ss7_chan *pvt) {
if(pvt->t36 != -1) {
stop_timer(pvt->t36);
pvt->t36 = -1;
}
}
/* This should be called with pvt->lock held. */
static void t36_start(struct ss7_chan* pvt)
{
t36_clear(pvt);
pvt->t36 = start_timer(12000, t36_timeout, pvt);
}
static void isup_send_grs(struct ss7_chan *pvt, int count, int do_timers) {
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
unsigned char param[1];
if(pvt == NULL) {
ast_log(LOG_NOTICE, "Error: NULL pvt passed in?!?.\n");
return;
}
if(count < 2) {
ast_log(LOG_NOTICE, "Error (CIC=%d), cannot send group reset for %d "
"circuits (need at least 2).\n", pvt->cic, count);
return;
}
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_GRS, ¤t);
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 1, 0);
param[0] = count - 1;
isup_msg_add_variable(msg, sizeof(msg), &varptr, ¤t, param, 1);
mtp_enqueue_isup(pvt, msg, current);
if(do_timers) {
t22_start(pvt);
t23_start(pvt);
}
}
/* At startup, send an initial GRS to reset all circuits, and setup a timer
to wait for the ack. */
static void send_init_grs(struct linkset* linkset) {
int i;
int first_equipped; /* Left end of a range in CIC scan. */
int range;
ast_log(LOG_DEBUG, "Sending GROUP RESET messages on linkset '%s'.\n", linkset->name);
lock_global();
/* Send a GRS for each continuous range of circuits. */
first_equipped = -1;
for(i = linkset->first_cic; i <= linkset->last_cic; i++) {
if(linkset->cic_list[i] && linkset->cic_list[i]->equipped) {
/* Clear the blocked status for the circuits; any remote blocking will be
reported by the peer. */
linkset->cic_list[i]->blocked = 0;
/* Look for the start of a range. */
if(first_equipped == -1) {
first_equipped = i;
}
}
/* Look for the end of a range. */
if(first_equipped != -1 &&
(i == linkset->last_cic || !(linkset->cic_list[i+1] && linkset->cic_list[i+1]->equipped) || first_equipped + 31 == i)) {
range = i - first_equipped;
if(range == 0) {
struct ss7_chan *pvt = linkset->cic_list[first_equipped];
ast_mutex_lock(&pvt->lock);
pvt->state = ST_SENT_REL;
isup_send_rsc(pvt);
t16_start(pvt);
ast_mutex_unlock(&pvt->lock);
first_equipped = -1;
} else {
linkset->cic_list[first_equipped]->grs_count = range + 1;
isup_send_grs(linkset->cic_list[first_equipped], range + 1, 1);
}
ast_log(LOG_DEBUG, "Group reset first %d, range %d \n", first_equipped, range);
first_equipped = -1;
}
}
unlock_global();
/* When the reset acknowledge arrives, the pvt->reset_done is set true for
all affected circuits. Until then, messages for that circuit are
discarded. */
}
/* Release circuit after receiving GRS */
static void release_circuit(struct ss7_chan* pvt)
{
struct ast_channel *chan = pvt->owner;
if(chan != NULL) {
ast_mutex_lock(&chan->lock);
}
ast_mutex_lock(&pvt->lock);
if(pvt->state != ST_IDLE) {
pvt->state = ST_IDLE;
if(chan != NULL) {
request_hangup(chan, AST_CAUSE_NETWORK_OUT_OF_ORDER);
} else {
/* Channel already hung up */
}
}
t1_clear(pvt);
t2_clear(pvt);
t5_clear(pvt);
t6_clear(pvt);
t7_clear(pvt);
t9_clear(pvt);
t16_clear(pvt);
t17_clear(pvt);
t18_clear(pvt);
t19_clear(pvt);
t20_clear(pvt);
t21_clear(pvt);
t35_clear(pvt);
ast_mutex_unlock(&pvt->lock);
if(chan != NULL) {
ast_mutex_unlock(&chan->lock);
}
}
static void free_cic(struct ss7_chan* pvt)
{
pvt->state = ST_IDLE;
pvt->hangupcause = 0;
pvt->dohangup = 0;
pvt->has_inband_ind = 0;
pvt->charge_indicator = 0;
pvt->is_digital = 0;
pvt->sending_dtmf = 0;
pvt->owner = NULL;
add_to_idlelist(pvt);
}
static void handle_complete_address(struct ss7_chan *pvt)
{
int res;
struct iam* iam = &pvt->iam;
struct ast_channel *chan = ss7_new(pvt, AST_STATE_RING, iam->ani.present ? iam->ani.num : NULL, iam->dni.num);
//ast_log(LOG_ERROR,"present is %d,ani is %s,dni is %s.\n",iam->ani.present,iam->ani.num,iam->dni.num);
if(chan == NULL) {
ast_log(LOG_WARNING, "Failed to allocate struct ast_channel * "
"for CIC=%d.\n", pvt->cic);
/* Q.764 2.2 c) Initiate release procedure */
initiate_release_circuit(pvt, AST_CAUSE_NORMAL_CLEARING);
return;
}
#ifdef USE_ASTERISK_1_2
ast_copy_string(chan->exten, iam->dni.num, sizeof(chan->exten));
ast_copy_string(chan->context, pvt->context, sizeof(chan->context));
ast_copy_string(chan->language, pvt->language, sizeof(chan->language));
#else
ast_string_field_set(chan, language, pvt->language);
#endif
if(iam->ani.present) {
chan->cid.cid_num = strdup(iam->ani.num);
/* ToDo: Handle screening. */
if(iam->ani.restricted) {
chan->cid.cid_pres = AST_PRES_PROHIB_NETWORK_NUMBER;
} else {
chan->cid.cid_pres = AST_PRES_ALLOWED_NETWORK_NUMBER;
}
}
if(iam->rni.present) {
/* ToDo: implement redirection reason in Asterisk, and handle it here. */
chan->cid.cid_rdnis = strdup(iam->rni.num);
}
//ast_log(LOG_ERROR,"ANI=======NUM IS %d,DNI========NUM IS %d",chan->cid.cid_num,chan->cid.cid_rdnis);
if(iam->redir_inf.is_redirect) {
char *string_reason;
/* The names here are taken to match with those used in chan_zap.c
redirectingreason2str(). */
switch(iam->redir_inf.reason) {
case 1:
string_reason = "BUSY";
break;
case 2:
/* Cause 4 "deflection during alerting"; not sure, but it seems to be
more or less equivalent to "no reply".*/
case 4:
string_reason = "NO_REPLY";
break;
case 3:
/* Cause 5 "deflection immediate response"; not sure, but it seems to
be more or less equivalent to "unconditional".*/
case 5:
string_reason = "UNCONDITIONAL";
break;
case 6:
string_reason = "UNREACHABLE";
break;
default:
string_reason = "UNKNOWN";
break;
}
/* Use underscore variable to make it inherit like other callerid info. */
pbx_builtin_setvar_helper(chan, "__PRIREDIRECTREASON", string_reason);
}
if (!pvt->link->linkset->use_connect) {
isup_send_acm(pvt);
pvt->state = ST_SENT_ACM;
}
res = ast_pbx_start(chan);
if(res != 0) {
ast_log(LOG_WARNING, "Unable to start PBX for incoming call on CIC=%d.\n",
pvt->cic);
ast_hangup(chan);
}
}
static void check_iam_sam(struct ss7_chan* pvt)
{
int complete = (pvt->link->linkset->enable_st && pvt->iam.dni.complete) ||
ast_exists_extension(pvt->owner, pvt->context, pvt->iam.dni.num, 1, pvt->iam.rni.num);
if (complete) {
pvt->iam.dni.complete = 1;
ast_log(LOG_DEBUG, "Setting iam.dni.complete\n");
handle_complete_address(pvt);
} else {
if (ast_canmatch_extension(pvt->owner, pvt->context, pvt->iam.dni.num, 1, pvt->iam.rni.num) != 0) {
ast_log(LOG_DEBUG, "Processing addr %s, incomplete, starting T35\n", pvt->iam.dni.num);
t35_start(pvt);
}
else {
ast_log(LOG_DEBUG, "Unable to match extension, context: %s, dni: %s, rni: %s\n", pvt->context, pvt->iam.dni.num, pvt->iam.rni.num);
initiate_release_circuit(pvt, AST_CAUSE_UNALLOCATED);
}
}
}
static void check_obci(struct ss7_chan* pvt, int obci)
{
struct ast_channel* chan = pvt->owner;
if ((obci & 0x1) == 1) {
if (!pvt->has_inband_ind) {
ast_log(LOG_DEBUG, "Got optional backward call indicator, queueing PROGRESS (Inband-information available) indication for Asterisk, CIC=%d.\n", pvt->cic);
ast_queue_control(chan, AST_CONTROL_PROGRESS);
pvt->has_inband_ind = 1;
}
}
}
static int isup_phonenum_check(char **number, int *nlen,
int *is_international) {
if(*number == NULL) {
ast_log(LOG_DEBUG, "NULL phonenumber, encoding failed.\n");
return -1;
}
*nlen = strlen(*number);
if(*nlen == 0) {
ast_log(LOG_DEBUG, "Empty phonenumber, encoding failed.\n");
return -1;
}
/* Handle both '00' and '+' as international prefix. */
if(strncmp(*number, "00", 2) == 0) {
*is_international = 1;
*number += 2;
*nlen -= 2;
} else if(strncmp(*number, "+", 1) == 0) {
*is_international = 1;
*number += 1;
*nlen -= 1;
} else {
*is_international = 0;
}
return 0; /* Success */
}
static int isup_phonenum_digits(char *number, int add_st,
int nlen, unsigned char *param) {
int i, d;
for(i = 0; i <= nlen; i++) {
if(i == nlen) {
if(add_st) {
d = 0xf; /* Digit "ST", meaning "number complete" */
} else {
break;
}
} else {
if ((number[i] >= '0') && (number[i] <= '9'))
d = number[i] - '0';
else if ((number[i] == 'b') || (number[i] == 'B'))
d = 0x0b;
else if ((number[i] == 'c') || (number[i] == 'C'))
d = 0x0c;
else if ((number[i] == 'e') || (number[i] == 'E'))
d = 0x0e;
else {
ast_log(LOG_DEBUG, "Invalid digit '%c' in phonenumber.\n", number[i]);
return -1;
}
}
if((i % 2) == 0) {
param[2 + i/2] = d;
} else {
param[2 + (i - 1)/2] |= d << 4;
}
}
return 0;
}
/* Encode a phone number in ISUP "Called Party Number" format. (Q.763 (3.9))
Returns encoded length on success, -1 on error. */
int isup_called_party_num_encode(char *number, unsigned char *param,
int plen) {
int nlen;
int is_odd;
int is_international;
int result_len;
if(isup_phonenum_check(&number, &nlen, &is_international) == -1) {
return -1;
}
/* We terminate the number with ST to signify that the number is complete
(no overlapped dialing). Hence length is one more than nlen. */
is_odd = (nlen + 1) % 2;
/* Need room for two header bytes + all of the (nlen + 1) digits. */
result_len = 2 + (nlen + 2)/2;
if(result_len > plen) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?