summaryrefslogtreecommitdiff
path: root/main/bridge_channel.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-06-08 19:38:51 +0000
committerJoshua Colp <jcolp@digium.com>2017-06-13 17:06:15 -0500
commitd6386a8f0ca635ba770c1d102f69361beebef7d6 (patch)
tree33a51988fc9400a2993dcce7a8287852004eddb0 /main/bridge_channel.c
parentabe1dd303909416a1b57747bdb162b82fb08f72b (diff)
bridge: Add a deferred queue.
This change adds a deferred queue to bridging. If a bridge technology determines that a frame can not be written and should be deferred it can indicate back to bridging to do so. Bridging will then requeue any deferred frames upon a new channel joining the bridge. This change has been leveraged for T.38 request negotiate control frames. Without the deferred queue there is a race condition between the bridge receiving the T.38 request negotiate and the second channel joining and being in the bridge. If the channel is not yet in the bridge then the T.38 negotiation fails. A unit test has also been added that confirms that a T.38 request negotiate control frame is deferred when no other channel is in the bridge and that it is requeued when a new channel joins the bridge. ASTERISK-26923 Change-Id: Ie05b08523f399eae579130f4a5f562a344d2e415
Diffstat (limited to 'main/bridge_channel.c')
-rw-r--r--main/bridge_channel.c36
1 files changed, 28 insertions, 8 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 02783b103..e8ab8a898 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -638,18 +638,21 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int caus
static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
const struct ast_control_t38_parameters *t38_parameters;
+ int deferred;
ast_assert(frame->frametype != AST_FRAME_BRIDGE_ACTION_SYNC);
ast_bridge_channel_lock_bridge(bridge_channel);
-/*
- * XXX need to implement a deferred write queue for when there
- * is no peer channel in the bridge (yet or it was kicked).
- *
- * The tech decides if a frame needs to be pushed back for deferral.
- * simple_bridge/native_bridge are likely the only techs that will do this.
- */
- bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
+
+ deferred = bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
+ if (deferred) {
+ struct ast_frame *dup;
+
+ dup = ast_frdup(frame);
+ if (dup) {
+ AST_LIST_INSERT_HEAD(&bridge_channel->deferred_queue, dup, frame_list);
+ }
+ }
/* Remember any owed events to the bridge. */
switch (frame->frametype) {
@@ -753,6 +756,18 @@ void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct as
}
}
+void bridge_channel_queue_deferred_frames(struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_frame *frame;
+
+ ast_channel_lock(bridge_channel->chan);
+ while ((frame = AST_LIST_REMOVE_HEAD(&bridge_channel->deferred_queue, frame_list))) {
+ ast_queue_frame_head(bridge_channel->chan, frame);
+ ast_frfree(frame);
+ }
+ ast_channel_unlock(bridge_channel->chan);
+}
+
/*!
* \internal
* \brief Suspend a channel from a bridge.
@@ -2933,6 +2948,11 @@ static void bridge_channel_destroy(void *obj)
}
ast_alertpipe_close(bridge_channel->alert_pipe);
+ /* Flush any unhandled deferred_queue frames. */
+ while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->deferred_queue, frame_list))) {
+ ast_frfree(fr);
+ }
+
ast_cond_destroy(&bridge_channel->cond);
ao2_cleanup(bridge_channel->write_format);