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, &current);
  isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 1, 0);
  param[0] = count - 1;
  isup_msg_add_variable(msg, sizeof(msg), &varptr, &current, 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 + -
显示快捷键?