[Asterisk-code-review] openr2(5/6): added cli command -- mfcr2 destroy link <index> (...asterisk[13])

Oron Peled asteriskteam at digium.com
Mon Jul 8 18:09:06 CDT 2019


Hello Tzafrir Cohen,

I'd like you to do a code review. Please visit

    https://gerrit.asterisk.org/c/asterisk/+/11537

to review the following change.


Change subject: openr2(5/6): added cli command -- mfcr2 destroy link <index>
......................................................................

openr2(5/6): added cli command -- mfcr2 destroy link <index>

Change-Id: I452d6a853bcd8c6e194455b19e5e017713e9c0fe
Signed-off-by: Oron Peled <oron.peled at xorcom.com>
---
M channels/chan_dahdi.c
1 file changed, 185 insertions(+), 24 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/37/11537/1

diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 282ce56..35d9f96 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -762,6 +762,7 @@
 	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 @@
 	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 @@
 }
 
 #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 @@
 	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);
@@ -5556,6 +5577,50 @@
 }
 #endif	/* defined(HAVE_SS7) */
 
+#if defined(HAVE_OPENR2)
+/*!
+ * \internal
+ * \brief Unlink the channel interface from the MFC/R2 private pointer array.
+ * \since 1.8
+ *
+ * \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 +5650,9 @@
 #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:
 		break;
@@ -11098,6 +11166,40 @@
 	}
 }
 
+#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);
 
@@ -11721,6 +11823,9 @@
 		}
 		ast_mutex_unlock(&iflock);
 		release_doomed_pris();
+#ifdef HAVE_OPENR2
+		dahdi_r2_destroy_nodev();
+#endif
 	}
 	/* Never reached */
 	pthread_cleanup_pop(1);
@@ -11907,21 +12012,17 @@
 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 */
@@ -12287,6 +12388,7 @@
 					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);
@@ -13852,6 +13954,8 @@
 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
@@ -13868,8 +13972,11 @@
 	/* 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
@@ -13878,20 +13985,23 @@
 		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) {
@@ -13918,8 +14028,11 @@
 		/* 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);
@@ -15223,6 +15336,51 @@
 	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"),
@@ -15232,6 +15390,7 @@
 	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 */
@@ -19567,13 +19726,15 @@
 		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);
 	}

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/11537
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Change-Id: I452d6a853bcd8c6e194455b19e5e017713e9c0fe
Gerrit-Change-Number: 11537
Gerrit-PatchSet: 1
Gerrit-Owner: Oron Peled <oron.peled at xorcom.com>
Gerrit-Reviewer: Tzafrir Cohen <tzafrir.cohen at xorcom.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190708/f49cd52e/attachment-0001.html>


More information about the asterisk-code-review mailing list