Wed Jan 8 2020 09:49:40

Asterisk developer's documentation


app_test.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  * Russell Bryant <russelb@clemson.edu>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*! \file
21  *
22  * \brief Applications to test connection and produce report in text file
23  *
24  * \author Mark Spencer <markster@digium.com>
25  * \author Russell Bryant <russelb@clemson.edu>
26  *
27  * \ingroup applications
28  */
29 
30 /*** MODULEINFO
31  <support_level>extended</support_level>
32  ***/
33 
34 #include "asterisk.h"
35 
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
37 
38 #include <sys/stat.h>
39 
40 #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
41 #include "asterisk/channel.h"
42 #include "asterisk/module.h"
43 #include "asterisk/lock.h"
44 #include "asterisk/app.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/utils.h"
47 
48 /*** DOCUMENTATION
49  <application name="TestServer" language="en_US">
50  <synopsis>
51  Execute Interface Test Server.
52  </synopsis>
53  <syntax />
54  <description>
55  <para>Perform test server function and write call report. Results stored in
56  <filename>/var/log/asterisk/testreports/&lt;testid&gt;-server.txt</filename></para>
57  </description>
58  <see-also>
59  <ref type="application">TestClient</ref>
60  </see-also>
61  </application>
62  <application name="TestClient" language="en_US">
63  <synopsis>
64  Execute Interface Test Client.
65  </synopsis>
66  <syntax>
67  <parameter name="testid" required="true">
68  <para>An ID to identify this test.</para>
69  </parameter>
70  </syntax>
71  <description>
72  <para>Executes test client with given <replaceable>testid</replaceable>. Results stored in
73  <filename>/var/log/asterisk/testreports/&lt;testid&gt;-client.txt</filename></para>
74  </description>
75  <see-also>
76  <ref type="application">TestServer</ref>
77  </see-also>
78  </application>
79  ***/
80 
81 static char *tests_app = "TestServer";
82 static char *testc_app = "TestClient";
83 
84 static int measurenoise(struct ast_channel *chan, int ms, char *who)
85 {
86  int res=0;
87  int mssofar;
88  int noise=0;
89  int samples=0;
90  int x;
91  short *foo;
92  struct timeval start;
93  struct ast_frame *f;
94  int rformat;
95  rformat = chan->readformat;
97  ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
98  return -1;
99  }
100  start = ast_tvnow();
101  for(;;) {
102  mssofar = ast_tvdiff_ms(ast_tvnow(), start);
103  if (mssofar > ms)
104  break;
105  res = ast_waitfor(chan, ms - mssofar);
106  if (res < 1)
107  break;
108  f = ast_read(chan);
109  if (!f) {
110  res = -1;
111  break;
112  }
113  if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.codec == AST_FORMAT_SLINEAR)) {
114  foo = (short *)f->data.ptr;
115  for (x=0;x<f->samples;x++) {
116  noise += abs(foo[x]);
117  samples++;
118  }
119  }
120  ast_frfree(f);
121  }
122 
123  if (rformat) {
124  if (ast_set_read_format(chan, rformat)) {
125  ast_log(LOG_NOTICE, "Unable to restore original format!\n");
126  return -1;
127  }
128  }
129  if (res < 0)
130  return res;
131  if (!samples) {
132  ast_log(LOG_NOTICE, "No samples were received from the other side!\n");
133  return -1;
134  }
135  ast_debug(1, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples);
136  return (noise / samples);
137 }
138 
139 static int sendnoise(struct ast_channel *chan, int ms)
140 {
141  int res;
142  res = ast_tonepair_start(chan, 1537, 2195, ms, 8192);
143  if (!res) {
144  res = ast_waitfordigit(chan, ms);
145  ast_tonepair_stop(chan);
146  }
147  return res;
148 }
149 
150 static int testclient_exec(struct ast_channel *chan, const char *data)
151 {
152  int res = 0;
153  const char *testid=data;
154  char fn[80];
155  char serverver[80];
156  FILE *f;
157 
158  /* Check for test id */
159  if (ast_strlen_zero(testid)) {
160  ast_log(LOG_WARNING, "TestClient requires an argument - the test id\n");
161  return -1;
162  }
163 
164  if (chan->_state != AST_STATE_UP)
165  res = ast_answer(chan);
166 
167  /* Wait a few just to be sure things get started */
168  res = ast_safe_sleep(chan, 3000);
169  /* Transmit client version */
170  if (!res)
171  res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0);
172  ast_debug(1, "Transmit client version\n");
173 
174  /* Read server version */
175  ast_debug(1, "Read server version\n");
176  if (!res)
177  res = ast_app_getdata(chan, NULL, serverver, sizeof(serverver) - 1, 0);
178  if (res > 0)
179  res = 0;
180  ast_debug(1, "server version: %s\n", serverver);
181 
182  if (res > 0)
183  res = 0;
184 
185  if (!res)
186  res = ast_safe_sleep(chan, 1000);
187  /* Send test id */
188  if (!res)
189  res = ast_dtmf_stream(chan, NULL, testid, 0, 0);
190  if (!res)
191  res = ast_dtmf_stream(chan, NULL, "#", 0, 0);
192  ast_debug(1, "send test identifier: %s\n", testid);
193 
194  if ((res >=0) && (!ast_strlen_zero(testid))) {
195  /* Make the directory to hold the test results in case it's not there */
196  snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
197  ast_mkdir(fn, 0777);
198  snprintf(fn, sizeof(fn), "%s/testresults/%s-client.txt", ast_config_AST_LOG_DIR, testid);
199  if ((f = fopen(fn, "w+"))) {
200  setlinebuf(f);
201  fprintf(f, "CLIENTCHAN: %s\n", chan->name);
202  fprintf(f, "CLIENTTEST ID: %s\n", testid);
203  fprintf(f, "ANSWER: PASS\n");
204  res = 0;
205 
206  if (!res) {
207  /* Step 1: Wait for "1" */
208  ast_debug(1, "TestClient: 2. Wait DTMF 1\n");
209  res = ast_waitfordigit(chan, 3000);
210  fprintf(f, "WAIT DTMF 1: %s\n", (res != '1') ? "FAIL" : "PASS");
211  if (res == '1')
212  res = 0;
213  else
214  res = -1;
215  }
216  if (!res) {
217  res = ast_safe_sleep(chan, 1000);
218  }
219  if (!res) {
220  /* Step 2: Send "2" */
221  ast_debug(1, "TestClient: 2. Send DTMF 2\n");
222  res = ast_dtmf_stream(chan, NULL, "2", 0, 0);
223  fprintf(f, "SEND DTMF 2: %s\n", (res < 0) ? "FAIL" : "PASS");
224  if (res > 0)
225  res = 0;
226  }
227  if (!res) {
228  /* Step 3: Wait one second */
229  ast_debug(1, "TestClient: 3. Wait one second\n");
230  res = ast_safe_sleep(chan, 1000);
231  fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS");
232  if (res > 0)
233  res = 0;
234  }
235  if (!res) {
236  /* Step 4: Measure noise */
237  ast_debug(1, "TestClient: 4. Measure noise\n");
238  res = measurenoise(chan, 5000, "TestClient");
239  fprintf(f, "MEASURENOISE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
240  if (res > 0)
241  res = 0;
242  }
243  if (!res) {
244  /* Step 5: Wait for "4" */
245  ast_debug(1, "TestClient: 5. Wait DTMF 4\n");
246  res = ast_waitfordigit(chan, 3000);
247  fprintf(f, "WAIT DTMF 4: %s\n", (res != '4') ? "FAIL" : "PASS");
248  if (res == '4')
249  res = 0;
250  else
251  res = -1;
252  }
253  if (!res) {
254  /* Step 6: Transmit tone noise */
255  ast_debug(1, "TestClient: 6. Transmit tone\n");
256  res = sendnoise(chan, 6000);
257  fprintf(f, "SENDTONE: %s\n", (res < 0) ? "FAIL" : "PASS");
258  }
259  if (!res || (res == '5')) {
260  /* Step 7: Wait for "5" */
261  ast_debug(1, "TestClient: 7. Wait DTMF 5\n");
262  if (!res)
263  res = ast_waitfordigit(chan, 3000);
264  fprintf(f, "WAIT DTMF 5: %s\n", (res != '5') ? "FAIL" : "PASS");
265  if (res == '5')
266  res = 0;
267  else
268  res = -1;
269  }
270  if (!res) {
271  /* Step 8: Wait one second */
272  ast_debug(1, "TestClient: 8. Wait one second\n");
273  res = ast_safe_sleep(chan, 1000);
274  fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS");
275  if (res > 0)
276  res = 0;
277  }
278  if (!res) {
279  /* Step 9: Measure noise */
280  ast_debug(1, "TestClient: 9. Measure tone\n");
281  res = measurenoise(chan, 4000, "TestClient");
282  fprintf(f, "MEASURETONE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
283  if (res > 0)
284  res = 0;
285  }
286  if (!res) {
287  /* Step 10: Send "7" */
288  ast_debug(1, "TestClient: 10. Send DTMF 7\n");
289  res = ast_dtmf_stream(chan, NULL, "7", 0, 0);
290  fprintf(f, "SEND DTMF 7: %s\n", (res < 0) ? "FAIL" : "PASS");
291  if (res > 0)
292  res =0;
293  }
294  if (!res) {
295  /* Step 11: Wait for "8" */
296  ast_debug(1, "TestClient: 11. Wait DTMF 8\n");
297  res = ast_waitfordigit(chan, 3000);
298  fprintf(f, "WAIT DTMF 8: %s\n", (res != '8') ? "FAIL" : "PASS");
299  if (res == '8')
300  res = 0;
301  else
302  res = -1;
303  }
304  if (!res) {
305  res = ast_safe_sleep(chan, 1000);
306  }
307  if (!res) {
308  /* Step 12: Hangup! */
309  ast_debug(1, "TestClient: 12. Hangup\n");
310  }
311 
312  ast_debug(1, "-- TEST COMPLETE--\n");
313  fprintf(f, "-- END TEST--\n");
314  fclose(f);
315  res = -1;
316  } else
317  res = -1;
318  } else {
319  ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", chan->name);
320  res = -1;
321  }
322  return res;
323 }
324 
325 static int testserver_exec(struct ast_channel *chan, const char *data)
326 {
327  int res = 0;
328  char testid[80]="";
329  char fn[80];
330  FILE *f;
331  if (chan->_state != AST_STATE_UP)
332  res = ast_answer(chan);
333  /* Read version */
334  ast_debug(1, "Read client version\n");
335  if (!res)
336  res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
337  if (res > 0)
338  res = 0;
339 
340  ast_debug(1, "client version: %s\n", testid);
341  ast_debug(1, "Transmit server version\n");
342 
343  res = ast_safe_sleep(chan, 1000);
344  if (!res)
345  res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0);
346  if (res > 0)
347  res = 0;
348 
349  if (!res)
350  res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
351  ast_debug(1, "read test identifier: %s\n", testid);
352  /* Check for sneakyness */
353  if (strchr(testid, '/'))
354  res = -1;
355  if ((res >=0) && (!ast_strlen_zero(testid))) {
356  /* Got a Test ID! Whoo hoo! */
357  /* Make the directory to hold the test results in case it's not there */
358  snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
359  ast_mkdir(fn, 0777);
360  snprintf(fn, sizeof(fn), "%s/testresults/%s-server.txt", ast_config_AST_LOG_DIR, testid);
361  if ((f = fopen(fn, "w+"))) {
362  setlinebuf(f);
363  fprintf(f, "SERVERCHAN: %s\n", chan->name);
364  fprintf(f, "SERVERTEST ID: %s\n", testid);
365  fprintf(f, "ANSWER: PASS\n");
366  ast_debug(1, "Processing Test ID '%s'\n", testid);
367  res = ast_safe_sleep(chan, 1000);
368  if (!res) {
369  /* Step 1: Send "1" */
370  ast_debug(1, "TestServer: 1. Send DTMF 1\n");
371  res = ast_dtmf_stream(chan, NULL, "1", 0,0 );
372  fprintf(f, "SEND DTMF 1: %s\n", (res < 0) ? "FAIL" : "PASS");
373  if (res > 0)
374  res = 0;
375  }
376  if (!res) {
377  /* Step 2: Wait for "2" */
378  ast_debug(1, "TestServer: 2. Wait DTMF 2\n");
379  res = ast_waitfordigit(chan, 3000);
380  fprintf(f, "WAIT DTMF 2: %s\n", (res != '2') ? "FAIL" : "PASS");
381  if (res == '2')
382  res = 0;
383  else
384  res = -1;
385  }
386  if (!res) {
387  /* Step 3: Measure noise */
388  ast_debug(1, "TestServer: 3. Measure noise\n");
389  res = measurenoise(chan, 6000, "TestServer");
390  fprintf(f, "MEASURENOISE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
391  if (res > 0)
392  res = 0;
393  }
394  if (!res) {
395  /* Step 4: Send "4" */
396  ast_debug(1, "TestServer: 4. Send DTMF 4\n");
397  res = ast_dtmf_stream(chan, NULL, "4", 0, 0);
398  fprintf(f, "SEND DTMF 4: %s\n", (res < 0) ? "FAIL" : "PASS");
399  if (res > 0)
400  res = 0;
401  }
402  if (!res) {
403  /* Step 5: Wait one second */
404  ast_debug(1, "TestServer: 5. Wait one second\n");
405  res = ast_safe_sleep(chan, 1000);
406  fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS");
407  if (res > 0)
408  res = 0;
409  }
410  if (!res) {
411  /* Step 6: Measure noise */
412  ast_debug(1, "TestServer: 6. Measure tone\n");
413  res = measurenoise(chan, 4000, "TestServer");
414  fprintf(f, "MEASURETONE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
415  if (res > 0)
416  res = 0;
417  }
418  if (!res) {
419  /* Step 7: Send "5" */
420  ast_debug(1, "TestServer: 7. Send DTMF 5\n");
421  res = ast_dtmf_stream(chan, NULL, "5", 0, 0);
422  fprintf(f, "SEND DTMF 5: %s\n", (res < 0) ? "FAIL" : "PASS");
423  if (res > 0)
424  res = 0;
425  }
426  if (!res) {
427  /* Step 8: Transmit tone noise */
428  ast_debug(1, "TestServer: 8. Transmit tone\n");
429  res = sendnoise(chan, 6000);
430  fprintf(f, "SENDTONE: %s\n", (res < 0) ? "FAIL" : "PASS");
431  }
432 
433  if (!res || (res == '7')) {
434  /* Step 9: Wait for "7" */
435  ast_debug(1, "TestServer: 9. Wait DTMF 7\n");
436  if (!res)
437  res = ast_waitfordigit(chan, 3000);
438  fprintf(f, "WAIT DTMF 7: %s\n", (res != '7') ? "FAIL" : "PASS");
439  if (res == '7')
440  res = 0;
441  else
442  res = -1;
443  }
444  if (!res) {
445  res = ast_safe_sleep(chan, 1000);
446  }
447  if (!res) {
448  /* Step 10: Send "8" */
449  ast_debug(1, "TestServer: 10. Send DTMF 8\n");
450  res = ast_dtmf_stream(chan, NULL, "8", 0, 0);
451  fprintf(f, "SEND DTMF 8: %s\n", (res < 0) ? "FAIL" : "PASS");
452  if (res > 0)
453  res = 0;
454  }
455  if (!res) {
456  /* Step 11: Wait for hangup to arrive! */
457  ast_debug(1, "TestServer: 11. Waiting for hangup\n");
458  res = ast_safe_sleep(chan, 10000);
459  fprintf(f, "WAIT HANGUP: %s\n", (res < 0) ? "PASS" : "FAIL");
460  }
461 
462  ast_log(LOG_NOTICE, "-- TEST COMPLETE--\n");
463  fprintf(f, "-- END TEST--\n");
464  fclose(f);
465  res = -1;
466  } else
467  res = -1;
468  } else {
469  ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", chan->name);
470  res = -1;
471  }
472  return res;
473 }
474 
475 static int unload_module(void)
476 {
477  int res;
478 
479  res = ast_unregister_application(testc_app);
480  res |= ast_unregister_application(tests_app);
481 
482  return res;
483 }
484 
485 static int load_module(void)
486 {
487  int res;
488 
491 
492  return res;
493 }
494 
495 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Interface Test Application");
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1916
union ast_frame_subclass subclass
Definition: frame.h:146
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
Definition: app.c:178
static char * testc_app
Definition: app_test.c:82
void * ptr
Definition: frame.h:160
#define LOG_WARNING
Definition: logger.h:144
static char * tests_app
Definition: app_test.c:81
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
static int testclient_exec(struct ast_channel *chan, const char *data)
Definition: app_test.c:150
for(;;)
Definition: ast_expr2.c:2460
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
format_t codec
Definition: frame.h:137
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
Utility functions.
int ast_set_read_format(struct ast_channel *chan, format_t format)
Sets read format on channel chan Set read format for channel to whichever component of &quot;format&quot; is be...
Definition: channel.c:5301
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Core PBX routines and definitions.
static int testserver_exec(struct ast_channel *chan, const char *data)
Definition: app_test.c:325
enum ast_channel_state _state
Definition: channel.h:839
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
const char * ast_config_AST_LOG_DIR
Definition: asterisk.c:263
static struct ast_format f[]
Definition: format_g726.c:181
static int load_module(void)
Definition: app_test.c:485
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3552
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
void ast_tonepair_stop(struct ast_channel *chan)
Definition: channel.c:7964
format_t readformat
Definition: channel.h:853
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Data structure associated with a single frame of data.
Definition: frame.h:142
static int measurenoise(struct ast_channel *chan, int ms, char *who)
Definition: app_test.c:84
int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
Definition: channel.c:7951
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_frfree(fr)
Definition: frame.h:583
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
Send DTMF to a channel.
Definition: app.c:501
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
union ast_frame::@172 data
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static int unload_module(void)
Definition: app_test.c:475
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int samples
Definition: frame.h:150
static int sendnoise(struct ast_channel *chan, int ms)
Definition: app_test.c:139
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2151