Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Enumerations | Functions | Variables
pbx_spool.c File Reference

Full-featured outgoing call spool support. More...

#include "asterisk.h"
#include <sys/stat.h>
#include <time.h>
#include <utime.h>
#include <dirent.h>
#include <sys/inotify.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/callerid.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
#include "asterisk/format.h"
#include "asterisk/format_cache.h"

Go to the source code of this file.

Data Structures

struct  createlist
 
struct  direntry
 
struct  dirlist
 
struct  openlist
 
struct  outgoing
 

Macros

#define LINE_BUFFER_SIZE   1024
 

Enumerations

enum  { SPOOL_FLAG_ALWAYS_DELETE = (1 << 0), SPOOL_FLAG_ARCHIVE = (1 << 1), SPOOL_FLAG_EARLY_MEDIA = (1 << 2) }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void append_variable (struct outgoing *o, const char *name, const char *value)
 
static int apply_outgoing (struct outgoing *o, FILE *f)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void * attempt_thread (void *data)
 
static void free_outgoing (struct outgoing *o)
 
static void launch_service (struct outgoing *o)
 
static int load_module (void)
 
static struct outgoingnew_outgoing (const char *fn)
 
static void parse_line (char *line, unsigned int lineno, struct outgoing *o)
 
static void queue_created_files (void)
 
static void queue_file (const char *filename, time_t when)
 
static void queue_file_create (const char *filename)
 
static void queue_file_open (const char *filename)
 
static void queue_file_write (const char *filename)
 
static int remove_from_queue (struct outgoing *o, const char *status)
 Remove a call file from the outgoing queue optionally moving it in the archive dir. More...
 
static void safe_append (struct outgoing *o, time_t now, char *s)
 
static int scan_service (const char *fn, time_t now)
 
static void * scan_thread (void *unused)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Outgoing Spool Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "da6642af068ee5e6490c5b1d2cc1d238" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct createlist createlist = { .first = NULL, .last = NULL, }
 
static struct dirlist dirlist = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static struct openlist openlist = { .first = NULL, .last = NULL, }
 
static char qdir [255]
 
static char qdonedir [255]
 

Detailed Description

Full-featured outgoing call spool support.

Definition in file pbx_spool.c.

Enumeration Type Documentation

anonymous enum
Enumerator
SPOOL_FLAG_ALWAYS_DELETE 

Always delete the call file after a call succeeds or the maximum number of retries is exceeded, even if the modification time of the call file is in the future.

Definition at line 62 of file pbx_spool.c.

62  {
63  /*! Always delete the call file after a call succeeds or the
64  * maximum number of retries is exceeded, even if the
65  * modification time of the call file is in the future.
66  */
67  SPOOL_FLAG_ALWAYS_DELETE = (1 << 0),
68  /* Don't unlink the call file after processing, move in qdonedir */
69  SPOOL_FLAG_ARCHIVE = (1 << 1),
70  /* Connect the channel with the outgoing extension once early media is received */
71  SPOOL_FLAG_EARLY_MEDIA = (1 << 2),
72 };

Function Documentation

static int remove_from_queue ( struct outgoing o,
const char *  status 
)
static

Remove a call file from the outgoing queue optionally moving it in the archive dir.

Parameters
othe pointer to outgoing struct
statusthe exit status of the call. Can be "Completed", "Failed" or "Expired"

Definition at line 363 of file pbx_spool.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_mkdir(), outgoing::fn, outgoing::options, and SPOOL_FLAG_ALWAYS_DELETE.

Referenced by scan_service().

364 {
365  FILE *f;
366  char newfn[256];
367  const char *bname;
368 
369 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
370  struct direntry *cur;
371 #endif
372 
373  if (!ast_test_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE)) {
374  struct stat current_file_status;
375 
376  if (!stat(o->fn, &current_file_status)) {
377  if (time(NULL) < current_file_status.st_mtime) {
378  return 0;
379  }
380  }
381  }
382 
383 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
386  if (!strcmp(cur->name, o->fn)) {
388  ast_free(cur);
389  break;
390  }
391  }
394 #endif
395 
396  if (!ast_test_flag(&o->options, SPOOL_FLAG_ARCHIVE)) {
397  unlink(o->fn);
398  return 0;
399  }
400 
401  if (ast_mkdir(qdonedir, 0777)) {
402  ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool archiving disabled\n", qdonedir);
403  unlink(o->fn);
404  return -1;
405  }
406 
407  if (!(bname = strrchr(o->fn, '/'))) {
408  bname = o->fn;
409  } else {
410  bname++;
411  }
412 
413  snprintf(newfn, sizeof(newfn), "%s/%s", qdonedir, bname);
414  /* If there is already a call file with the name in the archive dir, it will be overwritten. */
415  unlink(newfn);
416  if (rename(o->fn, newfn) != 0) {
417  unlink(o->fn);
418  return -1;
419  }
420 
421  /* Only append to the file AFTER we move it out of the watched directory,
422  * otherwise the fclose() causes another event for inotify(7) */
423  if ((f = fopen(newfn, "a"))) {
424  fprintf(f, "Status: %s\n", status);
425  fclose(f);
426  }
427 
428  return 0;
429 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
struct ast_flags options
Definition: pbx_spool.c:99
const ast_string_field fn
Definition: pbx_spool.c:95
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479
static int scan_service ( const char *  fn,
time_t  now 
)
static
Todo:
XXX There is some odd delayed duplicate servicing of call files going on. We need to suppress the error message if the file does not exist as a result.

Definition at line 482 of file pbx_spool.c.

References ast_debug, outgoing::callingpid, outgoing::dest, outgoing::fn, outgoing::maxretries, remove_from_queue(), outgoing::retries, outgoing::retrytime, and outgoing::tech.

483 {
484  struct outgoing *o;
485  FILE *f;
486  int res;
487 
488  o = new_outgoing(fn);
489  if (!o) {
490  return -1;
491  }
492 
493  /* Attempt to open the file */
494  f = fopen(o->fn, "r");
495  if (!f) {
496 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
497  /*!
498  * \todo XXX There is some odd delayed duplicate servicing of
499  * call files going on. We need to suppress the error message
500  * if the file does not exist as a result.
501  */
502  if (errno != ENOENT)
503 #endif
504  {
505  ast_log(LOG_WARNING, "Unable to open %s: '%s'(%d), deleting\n",
506  o->fn, strerror(errno), (int) errno);
507  }
508  remove_from_queue(o, "Failed");
509  free_outgoing(o);
510  return -1;
511  }
512 
513  /* Read in and verify the contents */
514  res = apply_outgoing(o, f);
515  fclose(f);
516  if (res) {
517  ast_log(LOG_WARNING, "Invalid file contents in %s, deleting\n", o->fn);
518  remove_from_queue(o, "Failed");
519  free_outgoing(o);
520  return -1;
521  }
522 
523  ast_debug(1, "Filename: %s, Retries: %d, max: %d\n", o->fn, o->retries, o->maxretries);
524  if (o->retries <= o->maxretries) {
525  now += o->retrytime;
526  if (o->callingpid && (o->callingpid == ast_mainpid)) {
527  safe_append(o, time(NULL), "DelayedRetry");
528  ast_debug(1, "Delaying retry since we're currently running '%s'\n", o->fn);
529  free_outgoing(o);
530  } else {
531  /* Increment retries */
532  o->retries++;
533  /* If someone else was calling, they're presumably gone now
534  so abort their retry and continue as we were... */
535  if (o->callingpid)
536  safe_append(o, time(NULL), "AbortRetry");
537 
538  safe_append(o, now, "StartRetry");
539  launch_service(o);
540  }
541  return now;
542  }
543 
544  ast_log(LOG_NOTICE, "Queued call to %s/%s expired without completion after %d attempt%s\n",
545  o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : "");
546  remove_from_queue(o, "Expired");
547  free_outgoing(o);
548  return 0;
549 }
int maxretries
Definition: pbx_spool.c:79
static int remove_from_queue(struct outgoing *o, const char *status)
Remove a call file from the outgoing queue optionally moving it in the archive dir.
Definition: pbx_spool.c:363
int retries
Definition: pbx_spool.c:78
#define ast_debug(level,...)
Log a DEBUG message.
int retrytime
Definition: pbx_spool.c:80
const ast_string_field fn
Definition: pbx_spool.c:95
const ast_string_field dest
Definition: pbx_spool.c:95
const ast_string_field tech
Definition: pbx_spool.c:95
long callingpid
Definition: pbx_spool.c:82