Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Functions | Variables
app_waitforcond.c File Reference

Sleep until a condition is true. More...

#include "asterisk.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
Include dependency graph for app_waitforcond.c:

Go to the source code of this file.

Functions

 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "Wait until condition is true")
 
static int load_module (void)
 
static int unload_module (void)
 
static int waitforcond_exec (struct ast_channel *chan, const char *data)
 

Variables

static char * app = "WaitForCondition"
 

Detailed Description

Sleep until a condition is true.

Author
Naveen Albert aster.nosp@m.isk@.nosp@m.phrea.nosp@m.knet.nosp@m..org

Definition in file app_waitforcond.c.

Function Documentation

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"Wait until condition is true"   
)

◆ load_module()

static int load_module ( void  )
static

Definition at line 234 of file app_waitforcond.c.

235 {
237 }
static char * app
static int waitforcond_exec(struct ast_channel *chan, const char *data)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

References app, ast_register_application_xml, and waitforcond_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 229 of file app_waitforcond.c.

230 {
232 }
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References app, and ast_unregister_application().

◆ waitforcond_exec()

static int waitforcond_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 100 of file app_waitforcond.c.

101 {
102  int ms, i;
103  double timeout = 0, poll = 0;
104  int timeout_ms = 0;
105  int poll_ms = 50; /* default is evaluate the condition every 50ms */
106  struct timeval start = ast_tvnow();
107  char dollarsignrep;
108  int brackets = 0;
109  char *pos, *open_bracket, *expression, *optargs = NULL;
110  char condition[512];
111 
113  AST_APP_ARG(timeout);
114  AST_APP_ARG(interval);
115  );
116 
117  pos = ast_strdupa(data);
118 
119  if (ast_strlen_zero(pos)) {
120  ast_log(LOG_ERROR, "WaitForCondition requires a condition\n");
121  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");
122  return 0;
123  }
124 
125  /* is there at least a [ followed by a ] somewhere ? */
126  if (!(open_bracket = strchr(pos, '[')) || !strchr(open_bracket, ']')) {
127  ast_log(LOG_ERROR, "No expression detected. Did you forget to replace the $ signs?\n");
128  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");
129  return 0;
130  }
131 
132  dollarsignrep = pos[0];
133  if (dollarsignrep == '$' || dollarsignrep == '[' || dollarsignrep == ']'
134  || dollarsignrep == '{' || dollarsignrep == '}') {
135  ast_log(LOG_ERROR, "Dollar sign replacement cannot be %c.\n", dollarsignrep);
136  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");
137  return 0;
138  }
139  ++pos;
140  if (pos[0] != ',') {
141  ast_log(LOG_ERROR, "Invalid separator: %c\n", pos[0]);
142  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");
143  return 0;
144  }
145  ++pos;
146  if (pos[0] != dollarsignrep) {
147  ast_log(LOG_ERROR, "Expression start does not match provided replacement: %c\n", pos[0]);
148  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");
149  return 0;
150  }
151 
152  expression = pos; /* we're at the start of the expression */
153 
154  /* commas may appear within the expression, so go until we've encountered as many closing brackets as opening */
155  while (++pos) {
156  if (pos[0] == '\0') {
157  ast_log(LOG_ERROR, "Could not parse end of expression.\n");
158  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");
159  return 0;
160  }
161  if (pos[0] == '[') {
162  brackets++;
163  } else if (pos[0] == ']') {
164  brackets--;
165  }
166  if (brackets == 0) { /* reached end of expression */
167  break;
168  }
169  }
170  ++pos;
171  if (pos[0] != '\0') {
172  ++pos; /* eat comma separator */
173  if (pos[0] != '\0') {
174  optargs = ast_strdupa(pos);
175  AST_STANDARD_APP_ARGS(args, optargs);
176  if (!ast_strlen_zero(args.timeout)) {
177  if (sscanf(args.timeout, "%30lg", &timeout) != 1) {
178  ast_log(LOG_WARNING, "Invalid timeout provided: %s. No timeout set.\n", args.timeout);
179  return -1;
180  }
181  timeout_ms = timeout * 1000.0;
182  }
183 
184  if (!ast_strlen_zero(args.interval)) {
185  if (sscanf(args.interval, "%30lg", &poll) != 1) {
186  ast_log(LOG_WARNING, "Invalid polling interval provided: %s. Default unchanged.\n", args.interval);
187  return -1;
188  }
189  if (poll < 0.001) {
190  ast_log(LOG_WARNING, "Polling interval cannot be less than 1ms. Default unchanged.\n");
191  return -1;
192  }
193  poll_ms = poll * 1000.0;
194  }
195  }
196  }
197 
198  for (i = 0; expression[i] != '\0'; i++) {
199  if (expression[i] == dollarsignrep) {
200  expression[i] = '$'; /* replace $s back into expression for variable parsing */
201  }
202  }
203 
204  if (timeout_ms > 0) {
205  ast_debug(1, "Waiting for condition for %f seconds: %s (checking every %d ms)", timeout, expression, poll_ms);
206  } else {
207  ast_debug(1, "Waiting for condition, forever: %s (checking every %d ms)", expression, poll_ms);
208  }
209 
210  while (1) {
211  /* Substitute variables now */
212  pbx_substitute_variables_helper(chan, expression, condition, sizeof(condition) - 1);
213  if (pbx_checkcondition(condition)) {
214  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "TRUE");
215  return 0;
216  }
217  /* If a timeout was specified, check that it hasn't expired */
218  if ((timeout_ms > 0) && !(ms = ast_remaining_ms(start, timeout_ms))) {
219  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "TIMEOUT");
220  return 0;
221  }
222  if (ast_safe_sleep(chan, poll_ms)) { /* don't waste CPU, we don't need a super tight loop */
223  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "HANGUP");
224  return -1; /* channel hung up */
225  }
226  }
227 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1568
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int pbx_checkcondition(const char *condition)
Evaluate a condition.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
const char * args
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2179
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:157

References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log, ast_remaining_ms(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_tvnow(), LOG_ERROR, LOG_WARNING, NULL, pbx_builtin_setvar_helper(), pbx_checkcondition(), and pbx_substitute_variables_helper().

Referenced by load_module().

Variable Documentation

◆ app

char* app = "WaitForCondition"
static

Definition at line 98 of file app_waitforcond.c.

Referenced by load_module(), and unload_module().