Asterisk - The Open Source Telephony Project  GIT-master-a24979a
test_bridging.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  * \brief Bridging unit tests
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  */
26 
27 /*** MODULEINFO
28  <depend>TEST_FRAMEWORK</depend>
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 #include "asterisk/module.h"
35 #include "asterisk/test.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/time.h"
38 #include "asterisk/bridge.h"
39 #include "asterisk/bridge_basic.h"
40 #include "asterisk/features.h"
41 #include "asterisk/format_cache.h"
42 
43 #define TEST_CATEGORY "/main/bridging/"
44 
45 #define CHANNEL_TECH_NAME "BridgingTestChannel"
46 
47 #define TEST_CHANNEL_FORMAT ast_format_slin
48 
49 /*! \brief A private structure for the test channel */
51  /*! \brief The expected indication */
52  int condition;
53  /*! \brief The number of indicated things */
54  unsigned int indicated;
55 };
56 
57 /*! \brief Callback function for when a frame is written to a channel */
58 static int test_bridging_chan_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
59 {
60  struct test_bridging_chan_pvt *test_pvt = ast_channel_tech_pvt(chan);
61 
62  if (condition == test_pvt->condition) {
63  test_pvt->indicated++;
64  }
65 
66  return 0;
67 }
68 
69 /*! \brief Callback function for when a channel is hung up */
70 static int test_bridging_chan_hangup(struct ast_channel *chan)
71 {
72  struct test_bridging_chan_pvt *test_pvt = ast_channel_tech_pvt(chan);
73 
74  ast_free(test_pvt);
76 
77  return 0;
78 }
79 
80 /*! \brief A channel technology used for the unit tests */
83  .description = "Mock channel technology for bridge tests",
84  .indicate = test_bridging_chan_indicate,
85  .hangup = test_bridging_chan_hangup,
86  .properties = AST_CHAN_TP_INTERNAL,
87 };
88 
89 static void test_nanosleep(int secs, long nanosecs)
90 {
91  struct timespec sleep_time = {secs, nanosecs};
92 
93  while ((nanosleep(&sleep_time, &sleep_time) == -1) && (errno == EINTR)) {
94  }
95 }
96 
97 /*! \brief Wait until a channel is bridged */
98 static void wait_for_bridged(struct ast_channel *channel)
99 {
100  ast_channel_lock(channel);
101  while (!ast_channel_is_bridged(channel)) {
102  ast_channel_unlock(channel);
103  test_nanosleep(0, 1000000);
104  ast_channel_lock(channel);
105  }
106  ast_channel_unlock(channel);
107 }
108 
109 /*! \brief Wait until a channel is not bridged */
110 static void wait_for_unbridged(struct ast_channel *channel)
111 {
112  ast_channel_lock(channel);
113  while (ast_channel_is_bridged(channel)) {
114  ast_channel_unlock(channel);
115  test_nanosleep(0, 1000000);
116  ast_channel_lock(channel);
117  }
118  ast_channel_unlock(channel);
119 }
120 
121 /*! \brief Wait until a channel has no frames on its read queue */
122 static void wait_for_empty_queue(struct ast_channel *channel)
123 {
124  ast_channel_lock(channel);
125  while (!AST_LIST_EMPTY(ast_channel_readq(channel))) {
126  ast_channel_unlock(channel);
127  test_nanosleep(0, 1000000);
128  ast_channel_lock(channel);
129  }
130  ast_channel_unlock(channel);
131 }
132 
133 /*! \brief Create a \ref test_bridging_chan_tech for Alice. */
134 #define START_ALICE(channel, pvt) START_CHANNEL(channel, pvt, "Alice", "100")
135 
136 /*! \brief Create a \ref test_bridging_chan_tech for Bob. */
137 #define START_BOB(channel, pvt) START_CHANNEL(channel, pvt, "Bob", "200")
138 
139 #define START_CHANNEL(channel, pvt, name, number) do { \
140  channel = ast_channel_alloc(0, AST_STATE_UP, number, name, number, number, \
141  "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/" name); \
142  pvt = ast_calloc(1, sizeof(*pvt)); \
143  ast_channel_tech_pvt_set(channel, pvt); \
144  ast_channel_nativeformats_set(channel, test_bridging_chan_tech.capabilities); \
145  ast_channel_set_rawwriteformat(channel, TEST_CHANNEL_FORMAT); \
146  ast_channel_set_rawreadformat(channel, TEST_CHANNEL_FORMAT); \
147  ast_channel_set_writeformat(channel, TEST_CHANNEL_FORMAT); \
148  ast_channel_set_readformat(channel, TEST_CHANNEL_FORMAT); \
149  ast_channel_unlock(channel); \
150  } while (0)
151 
152 /*! \brief Hang up a test channel safely */
153 #define HANGUP_CHANNEL(channel) do { \
154  ao2_ref(channel, +1); \
155  ast_hangup((channel)); \
156  ao2_cleanup(channel); \
157  channel = NULL; \
158  } while (0)
159 
160 static void safe_channel_release(struct ast_channel *chan)
161 {
162  if (!chan) {
163  return;
164  }
165  ast_channel_release(chan);
166 }
167 
168 static void safe_bridge_destroy(struct ast_bridge *bridge)
169 {
170  if (!bridge) {
171  return;
172  }
173  ast_bridge_destroy(bridge, 0);
174 }
175 
176 static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms)
177 {
178  long nanosecs;
179 
180  ast_assert(chan != NULL);
181  ast_assert(0 < ms);
182  ast_assert(0 < interval_ms);
183 
184  nanosecs = interval_ms * 1000000L;
185  while (0 < ms) {
187 
188  if (interval_ms < ms) {
189  ms -= interval_ms;
190  } else {
191  nanosecs = ms * 1000000L;
192  ms = 0;
193  }
194  test_nanosleep(0, nanosecs);
195  }
196 }
197 
198 AST_TEST_DEFINE(test_bridging_deferred_queue)
199 {
200  RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
201  struct test_bridging_chan_pvt *alice_pvt;
202  struct ast_control_t38_parameters t38_parameters = {
204  };
205  struct ast_frame frame = {
207  .subclass.integer = AST_CONTROL_T38_PARAMETERS,
208  .data.ptr = &t38_parameters,
209  .datalen = sizeof(t38_parameters),
210  };
211  RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
212  struct test_bridging_chan_pvt *bob_pvt;
213  RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
214 
215  switch (cmd) {
216  case TEST_INIT:
217  info->name = __func__;
218  info->category = TEST_CATEGORY;
219  info->summary = "Test that deferred frames from a channel in a bridge get written";
220  info->description =
221  "This test creates two channels, queues a deferrable frame on one, places it into\n"
222  "a bridge, confirms the frame was read by the bridge, adds the second channel to the\n"
223  "bridge, and makes sure the deferred frame is written to it.";
224  return AST_TEST_NOT_RUN;
225  case TEST_EXECUTE:
226  break;
227  }
228 
229  /* Create the bridges */
230  bridge1 = ast_bridge_basic_new();
231  ast_test_validate(test, bridge1 != NULL);
232 
233  /* Create channels that will go into the bridge */
234  START_ALICE(chan_alice, alice_pvt);
235  START_BOB(chan_bob, bob_pvt);
237 
238  /* Bridge alice and wait for the frame to be deferred */
239  ast_test_validate(test, !ast_bridge_impart(bridge1, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
240  wait_for_bridged(chan_alice);
241  ast_queue_frame(chan_alice, &frame);
242  wait_for_empty_queue(chan_alice);
243 
244  /* Bridge bob for a second so it can receive the deferred T.38 request negotiate frame */
245  ast_test_validate(test, !ast_bridge_impart(bridge1, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
246  wait_for_bridged(chan_bob);
247  stream_periodic_frames(chan_alice, 1000, 20);
248  ast_test_validate(test, !ast_bridge_depart(chan_bob));
249  wait_for_unbridged(chan_bob);
250 
251  /* Ensure that we received the expected indications while it was in there (request to negotiate, and to terminate) */
252  ast_test_validate(test, bob_pvt->indicated == 2);
253 
254  /* Now remove alice since we are done */
255  ast_test_validate(test, !ast_bridge_depart(chan_alice));
256  wait_for_unbridged(chan_alice);
257 
258  /* Hangup the channels */
259  HANGUP_CHANNEL(chan_alice);
260  HANGUP_CHANNEL(chan_bob);
261 
262  return AST_TEST_PASS;
263 }
264 
265 static int unload_module(void)
266 {
267  AST_TEST_UNREGISTER(test_bridging_deferred_queue);
268 
272 
273  return 0;
274 }
275 
276 static int load_module(void)
277 {
281  }
284 
285  AST_TEST_REGISTER(test_bridging_deferred_queue);
286 
288 }
289 
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
Bridging API.
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1906
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:944
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition: bridge.c:1878
@ AST_BRIDGE_IMPART_CHAN_DEPARTABLE
Definition: bridge.h:588
Basic bridge subclass API.
struct ast_bridge * ast_bridge_basic_new(void)
Create a new basic class bridge.
General Asterisk PBX channel definitions.
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1578
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2922
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1133
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10731
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:971
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:539
struct ast_readq_list * ast_channel_readq(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Media Format Cache API.
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
@ AST_T38_REQUEST_NEGOTIATE
@ AST_FRAME_CONTROL
@ AST_CONTROL_T38_PARAMETERS
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
int errno
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
def info(msg)
#define NULL
Definition: resample.c:96
Structure that contains information about a bridge.
Definition: bridge.h:349
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:628
struct ast_format_cap * capabilities
Definition: channel.h:632
const char *const type
Definition: channel.h:629
Main Channel structure associated with a channel.
enum ast_control_t38 request_response
Data structure associated with a single frame of data.
enum ast_frame_type frametype
A private structure for the test channel.
Definition: test_bridging.c:50
int condition
The expected indication.
Definition: test_bridging.c:52
unsigned int indicated
The number of indicated things.
Definition: test_bridging.c:54
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_NOT_RUN
Definition: test.h:194
#define TEST_CHANNEL_FORMAT
Definition: test_bridging.c:47
static void wait_for_empty_queue(struct ast_channel *channel)
Wait until a channel has no frames on its read queue.
static int test_bridging_chan_hangup(struct ast_channel *chan)
Callback function for when a channel is hung up.
Definition: test_bridging.c:70
static void safe_bridge_destroy(struct ast_bridge *bridge)
#define CHANNEL_TECH_NAME
Definition: test_bridging.c:45
static int test_bridging_chan_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Callback function for when a frame is written to a channel.
Definition: test_bridging.c:58
#define START_ALICE(channel, pvt)
Create a test_bridging_chan_tech for Alice.
static void safe_channel_release(struct ast_channel *chan)
static void wait_for_unbridged(struct ast_channel *channel)
Wait until a channel is not bridged.
static void test_nanosleep(int secs, long nanosecs)
Definition: test_bridging.c:89
static int load_module(void)
#define START_BOB(channel, pvt)
Create a test_bridging_chan_tech for Bob.
static int unload_module(void)
#define TEST_CATEGORY
Definition: test_bridging.c:43
static void wait_for_bridged(struct ast_channel *channel)
Wait until a channel is bridged.
Definition: test_bridging.c:98
static struct ast_channel_tech test_bridging_chan_tech
A channel technology used for the unit tests.
Definition: test_bridging.c:81
AST_TEST_DEFINE(test_bridging_deferred_queue)
#define HANGUP_CHANNEL(channel)
Hang up a test channel safely.
static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms)
Time-related functions and macros.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:936
#define ast_assert(a)
Definition: utils.h:734