Merge "openr2(5/6): added cli command -- mfcr2 destroy link <index>" into 16
This commit is contained in:
commit
d2a2131447
|
@ -749,6 +749,7 @@ struct dahdi_mfcr2 {
|
|||
openr2_context_t *protocol_context; /*!< OpenR2 context handle */
|
||||
struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
|
||||
int numchans; /*!< Number of channels in this R2 block */
|
||||
int live_chans; /*!< Number of unremoved channels in this R2 block */
|
||||
int nodev; /*!< Link disconnected? */
|
||||
struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
|
||||
};
|
||||
|
@ -758,6 +759,8 @@ struct r2link_entry {
|
|||
AST_LIST_ENTRY(r2link_entry) list;
|
||||
};
|
||||
static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
|
||||
static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
|
||||
|
||||
|
||||
/* how many r2links have been malloc'd */
|
||||
static int r2links_count = 0;
|
||||
|
@ -3548,6 +3551,21 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
|
|||
}
|
||||
|
||||
#ifdef HAVE_OPENR2
|
||||
static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
|
||||
{
|
||||
const struct dahdi_mfcr2 *r2link = p->mfcr2;
|
||||
struct r2link_entry *cur;
|
||||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
||||
if (r2link == &cur->mfcr2) {
|
||||
ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
|
||||
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
}
|
||||
|
||||
static int dahdi_r2_answer(struct dahdi_pvt *p)
|
||||
{
|
||||
|
@ -3633,6 +3651,9 @@ static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
|
|||
p->inalarm = alarm ? 1 : 0;
|
||||
if (p->inalarm) {
|
||||
res = get_alarms(p);
|
||||
if (res == DAHDI_ALARM_NOTOPEN) {
|
||||
mfcr2_queue_for_destruction(p);
|
||||
}
|
||||
handle_alarms(p, res);
|
||||
} else {
|
||||
handle_clear_alarms(p);
|
||||
|
@ -5490,6 +5511,49 @@ static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
|
|||
}
|
||||
#endif /* defined(HAVE_SS7) */
|
||||
|
||||
#if defined(HAVE_OPENR2)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Unlink the channel interface from the MFC/R2 private pointer array.
|
||||
*
|
||||
* \param pvt chan_dahdi private interface structure to unlink.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
|
||||
{
|
||||
unsigned idx;
|
||||
struct dahdi_mfcr2 *mfcr2;
|
||||
int should_destroy_link = 0;
|
||||
|
||||
ast_mutex_lock(&pvt->lock);
|
||||
if (pvt->r2chan) {
|
||||
ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
|
||||
openr2_chan_disable_read(pvt->r2chan);
|
||||
}
|
||||
mfcr2 = pvt->mfcr2;
|
||||
if (mfcr2) {
|
||||
for (idx = 0; idx < mfcr2->numchans; ++idx) {
|
||||
if (mfcr2->pvts[idx] == pvt) {
|
||||
ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
|
||||
mfcr2->pvts[idx] = NULL;
|
||||
mfcr2->live_chans--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mfcr2->live_chans) {
|
||||
ast_debug(1, "MFC/R2 link is now empty\n");
|
||||
should_destroy_link = 1;
|
||||
}
|
||||
}
|
||||
ast_mutex_unlock(&pvt->lock);
|
||||
if (should_destroy_link) {
|
||||
ast_debug(1, "MFC/R2 link is now empty\n");
|
||||
mfcr2_queue_for_destruction(pvt);
|
||||
}
|
||||
}
|
||||
#endif /* defined(HAVE_OPENR2) */
|
||||
|
||||
static struct dahdi_pvt *find_next_iface_in_span(struct dahdi_pvt *cur)
|
||||
{
|
||||
if (cur->next && cur->next->span == cur->span) {
|
||||
|
@ -5518,6 +5582,9 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
|
|||
#endif /* defined(HAVE_PRI) */
|
||||
#if defined(HAVE_SS7)
|
||||
dahdi_unlink_ss7_pvt(p);
|
||||
#endif /* defined(HAVE_SS7) */
|
||||
#if defined(HAVE_OPENR2)
|
||||
dahdi_unlink_mfcr2_pvt(p);
|
||||
#endif /* defined(HAVE_SS7) */
|
||||
switch (pvt->which_iflist) {
|
||||
case DAHDI_IFLIST_NONE:
|
||||
|
@ -11032,6 +11099,40 @@ static void dahdi_destroy_channel_range(int start, int end)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENR2
|
||||
static void dahdi_r2_destroy_nodev(void)
|
||||
{
|
||||
struct r2link_entry *cur;
|
||||
AST_LIST_LOCK(&nodev_r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
|
||||
int i;
|
||||
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
||||
ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
|
||||
for (i = 0; i < r2->numchans; i++) {
|
||||
int channel;
|
||||
struct dahdi_pvt *pvt = r2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
channel = pvt->channel;
|
||||
ast_debug(3, "About to destroy B-channel %d.\n", channel);
|
||||
dahdi_destroy_channel_range(channel, channel);
|
||||
}
|
||||
ast_debug(3, "Destroying R2 link\n");
|
||||
AST_LIST_REMOVE(&nodev_r2links, cur, list);
|
||||
if (r2->r2master != AST_PTHREADT_NULL) {
|
||||
pthread_cancel(r2->r2master);
|
||||
pthread_join(r2->r2master, NULL);
|
||||
r2->r2master = AST_PTHREADT_NULL;
|
||||
openr2_context_delete(r2->protocol_context);
|
||||
}
|
||||
ast_free(cur);
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&nodev_r2links);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int setup_dahdi(int reload);
|
||||
static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
|
||||
|
||||
|
@ -11655,6 +11756,9 @@ static void *do_monitor(void *data)
|
|||
}
|
||||
ast_mutex_unlock(&iflock);
|
||||
release_doomed_pris();
|
||||
#ifdef HAVE_OPENR2
|
||||
dahdi_r2_destroy_nodev();
|
||||
#endif
|
||||
}
|
||||
/* Never reached */
|
||||
pthread_cleanup_pop(1);
|
||||
|
@ -11841,21 +11945,17 @@ static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
|
|||
static void dahdi_r2_destroy_links(void)
|
||||
{
|
||||
struct r2link_entry *cur;
|
||||
|
||||
/* Queue everything for removal */
|
||||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
||||
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
||||
ast_debug(3, "Destroying R2 link\n");
|
||||
AST_LIST_REMOVE(&r2links, cur, list);
|
||||
if (r2->r2master != AST_PTHREADT_NULL) {
|
||||
pthread_cancel(r2->r2master);
|
||||
pthread_join(r2->r2master, NULL);
|
||||
openr2_context_delete(r2->protocol_context);
|
||||
}
|
||||
ast_free(cur);
|
||||
ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
|
||||
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
r2links_count = 0;
|
||||
/* Now destroy properly */
|
||||
dahdi_r2_destroy_nodev();
|
||||
}
|
||||
|
||||
/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
|
||||
|
@ -12189,6 +12289,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
destroy_dahdi_pvt(tmp);
|
||||
return NULL;
|
||||
}
|
||||
r2_link->live_chans++;
|
||||
tmp->mfcr2 = r2_link;
|
||||
if (conf->mfcr2.call_files) {
|
||||
openr2_chan_enable_call_files(tmp->r2chan);
|
||||
|
@ -13757,6 +13858,8 @@ static void dahdi_ss7_error(struct ss7 *ss7, char *s)
|
|||
static void *mfcr2_monitor(void *data)
|
||||
{
|
||||
struct dahdi_mfcr2 *mfcr2 = data;
|
||||
struct dahdi_pvt *pvt;
|
||||
|
||||
/* we should be using pthread_key_create
|
||||
and allocate pollers dynamically.
|
||||
I think do_monitor() could be leaking, since it
|
||||
|
@ -13773,8 +13876,12 @@ static void *mfcr2_monitor(void *data)
|
|||
/* now that we're ready to get calls, unblock our side and
|
||||
get current line state */
|
||||
for (i = 0; i < mfcr2->numchans; i++) {
|
||||
openr2_chan_set_idle(mfcr2->pvts[i]->r2chan);
|
||||
openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);
|
||||
pvt = mfcr2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
openr2_chan_set_idle(pvt->r2chan);
|
||||
openr2_chan_handle_cas(pvt->r2chan);
|
||||
}
|
||||
while (1) {
|
||||
/* we trust here that the mfcr2 channel list will not ever change once
|
||||
|
@ -13783,20 +13890,24 @@ static void *mfcr2_monitor(void *data)
|
|||
for (i = 0; i < mfcr2->numchans; i++) {
|
||||
pollers[i].revents = 0;
|
||||
pollers[i].events = 0;
|
||||
if (mfcr2->pvts[i]->owner) {
|
||||
pvt = mfcr2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
if (pvt->owner) {
|
||||
continue;
|
||||
}
|
||||
if (mfcr2->nodev) {
|
||||
continue;
|
||||
}
|
||||
if (!mfcr2->pvts[i]->r2chan) {
|
||||
ast_debug(1, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);
|
||||
if (!pvt->r2chan) {
|
||||
ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
|
||||
quit_loop = 1;
|
||||
break;
|
||||
}
|
||||
openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);
|
||||
openr2_chan_enable_read(pvt->r2chan);
|
||||
pollers[i].events = POLLIN | POLLPRI;
|
||||
pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;
|
||||
pollers[i].fd = pvt->subs[SUB_REAL].dfd;
|
||||
pollsize++;
|
||||
}
|
||||
if (quit_loop) {
|
||||
|
@ -13823,8 +13934,12 @@ static void *mfcr2_monitor(void *data)
|
|||
/* do we want to allow to cancel while processing events? */
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
for (i = 0; i < mfcr2->numchans; i++) {
|
||||
pvt = mfcr2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
|
||||
openr2_chan_process_event(mfcr2->pvts[i]->r2chan);
|
||||
openr2_chan_process_event(pvt->r2chan);
|
||||
}
|
||||
}
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
|
||||
|
@ -15128,6 +15243,51 @@ static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct as
|
|||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
int res;
|
||||
int wanted_link_index;
|
||||
int found_link = 0;
|
||||
struct r2link_entry *cur = NULL;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "mfcr2 destroy link";
|
||||
e->usage =
|
||||
"Usage: mfcr2 destroy link <index-number>\n"
|
||||
" Destorys D-channel of link and its B-channels.\n"
|
||||
" DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
if (a->argc < 4) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
res = sscanf(a->argv[3], "%30d", &wanted_link_index);
|
||||
if ((res != 1) || wanted_link_index < 1) {
|
||||
ast_cli(a->fd,
|
||||
"Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
||||
struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
|
||||
if (wanted_link_index == mfcr2->index) {
|
||||
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
||||
r2links_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
if (! found_link) {
|
||||
ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static struct ast_cli_entry dahdi_mfcr2_cli[] = {
|
||||
AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
|
||||
|
@ -15137,6 +15297,7 @@ static struct ast_cli_entry dahdi_mfcr2_cli[] = {
|
|||
AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
|
||||
};
|
||||
|
||||
#endif /* HAVE_OPENR2 */
|
||||
|
@ -19444,13 +19605,15 @@ static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, str
|
|||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE(&r2links, cur, list) {
|
||||
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
||||
if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
|
||||
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
|
||||
return -1;
|
||||
} else {
|
||||
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
|
||||
if (r2->r2master == AST_PTHREADT_NULL) {
|
||||
if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
|
||||
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
|
||||
return -1;
|
||||
} else {
|
||||
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue