⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l4isup.c

📁 asterisk1.4.6版本下 7#信令驱动 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
{
  mtp_enqueue_isup_packet(pvt->link, pvt->cic, msg, msglen, MTP_REQ_ISUP);
}

static void mtp_enqueue_isup_forward(struct ss7_chan* pvt, unsigned char *msg, int msglen)
{
  mtp_enqueue_isup_packet(pvt->link, pvt->cic, msg, msglen, MTP_REQ_ISUP_FORWARD);
}

static struct ss7_chan* find_pvt(struct link* slink, int cic)
{
  struct linkset* ls;
  int lsi;

  ls = slink->linkset;
  if (ls->cic_list[cic])
    return ls->cic_list[cic];
  for (lsi = 0; lsi < n_linksets; lsi++)
    if (is_combined_linkset(ls, &linksets[lsi]))
      if (linksets[lsi].cic_list[cic])
	return linksets[lsi].cic_list[cic];
  return NULL;
}


/* This function must be called with the global lock mutex held. */
static void remove_from_idlelist(struct ss7_chan *pvt) {
  struct linkset* linkset = pvt->link->linkset;
  struct ss7_chan *prev, *cur;

  cur = linkset->idle_list;
  prev = NULL;
  while(cur != NULL) {
    if(pvt->cic == cur->cic) {
      if(prev == NULL) {
        linkset->idle_list = pvt->next_idle;
      } else {
        prev->next_idle = pvt->next_idle;
      }
      pvt->next_idle = NULL;
      return;
    }
    prev = cur;
    cur = cur->next_idle;
  }
  ast_log(LOG_NOTICE, "Trying to remove CIC=%d from idle list, but not "
          "found?!?.\n", pvt->cic);
}

/* This function must be called with the global lock mutex held. */
static void add_to_idlelist(struct ss7_chan *pvt) {
  struct linkset* linkset = pvt->link->linkset;
  struct ss7_chan *prev, *cur;

#if 1
  cur = linkset->idle_list;
  prev = NULL;
  while(cur != NULL) {
    if(pvt->cic == cur->cic) {
      ast_log(LOG_NOTICE, "Trying to add CIC=%d to idle list, but already there?!?\n", pvt->cic);
      return;
    }
    cur = cur->next_idle;
  }
#endif

  pvt->next_idle = linkset->idle_list;
  linkset->idle_list = pvt;
}

/* This implements hunting policy. It must be called with the global lock mutex
   held. */

/* This implements the policy: Primary hunting group odd CICs, secondary
   hunting group even CICs. Choose least recently used CIC. */
static struct ss7_chan *cic_hunt_odd_lru(struct linkset* linkset) {
  struct ss7_chan *cur, *prev, *best, *best_prev;
  int odd;

  best = NULL;
  best_prev = NULL;
  for(odd = 1; odd >= 0; odd--) {
    for(cur = linkset->idle_list, prev = NULL; cur != NULL; prev = cur, cur = cur->next_idle) {
      /* Don't select lines that are resetting or blocked. */
      if(!cur->reset_done || (cur->blocked & (BL_LH|BL_RM|BL_RH|BL_UNEQUIPPED|BL_LINKDOWN))) {
        continue;
      }
      if((cur->cic % 2) == odd) {
        best = cur;
        best_prev = prev;
      }
    }
    if(best != NULL) {
      if(best_prev == NULL) {
        linkset->idle_list = best->next_idle;
      } else {
        best_prev->next_idle = best->next_idle;
      }
      best->next_idle = NULL;
      return best;
    }
  }
  ast_log(LOG_WARNING, "No idle circuit found.\n");
  return NULL;
}

/* This implements the policy: Primary hunting group even CICs, secondary
   hunting group odd CICs. Choose most recently used CIC. */
static struct ss7_chan *cic_hunt_even_mru(struct linkset* linkset) {
  struct ss7_chan *cur, *prev, *best, *best_prev;

  best = NULL;
  best_prev = NULL;

  for(cur = linkset->idle_list, prev = NULL; cur != NULL; prev = cur, cur = cur->next_idle) {
    /* Don't select lines that are resetting or blocked. */
    if(!cur->reset_done || (cur->blocked & (BL_LH|BL_RM|BL_RH|BL_UNEQUIPPED|BL_LINKDOWN))) {
      continue;
    }
    if((cur->cic % 2) == 0) {
      /* Choose the first idle even circuit, if any. */
      best = cur;
      best_prev = prev;
      break;
    } else if(best == NULL) {
      /* Remember the first odd circuit, in case no even circuits are
         available. */
      best = cur;
      best_prev = prev;
    }
  }

  if(best != NULL) {
    if(best_prev == NULL) {
      linkset->idle_list = best->next_idle;
    } else {
      best_prev->next_idle = best->next_idle;
    }
    best->next_idle = NULL;
    return best;
  } else {
    ast_log(LOG_WARNING, "No idle circuit found.\n");
    return NULL;
  }
}

/* This implements the policy: Sequential low to high CICs */
static struct ss7_chan *cic_hunt_seq_lth_htl(struct linkset* linkset, int lth)
{
  struct ss7_chan *cur, *prev, *best = NULL, *best_prev = NULL;

  for(cur = linkset->idle_list, prev = NULL; cur != NULL; prev = cur, cur = cur->next_idle) {
    /* Don't select lines that are resetting or blocked. */
    if(!cur->reset_done || (cur->blocked & (BL_LH|BL_RM|BL_RH|BL_UNEQUIPPED|BL_LINKDOWN))) {
      continue;
    }
    if (!best) {
      best = cur;
      continue;
    }
    if (lth) {
      if (cur->cic < best->cic) {
	best = cur;
	best_prev = prev;
      }
    }
    else {
      if (cur->cic > best->cic) {
	best = cur;
	best_prev = prev;
      }
    }
  }

  if(best != NULL) {
    if(best_prev == NULL) {
      linkset->idle_list = best->next_idle;
    } else {
      best_prev->next_idle = best->next_idle;
    }
    best->next_idle = NULL;
    return best;
  } else {
    ast_log(LOG_WARNING, "No idle circuit found.\n");
    return NULL;
  }
}

/* Send a "release" message. */
static void isup_send_rel(struct ss7_chan *pvt, int cause) {
  unsigned char msg[MTP_MAX_PCK_SIZE];
  int current, varptr;
  unsigned char param[2];

  isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_REL, &current);
  isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 1, 1);
  param[0] = 0x85;              /* Last octet, ITU-T coding, private network */
  param[1] = 0x80 | (cause & 0x7f); /* Last octet */
  isup_msg_add_variable(msg, sizeof(msg), &varptr, &current, param, 2);
  isup_msg_start_optional_part(msg, sizeof(msg), &varptr, &current);
  isup_msg_end_optional_part(msg, sizeof(msg), &current);
  mtp_enqueue_isup(pvt, msg, current);
}

/* Send a "release confirmed" message. */
static void isup_send_rlc(struct ss7_chan* pvt) {
  unsigned char msg[MTP_MAX_PCK_SIZE];
  int current, varptr;
  int cic = pvt->cic;

  isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), cic, ISUP_RLC, &current);
  isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 0, 1);
  isup_msg_start_optional_part(msg, sizeof(msg), &varptr, &current);
  isup_msg_end_optional_part(msg, sizeof(msg), &current);
  mtp_enqueue_isup(pvt, msg, current);
}

/* Send a "reset circuit" message. */
static void isup_send_rsc(struct ss7_chan* pvt) {
  unsigned char msg[MTP_MAX_PCK_SIZE];
  int current, varptr;
  int cic = pvt->cic;

  isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), cic, ISUP_RSC, &current);
  isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 0, 0);
  mtp_enqueue_isup(pvt, msg, current);
}

/* Send an "address complete" message. */
static void isup_send_acm(struct ss7_chan* pvt) {
  unsigned char msg[MTP_MAX_PCK_SIZE];
  int current, varptr;
  unsigned char param[2];
  int cic = pvt->cic;

  isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), cic, ISUP_ACM, &current);
  param[0] = 0x12;
  param[1] = 0x14;
	   
  isup_msg_add_fixed(msg, sizeof(msg), &current, param, 2);
  if (pvt->has_inband_ind) {
    unsigned char param_opt_backw_ind[1];
    param_opt_backw_ind[0] = 0x01;
    isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 0, 1);
    isup_msg_start_optional_part(msg, sizeof(msg), &varptr, &current);
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_OPTIONAL_BACKWARD_CALL_INDICATORS,
			  param_opt_backw_ind, 1);
    isup_msg_end_optional_part(msg, sizeof(msg), &current);
  }
  else {
    isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 0, 1);
  }
  mtp_enqueue_isup(pvt, msg, current);
}

/* Send a "circuit group blocking" message. */
static void isup_send_cgb(struct ss7_chan* pvt, int mask) {
  int sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
  int cic = pvt->cic;

  if (pvt->equipped)
    sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
  else
    sup_type_ind = 0x01; /* Hardware failure oriented */
  do_group_circuit_block_unblock(pvt->link->linkset, cic, mask, sup_type_ind, 0, 0, 1);
}

/* Send a "circuit group unblocking" message. */
static void isup_send_cgu(struct ss7_chan* pvt, int mask) {
  int sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
  int cic = pvt->cic;

  if (pvt->equipped)
    sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
  else
    sup_type_ind = 0x01; /* Hardware failure oriented */
  do_group_circuit_block_unblock(pvt->link->linkset, cic, mask, sup_type_ind, 0, 0, 0);
}

/* Send a "blocked" message. */
static void isup_send_blk(struct ss7_chan *pvt)
{
  unsigned char msg[MTP_MAX_PCK_SIZE];
  int current, varptr;
  
  isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_BLK, &current);
  isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 0, 0);
  mtp_enqueue_isup(pvt, msg, current);
}

/* Reset circuit. Called with pvt->lock held */
static void reset_circuit(struct ss7_chan* pvt)
{
  isup_send_rsc(pvt);
  t16_start(pvt);
}

/* Initiate release circuit. Called with pvt->lock held */
static void initiate_release_circuit(struct ss7_chan* pvt, int cause)
{
  pvt->hangupcause = cause; /* Remember for REL retransmit */
  /* We sometimes get hangupcause=0 (seen when no match in dialplan, not
     even invalid handler). This doesn't work too well, for example
     ast_softhangup() doesn't actually hang up when hangupcause=0. */
  if(pvt->hangupcause == 0) {
    pvt->hangupcause = AST_CAUSE_NORMAL_CLEARING;
  }
  isup_send_rel(pvt, pvt->hangupcause);
  pvt->state = ST_SENT_REL;
  /* Set up timer T1 and T5 waiting for RLC. */
  t1_start(pvt);
  t5_start(pvt);
}

/* Setup a new channel, for an incoming or an outgoing call.
   Assumes called with global lock and pvt->lock held. */
static struct ast_channel *ss7_new(struct ss7_chan *pvt, int state, char* cid_num, char* exten) {
  struct ast_channel *chan;

#ifdef USE_ASTERISK_1_2
  chan = ast_channel_alloc(1);
  if(!chan) {
    return NULL;
  }
  snprintf(chan->name, sizeof(chan->name), "%s/%s/%d", type, pvt->link->linkset->name, pvt->cic);
  chan->type = type;
#else
  chan = ast_channel_alloc(1, state, cid_num, NULL, NULL, exten, pvt->context, 0, "%s/%s/%d", type, pvt->link->linkset->name, pvt->cic);
  ast_jb_configure(chan, ss7_get_global_jbconf());
  if(!chan) {
    return NULL;
  }
#endif

  chan->tech = &ss7_tech;
  chan->nativeformats = AST_FORMAT_ALAW;
  chan->rawreadformat = AST_FORMAT_ALAW;
  chan->rawwriteformat = AST_FORMAT_ALAW;
  chan->readformat = AST_FORMAT_ALAW;
  chan->writeformat = AST_FORMAT_ALAW;
  ast_setstate(chan, state);
  chan->fds[0] = pvt->zaptel_fd;

  chan->tech_pvt = pvt;
  pvt->owner = chan;

  incr_usecount();

  flushchannel(pvt->zaptel_fd, pvt->cic);
  pvt->lastread.tv_sec = pvt->lastread.tv_usec = 0;
  return chan;
}

/* hunt free CIC */
static struct ss7_chan* cic_hunt(struct linkset* linkset)
{
  struct ss7_chan* pvt;
  switch(linkset->hunt_policy) {
  case HUNT_ODD_LRU:
    pvt = cic_hunt_odd_lru(linkset);
    break;
  case HUNT_EVEN_MRU:
    pvt = cic_hunt_even_mru(linkset);
    break;
  case HUNT_SEQ_LTH:
    pvt = cic_hunt_seq_lth_htl(linkset, 1);
    break;
  case HUNT_SEQ_HTL:
    pvt = cic_hunt_seq_lth_htl(linkset, 0);
    break;
  default:
    pvt = NULL;
    ast_log(LOG_ERROR, "Internal error: invalid hunting policy %d.\n",
	    linkset->hunt_policy);
  }
  return pvt;
}

/* Request an SS7 channel. */
static struct ast_channel *ss7_requester(const char *type, int format,
                                         void *data, int *cause) {
  char *arg = data;
  struct ast_channel *chan;
  struct ss7_chan *pvt;
  struct linkset* linkset = this_host->default_linkset;
  char *sep = strchr(arg, '/');

  ast_log(LOG_DEBUG, "SS7 request (%s/%s) format = 0x%X.\n", type, arg, format);

  if(!(format & AST_FORMAT_ALAW)) {
    ast_log(LOG_NOTICE, "Audio format 0x%X not supported by SS7 channel.\n",
            format);
    return NULL;
  }
  if (sep) {
    char name_buf[100];
    strncpy(name_buf, arg, sep-arg);
    name_buf[sep-arg] = 0;
    linkset = lookup_linkset(name_buf);
    if (!linkset) {
      ast_log(LOG_ERROR, "SS7 requester: No such linkset: '%s', using default\n", name_buf);
      linkset = this_host->default_linkset;
    }
  }
  lock_global();
  pvt = cic_hunt(linkset);

  if(pvt == NULL) {
    unlock_global();
    *cause = AST_CAUSE_CONGESTION;
    ast_log(LOG_WARNING, "SS7 requester: No idle circuit available.\n");
    return NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -