122 static const char *
const app =
"Signal";
123 static const char *
const app2 =
"WaitForSignal";
128 int sig_alert_pipe[2];
130 unsigned int signaled:1;
137 static struct signalitem *alloc_signal(
const char *sname)
145 ast_mutex_init(&s->lock);
148 s->sig_alert_pipe[0] = -1;
149 s->sig_alert_pipe[1] = -1;
157 static int dealloc_signal(
struct signalitem *s)
160 ast_debug(1,
"Signal '%s' is still being used by %d listener(s)\n", s->name, s->watchers);
164 ast_mutex_destroy(&s->lock);
166 ast_free(s->payload);
174 static int remove_signal(
char *sname)
180 if (!strcmp(s->name, sname)) {
182 res = dealloc_signal(s);
183 ast_debug(1,
"Removed signal '%s'\n", sname);
191 static struct signalitem *get_signal(
char *sname,
int addnew)
196 if (!strcasecmp(s->name, sname)) {
197 ast_debug(1,
"Using existing signal item '%s'\n", sname);
203 s = alloc_signal(sname);
206 ast_debug(1,
"Created new signal item '%s'\n", sname);
209 ast_log(LOG_WARNING,
"Failed to create signal item for '%s'\n", sname);
212 ast_debug(1,
"Signal '%s' doesn't exist, and not creating it\n", sname);
219 static int wait_for_signal_or_hangup(
struct ast_channel *chan,
char *signame,
int timeout)
222 int ms, remaining_time, res = 1, goaway = 0;
223 struct timeval start;
226 remaining_time = timeout;
229 s = get_signal(signame, 1);
231 ast_mutex_lock(&s->lock);
232 s->watchers = s->watchers + 1;
233 ast_mutex_unlock(&s->lock);
235 while (timeout == 0 || remaining_time > 0) {
242 ast_debug(1,
"Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
248 }
else if (ofd == s->sig_alert_pipe[0]) {
250 ast_debug(1,
"Alert pipe has data for us\n");
254 ast_debug(1,
"Alert pipe does not have data for us\n");
257 if (ms && (ofd < 0)) {
258 if (!((errno == 0) || (errno == EINTR))) {
259 ast_log(LOG_WARNING,
"Something bad happened while channel '%s' was polling.\n", ast_channel_name(chan));
271 ast_mutex_lock(&s->lock);
275 s->watchers = s->watchers - 1;
277 int save_errno = errno;
279 ast_log(LOG_WARNING,
"%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
285 ast_mutex_unlock(&s->lock);
289 remove_signal(signame);
296 static int send_signal(
char *signame,
char *payload)
299 int save_errno = errno;
302 s = get_signal(signame, 0);
309 ast_mutex_lock(&s->lock);
311 if (payload && *payload) {
312 int len = strlen(payload);
314 ast_free(s->payload);
319 ast_log(LOG_WARNING,
"Failed to allocate signal payload '%s'\n", payload);
325 ast_log(LOG_WARNING,
"%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
330 ast_debug(1,
"Sent '%s' signal to %d listeners\n", signame, s->watchers);
331 ast_mutex_unlock(&s->lock);
336 static int waitsignal_exec(
struct ast_channel *chan,
const char *data)
339 int r = 0, timeoutms = 0;
347 if (ast_strlen_zero(data)) {
348 ast_log(LOG_WARNING,
"Signal() requires arguments\n");
355 if (ast_strlen_zero(args.signame)) {
356 ast_log(LOG_WARNING,
"Missing signal name\n");
360 ast_log(LOG_WARNING,
"Signal name '%s' is too long\n", args.signame);
363 if (!ast_strlen_zero(args.sigtimeout)) {
364 if (sscanf(args.sigtimeout,
"%30lg", &timeout) != 1 || timeout < 0) {
365 ast_log(LOG_WARNING,
"Invalid timeout provided: %s. Defaulting to no timeout.\n", args.sigtimeout);
367 timeoutms = timeout * 1000;
372 ast_debug(1,
"Waiting for signal '%s' for %d ms\n", args.signame, timeoutms);
374 ast_debug(1,
"Waiting for signal '%s', indefinitely\n", args.signame);
377 r = wait_for_signal_or_hangup(chan, args.signame, timeoutms);
380 ast_verb(3,
"Channel '%s' timed out, waiting for signal '%s'\n", ast_channel_name(chan), args.signame);
383 ast_verb(3,
"Received signal '%s' on channel '%s'\n", args.signame, ast_channel_name(chan));
387 ast_verb(3,
"Channel '%s' hung up\n", ast_channel_name(chan));
394 static int signal_exec(
struct ast_channel *chan,
const char *data)
402 if (ast_strlen_zero(data)) {
403 ast_log(LOG_WARNING,
"Signal() requires arguments\n");
410 if (ast_strlen_zero(args.signame)) {
411 ast_log(LOG_WARNING,
"Missing signal name\n");
415 ast_log(LOG_WARNING,
"Signal name '%s' is too long\n", args.signame);
419 if (send_signal(args.signame, args.payload)) {
428 static int unload_module(
void)
440 int mres = dealloc_signal(s);
451 ast_log(LOG_WARNING,
"One or more signals is currently in use. Unload failed.\n");
461 static int load_module(
void)
471 AST_MODULE_INFO_STANDARD_EXTENDED(
ASTERISK_GPL_KEY,
"Channel Signaling Applications");
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
void ast_alertpipe_close(int alert_pipe[2])
Close an alert pipe.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_unregister_application(const char *app)
Unregister an application.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
struct signalitem::@62 entry
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
ast_alert_status_t ast_alertpipe_read(int alert_pipe[2])
Read an event from an alert pipe.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
Core PBX routines and definitions.
int ast_alertpipe_init(int alert_pipe[2])
Initialize an alert pipe.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define ast_calloc(num, len)
A wrapper for calloc()
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...
ssize_t ast_alertpipe_write(int alert_pipe[2])
Write an event to an alert pipe.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Data structure associated with a single frame of data.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Structure for mutex and tracking information.
#define AST_APP_ARG(name)
Define an application argument.