Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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 */
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 */
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 
269  ast_channel_unregister(&test_bridging_chan_tech);
270  ao2_cleanup(test_bridging_chan_tech.capabilities);
271  test_bridging_chan_tech.capabilities = NULL;
272 
273  return 0;
274 }
275 
276 static int load_module(void)
277 {
279  if (!test_bridging_chan_tech.capabilities) {
281  }
282  ast_format_cap_append(test_bridging_chan_tech.capabilities, TEST_CHANNEL_FORMAT, 0);
283  ast_channel_register(&test_bridging_chan_tech);
284 
285  AST_TEST_REGISTER(test_bridging_deferred_queue);
286 
288 }
289 
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
static int load_module(void)
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
const char *const type
Definition: channel.h:630
Asterisk main include file. File version handling, generic pbx functions.
static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms)
#define TEST_CATEGORY
Definition: test_bridging.c:43
void * ast_channel_tech_pvt(const struct ast_channel *chan)
Time-related functions and macros.
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
#define START_ALICE(channel, pvt)
Create a test_bridging_chan_tech for Alice.
A private structure for the test channel.
Definition: test_bridging.c:50
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1584
static void wait_for_unbridged(struct ast_channel *channel)
Wait until a channel is not bridged.
Test Framework API.
enum ast_control_t38 request_response
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:970
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define ast_assert(a)
Definition: utils.h:695
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
Definition: muted.c:95
static void safe_bridge_destroy(struct ast_bridge *bridge)
#define NULL
Definition: resample.c:96
unsigned int indicated
The number of indicated things.
Definition: test_bridging.c:54
static void wait_for_bridged(struct ast_channel *channel)
Wait until a channel is bridged.
Definition: test_bridging.c:98
struct ast_readq_list * ast_channel_readq(struct ast_channel *chan)
#define CHANNEL_TECH_NAME
Definition: test_bridging.c:45
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:1924
General Asterisk PBX channel definitions.
#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:911
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:972
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1139
AST_TEST_DEFINE(test_bridging_deferred_queue)
#define HANGUP_CHANNEL(channel)
Hang up a test channel safely.
Structure that contains information about a bridge.
Definition: bridge.h:357
#define TEST_CHANNEL_FORMAT
Definition: test_bridging.c:47
static int unload_module(void)
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
int errno
static void wait_for_empty_queue(struct ast_channel *channel)
Wait until a channel has no frames on its read queue.
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1952
struct ast_format_cap * capabilities
Definition: channel.h:633
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10746
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
static void safe_channel_release(struct ast_channel *chan)
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Basic bridge subclass API.
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
struct ast_frame ast_null_frame
Definition: main/frame.c:79
static void test_nanosleep(int secs, long nanosecs)
Definition: test_bridging.c:89
struct ast_bridge * ast_bridge_basic_new(void)
Create a new basic class bridge.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_channel_tech test_bridging_chan_tech
A channel technology used for the unit tests.
Definition: test_bridging.c:81
Data structure associated with a single frame of data.
enum ast_frame_type frametype
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
#define START_BOB(channel, pvt)
Create a test_bridging_chan_tech for Bob.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Bridging API.
static int test_bridging_chan_hangup(struct ast_channel *chan)
Callback function for when a channel is hung up.
Definition: test_bridging.c:70
Asterisk module definitions.
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
Media Format Cache API.