Asterisk - The Open Source Telephony Project GIT-master-7805f28
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Functions | Variables
app_signal.c File Reference

Channel signaling applications. More...

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

Go to the source code of this file.

Data Structures

struct  signalitem
 
struct  signals
 

Functions

static struct signalitemalloc_signal (const char *sname)
 
 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "Channel Signaling Applications")
 
static int dealloc_signal (struct signalitem *s)
 
static struct signalitemget_signal (char *sname, int addnew)
 
static int load_module (void)
 
static int remove_signal (char *sname)
 
static int send_signal (char *signame, char *payload)
 
static int signal_exec (struct ast_channel *chan, const char *data)
 
static int unload_module (void)
 
static int wait_for_signal_or_hangup (struct ast_channel *chan, char *signame, int timeout)
 
static int waitsignal_exec (struct ast_channel *chan, const char *data)
 

Variables

static const char *const app = "Signal"
 
static const char *const app2 = "WaitForSignal"
 
static struct signals signals = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 

Detailed Description

Channel signaling applications.

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

Definition in file app_signal.c.

Function Documentation

◆ alloc_signal()

static struct signalitem * alloc_signal ( const char *  sname)
static

Definition at line 145 of file app_signal.c.

146{
147 struct signalitem *s;
148
149 if (!(s = ast_calloc(1, sizeof(*s)))) {
150 return NULL;
151 }
152
153 ast_mutex_init(&s->lock);
154 ast_copy_string(s->name, sname, sizeof(s->name));
155
156 s->sig_alert_pipe[0] = -1;
157 s->sig_alert_pipe[1] = -1;
158 s->watchers = 0;
159 s->payload = NULL;
161
162 return s;
163}
int ast_alertpipe_init(int alert_pipe[2])
Initialize an alert pipe.
Definition: alertpipe.c:38
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_mutex_init(pmutex)
Definition: lock.h:193
#define NULL
Definition: resample.c:96
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * payload
Definition: app_signal.c:139
int sig_alert_pipe[2]
Definition: app_signal.c:136
int watchers
Definition: app_signal.c:137
char name[AST_MAX_CONTEXT]
Definition: app_signal.c:135
ast_mutex_t lock
Definition: app_signal.c:134

References ast_alertpipe_init(), ast_calloc, ast_copy_string(), ast_mutex_init, signalitem::lock, signalitem::name, NULL, signalitem::payload, signalitem::sig_alert_pipe, and signalitem::watchers.

Referenced by get_signal().

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"Channel Signaling Applications"   
)

◆ dealloc_signal()

static int dealloc_signal ( struct signalitem s)
static

Definition at line 165 of file app_signal.c.

166{
167 if (s->watchers) { /* somebody is still using us... refuse to go away */
168 ast_debug(1, "Signal '%s' is still being used by %d listener(s)\n", s->name, s->watchers);
169 return -1;
170 }
173 if (s->payload) {
174 ast_free(s->payload);
175 s->payload = NULL;
176 }
177 ast_free(s);
178 s = NULL;
179 return 0;
180}
void ast_alertpipe_close(int alert_pipe[2])
Close an alert pipe.
Definition: alertpipe.c:79
#define ast_free(a)
Definition: astmm.h:180
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_mutex_destroy(a)
Definition: lock.h:195

References ast_alertpipe_close(), ast_debug, ast_free, ast_mutex_destroy, signalitem::lock, signalitem::name, NULL, signalitem::payload, signalitem::sig_alert_pipe, and signalitem::watchers.

Referenced by remove_signal(), and unload_module().

◆ get_signal()

static struct signalitem * get_signal ( char *  sname,
int  addnew 
)
static

Definition at line 199 of file app_signal.c.

200{
201 struct signalitem *s = NULL;
204 if (!strcasecmp(s->name, sname)) {
205 ast_debug(1, "Using existing signal item '%s'\n", sname);
206 break;
207 }
208 }
209 if (!s) {
210 if (addnew) { /* signal doesn't exist, so create it */
211 s = alloc_signal(sname);
212 /* Totally fail if we fail to find/create an entry */
213 if (s) {
214 ast_debug(1, "Created new signal item '%s'\n", sname);
216 } else {
217 ast_log(LOG_WARNING, "Failed to create signal item for '%s'\n", sname);
218 }
219 } else {
220 ast_debug(1, "Signal '%s' doesn't exist, and not creating it\n", sname);
221 }
222 }
224 return s;
225}
static struct signalitem * alloc_signal(const char *sname)
Definition: app_signal.c:145
#define ast_log
Definition: astobj2.c:42
#define LOG_WARNING
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
struct signalitem::@62 entry

References alloc_signal(), ast_debug, AST_LIST_TRAVERSE, ast_log, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, signalitem::entry, LOG_WARNING, signalitem::name, and NULL.

Referenced by send_signal(), and wait_for_signal_or_hangup().

◆ load_module()

static int load_module ( void  )
static

Definition at line 469 of file app_signal.c.

470{
471 int res;
472
475
476 return res;
477}
static int signal_exec(struct ast_channel *chan, const char *data)
Definition: app_signal.c:402
static int waitsignal_exec(struct ast_channel *chan, const char *data)
Definition: app_signal.c:344
static const char *const app
Definition: app_signal.c:130
static const char *const app2
Definition: app_signal.c:131
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640

References app, app2, ast_register_application_xml, signal_exec(), and waitsignal_exec().

◆ remove_signal()

static int remove_signal ( char *  sname)
static

Definition at line 182 of file app_signal.c.

183{
184 int res = -1;
185 struct signalitem *s;
186
188 if (!strcmp(s->name, sname)) {
190 res = dealloc_signal(s);
191 ast_debug(1, "Removed signal '%s'\n", sname);
192 }
193 }
195
196 return res;
197}
static int dealloc_signal(struct signalitem *s)
Definition: app_signal.c:165
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557

References ast_debug, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, dealloc_signal(), signalitem::entry, and signalitem::name.

Referenced by wait_for_signal_or_hangup().

◆ send_signal()

static int send_signal ( char *  signame,
char *  payload 
)
static

Definition at line 304 of file app_signal.c.

305{
306 struct signalitem *s;
307 int save_errno = errno;
308 int res = 0;
309
310 s = get_signal(signame, 0); /* if signal doesn't exist already, no point in creating it, because nobody could be waiting for it! */
311
312 if (!s) {
313 return -1; /* this signal didn't exist, so we can't send a signal for it */
314 }
315
316 /* at this point, we know someone is listening, since signals are destroyed when watchers gets down to 0 */
317 ast_mutex_lock(&s->lock);
318 s->signaled = 1;
319 if (payload && *payload) {
320 int len = strlen(payload);
321 if (s->payload) {
322 ast_free(s->payload); /* if there was already a payload, replace it */
323 s->payload = NULL;
324 }
325 s->payload = ast_malloc(len + 1);
326 if (!s->payload) {
327 ast_log(LOG_WARNING, "Failed to allocate signal payload '%s'\n", payload);
328 } else {
330 }
331 }
333 ast_log(LOG_WARNING, "%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
334 s->signaled = 0; /* okay, so we didn't send a signal after all... */
335 res = -1;
336 }
337 errno = save_errno;
338 ast_debug(1, "Sent '%s' signal to %d listeners\n", signame, s->watchers);
340
341 return res;
342}
ssize_t ast_alertpipe_write(int alert_pipe[2])
Write an event to an alert pipe.
Definition: alertpipe.c:120
static struct signalitem * get_signal(char *sname, int addnew)
Definition: app_signal.c:199
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_mutex_unlock(a)
Definition: lock.h:197
#define ast_mutex_lock(a)
Definition: lock.h:196
int errno
unsigned int signaled
Definition: app_signal.c:138

References ast_alertpipe_write(), ast_copy_string(), ast_debug, ast_free, ast_log, ast_malloc, ast_mutex_lock, ast_mutex_unlock, errno, get_signal(), len(), signalitem::lock, LOG_WARNING, NULL, signalitem::payload, signalitem::sig_alert_pipe, signalitem::signaled, and signalitem::watchers.

Referenced by signal_exec().

◆ signal_exec()

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

Definition at line 402 of file app_signal.c.

403{
404 char *argcopy;
406 AST_APP_ARG(signame);
407 AST_APP_ARG(payload);
408 );
409
410 if (ast_strlen_zero(data)) {
411 ast_log(LOG_WARNING, "Signal() requires arguments\n");
412 return -1;
413 }
414
415 argcopy = ast_strdupa(data);
416 AST_STANDARD_APP_ARGS(args, argcopy);
417
418 if (ast_strlen_zero(args.signame)) {
419 ast_log(LOG_WARNING, "Missing signal name\n");
420 return -1;
421 }
422 if (strlen(args.signame) >= AST_MAX_CONTEXT) {
423 ast_log(LOG_WARNING, "Signal name '%s' is too long\n", args.signame);
424 return -1;
425 }
426
427 if (send_signal(args.signame, args.payload)) {
428 pbx_builtin_setvar_helper(chan, "SIGNALSTATUS", "FAILURE");
429 } else {
430 pbx_builtin_setvar_helper(chan, "SIGNALSTATUS", "SUCCESS");
431 }
432
433 return 0;
434}
static int send_signal(char *signame, char *payload)
Definition: app_signal.c:304
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define AST_MAX_CONTEXT
Definition: channel.h:135
#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.
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.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
const char * args

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_MAX_CONTEXT, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, signalitem::payload, pbx_builtin_setvar_helper(), and send_signal().

Referenced by load_module().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 436 of file app_signal.c.

437{
438 struct signalitem *s;
439 int res = 0;
440
441 /* To avoid a locking nightmare, and for logistical reasons, this module
442 * will refuse to unload if watchers > 0. That way we know a signal's
443 * pipe won't disappear while it's being used. */
444
446 /* Don't just use AST_RWLIST_REMOVE_HEAD, because if dealloc_signal fails, it should stay in the list. */
448 int mres = dealloc_signal(s);
449 res |= mres;
450 if (!mres) {
452 }
453 }
456
457 /* One or more signals still has watchers. */
458 if (res) {
459 ast_log(LOG_WARNING, "One or more signals is currently in use. Unload failed.\n");
460 return res;
461 }
462
465
466 return res;
467}
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References app, app2, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_unregister_application(), dealloc_signal(), signalitem::entry, and LOG_WARNING.

◆ wait_for_signal_or_hangup()

static int wait_for_signal_or_hangup ( struct ast_channel chan,
char *  signame,
int  timeout 
)
static

Definition at line 227 of file app_signal.c.

228{
229 struct signalitem *s = NULL;
230 int ms, remaining_time, res = 1, goaway = 0;
231 struct timeval start;
232 struct ast_frame *frame = NULL;
233
234 remaining_time = timeout;
235 start = ast_tvnow();
236
237 s = get_signal(signame, 1);
238
239 ast_mutex_lock(&s->lock);
240 s->watchers = s->watchers + 1; /* we unlock, because a) other people need to use this and */
241 ast_mutex_unlock(&s->lock); /* b) the signal will be available to us as long as watchers > 0 */
242
243 while (timeout == 0 || remaining_time > 0) {
244 int ofd, exception;
245
246 ms = 1000;
247 errno = 0;
248 if (ast_waitfor_nandfds(&chan, 1, &s->sig_alert_pipe[0], 1, &exception, &ofd, &ms)) { /* channel won */
249 if (!(frame = ast_read(chan))) { /* channel hung up */
250 ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
251 res = -1;
252 break;
253 } else {
254 ast_frfree(frame); /* handle frames */
255 }
256 } else if (ofd == s->sig_alert_pipe[0]) { /* fd won */
258 ast_debug(1, "Alert pipe has data for us\n");
259 res = 0;
260 break;
261 } else {
262 ast_debug(1, "Alert pipe does not have data for us\n");
263 }
264 } else { /* nobody won */
265 if (ms && (ofd < 0)) {
266 if (!((errno == 0) || (errno == EINTR))) {
267 ast_log(LOG_WARNING, "Something bad happened while channel '%s' was polling.\n", ast_channel_name(chan));
268 break;
269 }
270 } /* else, nothing happened */
271 }
272 if (timeout) {
273 remaining_time = ast_remaining_ms(start, timeout);
274 }
275 }
276
277 /* WRLOCK the list so that if we're going to destroy the signal now, nobody else can grab it before that happens. */
279 ast_mutex_lock(&s->lock);
280 if (s->payload) {
281 pbx_builtin_setvar_helper(chan, "WAITFORSIGNALPAYLOAD", s->payload);
282 }
283 s->watchers = s->watchers - 1;
284 if (s->watchers) { /* folks are still waiting for this, pass it on... */
285 int save_errno = errno;
287 ast_log(LOG_WARNING, "%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
288 }
289 errno = save_errno;
290 } else { /* nobody else is waiting for this */
291 goaway = 1; /* we were the last guy using this, so mark signal item for destruction */
292 }
294
295 if (goaway) {
296 /* remove_signal calls ast_mutex_destroy, so don't call it with the mutex itself locked. */
297 remove_signal(signame);
298 }
300
301 return res;
302}
@ AST_ALERT_READ_SUCCESS
Definition: alertpipe.h:25
ast_alert_status_t ast_alertpipe_read(int alert_pipe[2])
Read an event from an alert pipe.
Definition: alertpipe.c:102
static int remove_signal(char *sname)
Definition: app_signal.c:182
const char * ast_channel_name(const struct ast_channel *chan)
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.
Definition: channel.c:2956
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4214
#define ast_frfree(fr)
Data structure associated with a single frame of data.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References AST_ALERT_READ_SUCCESS, ast_alertpipe_read(), ast_alertpipe_write(), ast_channel_name(), ast_debug, ast_frfree, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_remaining_ms(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_tvnow(), ast_waitfor_nandfds(), errno, get_signal(), signalitem::lock, LOG_WARNING, NULL, signalitem::payload, pbx_builtin_setvar_helper(), remove_signal(), signalitem::sig_alert_pipe, and signalitem::watchers.

Referenced by waitsignal_exec().

◆ waitsignal_exec()

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

Definition at line 344 of file app_signal.c.

345{
346 char *argcopy;
347 int r = 0, timeoutms = 0;
348 double timeout = 0;
349
351 AST_APP_ARG(signame);
352 AST_APP_ARG(sigtimeout);
353 );
354
355 if (ast_strlen_zero(data)) {
356 ast_log(LOG_WARNING, "Signal() requires arguments\n");
357 return -1;
358 }
359
360 argcopy = ast_strdupa(data);
361 AST_STANDARD_APP_ARGS(args, argcopy);
362
363 if (ast_strlen_zero(args.signame)) {
364 ast_log(LOG_WARNING, "Missing signal name\n");
365 return -1;
366 }
367 if (strlen(args.signame) >= AST_MAX_CONTEXT) {
368 ast_log(LOG_WARNING, "Signal name '%s' is too long\n", args.signame);
369 return -1;
370 }
371 if (!ast_strlen_zero(args.sigtimeout)) {
372 if (sscanf(args.sigtimeout, "%30lg", &timeout) != 1 || timeout < 0) {
373 ast_log(LOG_WARNING, "Invalid timeout provided: %s. Defaulting to no timeout.\n", args.sigtimeout);
374 } else {
375 timeoutms = timeout * 1000; /* sec to msec */
376 }
377 }
378
379 if (timeout > 0) {
380 ast_debug(1, "Waiting for signal '%s' for %d ms\n", args.signame, timeoutms);
381 } else {
382 ast_debug(1, "Waiting for signal '%s', indefinitely\n", args.signame);
383 }
384
385 r = wait_for_signal_or_hangup(chan, args.signame, timeoutms);
386
387 if (r == 1) {
388 ast_verb(3, "Channel '%s' timed out, waiting for signal '%s'\n", ast_channel_name(chan), args.signame);
389 pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "TIMEOUT");
390 } else if (!r) {
391 ast_verb(3, "Received signal '%s' on channel '%s'\n", args.signame, ast_channel_name(chan));
392 pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "SIGNALED");
393 } else {
394 pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "HANGUP");
395 ast_verb(3, "Channel '%s' hung up\n", ast_channel_name(chan));
396 return -1;
397 }
398
399 return 0;
400}
static int wait_for_signal_or_hangup(struct ast_channel *chan, char *signame, int timeout)
Definition: app_signal.c:227
#define ast_verb(level,...)

References args, AST_APP_ARG, ast_channel_name(), ast_debug, AST_DECLARE_APP_ARGS, ast_log, AST_MAX_CONTEXT, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, LOG_WARNING, pbx_builtin_setvar_helper(), and wait_for_signal_or_hangup().

Referenced by load_module().

Variable Documentation

◆ app

const char* const app = "Signal"
static

Definition at line 130 of file app_signal.c.

Referenced by load_module(), and unload_module().

◆ app2

const char* const app2 = "WaitForSignal"
static

Definition at line 131 of file app_signal.c.

Referenced by load_module(), and unload_module().

◆ signals

struct signals signals = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static