aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorbbryant <bbryant@f38db490-d61c-443f-a65b-d21fe96a405b>2010-09-09 18:51:52 +0000
committerbbryant <bbryant@f38db490-d61c-443f-a65b-d21fe96a405b>2010-09-09 18:51:52 +0000
commit722eb3c4c3cfa1c0cee915c949c5f95199ee24dd (patch)
tree25683963c5e51bdedd6211cd0ea92a85639505c3 /main
parent815b5b09da5e555add7bba3d8fca588e7611248a (diff)
Merged revisions 285710 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ........ r285710 | bbryant | 2010-09-09 14:50:13 -0400 (Thu, 09 Sep 2010) | 8 lines Fixes an issue with dialplan pattern matching where the specificity for pattern ranges and pattern special characters was inconsistent. (closes issue #16903) Reported by: Nick_Lewis Patches: pbx.c-specificity.patch uploaded by Nick Lewis (license 657) Tested by: Nick_Lewis ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.8@285711 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c46
-rw-r--r--main/ccss.c49
-rw-r--r--main/cdr.c39
-rw-r--r--main/cel.c6
-rw-r--r--main/channel.c14
-rw-r--r--main/cli.c43
-rw-r--r--main/config.c2
-rw-r--r--main/features.c89
-rw-r--r--main/loader.c20
-rw-r--r--main/manager.c33
-rw-r--r--main/netsock2.c16
-rw-r--r--main/pbx.c57
-rw-r--r--main/poll.c196
-rw-r--r--main/rtp_engine.c4
-rw-r--r--main/sched.c2
-rw-r--r--main/stun.c7
-rw-r--r--main/translate.c295
-rw-r--r--main/utils.c16
18 files changed, 674 insertions, 260 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index d8d3aebdf..f8d619a79 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2008, Digium, Inc.
+ * Copyright (C) 1999 - 2010, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
@@ -272,6 +272,8 @@ static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
+extern unsigned int ast_FD_SETSIZE;
+
static char *_argv[256];
static int shuttingdown;
static int restartnow;
@@ -3167,7 +3169,8 @@ int main(int argc, char *argv[])
char *buf;
const char *runuser = NULL, *rungroup = NULL;
char *remotesock = NULL;
- int moduleresult; /*!< Result from the module load subsystem */
+ int moduleresult; /*!< Result from the module load subsystem */
+ struct rlimit l;
/* Remember original args for restart */
if (argc > ARRAY_LEN(_argv) - 1) {
@@ -3352,7 +3355,6 @@ int main(int argc, char *argv[])
}
if (ast_opt_dump_core) {
- struct rlimit l;
memset(&l, 0, sizeof(l));
l.rlim_cur = RLIM_INFINITY;
l.rlim_max = RLIM_INFINITY;
@@ -3361,6 +3363,44 @@ int main(int argc, char *argv[])
}
}
+ if (getrlimit(RLIMIT_NOFILE, &l)) {
+ ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
+ }
+
+#if !defined(CONFIGURE_RAN_AS_ROOT)
+ /* Check if select(2) will run with more file descriptors */
+ do {
+ int fd, fd2;
+ ast_fdset readers;
+ struct timeval tv = { 0, };
+
+ if (l.rlim_cur <= FD_SETSIZE) {
+ /* The limit of select()able FDs is irrelevant, because we'll never
+ * open one that high. */
+ break;
+ }
+
+ if (!(fd = open("/dev/null", O_RDONLY))) {
+ ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
+ break; /* XXX Should we exit() here? XXX */
+ }
+
+ fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
+ if (dup2(fd, fd2)) {
+ ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
+ break;
+ }
+
+ FD_ZERO(&readers);
+ FD_SET(fd2, &readers);
+ if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
+ ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
+ }
+ } while (0);
+#elif defined(HAVE_VARIABLE_FDSET)
+ ast_FD_SETSIZE = l.rlim_cur;
+#endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
+
if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
rungroup = ast_config_AST_RUN_GROUP;
if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
diff --git a/main/ccss.c b/main/ccss.c
index 2cf828470..4dcacd360 100644
--- a/main/ccss.c
+++ b/main/ccss.c
@@ -501,38 +501,45 @@ static int count_agents_cb(void *obj, void *arg, void *data, int flags)
return 0;
}
-static const unsigned int CC_OFFER_TIMER_DEFAULT = 20u;
-static const unsigned int CCNR_AVAILABLE_TIMER_DEFAULT = 7200u;
-static const unsigned int CCBS_AVAILABLE_TIMER_DEFAULT = 4800u;
-static const unsigned int CC_RECALL_TIMER_DEFAULT = 20u;
-static const unsigned int CC_MAX_AGENTS_DEFAULT = 5u;
-static const unsigned int CC_MAX_MONITORS_DEFAULT = 5u;
-static const unsigned int GLOBAL_CC_MAX_REQUESTS_DEFAULT = 20u;
+#define CC_OFFER_TIMER_DEFAULT 20 /* Seconds */
+#define CCNR_AVAILABLE_TIMER_DEFAULT 7200 /* Seconds */
+#define CCBS_AVAILABLE_TIMER_DEFAULT 4800 /* Seconds */
+#define CC_RECALL_TIMER_DEFAULT 20 /* Seconds */
+#define CC_MAX_AGENTS_DEFAULT 5
+#define CC_MAX_MONITORS_DEFAULT 5
+#define GLOBAL_CC_MAX_REQUESTS_DEFAULT 20
+
+static const struct ast_cc_config_params cc_default_params = {
+ .cc_agent_policy = AST_CC_AGENT_NEVER,
+ .cc_monitor_policy = AST_CC_MONITOR_NEVER,
+ .cc_offer_timer = CC_OFFER_TIMER_DEFAULT,
+ .ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT,
+ .ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT,
+ .cc_recall_timer = CC_RECALL_TIMER_DEFAULT,
+ .cc_max_agents = CC_MAX_AGENTS_DEFAULT,
+ .cc_max_monitors = CC_MAX_MONITORS_DEFAULT,
+ .cc_callback_macro = "",
+ .cc_agent_dialstring = "",
+};
+
+void ast_cc_default_config_params(struct ast_cc_config_params *params)
+{
+ *params = cc_default_params;
+}
struct ast_cc_config_params *__ast_cc_config_params_init(const char *file, int line, const char *function)
{
#if defined(__AST_DEBUG_MALLOC)
- struct ast_cc_config_params *params = __ast_calloc(1, sizeof(*params), file, line, function);
+ struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function);
#else
- struct ast_cc_config_params *params = ast_calloc(1, sizeof(*params));
+ struct ast_cc_config_params *params = ast_malloc(sizeof(*params));
#endif
if (!params) {
return NULL;
}
- /* Yeah, I could use the get/set functions, but what's the point since
- * I have direct access to the structure fields in this file.
- */
- params->cc_agent_policy = AST_CC_AGENT_NEVER;
- params->cc_monitor_policy = AST_CC_MONITOR_NEVER;
- params->cc_offer_timer = CC_OFFER_TIMER_DEFAULT;
- params->ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT;
- params->ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT;
- params->cc_recall_timer = CC_RECALL_TIMER_DEFAULT;
- params->cc_max_agents = CC_MAX_AGENTS_DEFAULT;
- params->cc_max_monitors = CC_MAX_MONITORS_DEFAULT;
- /* No need to set cc_callback_macro since calloc will 0 it out anyway */
+ ast_cc_default_config_params(params);
return params;
}
diff --git a/main/cdr.c b/main/cdr.c
index a6096976d..c9b58238b 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -84,18 +84,26 @@ static struct sched_context *sched;
static int cdr_sched = -1;
static pthread_t cdr_thread = AST_PTHREADT_NULL;
-#define BATCH_SIZE_DEFAULT 100
-#define BATCH_TIME_DEFAULT 300
-#define BATCH_SCHEDULER_ONLY_DEFAULT 0
-#define BATCH_SAFE_SHUTDOWN_DEFAULT 1
+static int enabled;
+static const int ENABLED_DEFAULT = 1;
-static int enabled; /*! Is the CDR subsystem enabled ? */
-static int unanswered;
static int batchmode;
+static const int BATCHMODE_DEFAULT = 0;
+
+static int unanswered;
+static const int UNANSWERED_DEFAULT = 0;
+
static int batchsize;
+static const int BATCH_SIZE_DEFAULT = 100;
+
static int batchtime;
+static const int BATCH_TIME_DEFAULT = 300;
+
static int batchscheduleronly;
+static const int BATCH_SCHEDULER_ONLY_DEFAULT = 0;
+
static int batchsafeshutdown;
+static const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1;
AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
@@ -1492,22 +1500,27 @@ static int do_reload(int reload)
int res=0;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
- return 0;
- if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
+ if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
}
ast_mutex_lock(&cdr_batch_lock);
+ was_enabled = enabled;
+ was_batchmode = batchmode;
+
batchsize = BATCH_SIZE_DEFAULT;
batchtime = BATCH_TIME_DEFAULT;
batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
- was_enabled = enabled;
- was_batchmode = batchmode;
- enabled = 1;
- batchmode = 0;
+ enabled = ENABLED_DEFAULT;
+ batchmode = BATCHMODE_DEFAULT;
+ unanswered = UNANSWERED_DEFAULT;
+
+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
+ ast_mutex_unlock(&cdr_batch_lock);
+ return 0;
+ }
/* don't run the next scheduled CDR posting while reloading */
AST_SCHED_DEL(sched, cdr_sched);
diff --git a/main/cel.c b/main/cel.c
index 0af890bde..7f5c24f40 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -122,6 +122,7 @@ static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
* \brief Map of ast_cel_ama_flags to strings
*/
static const char * const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] = {
+ [AST_CEL_AMA_FLAG_NONE] = "NONE",
[AST_CEL_AMA_FLAG_OMIT] = "OMIT",
[AST_CEL_AMA_FLAG_BILLING] = "BILLING",
[AST_CEL_AMA_FLAG_DOCUMENTATION] = "DOCUMENTATION",
@@ -349,6 +350,11 @@ const char *ast_cel_get_type_name(enum ast_cel_event_type type)
const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag)
{
+ if (flag < 0 || flag >= ARRAY_LEN(cel_ama_flags)) {
+ ast_log(LOG_WARNING, "Invalid AMA flag: %d\n", flag);
+ return "Unknown";
+ }
+
return S_OR(cel_ama_flags[flag], "Unknown");
}
diff --git a/main/channel.c b/main/channel.c
index 32d559d0f..c0a37aaa6 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -5863,6 +5863,7 @@ int ast_do_masquerade(struct ast_channel *original)
struct ast_party_redirecting redirecting;
} exchange;
struct ast_channel *clonechan, *chans[2];
+ struct ast_channel *bridged;
struct ast_cdr *cdr;
format_t rformat = original->readformat;
format_t wformat = original->writeformat;
@@ -6185,6 +6186,14 @@ int ast_do_masquerade(struct ast_channel *original)
pthread_kill(original->blocker, SIGURG);
ast_debug(1, "Done Masquerading %s (%d)\n", original->name, original->_state);
+ if ((bridged = ast_bridged_channel(original))) {
+ ast_channel_lock(bridged);
+ ast_indicate(bridged, AST_CONTROL_SRCCHANGE);
+ ast_channel_unlock(bridged);
+ }
+
+ ast_indicate(original, AST_CONTROL_SRCCHANGE);
+
done:
/* it is possible for the clone channel to disappear during this */
if (clonechan) {
@@ -6196,6 +6205,7 @@ done:
ast_channel_unlock(original);
ao2_link(channels, original);
}
+
return 0;
}
@@ -6716,8 +6726,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
manager_bridge_event(1, 1, c0, c1);
/* Before we enter in and bridge these two together tell them both the source of audio has changed */
- ast_indicate(c0, AST_CONTROL_SRCUPDATE);
- ast_indicate(c1, AST_CONTROL_SRCUPDATE);
+ ast_indicate(c0, AST_CONTROL_SRCCHANGE);
+ ast_indicate(c1, AST_CONTROL_SRCCHANGE);
for (/* ever */;;) {
struct timeval now = { 0, };
diff --git a/main/cli.c b/main/cli.c
index c9dbc6d02..77e52b863 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/lock.h"
#include "editline/readline/readline.h"
#include "asterisk/threadstorage.h"
+#include "asterisk/translate.h"
/*!
* \brief List of restrictions per user.
@@ -302,6 +303,28 @@ static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args
return CLI_SUCCESS;
}
+static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core reload";
+ e->usage =
+ "Usage: core reload\n"
+ " Execute a global reload.\n";
+ return NULL;
+
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != e->args) {
+ return CLI_SHOWUSAGE;
+ }
+
+ ast_module_reload(NULL);
+
+ return CLI_SUCCESS;
+}
/*!
* \brief Find the debug or verbose file setting
* \arg debug 1 for debug, 0 for verbose
@@ -1343,6 +1366,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
struct ast_str *out = ast_str_thread_get(&ast_str_thread_global_buf, 16);
char cdrtime[256];
char nf[256], wf[256], rf[256];
+ struct ast_str *write_transpath = ast_str_alloca(256);
+ struct ast_str *read_transpath = ast_str_alloca(256);
long elapsed_seconds=0;
int hour=0, min=0, sec=0;
#ifdef CHANNEL_TRACE
@@ -1398,8 +1423,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
" NativeFormats: %s\n"
" WriteFormat: %s\n"
" ReadFormat: %s\n"
- " WriteTranscode: %s\n"
- " ReadTranscode: %s\n"
+ " WriteTranscode: %s %s\n"
+ " ReadTranscode: %s %s\n"
"1st File Descriptor: %d\n"
" Frames in: %d%s\n"
" Frames out: %d%s\n"
@@ -1426,7 +1451,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
c->writetrans ? "Yes" : "No",
+ ast_translate_path_to_str(c->writetrans, &write_transpath),
c->readtrans ? "Yes" : "No",
+ ast_translate_path_to_str(c->readtrans, &read_transpath),
c->fds[0],
c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
@@ -1485,7 +1512,13 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta
return NULL;
}
- if (!(iter = ast_channel_iterator_by_name_new(word, strlen(word)))) {
+ if (ast_strlen_zero(word)) {
+ iter = ast_channel_iterator_all_new();
+ } else {
+ iter = ast_channel_iterator_by_name_new(word, strlen(word));
+ }
+
+ if (!iter) {
return NULL;
}
@@ -1609,7 +1642,9 @@ static struct ast_cli_entry cli_cli[] = {
AST_CLI_DEFINE(handle_load, "Load a module by name"),
- AST_CLI_DEFINE(handle_reload, "Reload configuration"),
+ AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"),
+
+ AST_CLI_DEFINE(handle_core_reload, "Global reload"),
AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
diff --git a/main/config.c b/main/config.c
index 34e4247a7..d763adac4 100644
--- a/main/config.c
+++ b/main/config.c
@@ -2361,7 +2361,7 @@ char *ast_realtime_decode_chunk(char *chunk)
char *orig = chunk;
for (; *chunk; chunk++) {
if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
- sscanf(chunk + 1, "%02hhd", chunk);
+ sscanf(chunk + 1, "%02hhX", chunk);
memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
}
}
diff --git a/main/features.c b/main/features.c
index ac0bc7cbf..99cde8bff 100644
--- a/main/features.c
+++ b/main/features.c
@@ -438,7 +438,7 @@ static const struct ast_datastore_info dial_features_info = {
static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
static void parkinglot_unref(struct ast_parkinglot *parkinglot);
static void parkinglot_destroy(void *obj);
-int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *fs, int *max);
+int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *fs);
struct ast_parkinglot *find_parkinglot(const char *name);
static struct ast_parkinglot *create_parkinglot(const char *name);
static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
@@ -2802,7 +2802,7 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
}
} else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
- ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ ast_indicate_data(caller, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
}
} else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
@@ -3603,9 +3603,10 @@ static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_
}
/*! \brief Run management on parkinglots, called once per parkinglot */
-int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
+int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *ms)
{
-
+ struct pollfd *new_fds = NULL;
+ int new_nfds = 0;
struct parkeduser *pu;
int res = 0;
char parkingslot[AST_MAX_EXTENSION];
@@ -3628,12 +3629,12 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
/* Get chan, exten from derived kludge */
if (pu->peername[0]) {
char *peername = ast_strdupa(pu->peername);
- char *cp = strrchr(peername, '-');
+ char *dash = strrchr(peername, '-');
char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
int i;
- if (cp) {
- *cp = 0;
+ if (dash) {
+ *dash = '\0';
}
peername_flat = ast_strdupa(peername);
@@ -3712,14 +3713,33 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
} else { /* still within parking time, process descriptors */
for (x = 0; x < AST_MAX_FDS; x++) {
struct ast_frame *f;
+ int y;
- if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds)))
+ if (chan->fds[x] == -1) {
+ continue; /* nothing on this descriptor */
+ }
+
+ for (y = 0; y < *nfds; y++) {
+ if ((*pfds[y]).fd == chan->fds[x]) {
+ /* Found poll record! */
+ break;
+ }
+ }
+ if (y == *nfds) {
+ /* Not found */
continue;
-
- if (FD_ISSET(chan->fds[x], efds))
+ }
+
+ if (!((*pfds[y]).revents & (POLLIN | POLLERR))) {
+ /* Next x */
+ continue;
+ }
+
+ if ((*pfds[y]).revents & POLLERR) {
ast_set_flag(chan, AST_FLAG_EXCEPTION);
- else
+ } else {
ast_clear_flag(chan, AST_FLAG_EXCEPTION);
+ }
chan->fdno = x;
/* See if they need servicing */
@@ -3760,22 +3780,32 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
}
} /* End for */
if (x >= AST_MAX_FDS) {
-std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
+std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
if (chan->fds[x] > -1) {
- FD_SET(chan->fds[x], nrfds);
- FD_SET(chan->fds[x], nefds);
- if (chan->fds[x] > *max)
- *max = chan->fds[x];
+ void *tmp = ast_realloc(new_fds, (new_nfds + 1) * sizeof(*new_fds));
+ if (!tmp) {
+ continue;
+ }
+ new_fds = tmp;
+ new_fds[new_nfds].fd = chan->fds[x];
+ new_fds[new_nfds].events = POLLIN | POLLERR;
+ new_fds[new_nfds].revents = 0;
+ new_nfds++;
}
}
/* Keep track of our shortest wait */
- if (tms < *ms || *ms < 0)
+ if (tms < *ms || *ms < 0) {
*ms = tms;
+ }
}
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&curlot->parkings);
+
+ ast_free(*pfds);
+ *pfds = new_fds;
+ *nfds = new_nfds;
return res;
}
@@ -3789,35 +3819,26 @@ std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
*/
static void *do_parking_thread(void *ignore)
{
- fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
- fd_set nrfds, nefds; /* args for the next select */
- FD_ZERO(&rfds);
- FD_ZERO(&efds);
+ struct pollfd *pfds = NULL;
+ int nfds = 0;
for (;;) {
- int res = 0;
- int ms = -1; /* select timeout, uninitialized */
- int max = -1; /* max fd, none there yet */
struct ao2_iterator iter;
struct ast_parkinglot *curlot;
- FD_ZERO(&nrfds);
- FD_ZERO(&nefds);
+ int ms = -1; /* poll2 timeout, uninitialized */
iter = ao2_iterator_init(parkinglots, 0);
while ((curlot = ao2_iterator_next(&iter))) {
- res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
+ manage_parkinglot(curlot, &pfds, &nfds, &ms);
ao2_ref(curlot, -1);
}
+ ao2_iterator_destroy(&iter);
- rfds = nrfds;
- efds = nefds;
- {
- struct timeval wait = ast_samp2tv(ms, 1000);
- /* Wait for something to happen */
- ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
- }
+ /* Wait for something to happen */
+ ast_poll(pfds, nfds, ms);
pthread_testcancel();
}
+ /* If this WERE reached, we'd need to free(pfds) */
return NULL; /* Never reached */
}
diff --git a/main/loader.c b/main/loader.c
index 17bb1f821..dea236b05 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -414,6 +414,26 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
return NULL;
}
+ /* This section is a workaround for a gcc 4.1 bug that has already been
+ * fixed in later versions. Unfortunately, some distributions, such as
+ * RHEL/CentOS 5, distribute gcc 4.1, so we're stuck with having to deal
+ * with this issue. This basically ensures that optional_api modules are
+ * loaded before any module which requires their functionality. */
+#if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
+ if (!ast_strlen_zero(mod->info->nonoptreq)) {
+ /* Force any required dependencies to load */
+ char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
+ while ((each = strsep(&required_resource, ","))) {
+ each = ast_strip(each);
+
+ /* Is it already loaded? */
+ if (!find_resource(each, 0)) {
+ load_dynamic_module(each, global_symbols_only);
+ }
+ }
+ }
+#endif
+
while (!dlclose(lib));
resource_being_loaded = NULL;
diff --git a/main/manager.c b/main/manager.c
index e9007d804..97ab64c02 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -850,11 +850,19 @@ struct eventqent {
static AST_RWLIST_HEAD_STATIC(all_events, eventqent);
-static int displayconnects = 1;
+static const int DEFAULT_ENABLED = 0; /*!< Default setting for manager to be enabled */
+static const int DEFAULT_WEBENABLED = 0; /*!< Default setting for the web interface to be enabled */
+static const int DEFAULT_BLOCKSOCKETS = 0; /*!< Default setting for block-sockets */
+static const int DEFAULT_DISPLAYCONNECTS = 1; /*!< Default setting for displaying manager connections */
+static const int DEFAULT_TIMESTAMPEVENTS = 0; /*!< Default setting for timestampevents */
+static const int DEFAULT_HTTPTIMEOUT = 60; /*!< Default manager http timeout */
+static const int DEFAULT_BROKENEVENTSACTION = 0; /*!< Default setting for brokeneventsaction */
+
+static int displayconnects;
static int allowmultiplelogin = 1;
static int timestampevents;
-static int httptimeout = 60;
-static int broken_events_action = 0;
+static int httptimeout;
+static int broken_events_action;
static int manager_enabled = 0;
static int webmanager_enabled = 0;
static char *manager_channelvars;
@@ -1697,8 +1705,9 @@ static const char *__astman_get_header(const struct message *m, char *var, int m
for (x = 0; x < m->hdrcount; x++) {
const char *h = m->headers[x];
- if (!strncasecmp(var, h, l) && h[l] == ':' && h[l+1] == ' ') {
- const char *value = h + l + 2;
+ if (!strncasecmp(var, h, l) && h[l] == ':') {
+ const char *value = h + l + 1;
+ value = ast_skip_blanks(value); /* ignore leading spaces in the value */
/* found a potential candidate */
if (mode & GET_HEADER_SKIP_EMPTY && ast_strlen_zero(value))
continue; /* not interesting */
@@ -6130,7 +6139,7 @@ static int __init_manager(int reload)
struct ast_config *ucfg = NULL, *cfg = NULL;
const char *val;
char *cat = NULL;
- int newhttptimeout = 60;
+ int newhttptimeout = DEFAULT_HTTPTIMEOUT;
struct ast_manager_user *user = NULL;
struct ast_variable *var;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
@@ -6139,8 +6148,6 @@ static int __init_manager(int reload)
struct sockaddr_in ami_desc_local_address_tmp = { 0, };
struct sockaddr_in amis_desc_local_address_tmp = { 0, };
- manager_enabled = 0;
-
if (!registered) {
/* Register default actions */
ast_manager_register_xml("Ping", 0, action_ping);
@@ -6187,8 +6194,14 @@ static int __init_manager(int reload)
return 0;
}
- displayconnects = 1;
- broken_events_action = 0;
+ manager_enabled = DEFAULT_ENABLED;
+ webmanager_enabled = DEFAULT_WEBENABLED;
+ displayconnects = DEFAULT_DISPLAYCONNECTS;
+ broken_events_action = DEFAULT_BROKENEVENTSACTION;
+ block_sockets = DEFAULT_BLOCKSOCKETS;
+ timestampevents = DEFAULT_TIMESTAMPEVENTS;
+ httptimeout = DEFAULT_HTTPTIMEOUT;
+
if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n");
return 0;
diff --git a/main/netsock2.c b/main/netsock2.c
index 929f4b337..99f7eac89 100644
--- a/main/netsock2.c
+++ b/main/netsock2.c
@@ -118,7 +118,7 @@ char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format)
return ast_str_buffer(str);
}
-int static _ast_sockaddr_parse(char *str, char **host, char **port, int flags)
+int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
{
char *s = str;
@@ -187,7 +187,7 @@ int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
int e;
s = ast_strdupa(str);
- if (!_ast_sockaddr_parse(s, &host, &port, flags)) {
+ if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
return 0;
}
@@ -233,7 +233,7 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
int e, i, res_cnt;
s = ast_strdupa(str);
- if (!_ast_sockaddr_parse(s, &host, &port, flags)) {
+ if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
return 0;
}
@@ -343,7 +343,9 @@ uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, i
addr->len == sizeof(struct sockaddr_in6)) {
return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port);
}
- ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
+ if (option_debug >= 1) {
+ ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
+ }
return 0;
}
@@ -355,7 +357,7 @@ void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char
} else if (addr->ss.ss_family == AF_INET6 &&
addr->len == sizeof(struct sockaddr_in6)) {
((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
- } else {
+ } else if (option_debug >= 1) {
ast_log(__LOG_DEBUG, file, line, func,
"Not an IPv4 nor IPv6 address, cannot set port.\n");
}
@@ -485,7 +487,7 @@ int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
return 0;
}
- if (addr->ss.ss_family != AF_INET) {
+ if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
}
@@ -498,7 +500,7 @@ void _ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in
{
memcpy(&addr->ss, sin, sizeof(*sin));
- if (addr->ss.ss_family != AF_INET) {
+ if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
}
diff --git a/main/pbx.c b/main/pbx.c
index 4216b853a..8e20f8686 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -1164,7 +1164,11 @@ static struct pbx_builtin {
static struct ast_context *contexts;
static struct ast_hashtab *contexts_table = NULL;
-AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
+/*!\brief Lock for the ast_context list
+ * This lock MUST be recursive, or a deadlock on reload may result. See
+ * https://issues.asterisk.org/view.php?id=17643
+ */
+AST_MUTEX_DEFINE_STATIC(conlock);
static AST_RWLIST_HEAD_STATIC(apps, ast_app);
@@ -1904,15 +1908,15 @@ static struct match_char *add_pattern_node(struct ast_context *con, struct match
pattern matcher. */
m->is_pattern = is_pattern;
if (specificity == 1 && is_pattern && pattern[0] == 'N')
- m->specificity = 0x0802;
+ m->specificity = 0x0832;
else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
- m->specificity = 0x0901;
+ m->specificity = 0x0931;
else if (specificity == 1 && is_pattern && pattern[0] == 'X')
- m->specificity = 0x0a00;
+ m->specificity = 0x0a30;
else if (specificity == 1 && is_pattern && pattern[0] == '.')
- m->specificity = 0x10000;
+ m->specificity = 0x18000;
else if (specificity == 1 && is_pattern && pattern[0] == '!')
- m->specificity = 0x20000;
+ m->specificity = 0x28000;
else
m->specificity = specificity;
@@ -2189,10 +2193,10 @@ static int ext_cmp1(const char **p, unsigned char *bitwise)
return 0x0900 | '1';
case '.': /* wildcard */
- return 0x10000;
+ return 0x18000;
case '!': /* earlymatch */
- return 0x20000; /* less specific than NULL */
+ return 0x28000; /* less specific than NULL */
case '\0': /* empty string */
*p = NULL;
@@ -6850,7 +6854,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
ast_unlock_contexts();
ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
- ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
+ ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
} else {
tmp->next = *local_contexts;
if (exttable)
@@ -6858,7 +6862,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
*local_contexts = tmp;
ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
- ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
+ ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
}
return tmp;
}
@@ -7016,7 +7020,6 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
*/
struct timeval begintime, writelocktime, endlocktime, enddeltime;
- int wrlock_ver;
begintime = ast_tvnow();
ast_rdlock_contexts();
@@ -7025,15 +7028,6 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
context_merge(extcontexts, exttable, tmp, registrar);
}
ast_hashtab_end_traversal(iter);
- wrlock_ver = ast_wrlock_contexts_version();
-
- ast_unlock_contexts(); /* this feels real retarded, but you must do
- what you must do If this isn't done, the following
- wrlock is a guraranteed deadlock */
- ast_wrlock_contexts();
- if (ast_wrlock_contexts_version() > wrlock_ver+1) {
- ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
- }
AST_RWLIST_WRLOCK(&hints);
writelocktime = ast_tvnow();
@@ -8209,11 +8203,11 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
}
if (tmp->matchcid) {
- ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
- tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
+ ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
+ tmp->exten, tmp->priority, tmp->cidmatch, con->name);
} else {
- ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
- tmp->exten, tmp->priority, con->name, con);
+ ast_verb(3, "Added extension '%s' priority %d to %s\n",
+ tmp->exten, tmp->priority, con->name);
}
return 0;
@@ -9836,32 +9830,23 @@ int load_pbx(void)
return 0;
}
-static int conlock_wrlock_version = 0;
-
-int ast_wrlock_contexts_version(void)
-{
- return conlock_wrlock_version;
-}
/*
* Lock context list functions ...
*/
int ast_wrlock_contexts()
{
- int res = ast_rwlock_wrlock(&conlock);
- if (!res)
- ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
- return res;
+ return ast_mutex_lock(&conlock);
}
int ast_rdlock_contexts()
{
- return ast_rwlock_rdlock(&conlock);
+ return ast_mutex_lock(&conlock);
}
int ast_unlock_contexts()
{
- return ast_rwlock_unlock(&conlock);
+ return ast_mutex_unlock(&conlock);
}
/*
diff --git a/main/poll.c b/main/poll.c
index d10639077..e0f695504 100644
--- a/main/poll.c
+++ b/main/poll.c
@@ -10,9 +10,9 @@
struct pollfd
{
- int fd;
- short events;
- short revents;
+ int fd;
+ short events;
+ short revents;
}
int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
@@ -73,54 +73,44 @@
#include "asterisk.h"
-#include <unistd.h> /* standard Unix definitions */
-#include <sys/types.h> /* system types */
-#include <sys/time.h> /* time definitions */
-#include <assert.h> /* assertion macros */
-#include <string.h> /* string functions */
+#include <unistd.h> /* standard Unix definitions */
+#include <sys/types.h> /* system types */
+#include <sys/time.h> /* time definitions */
+#include <assert.h> /* assertion macros */
+#include <string.h> /* string functions */
+#include <errno.h>
#include "asterisk/utils.h" /* this package */
#include "asterisk/poll-compat.h" /* this package */
-#ifdef AST_POLL_COMPAT
+unsigned int ast_FD_SETSIZE = FD_SETSIZE;
#ifndef MAX
#define MAX(a,b) a > b ? a : b
#endif
/*---------------------------------------------------------------------------*\
- Private Functions
+ Private Functions
\*---------------------------------------------------------------------------*/
-static int map_poll_spec
-#if __STDC__ > 0
- (struct pollfd *pArray,
- unsigned long n_fds,
- fd_set *pReadSet,
- fd_set *pWriteSet,
- fd_set *pExceptSet)
-#else
- (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
- struct pollfd *pArray;
- unsigned long n_fds;
- fd_set *pReadSet;
- fd_set *pWriteSet;
- fd_set *pExceptSet;
-#endif
+#if defined(AST_POLL_COMPAT)
+static int map_poll_spec(struct pollfd *pArray, unsigned long n_fds,
+ ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
{
- register unsigned long i; /* loop control */
- register struct pollfd *pCur; /* current array element */
- register int max_fd = -1; /* return value */
+ register unsigned long i; /* loop control */
+ register struct pollfd *pCur; /* current array element */
+ register int max_fd = -1; /* return value */
- /*!\note
+ /*
* Map the poll() structures into the file descriptor sets required
* by select().
*/
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
/* Skip any bad FDs in the array. */
- if (pCur->fd < 0)
+ if (pCur->fd < 0) {
continue;
+ }
if (pCur->events & POLLIN) {
/* "Input Ready" notification desired. */
@@ -145,34 +135,28 @@ static int map_poll_spec
return max_fd;
}
-
-static struct timeval *map_timeout
-#if __STDC__ > 0
- (int poll_timeout, struct timeval *pSelTimeout)
-#else
- (poll_timeout, pSelTimeout)
- int poll_timeout;
- struct timeval *pSelTimeout;
-#endif
+
+#ifdef AST_POLL_COMPAT
+static struct timeval *map_timeout(int poll_timeout, struct timeval *pSelTimeout)
{
struct timeval *pResult;
- /*!\note
- * Map the poll() timeout value into a select() timeout. The possible
- * values of the poll() timeout value, and their meanings, are:
- *
- * VALUE MEANING
- *
- * -1 wait indefinitely (until signal occurs)
- * 0 return immediately, don't block
- * >0 wait specified number of milliseconds
- *
- * select() uses a "struct timeval", which specifies the timeout in
- * seconds and microseconds, so the milliseconds value has to be mapped
- * accordingly.
- */
+ /*
+ Map the poll() timeout value into a select() timeout. The possible
+ values of the poll() timeout value, and their meanings, are:
+
+ VALUE MEANING
- assert(pSelTimeout != (struct timeval *) NULL);
+ -1 wait indefinitely (until signal occurs)
+ 0 return immediately, don't block
+ >0 wait specified number of milliseconds
+
+ select() uses a "struct timeval", which specifies the timeout in
+ seconds and microseconds, so the milliseconds value has to be mapped
+ accordingly.
+ */
+
+ assert(pSelTimeout != NULL);
switch (poll_timeout) {
case -1:
@@ -203,25 +187,13 @@ static struct timeval *map_timeout
return pResult;
}
+#endif /* AST_POLL_COMPAT */
-static void map_select_results
-#if __STDC__ > 0
- (struct pollfd *pArray,
- unsigned long n_fds,
- fd_set *pReadSet,
- fd_set *pWriteSet,
- fd_set *pExceptSet)
-#else
- (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
- struct pollfd *pArray;
- unsigned long n_fds;
- fd_set *pReadSet;
- fd_set *pWriteSet;
- fd_set *pExceptSet;
-#endif
+static void map_select_results(struct pollfd *pArray, unsigned long n_fds,
+ ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
{
- register unsigned long i; /* loop control */
- register struct pollfd *pCur; /* current array element */
+ register unsigned long i; /* loop control */
+ register struct pollfd *pCur; /* current array element */
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
/* Skip any bad FDs in the array. */
@@ -231,59 +203,105 @@ static void map_select_results
}
/* Exception events take priority over input events. */
-
pCur->revents = 0;
- if (FD_ISSET (pCur->fd, pExceptSet)) {
+ if (FD_ISSET(pCur->fd, (fd_set *) pExceptSet)) {
pCur->revents |= POLLPRI;
- } else if (FD_ISSET (pCur->fd, pReadSet)) {
+ } else if (FD_ISSET(pCur->fd, (fd_set *) pReadSet)) {
pCur->revents |= POLLIN;
}
- if (FD_ISSET (pCur->fd, pWriteSet)) {
+ if (FD_ISSET(pCur->fd, (fd_set *) pWriteSet)) {
pCur->revents |= POLLOUT;
}
}
return;
}
+#endif /* defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL) */
/*---------------------------------------------------------------------------*\
- Public Functions
+ Public Functions
\*---------------------------------------------------------------------------*/
-
+#ifdef AST_POLL_COMPAT
int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout)
{
- fd_set read_descs; /* input file descs */
- fd_set write_descs; /* output file descs */
- fd_set except_descs; /* exception descs */
+ ast_fdset read_descs; /* input file descs */
+ ast_fdset write_descs; /* output file descs */
+ ast_fdset except_descs; /* exception descs */
struct timeval stime; /* select() timeout value */
- int ready_descriptors; /* function result */
- int max_fd = 0; /* maximum fd value */
+ int ready_descriptors; /* function result */
+ int max_fd = 0; /* maximum fd value */
struct timeval *pTimeout; /* actually passed */
+ int save_errno;
- FD_ZERO (&read_descs);
- FD_ZERO (&write_descs);
- FD_ZERO (&except_descs);
+ FD_ZERO(&read_descs);
+ FD_ZERO(&write_descs);
+ FD_ZERO(&except_descs);
/* Map the poll() file descriptor list in the select() data structures. */
if (pArray) {
- max_fd = map_poll_spec (pArray, n_fds,
+ max_fd = map_poll_spec (pArray, n_fds,
&read_descs, &write_descs, &except_descs);
}
/* Map the poll() timeout value in the select() timeout structure. */
- pTimeout = map_timeout(timeout, &stime);
+
+ pTimeout = map_timeout (timeout, &stime);
/* Make the select() call. */
- ready_descriptors = select(max_fd + 1, &read_descs, &write_descs,
+
+ ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs,
&except_descs, pTimeout);
+ save_errno = errno;
+
+ if (ready_descriptors >= 0) {
+ map_select_results (pArray, n_fds,
+ &read_descs, &write_descs, &except_descs);
+ }
+
+ errno = save_errno;
+ return ready_descriptors;
+}
+#endif /* AST_POLL_COMPAT */
+
+int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
+{
+#if !defined(AST_POLL_COMPAT)
+ struct timeval start = ast_tvnow();
+#if defined(HAVE_PPOLL)
+ struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 };
+ int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL);
+#else
+ int res = poll(pArray, n_fds, tv ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1);
+#endif
+ struct timeval after = ast_tvnow();
+ if (res > 0 && tv && ast_tvdiff_ms(ast_tvadd(*tv, start), after) > 0) {
+ *tv = ast_tvsub(*tv, ast_tvsub(after, start));
+ } else if (res > 0 && tv) {
+ *tv = ast_tv(0, 0);
+ }
+ return res;
+#else
+ ast_fdset read_descs, write_descs, except_descs;
+ int ready_descriptors, max_fd = 0;
+
+ FD_ZERO(&read_descs);
+ FD_ZERO(&write_descs);
+ FD_ZERO(&except_descs);
+
+ if (pArray) {
+ max_fd = map_poll_spec(pArray, n_fds, &read_descs, &write_descs, &except_descs);
+ }
+
+ ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, tv);
if (ready_descriptors >= 0) {
map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
}
return ready_descriptors;
+#endif
}
-#endif /* AST_POLL_COMPAT */
+
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 02c453ff9..9fe5c5a62 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -282,6 +282,10 @@ static void instance_destructor(void *obj)
return;
}
+ if (instance->srtp) {
+ res_srtp->destroy(instance->srtp);
+ }
+
/* Drop our engine reference */
ast_module_unref(instance->engine->mod);
diff --git a/main/sched.c b/main/sched.c
index 78de1a99e..8a3602a39 100644
--- a/main/sched.c
+++ b/main/sched.c
@@ -604,13 +604,13 @@ int ast_sched_runq(struct sched_context *con)
ast_mutex_lock(&con->lock);
+ when = ast_tvadd(ast_tvnow(), ast_tv(0, 1000));
for (numevents = 0; (current = ast_heap_peek(con->sched_heap, 1)); numevents++) {
/* schedule all events which are going to expire within 1ms.
* We only care about millisecond accuracy anyway, so this will
* help us get more than one event at one time if they are very
* close together.
*/
- when = ast_tvadd(ast_tvnow(), ast_tv(0, 1000));
if (ast_tvcmp(current->when, when) != -1) {
break;
}
diff --git a/main/stun.c b/main/stun.c
index 74652f90b..3ad326ee8 100644
--- a/main/stun.c
+++ b/main/stun.c
@@ -397,8 +397,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
/* send request, possibly wait for reply */
unsigned char reply_buf[1024];
- fd_set rfds;
- struct timeval to = { 3, 0 }; /* timeout, make it configurable */
+ struct pollfd pfds = { .fd = s, .events = POLLIN };
struct sockaddr_in src;
socklen_t srclen;
@@ -410,9 +409,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
}
if (answer == NULL)
break;
- FD_ZERO(&rfds);
- FD_SET(s, &rfds);
- res = ast_select(s + 1, &rfds, NULL, NULL, &to);
+ res = ast_poll(&pfds, 1, 3000);
if (res <= 0) /* timeout or error */
continue;
memset(&src, 0, sizeof(src));
diff --git a/main/translate.c b/main/translate.c
index 24d886473..61b4a4686 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -45,10 +45,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*! \brief the list of translators */
static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
+
+/*! \brief these values indicate how a translation path will affect the sample rate
+ *
+ * \note These must stay in this order. They are ordered by most optimal selection first.
+ */
+enum path_samp_change {
+ RATE_CHANGE_NONE = 0, /*!< path uses the same sample rate consistently */
+ RATE_CHANGE_UPSAMP = 1, /*!< path will up the sample rate during a translation */
+ RATE_CHANGE_DOWNSAMP = 2, /*!< path will have to down the sample rate during a translation. */
+ RATE_CHANGE_UPSAMP_DOWNSAMP = 3, /*!< path will both up and down the sample rate during translation */
+};
+
struct translator_path {
struct ast_translator *step; /*!< Next step translator */
unsigned int cost; /*!< Complete cost to destination */
unsigned int multistep; /*!< Multiple conversions required for this translation */
+ enum path_samp_change rate_change; /*!< does this path require a sample rate change, if so what kind. */
};
/*! \brief a matrix that, for any pair of supported formats,
@@ -402,6 +415,24 @@ static void calc_cost(struct ast_translator *t, int seconds)
t->cost = 1;
}
+static enum path_samp_change get_rate_change_result(format_t src, format_t dst)
+{
+ int src_rate = ast_format_rate(src);
+ int dst_rate = ast_format_rate(dst);
+
+ /* if src rate is less than dst rate, a sample upgrade is required */
+ if (src_rate < dst_rate) {
+ return RATE_CHANGE_UPSAMP;
+ }
+
+ /* if src rate is larger than dst rate, a downgrade is required */
+ if (src_rate > dst_rate) {
+ return RATE_CHANGE_DOWNSAMP;
+ }
+
+ return RATE_CHANGE_NONE;
+}
+
/*!
* \brief rebuild a translation matrix.
* \note This function expects the list of translators to be locked
@@ -409,6 +440,8 @@ static void calc_cost(struct ast_translator *t, int seconds)
static void rebuild_matrix(int samples)
{
struct ast_translator *t;
+ int new_rate_change;
+ int newcost;
int x; /* source format index */
int y; /* intermediate format index */
int z; /* destination format index */
@@ -427,10 +460,21 @@ static void rebuild_matrix(int samples)
if (samples)
calc_cost(t, samples);
-
- if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) {
+
+ new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt);
+
+ /* this translator is the best choice if any of the below are true.
+ * 1. no translation path is set between x and z yet.
+ * 2. the new translation costs less and sample rate is no worse than old one.
+ * 3. the new translation has a better sample rate conversion than the old one.
+ */
+ if (!tr_matrix[x][z].step ||
+ ((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) ||
+ (new_rate_change < tr_matrix[x][z].rate_change)) {
+
tr_matrix[x][z].step = t;
tr_matrix[x][z].cost = t->cost;
+ tr_matrix[x][z].rate_change = new_rate_change;
}
}
@@ -442,31 +486,73 @@ static void rebuild_matrix(int samples)
*/
for (;;) {
int changed = 0;
+ int better_choice = 0;
for (x = 0; x < MAX_FORMAT; x++) { /* source format */
for (y = 0; y < MAX_FORMAT; y++) { /* intermediate format */
if (x == y) /* skip ourselves */
continue;
-
- for (z = 0; z<MAX_FORMAT; z++) { /* dst format */
- int newcost;
-
+ for (z = 0; z < MAX_FORMAT; z++) { /* dst format */
if (z == x || z == y) /* skip null conversions */
continue;
if (!tr_matrix[x][y].step) /* no path from x to y */
continue;
if (!tr_matrix[y][z].step) /* no path from y to z */
continue;
+
+ /* Does x->y->z result in a less optimal sample rate change?
+ * Never downgrade the sample rate conversion quality regardless
+ * of any cost improvements */
+ if (tr_matrix[x][z].step &&
+ ((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) ||
+ (tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) {
+ continue;
+ }
+
+ /* is x->y->z a better sample rate confersion that the current x->z? */
+ new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change;
+
+ /* calculate cost from x->y->z */
newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
- if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost)
- continue; /* x->y->z is more expensive than
- * the existing path */
+
+ /* Is x->y->z a better choice than x->z?
+ * There are three conditions for x->y->z to be a better choice than x->z
+ * 1. if there is no step directly between x->z then x->y->z is the best and only current option.
+ * 2. if x->y->z costs less and the sample rate conversion is no less optimal.
+ * 3. if x->y->z results in a more optimal sample rate conversion. */
+ if (!tr_matrix[x][z].step) {
+ better_choice = 1;
+ } else if ((newcost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) {
+ better_choice = 1;
+ } else if (new_rate_change < tr_matrix[x][z].rate_change) {
+ better_choice = 1;
+ } else {
+ better_choice = 0;
+ }
+
+ if (!better_choice) {
+ continue;
+ }
/* ok, we can get from x to z via y with a cost that
- is the sum of the transition from x to y and
- from y to z */
-
+ is the sum of the transition from x to y and from y to z */
tr_matrix[x][z].step = tr_matrix[x][y].step;
tr_matrix[x][z].cost = newcost;
tr_matrix[x][z].multistep = 1;
+
+ /* now calculate what kind of sample rate change is required for this multi-step path
+ *
+ * if both paths require a change in rate, and they are not in the same direction
+ * then this is a up sample down sample conversion scenario. */
+ if ((tr_matrix[x][y].rate_change > RATE_CHANGE_NONE) &&
+ (tr_matrix[y][z].rate_change > RATE_CHANGE_NONE) &&
+ (tr_matrix[x][y].rate_change != tr_matrix[y][z].rate_change)) {
+
+ tr_matrix[x][z].rate_change = RATE_CHANGE_UPSAMP_DOWNSAMP;
+ } else {
+ /* else just set the rate change to whichever is worse */
+ tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change > tr_matrix[y][z].rate_change
+ ? tr_matrix[x][y].rate_change : tr_matrix[y][z].rate_change;
+ }
+
ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y));
changed++;
@@ -478,30 +564,134 @@ static void rebuild_matrix(int samples)
}
}
+const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
+{
+ struct ast_trans_pvt *pn = p;
+
+ if (!p || !p->t) {
+ return "";
+ }
+
+ ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt));
+
+ while ( (p = pn) ) {
+ pn = p->next;
+ ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt));
+ }
+
+ return ast_str_buffer(*str);
+}
+
+static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
+{
+ int which = 0;
+ int wordlen = strlen(word);
+ int i;
+ char *ret = NULL;
+ size_t len = 0;
+ const struct ast_format_list *format_list = ast_get_format_list(&len);
+
+ for (i = 0; i < len; i++) {
+ if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
+ continue;
+ }
+ if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
+ ret = ast_strdup(format_list[i].name);
+ break;
+ }
+ }
+ return ret;
+}
+
static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
-#define SHOW_TRANS 16
+#define SHOW_TRANS 64
+ static const char * const option1[] = { "recalc", "paths", NULL };
int x, y, z;
int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
switch (cmd) {
case CLI_INIT:
- e->command = "core show translation [recalc]";
+ e->command = "core show translation";
e->usage =
- "Usage: core show translation [recalc [<recalc seconds>]]\n"
- " Displays known codec translators and the cost associated\n"
- " with each conversion. If the argument 'recalc' is supplied along\n"
- " with optional number of seconds to test a new test will be performed\n"
- " as the chart is being displayed.\n";
+ "Usage: 'core show translation' can be used in two ways.\n"
+ " 1. 'core show translation [recalc [<recalc seconds>]]\n"
+ " Displays known codec translators and the cost associated\n"
+ " with each conversion. If the argument 'recalc' is supplied along\n"
+ " with optional number of seconds to test a new test will be performed\n"
+ " as the chart is being displayed.\n"
+ " 2. 'core show translation paths [codec]'\n"
+ " This will display all the translation paths associated with a codec\n";
return NULL;
case CLI_GENERATE:
+ if (a->pos == 3) {
+ return ast_cli_complete(a->word, option1, a->n);
+ }
+ if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) {
+ return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
+ }
return NULL;
}
if (a->argc > 5)
return CLI_SHOWUSAGE;
- if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
+ if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) {
+ format_t input_src = 0;
+ format_t src = 0;
+ size_t len = 0;
+ int dst;
+ int i;
+ const struct ast_format_list *format_list = ast_get_format_list(&len);
+ struct ast_str *str = ast_str_alloca(256);
+ struct ast_translator *step;
+
+ for (i = 0; i < len; i++) {
+ if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
+ continue;
+ }
+ if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
+ input_src = format_list[i].bits;
+ }
+ }
+
+ if (!input_src) {
+ ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
+ return CLI_FAILURE;
+ }
+
+ AST_RWLIST_RDLOCK(&translators);
+ ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src));
+ for (i = 0; i < len; i++) {
+ if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) {
+ continue;
+ }
+ dst = powerof(format_list[i].bits);
+ src = powerof(input_src);
+ ast_str_reset(str);
+ if (tr_matrix[src][dst].step) {
+ ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt));
+ while (src != dst) {
+ step = tr_matrix[src][dst].step;
+ if (!step) {
+ ast_str_reset(str);
+ break;
+ }
+ ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt));
+ src = step->dstfmt;
+ }
+ }
+
+ if (ast_strlen_zero(ast_str_buffer(str))) {
+ ast_str_set(&str, 0, "No Translation Path");
+ }
+
+ ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
+ }
+ AST_RWLIST_UNLOCK(&translators);
+
+ return CLI_SUCCESS;
+ } else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
z = a->argv[4] ? atoi(a->argv[4]) : 1;
if (z <= 0) {
@@ -526,22 +716,33 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n");
/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
for (x = 0; x < SHOW_TRANS; x++) {
+ /* translation only applies to audio right now. */
+ if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+ continue;
curlen = strlen(ast_getformatname(1LL << (x)));
if (curlen > longest)
longest = curlen;
for (y = 0; y < SHOW_TRANS; y++) {
+ if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
+ continue;
if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
magnitude[y] = floor(log10(tr_matrix[x][y].cost));
}
}
}
for (x = -1; x < SHOW_TRANS; x++) {
- struct ast_str *out = ast_str_alloca(125);
+ struct ast_str *out = ast_str_alloca(256);
+ /* translation only applies to audio right now. */
+ if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+ continue;
/*Go ahead and move to next iteration if dealing with an unknown codec*/
if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown"))
continue;
ast_str_set(&out, -1, " ");
for (y = -1; y < SHOW_TRANS; y++) {
+ /* translation only applies to audio right now. */
+ if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
+ continue;
/*Go ahead and move to next iteration if dealing with an unknown codec*/
if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown"))
continue;
@@ -715,37 +916,65 @@ void ast_translator_deactivate(struct ast_translator *t)
format_t ast_translator_best_choice(format_t *dst, format_t *srcs)
{
int x,y;
+ int better = 0;
+ int besttime = INT_MAX;
+ int beststeps = INT_MAX;
+ unsigned int best_rate_change = INT_MAX;
format_t best = -1;
format_t bestdst = 0;
format_t cur, cursrc;
- int besttime = INT_MAX;
- int beststeps = INT_MAX;
format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */
if (common) { /* yes, pick one and return */
for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
- if (cur & common) /* guaranteed to find one */
- break;
+ if (!(cur & common)) {
+ continue;
+ }
+
+ /* We are guaranteed to find one common format. */
+ if (best == -1) {
+ best = cur;
+ continue;
+ }
+ /* If there are multiple common formats, pick the one with the highest sample rate */
+ if (ast_format_rate(best) < ast_format_rate(cur)) {
+ best = cur;
+ continue;
+ }
}
/* We are done, this is a common format to both. */
- *srcs = *dst = cur;
+ *srcs = *dst = best;
return 0;
- } else { /* No, we will need to translate */
+ } else { /* No, we will need to translate */
AST_RWLIST_RDLOCK(&translators);
for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
- if (! (cur & *dst))
+ if (! (cur & *dst)) {
continue;
+ }
for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
- if (!(*srcs & cursrc) || !tr_matrix[x][y].step ||
- tr_matrix[x][y].cost > besttime)
- continue; /* not existing or no better */
- if (tr_matrix[x][y].cost < besttime ||
- tr_matrix[x][y].multistep < beststeps) {
+ if (!(*srcs & cursrc) || !tr_matrix[x][y].step) {
+ continue;
+ }
+
+ /* This is a better choice if any of the following are true.
+ * 1. The sample rate conversion is better than the current pick.
+ * 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better
+ */
+ better = 0;
+ if (tr_matrix[x][y].rate_change < best_rate_change) {
+ better = 1; /* this match has a better rate conversion */
+ }
+ if ((tr_matrix[x][y].rate_change <= best_rate_change) &&
+ (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) {
+ better = 1; /* this match has no worse rate conversion and the conversion cost is less */
+ }
+ if (better) {
/* better than what we have so far */
best = cursrc;
bestdst = cur;
besttime = tr_matrix[x][y].cost;
beststeps = tr_matrix[x][y].multistep;
+ best_rate_change = tr_matrix[x][y].rate_change;
}
}
}
diff --git a/main/utils.c b/main/utils.c
index 5961a7339..6f2c884d0 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1615,7 +1615,8 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
size_t space = (*pool_head)->size - (*pool_head)->used;
size_t to_alloc = needed + sizeof(ast_string_field_allocation);
- if (__builtin_expect(to_alloc > space, 0)) {
+ /* This +1 accounts for alignment on SPARC */
+ if (__builtin_expect(to_alloc + 1 > space, 0)) {
size_t new_size = (*pool_head)->size;
while (new_size < to_alloc) {
@@ -1632,6 +1633,13 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
}
result = (*pool_head)->base + (*pool_head)->used;
+#ifdef __sparc__
+ /* SPARC requires that the allocation field be aligned. */
+ if ((long) result % sizeof(ast_string_field_allocation)) {
+ result++;
+ (*pool_head)->used++;
+ }
+#endif
(*pool_head)->used += to_alloc;
(*pool_head)->active += needed;
result += sizeof(ast_string_field_allocation);
@@ -1706,6 +1714,12 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
}
} else {
target = (*pool_head)->base + (*pool_head)->used + sizeof(ast_string_field_allocation);
+#ifdef __sparc__
+ if ((long) target % sizeof(ast_string_field_allocation)) {
+ target++;
+ space--;
+ }
+#endif
available = space - sizeof(ast_string_field_allocation);
}