diff options
author | bbryant <bbryant@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-09-09 18:51:52 +0000 |
---|---|---|
committer | bbryant <bbryant@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-09-09 18:51:52 +0000 |
commit | 722eb3c4c3cfa1c0cee915c949c5f95199ee24dd (patch) | |
tree | 25683963c5e51bdedd6211cd0ea92a85639505c3 /main | |
parent | 815b5b09da5e555add7bba3d8fca588e7611248a (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.c | 46 | ||||
-rw-r--r-- | main/ccss.c | 49 | ||||
-rw-r--r-- | main/cdr.c | 39 | ||||
-rw-r--r-- | main/cel.c | 6 | ||||
-rw-r--r-- | main/channel.c | 14 | ||||
-rw-r--r-- | main/cli.c | 43 | ||||
-rw-r--r-- | main/config.c | 2 | ||||
-rw-r--r-- | main/features.c | 89 | ||||
-rw-r--r-- | main/loader.c | 20 | ||||
-rw-r--r-- | main/manager.c | 33 | ||||
-rw-r--r-- | main/netsock2.c | 16 | ||||
-rw-r--r-- | main/pbx.c | 57 | ||||
-rw-r--r-- | main/poll.c | 196 | ||||
-rw-r--r-- | main/rtp_engine.c | 4 | ||||
-rw-r--r-- | main/sched.c | 2 | ||||
-rw-r--r-- | main/stun.c | 7 | ||||
-rw-r--r-- | main/translate.c | 295 | ||||
-rw-r--r-- | main/utils.c | 16 |
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); } |