From fdaefbb20a4aa6187634a6a78c6b68f74009b2b0 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen <tzafrir.cohen@xorcom.com> Date: Mon, 22 Apr 2019 22:14:32 +0300 Subject: [PATCH] openr2(5/6): added cli command -- mfcr2 destroy link <index> Change-Id: I452d6a853bcd8c6e194455b19e5e017713e9c0fe Signed-off-by: Oron Peled <oron.peled@xorcom.com> --- channels/chan_dahdi.c | 211 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 187 insertions(+), 24 deletions(-) diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index a5f0ed5f6a..7a199ae0f3 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -762,6 +762,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 */ }; @@ -771,6 +772,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; @@ -3615,6 +3618,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) { @@ -3700,6 +3718,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); @@ -5557,6 +5578,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) { @@ -5585,6 +5649,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: @@ -11099,6 +11166,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); @@ -11722,6 +11823,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); @@ -11908,21 +12012,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 */ @@ -12288,6 +12388,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); @@ -13853,6 +13954,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 @@ -13869,8 +13972,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 @@ -13879,20 +13986,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) { @@ -13919,8 +14030,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); @@ -15224,6 +15339,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"), @@ -15233,6 +15393,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 */ @@ -19568,13 +19729,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); } -- GitLab