summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES52
-rw-r--r--addons/chan_ooh323.h1
-rw-r--r--addons/ooh323c/src/Makefile.in2
-rw-r--r--apps/app_dahdiras.c5
-rw-r--r--apps/app_dial.c5
-rw-r--r--apps/app_queue.c11
-rw-r--r--apps/app_voicemail.c79
-rw-r--r--channels/chan_console.c2
-rw-r--r--channels/chan_dahdi.c4
-rw-r--r--channels/chan_iax2.c1
-rw-r--r--channels/chan_mgcp.c1
-rw-r--r--channels/chan_motif.c2
-rw-r--r--channels/chan_rtp.c53
-rw-r--r--channels/chan_sip.c3
-rw-r--r--channels/chan_skinny.c1
-rw-r--r--configs/samples/res_odbc.conf.sample5
-rwxr-xr-xconfigure19
-rw-r--r--configure.ac9
-rw-r--r--include/asterisk/codec.h2
-rw-r--r--include/asterisk/compat.h2
-rw-r--r--include/asterisk/poll-compat.h2
-rw-r--r--include/asterisk/res_hep.h8
-rw-r--r--main/Makefile2
-rw-r--r--main/ast_expr2.c1
-rw-r--r--main/ast_expr2.y1
-rw-r--r--main/asterisk.c30
-rw-r--r--main/bridge_channel.c3
-rw-r--r--main/channel.c3
-rw-r--r--main/cli.c1
-rw-r--r--main/codec.c10
-rw-r--r--main/codec_builtin.c6
-rw-r--r--main/dial.c14
-rw-r--r--main/dns.c4
-rw-r--r--main/editline/Makefile.in2
-rw-r--r--main/features.c2
-rw-r--r--main/http.c2
-rw-r--r--main/manager.c18
-rw-r--r--main/say.c573
-rw-r--r--main/tcptls.c1
-rw-r--r--pbx/pbx_dundi.c2
-rw-r--r--res/ael/ael.flex6
-rw-r--r--res/ael/ael_lex.c6
-rw-r--r--res/ari/resource_channels.c88
-rw-r--r--res/ari/resource_channels.h6
-rw-r--r--res/res_ari_channels.c21
-rw-r--r--res/res_ari_recordings.c1
-rw-r--r--res/res_hep.c12
-rw-r--r--res/res_hep.exports.in1
-rw-r--r--res/res_hep_pjsip.c5
-rw-r--r--res/res_hep_rtcp.c4
-rw-r--r--res/res_musiconhold.c2
-rw-r--r--res/res_odbc.c232
-rw-r--r--res/res_srtp.c8
-rw-r--r--rest-api/api-docs/channels.json24
54 files changed, 1236 insertions, 124 deletions
diff --git a/CHANGES b/CHANGES
index 6ffefbf35..43dc18f4b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -135,6 +135,32 @@ chan_iax2
seconds. Setting this to a higher value may help in lagged networks or those
experiencing high packet loss.
+chan_rtp (was chan_multicast_rtp)
+------------------
+ * Added unicast RTP support and renamed chan_multicast_rtp to chan_rtp.
+
+ * The format for dialing a unicast RTP channel is:
+ UnicastRTP/<destination-addr>[/[<options>]]
+ Where <destination-addr> is something like '127.0.0.1:5060'.
+ Where <options> are in standard Asterisk flag options format:
+ c(<codec>) - Specify which codec/format to use such as 'ulaw'.
+ e(<engine>) - Specify which RTP engine to use such as 'asterisk'.
+
+ * New options were added for a multicast RTP channel. The format for
+ dialing a multicast RTP channel is:
+ MulticastRTP/<type>/<destination-addr>[/[<control-addr>][/[<options>]]]
+ Where <type> can be either 'basic' or 'linksys'.
+ Where <destination-addr> is something like '224.0.0.3:5060'.
+ Where <control-addr> is something like '127.0.0.1:5060'.
+ Where <options> are in standard Asterisk flag options format:
+ c(<codec>) - Specify which codec/format to use such as 'ulaw'.
+ i(<address>) - Specify the interface address from which multicast RTP
+ is sent.
+ l(<enable>) - Set whether packets are looped back to the sender. The
+ enable value can be 0 to set looping to off and non-zero to set
+ looping on.
+ t(<ttl>) - Set the time-to-live (TTL) value for multicast packets.
+
chan_sip
------------------
* New 'rtpbindaddr' global setting. This allows a user to define which
@@ -331,6 +357,11 @@ cdr_csv
--- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 -----------
------------------------------------------------------------------------------
+Core
+------------------
+ * A channel variable FORWARDERNAME is now set which indicates which channel
+ was responsible for a forwarding requests received on dial attempt.
+
func_odbc
------------------
* Added new global option "single_db_connection".
@@ -376,6 +407,12 @@ res_hep
valid value using the specified 'uuid_type', the module may fallback to a
more readily available source for the correlation UUID.
+res_odbc
+------------------
+ * A new option has been added, 'max_connections', which sets the maximum number
+ of concurrent connections to the database. This option defaults to 1 which
+ returns the behavior to that of Asterisk 13.7 and prior.
+
app_confbridge
------------------
* Added a bridge profile option called regcontext that allows you to
@@ -384,6 +421,18 @@ app_confbridge
server installations via alternate means (DUNDI for example). By default
this feature is not used.
+Codecs
+------------------
+ * Added the associated format name to 'core show codecs'.
+
+res_ari_channels
+------------------
+ * Added 'formats' to channel create/originate to allow setting the allowed
+ formats for a channel when no originator channel is available. Especially
+ useful for Local channel creation where no other format information is
+ available. 'core show codecs' can now be used to look up suitable format
+ names.
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.8.0 to Asterisk 13.9.0 ------------
------------------------------------------------------------------------------
@@ -1005,6 +1054,8 @@ Say
language. The 'language' parameter in say.conf now recognizes a setting of
'ja', which will enable Japanese language specific mechanisms for playing
back numbers, dates, and other items.
+ * Counting, enumeration and dates now supports Icelandic grammar with the
+ 'language' parameter set to 'is'.
SayCountPL
------------------
@@ -5158,6 +5209,7 @@ Voicemail Changes
the message as urgent after he has recorded a voicemail by following the voice instructions.
When listening to voicemails using VoiceMailMain urgent messages will be presented before other
messages
+ * Added "is" language support
Queue changes
-------------
diff --git a/addons/chan_ooh323.h b/addons/chan_ooh323.h
index 89caaff63..1279a2246 100644
--- a/addons/chan_ooh323.h
+++ b/addons/chan_ooh323.h
@@ -38,7 +38,6 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
-#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
diff --git a/addons/ooh323c/src/Makefile.in b/addons/ooh323c/src/Makefile.in
index d3a96024b..15b14f7df 100644
--- a/addons/ooh323c/src/Makefile.in
+++ b/addons/ooh323c/src/Makefile.in
@@ -104,7 +104,7 @@ CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
LIBRARIES = $(noinst_LIBRARIES)
-libooh323c_a_AR = $(AR) cru
+libooh323c_a_AR = $(AR) cr
libooh323c_a_LIBADD =
am_libooh323c_a_OBJECTS = ooLogChan.$(OBJEXT) ooUtils.$(OBJEXT) \
ooGkClient.$(OBJEXT) context.$(OBJEXT) ooDateTime.$(OBJEXT) \
diff --git a/apps/app_dahdiras.c b/apps/app_dahdiras.c
index e8bdad01e..51921a98e 100644
--- a/apps/app_dahdiras.c
+++ b/apps/app_dahdiras.c
@@ -36,12 +36,7 @@ ASTERISK_REGISTER_FILE()
#include <sys/ioctl.h>
#include <sys/wait.h>
-#ifdef __linux__
-#include <sys/signal.h>
-#else
#include <signal.h>
-#endif /* __linux__ */
-
#include <fcntl.h>
#include <dahdi/user.h>
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 5e034d3eb..c4d527303 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -35,7 +35,7 @@
ASTERISK_REGISTER_FILE()
#include <sys/time.h>
-#include <sys/signal.h>
+#include <signal.h>
#include <sys/stat.h>
#include <netinet/in.h>
@@ -834,6 +834,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
struct ast_party_id *forced_clid, struct ast_party_id *stored_clid)
{
char tmpchan[256];
+ char forwarder[AST_CHANNEL_NAME];
struct ast_channel *original = o->chan;
struct ast_channel *c = o->chan; /* the winner */
struct ast_channel *in = num->chan; /* the input channel */
@@ -842,6 +843,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
int cause;
struct ast_party_caller caller;
+ ast_copy_string(forwarder, ast_channel_name(c), sizeof(forwarder));
ast_copy_string(tmpchan, ast_channel_call_forward(c), sizeof(tmpchan));
if ((stuff = strchr(tmpchan, '/'))) {
*stuff++ = '\0';
@@ -895,6 +897,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
ast_channel_lock_both(in, o->chan);
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
+ pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
ast_max_forwards_decrement(o->chan);
ast_channel_unlock(in);
ast_channel_unlock(o->chan);
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 165924e0c..8f949635d 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -72,7 +72,7 @@
ASTERISK_REGISTER_FILE()
#include <sys/time.h>
-#include <sys/signal.h>
+#include <signal.h>
#include <netinet/in.h>
#include <ctype.h>
@@ -4854,16 +4854,22 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
continue;
} else if (!ast_strlen_zero(ast_channel_call_forward(o->chan))) {
struct ast_channel *original = o->chan;
+ char forwarder[AST_CHANNEL_NAME];
char tmpchan[256];
char *stuff;
char *tech;
ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
+ ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
if ((stuff = strchr(tmpchan, '/'))) {
*stuff++ = '\0';
tech = tmpchan;
} else {
- snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), ast_channel_context(o->chan));
+ const char *forward_context;
+ ast_channel_lock(o->chan);
+ forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
+ snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
+ ast_channel_unlock(o->chan);
stuff = tmpchan;
tech = "Local";
}
@@ -4895,6 +4901,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
ast_channel_lock_both(o->chan, in);
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
+ pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
ast_max_forwards_decrement(o->chan);
if (o->pending_connected_update) {
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index 1d5b2dcb3..586086c55 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -8527,6 +8527,8 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
} else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL);
+ } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
+ res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
} else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
} else if (!strcasecmp(ast_channel_language(chan),"ja")) { /* Japanese syntax */
@@ -8753,6 +8755,12 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
res = wait_file2(chan, vms, "vm-number");
res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
}
+ /* ICELANDIC syntax */
+ } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) {
+ res = wait_file2(chan, vms, "vm-message");
+ if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
+ res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "n");
+ }
/* VIETNAMESE syntax */
} else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
if (!vms->curmsg) {
@@ -9492,6 +9500,75 @@ static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
return res;
}
+/* ICELANDIC syntax */
+static int vm_intro_is(struct ast_channel *chan, struct vm_state *vms)
+{
+ int res;
+
+ /* Introduce messages they have */
+ res = ast_play_and_wait(chan, "vm-youhave");
+ if (!res) {
+ if (vms->urgentmessages) {
+ /* Digits 1-4 are spoken in neutral and plural when talking about messages,
+ however, feminine is used for 1 as it is the same as the neutral for plural,
+ and singular neutral is the same after 1. */
+ if (vms->urgentmessages < 5) {
+ char recname[16];
+ if (vms->urgentmessages == 1)
+ snprintf(recname, sizeof(recname), "digits/1kvk");
+ else
+ snprintf(recname, sizeof(recname), "digits/%dhk", vms->urgentmessages);
+ res = ast_play_and_wait(chan, recname);
+ } else if (!res)
+ res = ast_play_and_wait(chan, "vm-Urgent");
+ if ((vms->oldmessages || vms->newmessages) && !res) {
+ res = ast_play_and_wait(chan, "vm-and");
+ } else if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ if (vms->newmessages) {
+ if (vms->newmessages < 5) {
+ char recname[16];
+ if (vms->newmessages == 1)
+ snprintf(recname, sizeof(recname), "digits/1kvk");
+ else
+ snprintf(recname, sizeof(recname), "digits/%dhk", vms->newmessages);
+ res = ast_play_and_wait(chan, recname);
+ } else
+ res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-INBOX");
+ if (vms->oldmessages && !res)
+ res = ast_play_and_wait(chan, "vm-and");
+ else if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ if (!res && vms->oldmessages) {
+ if (vms->oldmessages < 5) {
+ char recname[16];
+ if (vms->oldmessages == 1)
+ snprintf(recname, sizeof(recname), "digits/1kvk");
+ else
+ snprintf(recname, sizeof(recname), "digits/%dhk", vms->oldmessages);
+ res = ast_play_and_wait(chan, recname);
+ } else
+ res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-Old");
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ if (!res) {
+ if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
+ res = ast_play_and_wait(chan, "vm-no");
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ }
+ }
+ return res;
+}
+
/* ITALIAN syntax */
static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
{
@@ -10156,6 +10233,8 @@ static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm
return vm_intro_gr(chan, vms);
} else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW syntax */
return vm_intro_he(chan, vms);
+ } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
+ return vm_intro_is(chan, vms);
} else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
return vm_intro_it(chan, vms);
} else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE syntax */
diff --git a/channels/chan_console.c b/channels/chan_console.c
index 9fdecd7d4..bd849ad53 100644
--- a/channels/chan_console.c
+++ b/channels/chan_console.c
@@ -64,7 +64,7 @@
ASTERISK_REGISTER_FILE()
-#include <sys/signal.h> /* SIGURG */
+#include <signal.h> /* SIGURG */
#include <portaudio.h>
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 2d923433c..e4b7c0ee8 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -58,10 +58,8 @@ ASTERISK_REGISTER_FILE()
#if defined(__NetBSD__) || defined(__FreeBSD__)
#include <pthread.h>
-#include <signal.h>
-#else
-#include <sys/signal.h>
#endif
+#include <signal.h>
#include <sys/stat.h>
#include <math.h>
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index af44de96c..721da9a04 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -68,7 +68,6 @@ ASTERISK_REGISTER_FILE()
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/time.h>
-#include <sys/signal.h>
#include <signal.h>
#include <strings.h>
#include <netdb.h>
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 8714ddbbc..6df5d3fd0 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -47,7 +47,6 @@ ASTERISK_REGISTER_FILE()
#include <net/if.h>
#include <fcntl.h>
#include <netdb.h>
-#include <sys/signal.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
diff --git a/channels/chan_motif.c b/channels/chan_motif.c
index 118d1d9fb..0c710923f 100644
--- a/channels/chan_motif.c
+++ b/channels/chan_motif.c
@@ -51,7 +51,7 @@ ASTERISK_REGISTER_FILE()
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <sys/signal.h>
+#include <signal.h>
#include <iksemel.h>
#include <pthread.h>
diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c
index 093602823..0fe66bd20 100644
--- a/channels/chan_rtp.c
+++ b/channels/chan_rtp.c
@@ -176,7 +176,7 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo
fmt = ast_format_cap_get_format(cap, 0);
}
if (!fmt) {
- ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n",
+ ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n",
args.destination);
goto failure;
}
@@ -230,6 +230,25 @@ failure:
return NULL;
}
+enum {
+ OPT_RTP_CODEC = (1 << 0),
+ OPT_RTP_ENGINE = (1 << 1),
+};
+
+enum {
+ OPT_ARG_RTP_CODEC,
+ OPT_ARG_RTP_ENGINE,
+ /* note: this entry _MUST_ be the last one in the enum */
+ OPT_ARG_ARRAY_SIZE
+};
+
+AST_APP_OPTIONS(unicast_rtp_options, BEGIN_OPTIONS
+ /*! Set the codec to be used for unicast RTP */
+ AST_APP_OPTION_ARG('c', OPT_RTP_CODEC, OPT_ARG_RTP_CODEC),
+ /*! Set the RTP engine to use for unicast RTP */
+ AST_APP_OPTION_ARG('e', OPT_RTP_ENGINE, OPT_ARG_RTP_ENGINE),
+END_OPTIONS );
+
/*! \brief Function called when we should prepare to call the unicast destination */
static struct ast_channel *unicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
{
@@ -240,11 +259,13 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
struct ast_channel *chan;
struct ast_format_cap *caps = NULL;
struct ast_format *fmt = NULL;
+ const char *engine_name;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(destination);
- AST_APP_ARG(engine);
- AST_APP_ARG(format);
+ AST_APP_ARG(options);
);
+ struct ast_flags opts = { 0, };
+ char *opt_args[OPT_ARG_ARRAY_SIZE];
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n");
@@ -262,17 +283,26 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
goto failure;
}
- if (!ast_strlen_zero(args.format)) {
- fmt = ast_format_cache_get(args.format);
+ if (!ast_strlen_zero(args.options)
+ && ast_app_parse_options(unicast_rtp_options, &opts, opt_args,
+ ast_strdupa(args.options))) {
+ ast_log(LOG_ERROR, "'UnicastRTP' channel options '%s' parse error\n",
+ args.options);
+ goto failure;
+ }
+
+ if (ast_test_flag(&opts, OPT_RTP_CODEC)
+ && !ast_strlen_zero(opt_args[OPT_ARG_RTP_CODEC])) {
+ fmt = ast_format_cache_get(opt_args[OPT_ARG_RTP_CODEC]);
if (!fmt) {
- ast_log(LOG_ERROR, "Format '%s' not found for sending RTP to '%s'\n",
- args.format, args.destination);
+ ast_log(LOG_ERROR, "Codec '%s' not found for sending RTP to '%s'\n",
+ opt_args[OPT_ARG_RTP_CODEC], args.destination);
goto failure;
}
} else {
fmt = ast_format_cap_get_format(cap, 0);
if (!fmt) {
- ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n",
+ ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n",
args.destination);
goto failure;
}
@@ -283,12 +313,15 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
goto failure;
}
+ engine_name = S_COR(ast_test_flag(&opts, OPT_RTP_ENGINE),
+ opt_args[OPT_ARG_RTP_ENGINE], NULL);
+
ast_ouraddrfor(&address, &local_address);
- instance = ast_rtp_instance_new(args.engine, NULL, &local_address, NULL);
+ instance = ast_rtp_instance_new(engine_name, NULL, &local_address, NULL);
if (!instance) {
ast_log(LOG_ERROR,
"Could not create %s RTP instance for sending media to '%s'\n",
- S_OR(args.engine, "default"), args.destination);
+ S_OR(engine_name, "default"), args.destination);
goto failure;
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 19f8aa308..eec904f57 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -224,7 +224,6 @@
ASTERISK_REGISTER_FILE()
#include <signal.h>
-#include <sys/signal.h>
#include <regex.h>
#include <inttypes.h>
@@ -12996,7 +12995,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
/* Opus mandates 2 channels in rtpmap */
if (ast_format_cmp(format, ast_format_opus) == AST_FORMAT_CMP_EQUAL) {
ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u/2\r\n", rtp_code, mime, rate);
- } else {
+ } else if ((35 <= rtp_code) || !(sip_cfg.compactheaders)) {
ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate);
}
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 76990d175..fb6e619a1 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -49,7 +49,6 @@ ASTERISK_REGISTER_FILE()
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
-#include <sys/signal.h>
#include <signal.h>
#include <ctype.h>
diff --git a/configs/samples/res_odbc.conf.sample b/configs/samples/res_odbc.conf.sample
index 66659ae42..a21e96d07 100644
--- a/configs/samples/res_odbc.conf.sample
+++ b/configs/samples/res_odbc.conf.sample
@@ -51,6 +51,11 @@ pre-connect => yes
; that we should attempt?
;limit => 5
;
+; The maximum number of connections to have open at any given time.
+; This defaults to 1 and it is highly recommended to only set this higher
+; if using a version of UnixODBC greater than 2.3.1.
+;max_connections => 20
+;
; When the channel is destroyed, should any uncommitted open transactions
; automatically be committed?
;forcecommit => no
diff --git a/configure b/configure
index 9e3772748..bcc427c84 100755
--- a/configure
+++ b/configure
@@ -4866,6 +4866,9 @@ case "${host_os}" in
linux-gnueabi* | linux-gnuspe)
OSARCH=linux-gnu
;;
+ linux-musl*)
+ OSARCH=linux-musl
+ ;;
kfreebsd*-gnu)
OSARCH=kfreebsd-gnu
;;
@@ -13772,7 +13775,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -13818,7 +13821,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -13842,7 +13845,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -13887,7 +13890,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -13911,7 +13914,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -19328,7 +19331,8 @@ fi
fi
-if test "x${OSARCH}" = "xlinux-gnu" ; then
+case "${OSARCH}" in
+linux*)
if test "x${PBX_CAP}" != "x1" -a "${USE_CAP}" != "no"; then
pbxlibdir=""
@@ -19433,7 +19437,8 @@ _ACEOF
fi
-fi
+ ;;
+esac
if test "x${PBX_DAHDI}" != "x1"; then
diff --git a/configure.ac b/configure.ac
index 5852d3fa2..3cc8588fe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -181,6 +181,9 @@ case "${host_os}" in
linux-gnueabi* | linux-gnuspe)
OSARCH=linux-gnu
;;
+ linux-musl*)
+ OSARCH=linux-musl
+ ;;
kfreebsd*-gnu)
OSARCH=kfreebsd-gnu
;;
@@ -1388,9 +1391,11 @@ if test "${PBX_BFD}" = "0"; then
AST_EXT_LIB_CHECK([BFD], [bfd], [bfd_check_format], [bfd.h], [-ldl -liberty -lz])
fi
-if test "x${OSARCH}" = "xlinux-gnu" ; then
+case "${OSARCH}" in
+linux*)
AST_EXT_LIB_CHECK([CAP], [cap], [cap_from_text], [sys/capability.h])
-fi
+ ;;
+esac
AST_C_DEFINE_CHECK([DAHDI], [DAHDI_RESET_COUNTERS], [dahdi/user.h], [230])
AST_C_DEFINE_CHECK([DAHDI], [DAHDI_DEFAULT_MTU_MRU], [dahdi/user.h], [220])
diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h
index 3873324b1..4ea94f9bb 100644
--- a/include/asterisk/codec.h
+++ b/include/asterisk/codec.h
@@ -77,6 +77,8 @@ struct ast_codec {
unsigned int smooth;
/*! \brief The module that registered this codec */
struct ast_module *mod;
+ /*! \brief A format name for a default sane format using this codec */
+ const char *format_name;
};
/*!
diff --git a/include/asterisk/compat.h b/include/asterisk/compat.h
index 3eb6c96a2..252ce914a 100644
--- a/include/asterisk/compat.h
+++ b/include/asterisk/compat.h
@@ -70,7 +70,7 @@
#endif
#ifndef AST_POLL_COMPAT
-#include <sys/poll.h>
+#include <poll.h>
#else
#include "asterisk/poll-compat.h"
#endif
diff --git a/include/asterisk/poll-compat.h b/include/asterisk/poll-compat.h
index cbb610925..72ac2c3e2 100644
--- a/include/asterisk/poll-compat.h
+++ b/include/asterisk/poll-compat.h
@@ -83,7 +83,7 @@
#ifndef AST_POLL_COMPAT
-#include <sys/poll.h>
+#include <poll.h>
#define ast_poll(a, b, c) poll(a, b, c)
diff --git a/include/asterisk/res_hep.h b/include/asterisk/res_hep.h
index bd0129eea..cfd213ad7 100644
--- a/include/asterisk/res_hep.h
+++ b/include/asterisk/res_hep.h
@@ -118,6 +118,14 @@ int hepv3_send_packet(struct hepv3_capture_info *capture_info);
*/
enum hep_uuid_type hepv3_get_uuid_type(void);
+/*!
+ * \brief Return whether or not we're currently loaded and active
+ *
+ * \retval 0 The module is not loaded
+ * \retval 1 The module is loaded
+ */
+int hepv3_is_loaded(void);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/main/Makefile b/main/Makefile
index 386397801..729ae9c01 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -46,7 +46,7 @@ AST_LIBS+=$(CRYPT_LIB)
AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS)
AST_LIBS+=$(RT_LIB)
-ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc kfreebsd-gnu),)
+ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc linux-musl kfreebsd-gnu),)
ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
AST_LIBS+=-ldl
endif
diff --git a/main/ast_expr2.c b/main/ast_expr2.c
index d41072d6e..c700b01d7 100644
--- a/main/ast_expr2.c
+++ b/main/ast_expr2.c
@@ -94,6 +94,7 @@
#define ASTMM_LIBC ASTMM_REDIRECT
#include "asterisk.h"
+#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
diff --git a/main/ast_expr2.y b/main/ast_expr2.y
index 762e83d84..df87bcc7f 100644
--- a/main/ast_expr2.y
+++ b/main/ast_expr2.y
@@ -15,6 +15,7 @@
#define ASTMM_LIBC ASTMM_REDIRECT
#include "asterisk.h"
+#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
diff --git a/main/asterisk.c b/main/asterisk.c
index 6cfbc1b33..25c6c9569 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -260,6 +260,12 @@ int daemon(int, int); /* defined in libresolv of all places */
<parameter name="Status">
<para>Informational message</para>
</parameter>
+ <parameter name="Uptime">
+ <para>Seconds since start</para>
+ </parameter>
+ <parameter name="LastReload">
+ <para>Seconds since last reload</para>
+ </parameter>
</syntax>
</managerEventInstance>
</managerEvent>
@@ -1020,9 +1026,25 @@ static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_c
static void publish_fully_booted(void)
{
RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+ int uptime = 0;
+ int lastreloaded = 0;
+ struct timeval tmp;
+ struct timeval curtime = ast_tvnow();
- json_object = ast_json_pack("{s: s}",
- "Status", "Fully Booted");
+ if (ast_startuptime.tv_sec) {
+ tmp = ast_tvsub(curtime, ast_startuptime);
+ uptime = (int) tmp.tv_sec;
+ }
+
+ if (ast_lastreloadtime.tv_sec) {
+ tmp = ast_tvsub(curtime, ast_lastreloadtime);
+ lastreloaded = (int) tmp.tv_sec;
+ }
+
+ json_object = ast_json_pack("{s: s, s: i, s: i}",
+ "Status", "Fully Booted",
+ "Uptime", uptime,
+ "LastReload", lastreloaded);
ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
}
@@ -4221,6 +4243,9 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
char *buf;
int moduleresult; /*!< Result from the module load subsystem */
+ /* Set time as soon as possible */
+ ast_lastreloadtime = ast_startuptime = ast_tvnow();
+
/* This needs to remain as high up in the initial start up as possible.
* daemon causes a fork to occur, which has all sorts of unintended
* consequences for things that interact with threads. This call *must*
@@ -4689,7 +4714,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
__ast_mm_init_phase_2();
#endif /* defined(__AST_DEBUG_MALLOC) */
- ast_lastreloadtime = ast_startuptime = ast_tvnow();
ast_cli_register_multiple(cli_asterisk_shutdown, ARRAY_LEN(cli_asterisk_shutdown));
ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
ast_register_cleanup(main_atexit);
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 6766dff8e..3ba61aa33 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -2162,9 +2162,10 @@ int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel,
ast_bridge_publish_enter(bridge, bridge_channel->chan, swap ? swap->chan : NULL);
- /* Clear any BLINDTRANSFER and ATTENDEDTRANSFER since the transfer has completed. */
+ /* Clear any BLINDTRANSFER,ATTENDEDTRANSFER and FORWARDERNAME since the transfer has completed. */
pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", NULL);
pbx_builtin_setvar_helper(bridge_channel->chan, "ATTENDEDTRANSFER", NULL);
+ pbx_builtin_setvar_helper(bridge_channel->chan, "FORWARDERNAME", NULL);
/* Wake up the bridge channel thread to reevaluate any interval timers. */
ast_queue_frame(bridge_channel->chan, &ast_null_frame);
diff --git a/main/channel.c b/main/channel.c
index 852de1aef..f654e4d25 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -5663,6 +5663,7 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe
struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, struct ast_format_cap *cap, struct outgoing_helper *oh, int *outstate)
{
char tmpchan[256];
+ char forwarder[AST_CHANNEL_NAME];
struct ast_channel *new_chan = NULL;
char *data, *type;
int cause = 0;
@@ -5670,6 +5671,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
/* gather data and request the new forward channel */
ast_copy_string(tmpchan, ast_channel_call_forward(orig), sizeof(tmpchan));
+ ast_copy_string(forwarder, ast_channel_name(orig), sizeof(forwarder));
if ((data = strchr(tmpchan, '/'))) {
*data++ = '\0';
type = tmpchan;
@@ -5713,6 +5715,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
ast_set_flag(ast_channel_flags(new_chan), AST_FLAG_ORIGINATED);
ast_channel_lock_both(orig, new_chan);
+ pbx_builtin_setvar_helper(new_chan, "FORWARDERNAME", forwarder);
ast_party_connected_line_copy(ast_channel_connected(new_chan), ast_channel_connected(orig));
ast_party_redirecting_copy(ast_channel_redirecting(new_chan), ast_channel_redirecting(orig));
ast_channel_req_accountcodes(new_chan, orig, AST_CHANNEL_REQUESTOR_REPLACEMENT);
diff --git a/main/cli.c b/main/cli.c
index f2bedc91a..8af20b61b 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -42,7 +42,6 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/_private.h"
#include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
-#include <sys/signal.h>
#include <signal.h>
#include <ctype.h>
#include <regex.h>
diff --git a/main/codec.c b/main/codec.c
index 9c4169a1c..a76264503 100644
--- a/main/codec.c
+++ b/main/codec.c
@@ -135,8 +135,8 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
"\tIt does not indicate anything about your configuration.\n");
}
- ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
- ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
+ ast_cli(a->fd, "%8s %-5s %-12s %-16s %s\n","ID","TYPE","NAME","FORMAT","DESCRIPTION");
+ ast_cli(a->fd, "------------------------------------------------------------------------------------------------\n");
ao2_rdlock(codecs);
i = ao2_iterator_init(codecs, AO2_ITERATOR_DONTLOCK);
@@ -164,10 +164,11 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
}
}
- ast_cli(a->fd, "%8u %5s %8s (%s)\n",
+ ast_cli(a->fd, "%8u %-5s %-12s %-16s (%s)\n",
codec->id,
ast_codec_media_type2str(codec->type),
codec->name,
+ S_OR(codec->format_name, "no cached format"),
codec->description);
}
@@ -216,7 +217,8 @@ static char *show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
return CLI_SUCCESS;
}
- ast_cli(a->fd, "%11u %s\n", (unsigned int) codec->id, codec->description);
+ ast_cli(a->fd, "%11u %s (%s)\n", (unsigned int) codec->id, codec->description,
+ S_OR(codec->format_name, "no format"));
ao2_ref(codec, -1);
diff --git a/main/codec_builtin.c b/main/codec_builtin.c
index f86a8dfc8..fdaa01825 100644
--- a/main/codec_builtin.c
+++ b/main/codec_builtin.c
@@ -774,6 +774,7 @@ static struct ast_codec t140 = {
int __res_ ## __LINE__ = 0; \
struct ast_format *__fmt_ ## __LINE__; \
struct ast_codec *__codec_ ## __LINE__; \
+ codec.format_name = (codec).name; \
res |= __ast_codec_register(&(codec), NULL); \
__codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \
__fmt_ ## __LINE__ = __codec_ ## __LINE__ ? ast_format_create(__codec_ ## __LINE__) : NULL; \
@@ -783,14 +784,15 @@ static struct ast_codec t140 = {
__res_ ## __LINE__; \
})
-#define CODEC_REGISTER_AND_CACHE_NAMED(format_name, codec) \
+#define CODEC_REGISTER_AND_CACHE_NAMED(fmt_name, codec) \
({ \
int __res_ ## __LINE__ = 0; \
struct ast_format *__fmt_ ## __LINE__; \
struct ast_codec *__codec_ ## __LINE__; \
+ codec.format_name = fmt_name; \
res |= __ast_codec_register(&(codec), NULL); \
__codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \
- __fmt_ ## __LINE__ = ast_format_create_named((format_name), __codec_ ## __LINE__); \
+ __fmt_ ## __LINE__ = ast_format_create_named((fmt_name), __codec_ ## __LINE__); \
res |= ast_format_cache_set(__fmt_ ## __LINE__); \
ao2_ref(__fmt_ ## __LINE__, -1); \
ao2_ref(__codec_ ## __LINE__, -1); \
diff --git a/main/dial.c b/main/dial.c
index bac191e06..7677c5a7d 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -454,16 +454,24 @@ int ast_dial_prerun(struct ast_dial *dial, struct ast_channel *chan, struct ast_
}
/*! \brief Helper function that does the beginning dialing per-appended channel */
-static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_channel *chan, int async, const char *predial_string)
+static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_channel *chan, int async, const char *predial_string, struct ast_channel *forwarder_chan)
{
char numsubst[AST_MAX_EXTENSION];
int res = 1;
+ char forwarder[AST_CHANNEL_NAME];
/* If no owner channel exists yet execute pre-run */
if (!channel->owner && begin_dial_prerun(channel, chan, NULL, predial_string)) {
return 0;
}
+ if (forwarder_chan) {
+ ast_copy_string(forwarder, ast_channel_name(forwarder_chan), sizeof(forwarder));
+ ast_channel_lock(channel->owner);
+ pbx_builtin_setvar_helper(channel->owner, "FORWARDERNAME", forwarder);
+ ast_channel_unlock(channel->owner);
+ }
+
/* Copy device string over */
ast_copy_string(numsubst, channel->device, sizeof(numsubst));
@@ -494,7 +502,7 @@ static int begin_dial(struct ast_dial *dial, struct ast_channel *chan, int async
/* Iterate through channel list, requesting and calling each one */
AST_LIST_LOCK(&dial->channels);
AST_LIST_TRAVERSE(&dial->channels, channel, list) {
- success += begin_dial_channel(channel, chan, async, predial_string);
+ success += begin_dial_channel(channel, chan, async, predial_string, NULL);
}
AST_LIST_UNLOCK(&dial->channels);
@@ -550,7 +558,7 @@ static int handle_call_forward(struct ast_dial *dial, struct ast_dial_channel *c
channel->owner = NULL;
/* Finally give it a go... send it out into the world */
- begin_dial_channel(channel, chan, chan ? 0 : 1, predial_string);
+ begin_dial_channel(channel, chan, chan ? 0 : 1, predial_string, original);
ast_channel_publish_dial_forward(chan, original, channel->owner, NULL, "CANCEL",
ast_channel_call_forward(original));
diff --git a/main/dns.c b/main/dns.c
index 96227949e..fa94089e7 100644
--- a/main/dns.c
+++ b/main/dns.c
@@ -254,12 +254,10 @@ static int dns_search_res(const char *dname, int rr_class, int rr_type,
{
int ret = AST_DNS_SEARCH_FAILURE;
- struct __res_state dns_state;
ast_mutex_lock(&res_lock);
res_init();
- ret = res_search(&dns_state,
- dname,
+ ret = res_search(dname,
rr_class,
rr_type,
dns_response,
diff --git a/main/editline/Makefile.in b/main/editline/Makefile.in
index 112b68b64..2be4333d5 100644
--- a/main/editline/Makefile.in
+++ b/main/editline/Makefile.in
@@ -187,7 +187,7 @@ distclean : clean
#
$(LIB_A) : $(BGCSRCS:.c=.o_a) $(CCSRCS:.c=.o_a)
- $(AR) cru $@ $?
+ $(AR) cr $@ $?
$(RANLIB) $@
$(LIB_S) : $(BGCSRCS:.c=.o_s) $(CCSRCS:.c=.o_s)
diff --git a/main/features.c b/main/features.c
index 7dfe4cde5..6806fe749 100644
--- a/main/features.c
+++ b/main/features.c
@@ -46,7 +46,7 @@ ASTERISK_REGISTER_FILE()
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
-#include <sys/signal.h>
+#include <signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
diff --git a/main/http.c b/main/http.c
index 5ec94a7e1..a8362829e 100644
--- a/main/http.c
+++ b/main/http.c
@@ -49,7 +49,7 @@ ASTERISK_REGISTER_FILE()
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
-#include <sys/signal.h>
+#include <signal.h>
#include <fcntl.h>
#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
diff --git a/main/manager.c b/main/manager.c
index d2fdc403d..94415b7a0 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -4157,10 +4157,26 @@ static int action_login(struct mansession *s, const struct message *m)
&& ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING);
const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth);
+ long uptime = 0;
+ long lastreloaded = 0;
+ struct timeval tmp;
+ struct timeval curtime = ast_tvnow();
+
+ if (ast_startuptime.tv_sec) {
+ tmp = ast_tvsub(curtime, ast_startuptime);
+ uptime = tmp.tv_sec;
+ }
+
+ if (ast_lastreloadtime.tv_sec) {
+ tmp = ast_tvsub(curtime, ast_lastreloadtime);
+ lastreloaded = tmp.tv_sec;
+ }
astman_append(s, "Event: FullyBooted\r\n"
"Privilege: %s\r\n"
- "Status: Fully Booted\r\n\r\n", cat_str);
+ "Uptime: %ld\r\n"
+ "LastReload: %ld\r\n"
+ "Status: Fully Booted\r\n\r\n", cat_str, uptime, lastreloaded);
}
return 0;
}
diff --git a/main/say.c b/main/say.c
index 957929326..6e51de201 100644
--- a/main/say.c
+++ b/main/say.c
@@ -317,6 +317,7 @@ static int say_digit_str_full(struct ast_channel *chan, const char *str, const c
\arg \b es - Spanish, Mexican
\arg \b fr - French
\arg \b he - Hebrew
+ \arg \b is - Icelandic
\arg \b it - Italian
\arg \b nl - Dutch
\arg \b no - Norwegian
@@ -373,6 +374,7 @@ static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const ch
static int ast_say_number_full_es(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
static int ast_say_number_full_fr(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
static int ast_say_number_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
+static int ast_say_number_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
static int ast_say_number_full_no(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
@@ -394,6 +396,7 @@ static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const
static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
static int ast_say_enumeration_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
static int ast_say_enumeration_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
+static int ast_say_enumeration_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
static int ast_say_enumeration_full_vi(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
/* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
@@ -409,6 +412,7 @@ static int ast_say_date_ka(struct ast_channel *chan, time_t t, const char *ints,
static int ast_say_date_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
static int ast_say_date_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
static int ast_say_date_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
+static int ast_say_date_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
static int ast_say_date_with_format_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
static int ast_say_date_with_format_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
@@ -416,6 +420,7 @@ static int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const
static int ast_say_date_with_format_es(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
static int ast_say_date_with_format_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
static int ast_say_date_with_format_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
+static int ast_say_date_with_format_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
static int ast_say_date_with_format_it(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
static int ast_say_date_with_format_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
static int ast_say_date_with_format_pl(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
@@ -511,6 +516,8 @@ static int say_number_full(struct ast_channel *chan, int num, const char *ints,
return ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd);
} else if (!strncasecmp(language, "hu", 2)) { /* Hungarian syntax */
return ast_say_number_full_hu(chan, num, ints, language, audiofd, ctrlfd);
+ } else if (!strncasecmp(language, "is", 2)) { /* Icelandic syntax */
+ return ast_say_number_full_is(chan, num, ints, language, options, audiofd, ctrlfd);
} else if (!strncasecmp(language, "it", 2)) { /* Italian syntax */
return ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd);
} else if (!strncasecmp(language, "ka", 2)) { /* Georgian syntax */
@@ -1518,6 +1525,129 @@ static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char
return res;
}
+/*! \brief ast_say_number_full_is: Icelandic syntax */
+/* New files:
+ In addition to American English, the following sounds are required: "hundreds", "millions", "1kvk", "1hk", "2kvk", "2hk", "3kvk", "3hk", "4kvk", "4hk"
+ */
+static int ast_say_number_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
+{
+ int res = 0;
+ int playh = 0;
+ int playa = 0;
+ int cn = 1; /* 1 = masc; 2 = fem; 3 = neut */
+ char fn[256] = "";
+
+ if (!num)
+ return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
+
+ if (options && !strncasecmp(options, "f", 1)) cn = 2;
+ if (options && !strncasecmp(options, "c", 1)) cn = 3;
+ /* It seems that sometimes people are using c and sometimes n. */
+ if (options && !strncasecmp(options, "n", 1)) cn = 3;
+
+ while (!res && (num || playh || playa )) {
+ if (num < 0) {
+ ast_copy_string(fn, "digits/minus", sizeof(fn));
+ if ( num > INT_MIN ) {
+ num = -num;
+ } else {
+ num = 0;
+ }
+ } else if (playh) {
+ if (playh > 1)
+ ast_copy_string(fn, "digits/hundreds", sizeof(fn));
+ else
+ ast_copy_string(fn, "digits/hundred", sizeof(fn));
+ playh = 0;
+ } else if (playa) {
+ ast_copy_string(fn, "digits/and", sizeof(fn));
+ playa = 0;
+ } else if (num < 5 && cn == 2) {
+ snprintf(fn, sizeof(fn), "digits/%dkvk", num);
+ num = 0;
+ } else if (num < 5 && cn == 3) {
+ snprintf(fn, sizeof(fn), "digits/%dhk", num);
+ num = 0;
+ } else if (num < 20) {
+ snprintf(fn, sizeof(fn), "digits/%d", num);
+ num = 0;
+ } else if (num < 100) {
+ snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
+ num %= 10;
+ if (num)
+ playa++;
+ } else if (num < 1000) {
+ int hundreds = num / 100;
+ /* The number prepending hundreds are in neutral */
+ if (hundreds < 5)
+ snprintf(fn, sizeof(fn), "digits/%dhk", hundreds);
+ else
+ snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
+
+ playh = hundreds;
+ num -= 100 * hundreds;
+ if (num && num < 20)
+ playa++;
+ /* The 'and' moves forward on even tens. */
+ if (num && (num % 10) == 0)
+ playa++;
+ } else if (num < 1000000) {
+ res = ast_say_number_full_is(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
+ /* Play 'and' if it's an even hundred. */
+ if ((num % 100) == 0 && (num % 1000 != 0)) {
+ playa++;
+ }
+ if (res)
+ return res;
+ ast_copy_string(fn, "digits/thousand", sizeof(fn));
+ num %= 1000;
+ if (num && (num < 20 || (num % 10 == 0)))
+ playa++;
+ } else if (num < 1000000000) {
+ int millions = num / 1000000;
+ /* The number of millions is feminine */
+ res = ast_say_number_full_is(chan, millions, ints, language, "f", audiofd, ctrlfd);
+ if (res)
+ return res;
+ if (millions > 1)
+ ast_copy_string(fn, "digits/millions", sizeof(fn));
+ else
+ ast_copy_string(fn, "digits/million", sizeof(fn));
+ num %= 1000000;
+ if (num && num < 100)
+ playa++;
+ } else if (num < INT_MAX) {
+ int milliards = num / 1000000000;
+ /* The number of milliards is masculine */
+ res = ast_say_number_full_is(chan, milliards, ints, language, "m", audiofd, ctrlfd);
+ if (res)
+ return res;
+ if (milliards > 1)
+ ast_copy_string(fn, "digits/milliards", sizeof(fn));
+ else
+ ast_copy_string(fn, "digits/milliard", sizeof(fn));
+ num %= 1000000000;
+ if (num && num < 100)
+ playa++;
+ } else {
+ ast_debug(1, "Number '%d' is too big for me\n", num);
+ res = -1;
+ }
+
+ if (!res) {
+ if (!ast_streamfile(chan, fn, language)) {
+ if ((audiofd > -1) && (ctrlfd > -1))
+ res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+ else
+ res = ast_waitstream(chan, ints);
+ }
+ ast_stopstream(chan);
+ }
+ }
+ return res;
+}
+
+
/*! \brief ast_say_number_full_it: Italian */
static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
{
@@ -2789,6 +2919,8 @@ static int say_enumeration_full(struct ast_channel *chan, int num, const char *i
return ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd);
} else if (!strncasecmp(language, "he", 2)) { /* Hebrew syntax */
return ast_say_enumeration_full_he(chan, num, ints, language, options, audiofd, ctrlfd);
+ } else if (!strncasecmp(language, "is", 2)) { /* Icelandic syntax */
+ return ast_say_enumeration_full_is(chan, num, ints, language, options, audiofd, ctrlfd);
} else if (!strncasecmp(language, "vi", 2)) { /* Vietnamese syntax */
return ast_say_enumeration_full_vi(chan, num, ints, language, audiofd, ctrlfd);
}
@@ -3329,6 +3461,182 @@ static int ast_say_enumeration_full_he(struct ast_channel *chan, int num, const
return res;
}
+/*! \brief ast_say_enumeration_full_is: Icelandic syntax */
+static int ast_say_enumeration_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
+{
+ /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
+ int res = 0, t = 0;
+ char fn[256] = "", fna[256] = "";
+ char *gender;
+
+ if (options && !strncasecmp(options, "f", 1)) {
+ gender = "F";
+ } else if (options && !strncasecmp(options, "n", 1)) {
+ gender = "N";
+ } else {
+ gender = "";
+ }
+
+ if (!num)
+ return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
+
+ while (!res && num) {
+ if (num < 0) {
+ ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */
+ if ( num > INT_MIN ) {
+ num = -num;
+ } else {
+ num = 0;
+ }
+ } else if (num < 100 && t) {
+ ast_copy_string(fn, "digits/and", sizeof(fn));
+ t = 0;
+ } else if (num < 20) {
+ snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
+ num = 0;
+ } else if (num < 100) {
+ int ones = num % 10;
+ if (ones) {
+ int tens = num - ones;
+ snprintf(fn, sizeof(fn), "digits/h-%d%s", tens, gender);
+ num = ones;
+ t++;
+ }
+ else if (t) {
+ snprintf(fn, sizeof(fn), "digits/and");
+ t = 0;
+ }
+ else {
+ snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
+ num = 0;
+ }
+
+ } else if (num == 100 && t == 0) {
+ snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
+ num = 0;
+ } else if (num < 1000) {
+ int hundreds = num / 100;
+ num = num % 100;
+ if (hundreds == 1) {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ } else {
+ snprintf(fn, sizeof(fn), "digits/%d", hundreds);
+ }
+ if (num) {
+ ast_copy_string(fna, "digits/hundred", sizeof(fna));
+ } else {
+ snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
+ }
+ t = 1;
+ } else if (num < 1000000) {
+ int thousands = num / 1000;
+ num = num % 1000;
+ if (thousands == 1) {
+ if (num) {
+ /* Thousand is a neutral word, so use the neutral recording */
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ ast_copy_string(fna, "digits/thousand", sizeof(fna));
+ } else {
+ if (t) {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
+ } else {
+ snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
+ }
+ }
+ } else {
+ res = ast_say_number_full_is(chan, thousands, ints, language, options, audiofd, ctrlfd);
+ if (res) {
+ return res;
+ }
+ if (num) {
+ ast_copy_string(fn, "digits/thousand", sizeof(fn));
+ } else {
+ snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
+ }
+ }
+ if (num)
+ t = 1;
+ } else if (num < 1000000000) {
+ int millions = num / 1000000;
+ num = num % 1000000;
+ if (millions == 1) {
+ if (num) {
+ /* Million is a feminine word, so use the female form */
+ ast_copy_string(fn, "digits/1kvk", sizeof(fn));
+ ast_copy_string(fna, "digits/million", sizeof(fna));
+ } else {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
+ }
+ } else {
+ res = ast_say_number_full_is(chan, millions, ints, language, options, audiofd, ctrlfd);
+ if (res) {
+ return res;
+ }
+ if (num) {
+ ast_copy_string(fn, "digits/millions", sizeof(fn));
+ } else {
+ snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
+ }
+ }
+ if (num)
+ t = 1;
+ } else if (num < INT_MAX) {
+ int billions = num / 1000000000;
+ num = num % 1000000000;
+ if (billions == 1) {
+ if (num) {
+ ast_copy_string(fn, "digits/1", sizeof(fn));
+ ast_copy_string(fna, "digits/milliard", sizeof(fna));
+ } else {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
+ }
+ } else {
+ res = ast_say_number_full_is(chan, billions, ints, language, options, audiofd, ctrlfd);
+ if (res)
+ return res;
+ if (num) {
+ ast_copy_string(fn, "digits/milliards", sizeof(fna));
+ } else {
+ snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
+ }
+ }
+ if (num)
+ t = 1;
+ } else if (num == INT_MAX) {
+ snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
+ num = 0;
+ } else {
+ ast_debug(1, "Number '%d' is too big for me\n", num);
+ res = -1;
+ }
+
+ if (!res) {
+ if (!ast_streamfile(chan, fn, language)) {
+ if ((audiofd > -1) && (ctrlfd > -1))
+ res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+ else
+ res = ast_waitstream(chan, ints);
+ }
+ ast_stopstream(chan);
+ if (!res) {
+ if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
+ if ((audiofd > -1) && (ctrlfd > -1)) {
+ res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+ } else {
+ res = ast_waitstream(chan, ints);
+ }
+ }
+ ast_stopstream(chan);
+ strcpy(fna, "");
+ }
+ }
+ }
+ return res;
+}
+
static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
{
if (!strncasecmp(lang, "en", 2)) { /* English syntax */
@@ -3353,6 +3661,8 @@ static int say_date(struct ast_channel *chan, time_t t, const char *ints, const
return ast_say_date_he(chan, t, ints, lang);
} else if (!strncasecmp(lang, "hu", 2)) { /* Hungarian syntax */
return ast_say_date_hu(chan, t, ints, lang);
+ } else if (!strncasecmp(lang, "is", 2)) { /* Icelandic syntax */
+ return ast_say_date_is(chan, t, ints, lang);
} else if (!strncasecmp(lang, "ka", 2)) { /* Georgian syntax */
return ast_say_date_ka(chan, t, ints, lang);
} else if (!strncasecmp(lang, "nl", 2)) { /* Dutch syntax */
@@ -3682,6 +3992,55 @@ int ast_say_date_he(struct ast_channel *chan, time_t t, const char *ints, const
return res;
}
+/* Icelandic syntax */
+int ast_say_date_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
+{
+ struct timeval when = { t, 0 };
+ struct ast_tm tm;
+ char fn[256];
+ int res = 0;
+ ast_localtime(&when, &tm, NULL);
+ if (!res) {
+ snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
+ res = ast_streamfile(chan, fn, lang);
+ if (!res)
+ res = ast_waitstream(chan, ints);
+ }
+ if (!res)
+ res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
+ if (!res)
+ res = ast_waitstream(chan, ints);
+ if (!res) {
+ snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
+ res = ast_streamfile(chan, fn, lang);
+ if (!res)
+ res = ast_waitstream(chan, ints);
+ }
+ if (!res) {
+ /* Year */
+ int year = tm.tm_year + 1900;
+ if (year > 1999) { /* year 2000 and later */
+ res = ast_say_number(chan, year, ints, lang, (char *) NULL);
+ } else {
+ if (year < 1100) {
+ /* I'm not going to handle 1100 and prior */
+ /* We'll just be silent on the year, instead of bombing out. */
+ } else {
+ /* year 1100 to 1999. will anybody need this?!? */
+ snprintf(fn, sizeof(fn), "digits/%d", (year / 100));
+ res = wait_file(chan, ints, fn, lang);
+ if (!res) {
+ res = wait_file(chan, ints, "digits/hundred", lang);
+ if (!res && year % 100 != 0) {
+ res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
+ }
+ }
+ }
+ }
+ }
+ return res;
+}
+
static int say_date_with_format(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone)
{
if (!strncasecmp(lang, "en", 2)) { /* English syntax */
@@ -3698,6 +4057,8 @@ static int say_date_with_format(struct ast_channel *chan, time_t t, const char *
return ast_say_date_with_format_fr(chan, t, ints, lang, format, tzone);
} else if (!strncasecmp(lang, "gr", 2)) { /* Greek syntax */
return ast_say_date_with_format_gr(chan, t, ints, lang, format, tzone);
+ } else if (!strncasecmp(lang, "is", 2)) { /* Icelandic syntax */
+ return ast_say_date_with_format_is(chan, t, ints, lang, format, tzone);
} else if (!strncasecmp(lang, "ja", 2)) { /* Japanese syntax */
return ast_say_date_with_format_ja(chan, t, ints, lang, format, tzone);
} else if (!strncasecmp(lang, "it", 2)) { /* Italian syntax */
@@ -4384,6 +4745,218 @@ int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const char *
return res;
}
+/* Icelandic syntax */
+int ast_say_date_with_format_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone)
+{
+ struct timeval when = { t, 0 };
+ struct ast_tm tm;
+ int res=0, offset, sndoffset;
+ char sndfile[256], nextmsg[256];
+
+ if (!format)
+ format = "A dBY HMS";
+
+ ast_localtime(&when, &tm, tzone);
+
+ for (offset=0 ; format[offset] != '\0' ; offset++) {
+ ast_debug(1, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
+ switch (format[offset]) {
+ /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
+ case '\'':
+ /* Literal name of a sound file */
+ for (sndoffset = 0; !strchr("\'\0", format[++offset]) && (sndoffset < sizeof(sndfile) - 1) ; sndoffset++) {
+ sndfile[sndoffset] = format[offset];
+ }
+ sndfile[sndoffset] = '\0';
+ res = wait_file(chan, ints, sndfile, lang);
+ break;
+ case 'A':
+ case 'a':
+ /* Sunday - Saturday */
+ snprintf(nextmsg, sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
+ res = wait_file(chan, ints, nextmsg, lang);
+ break;
+ case 'B':
+ case 'b':
+ case 'h':
+ /* January - December */
+ snprintf(nextmsg, sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
+ res = wait_file(chan, ints, nextmsg, lang);
+ break;
+ case 'm':
+ /* Month enumerated */
+ res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, "m");
+ break;
+ case 'd':
+ case 'e':
+ /* First - Thirtyfirst */
+ res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, "m");
+ break;
+ case 'Y':
+ /* Year */
+ {
+ int year = tm.tm_year + 1900;
+ if (year > 1999) { /* year 2000 and later */
+ res = ast_say_number(chan, year, ints, lang, (char *) NULL);
+ } else {
+ if (year < 1100) {
+ /* I'm not going to handle 1100 and prior */
+ /* We'll just be silent on the year, instead of bombing out. */
+ } else {
+ /* year 1100 to 1999. will anybody need this?!? */
+ /* say 1967 as 'nineteen hundred seven and sixty' */
+ snprintf(nextmsg, sizeof(nextmsg), "digits/%d", (year / 100) );
+ res = wait_file(chan, ints, nextmsg, lang);
+ if (!res) {
+ res = wait_file(chan, ints, "digits/hundred", lang);
+ if (!res && year % 100 != 0) {
+ res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 'I':
+ case 'l':
+ /* 12-Hour */
+ res = wait_file(chan, ints, "digits/oclock", lang);
+ if (tm.tm_hour == 0)
+ ast_copy_string(nextmsg, "digits/12", sizeof(nextmsg));
+ else if (tm.tm_hour > 12)
+ snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
+ else
+ snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour);
+ if (!res) {
+ res = wait_file(chan, ints, nextmsg, lang);
+ }
+ break;
+ case 'H':
+ /* 24-Hour, single digit hours preceeded by "oh" (0) */
+ if (tm.tm_hour < 10 && tm.tm_hour > 0) {
+ res = wait_file(chan, ints, "digits/0", lang);
+ }
+ /* FALLTRHU */
+ case 'k':
+ /* 24-Hour */
+ res = ast_say_number(chan, tm.tm_hour, ints, lang, "n");
+ break;
+ case 'M':
+ /* Minute */
+ if (tm.tm_min > 0 || next_item(&format[offset + 1]) == 'S') { /* zero 'digits/0' only if seconds follow */
+ if (tm.tm_min < 10)
+ res = wait_file(chan, ints, "digits/0", lang);
+ /* Gender depends on whether or not seconds follow */
+ if (next_item(&format[offset + 1]) == 'S')
+ res = ast_say_number(chan, tm.tm_min, ints, lang, "f");
+ else
+ res = ast_say_number(chan, tm.tm_min, ints, lang, "n");
+ }
+ if (!res && next_item(&format[offset + 1]) == 'S') { /* minutes only if seconds follow */
+ /* Say minute/minutes depending on whether minutes end in 1 */
+ if ((tm.tm_min % 10 == 1) && (tm.tm_min != 11)) {
+ res = wait_file(chan, ints, "digits/minute", lang);
+ } else {
+ res = wait_file(chan, ints, "digits/minutes", lang);
+ }
+ }
+ break;
+ case 'P':
+ case 'p':
+ /* AM/PM */
+ if (tm.tm_hour > 11)
+ ast_copy_string(nextmsg, "digits/p-m", sizeof(nextmsg));
+ else
+ ast_copy_string(nextmsg, "digits/a-m", sizeof(nextmsg));
+ res = wait_file(chan, ints, nextmsg, lang);
+ break;
+ case 'Q':
+ /* Shorthand for "Today", "Yesterday", or AdBY */
+ /* XXX As emphasized elsewhere, this should the native way in your
+ * language to say the date, with changes in what you say, depending
+ * upon how recent the date is. XXX */
+ {
+ struct timeval now = ast_tvnow();
+ struct ast_tm tmnow;
+ time_t beg_today;
+
+ ast_localtime(&now, &tmnow, tzone);
+ /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
+ /* In any case, it saves not having to do ast_mktime() */
+ beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
+ if (beg_today < t) {
+ /* Today */
+ res = wait_file(chan, ints, "digits/today", lang);
+ } else if (beg_today - 86400 < t) {
+ /* Yesterday */
+ res = wait_file(chan, ints, "digits/yesterday", lang);
+ } else {
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "AdBY", tzone);
+ }
+ }
+ break;
+ case 'q':
+ /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
+ /* XXX As emphasized elsewhere, this should the native way in your
+ * language to say the date, with changes in what you say, depending
+ * upon how recent the date is. XXX */
+ {
+ struct timeval now = ast_tvnow();
+ struct ast_tm tmnow;
+ time_t beg_today;
+
+ ast_localtime(&now, &tmnow, tzone);
+ /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
+ /* In any case, it saves not having to do ast_mktime() */
+ beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
+ if (beg_today < t) {
+ /* Today */
+ } else if ((beg_today - 86400) < t) {
+ /* Yesterday */
+ res = wait_file(chan, ints, "digits/yesterday", lang);
+ } else if (beg_today - 86400 * 6 < t) {
+ /* Within the last week */
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "A", tzone);
+ } else {
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "AdBY", tzone);
+ }
+ }
+ break;
+ case 'R':
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "HM", tzone);
+ break;
+ case 'S':
+ /* Seconds */
+ res = wait_file(chan, ints, "digits/and", lang);
+ if (!res) {
+ res = ast_say_number(chan, tm.tm_sec, ints, lang, "f");
+ /* Say minute/minutes depending on whether seconds end in 1 */
+ if (!res && (tm.tm_sec % 10 == 1) && (tm.tm_sec != 11)) {
+ res = wait_file(chan, ints, "digits/second", lang);
+ } else {
+ res = wait_file(chan, ints, "digits/seconds", lang);
+ }
+ }
+ break;
+ case 'T':
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "HMS", tzone);
+ break;
+ case ' ':
+ case ' ':
+ /* Just ignore spaces and tabs */
+ break;
+ default:
+ /* Unknown character */
+ ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
+ }
+ /* Jump out on DTMF */
+ if (res) {
+ break;
+ }
+ }
+ return res;
+}
+
/*! \brief Thai syntax */
int ast_say_date_with_format_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone)
{
diff --git a/main/tcptls.c b/main/tcptls.c
index f56e0aa70..046501b77 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -38,7 +38,6 @@ ASTERISK_REGISTER_FILE()
#endif
#include <signal.h>
-#include <sys/signal.h>
#include "asterisk/compat.h"
#include "asterisk/tcptls.h"
diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c
index 10495acb6..94b71a002 100644
--- a/pbx/pbx_dundi.c
+++ b/pbx/pbx_dundi.c
@@ -43,7 +43,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/network.h"
#include <sys/ioctl.h>
#include <zlib.h>
-#include <sys/signal.h>
+#include <signal.h>
#include <pthread.h>
#include <net/if.h>
diff --git a/res/ael/ael.flex b/res/ael/ael.flex
index b1b2bd76d..4e87f3a40 100644
--- a/res/ael/ael.flex
+++ b/res/ael/ael.flex
@@ -80,6 +80,12 @@ ASTERISK_REGISTER_FILE()
#if !defined(GLOB_ABORTED)
#define GLOB_ABORTED GLOB_ABEND
#endif
+#if !defined(GLOB_BRACE)
+#define GLOB_BRACE 0
+#endif
+#if !defined(GLOB_NOMAGIC)
+#define GLOB_NOMAGIC 0
+#endif
#include "asterisk/logger.h"
#include "asterisk/utils.h"
diff --git a/res/ael/ael_lex.c b/res/ael/ael_lex.c
index a7a20aa60..9fbd66429 100644
--- a/res/ael/ael_lex.c
+++ b/res/ael/ael_lex.c
@@ -839,6 +839,12 @@ ASTERISK_REGISTER_FILE()
#if !defined(GLOB_ABORTED)
#define GLOB_ABORTED GLOB_ABEND
#endif
+#if !defined(GLOB_BRACE)
+#define GLOB_BRACE 0
+#endif
+#if !defined(GLOB_NOMAGIC)
+#define GLOB_NOMAGIC 0
+#endif
#include "asterisk/logger.h"
#include "asterisk/utils.h"
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
index 0f18b2dc1..88a329598 100644
--- a/res/ari/resource_channels.c
+++ b/res/ari/resource_channels.c
@@ -916,6 +916,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
const char *args_channel_id,
const char *args_other_channel_id,
const char *args_originator,
+ const char *args_formats,
struct ast_ari_response *response)
{
char *dialtech;
@@ -934,6 +935,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
};
struct ari_origination *origination;
pthread_t thread;
+ struct ast_format_cap *format_cap = NULL;
if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid))
|| (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) {
@@ -948,6 +950,12 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
return;
}
+ if (!ast_strlen_zero(args_originator) && !ast_strlen_zero(args_formats)) {
+ ast_ari_response_error(response, 400, "Bad Request",
+ "Originator and formats can't both be specified");
+ return;
+ }
+
dialtech = ast_strdupa(args_endpoint);
if ((stuff = strchr(dialtech, '/'))) {
*stuff++ = '\0';
@@ -1070,7 +1078,41 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
}
}
- if (ast_dial_prerun(dial, other, NULL)) {
+ if (!ast_strlen_zero(args_formats)) {
+ char *format_name;
+ char *formats_copy = ast_strdupa(args_formats);
+
+ if (!(format_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+ ast_ari_response_alloc_failed(response);
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ ast_channel_cleanup(other);
+ return;
+ }
+
+ while ((format_name = ast_strip(strsep(&formats_copy, ",")))) {
+ struct ast_format *fmt = ast_format_cache_get(format_name);
+
+ if (!fmt || ast_format_cap_append(format_cap, fmt, 0)) {
+ if (!fmt) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Provided format (%s) was not found", format_name);
+ } else {
+ ast_ari_response_alloc_failed(response);
+ }
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ ast_channel_cleanup(other);
+ ao2_ref(format_cap, -1);
+ ao2_cleanup(fmt);
+ return;
+ }
+ ao2_ref(fmt, -1);
+ }
+ }
+
+ if (ast_dial_prerun(dial, other, format_cap)) {
ast_ari_response_alloc_failed(response);
ast_dial_destroy(dial);
ast_free(origination);
@@ -1079,6 +1121,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
}
ast_channel_cleanup(other);
+ ao2_cleanup(format_cap);
chan = ast_dial_get_channel(dial, 0);
if (!chan) {
@@ -1219,6 +1262,7 @@ void ast_ari_channels_originate_with_id(struct ast_variable *headers,
args->channel_id,
args->other_channel_id,
args->originator,
+ args->formats,
response);
ast_variables_destroy(variables);
}
@@ -1255,6 +1299,7 @@ void ast_ari_channels_originate(struct ast_variable *headers,
args->channel_id,
args->other_channel_id,
args->originator,
+ args->formats,
response);
ast_variables_destroy(variables);
}
@@ -1589,6 +1634,12 @@ void ast_ari_channels_create(struct ast_variable *headers,
return;
}
+ if (!ast_strlen_zero(args->originator) && !ast_strlen_zero(args->formats)) {
+ ast_ari_response_error(response, 400, "Bad Request",
+ "Originator and formats can't both be specified");
+ return;
+ }
+
chan_data->stasis_stuff = ast_str_create(32);
if (!chan_data->stasis_stuff) {
ast_ari_response_alloc_failed(response);
@@ -1610,8 +1661,41 @@ void ast_ari_channels_create(struct ast_variable *headers,
originator = ast_channel_get_by_name(args->originator);
if (originator) {
request_cap = ao2_bump(ast_channel_nativeformats(originator));
+ } else if (!ast_strlen_zero(args->formats)) {
+ char *format_name;
+ char *formats_copy = ast_strdupa(args->formats);
+
+ if (!(request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+ ast_ari_response_alloc_failed(response);
+ chan_data_destroy(chan_data);
+ return;
+ }
+
+ while ((format_name = ast_strip(strsep(&formats_copy, ",")))) {
+ struct ast_format *fmt = ast_format_cache_get(format_name);
+
+ if (!fmt || ast_format_cap_append(request_cap, fmt, 0)) {
+ if (!fmt) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Provided format (%s) was not found", format_name);
+ } else {
+ ast_ari_response_alloc_failed(response);
+ }
+ ao2_ref(request_cap, -1);
+ ao2_cleanup(fmt);
+ chan_data_destroy(chan_data);
+ return;
+ }
+ ao2_ref(fmt, -1);
+ }
} else {
- request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+ if (!(request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+ ast_ari_response_alloc_failed(response);
+ chan_data_destroy(chan_data);
+ return;
+ }
+
ast_format_cap_append_by_type(request_cap, AST_MEDIA_TYPE_AUDIO);
}
diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h
index c690d70c8..951433f13 100644
--- a/res/ari/resource_channels.h
+++ b/res/ari/resource_channels.h
@@ -78,6 +78,8 @@ struct ast_ari_channels_originate_args {
const char *other_channel_id;
/*! The unique id of the channel which is originating this one. */
const char *originator;
+ /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */
+ const char *formats;
};
/*!
* \brief Body parsing function for /channels.
@@ -114,6 +116,8 @@ struct ast_ari_channels_create_args {
const char *other_channel_id;
/*! Unique ID of the calling channel */
const char *originator;
+ /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */
+ const char *formats;
};
/*!
* \brief Body parsing function for /channels/create.
@@ -175,6 +179,8 @@ struct ast_ari_channels_originate_with_id_args {
const char *other_channel_id;
/*! The unique id of the channel which is originating this one. */
const char *originator;
+ /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */
+ const char *formats;
};
/*!
* \brief Body parsing function for /channels/{channelId}.
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
index 951a5475b..412c06d98 100644
--- a/res/res_ari_channels.c
+++ b/res/res_ari_channels.c
@@ -157,6 +157,10 @@ int ast_ari_channels_originate_parse_body(
if (field) {
args->originator = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "formats");
+ if (field) {
+ args->formats = ast_json_string_get(field);
+ }
return 0;
}
@@ -217,6 +221,9 @@ static void ast_ari_channels_originate_cb(
if (strcmp(i->name, "originator") == 0) {
args.originator = (i->value);
} else
+ if (strcmp(i->name, "formats") == 0) {
+ args.formats = (i->value);
+ } else
{}
}
/* Look for a JSON request entity */
@@ -298,6 +305,10 @@ int ast_ari_channels_create_parse_body(
if (field) {
args->originator = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "formats");
+ if (field) {
+ args->formats = ast_json_string_get(field);
+ }
return 0;
}
@@ -340,6 +351,9 @@ static void ast_ari_channels_create_cb(
if (strcmp(i->name, "originator") == 0) {
args.originator = (i->value);
} else
+ if (strcmp(i->name, "formats") == 0) {
+ args.formats = (i->value);
+ } else
{}
}
/* Look for a JSON request entity */
@@ -502,6 +516,10 @@ int ast_ari_channels_originate_with_id_parse_body(
if (field) {
args->originator = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "formats");
+ if (field) {
+ args->formats = ast_json_string_get(field);
+ }
return 0;
}
@@ -559,6 +577,9 @@ static void ast_ari_channels_originate_with_id_cb(
if (strcmp(i->name, "originator") == 0) {
args.originator = (i->value);
} else
+ if (strcmp(i->name, "formats") == 0) {
+ args.formats = (i->value);
+ } else
{}
}
for (i = path_vars; i; i = i->next) {
diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c
index abc264d9e..a21943520 100644
--- a/res/res_ari_recordings.c
+++ b/res/res_ari_recordings.c
@@ -257,6 +257,7 @@ static void ast_ari_recordings_get_stored_file_cb(
break;
case 500: /* Internal Server Error */
case 501: /* Not Implemented */
+ case 403: /* The recording file could not be opened */
case 404: /* Recording not found */
is_valid = 1;
break;
diff --git a/res/res_hep.c b/res/res_hep.c
index 45201359d..e79f2b67a 100644
--- a/res/res_hep.c
+++ b/res/res_hep.c
@@ -409,9 +409,21 @@ enum hep_uuid_type hepv3_get_uuid_type(void)
{
RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
+ if (!config) {
+ /* Well, that's unfortunate. Return something. */
+ return HEP_UUID_TYPE_CALL_ID;
+ }
+
return config->general->uuid_type;
}
+int hepv3_is_loaded(void)
+{
+ RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
+
+ return (config != NULL) ? 1 : 0;
+}
+
struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len)
{
struct hepv3_capture_info *info;
diff --git a/res/res_hep.exports.in b/res/res_hep.exports.in
index df0f2b4f7..e318ac97f 100644
--- a/res/res_hep.exports.in
+++ b/res/res_hep.exports.in
@@ -3,6 +3,7 @@
LINKER_SYMBOL_PREFIX*hepv3_send_packet;
LINKER_SYMBOL_PREFIX*hepv3_create_capture_info;
LINKER_SYMBOL_PREFIX*hepv3_get_uuid_type;
+ LINKER_SYMBOL_PREFIX*hepv3_is_loaded;
local:
*;
};
diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c
index 0cc54c237..a3a93e9b2 100644
--- a/res/res_hep_pjsip.c
+++ b/res/res_hep_pjsip.c
@@ -210,6 +210,11 @@ static int load_module(void)
{
CHECK_PJSIP_MODULE_LOADED();
+ if (!ast_module_check("res_hep.so") || !hepv3_is_loaded()) {
+ ast_log(AST_LOG_WARNING, "res_hep is not loaded or running; declining module load\n");
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
ast_sip_register_service(&logging_module);
return AST_MODULE_LOAD_SUCCESS;
}
diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c
index 8643d4db6..03db18159 100644
--- a/res/res_hep_rtcp.c
+++ b/res/res_hep_rtcp.c
@@ -149,6 +149,10 @@ static void rtp_topic_handler(void *data, struct stasis_subscription *sub, struc
static int load_module(void)
{
+ if (!ast_module_check("res_hep.so") || !hepv3_is_loaded()) {
+ ast_log(AST_LOG_WARNING, "res_hep is not loaded or running; declining module load\n");
+ return AST_MODULE_LOAD_DECLINE;
+ }
stasis_rtp_subscription = stasis_subscribe(ast_rtp_topic(),
rtp_topic_handler, NULL);
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index f124d58f2..3c7199ef4 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -44,7 +44,7 @@ ASTERISK_REGISTER_FILE()
#include <ctype.h>
#include <signal.h>
#include <sys/time.h>
-#include <sys/signal.h>
+#include <signal.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <dirent.h>
diff --git a/res/res_odbc.c b/res/res_odbc.c
index 81e1b3c13..a89c95492 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -78,10 +78,19 @@ struct odbc_class
unsigned int forcecommit:1; /*!< Should uncommitted transactions be auto-committed on handle release? */
unsigned int isolation; /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
unsigned int conntimeout; /*!< Maximum time the connection process should take */
+ unsigned int maxconnections; /*!< Maximum number of allowed connections */
/*! When a connection fails, cache that failure for how long? */
struct timeval negative_connection_cache;
/*! When a connection fails, when did that last occur? */
struct timeval last_negative_connect;
+ /*! A pool of available connections */
+ AST_LIST_HEAD_NOLOCK(, odbc_obj) connections;
+ /*! Lock to protect the connections */
+ ast_mutex_t lock;
+ /*! Condition to notify any pending connection requesters */
+ ast_cond_t cond;
+ /*! The total number of current connections */
+ size_t connection_cnt;
};
static struct ao2_container *class_container;
@@ -90,7 +99,7 @@ static AST_RWLIST_HEAD_STATIC(odbc_tables, odbc_cache_tables);
static odbc_status odbc_obj_connect(struct odbc_obj *obj);
static odbc_status odbc_obj_disconnect(struct odbc_obj *obj);
-static int odbc_register_class(struct odbc_class *class, int connect);
+static void odbc_register_class(struct odbc_class *class, int connect);
AST_THREADSTORAGE(errors_buf);
@@ -157,6 +166,8 @@ int ast_odbc_text2isolation(const char *txt)
static void odbc_class_destructor(void *data)
{
struct odbc_class *class = data;
+ struct odbc_obj *obj;
+
/* Due to refcounts, we can safely assume that any objects with a reference
* to us will prevent our destruction, so we don't need to worry about them.
*/
@@ -169,7 +180,14 @@ static void odbc_class_destructor(void *data)
if (class->sanitysql) {
ast_free(class->sanitysql);
}
+
+ while ((obj = AST_LIST_REMOVE_HEAD(&class->connections, list))) {
+ ao2_ref(obj, -1);
+ }
+
SQLFreeHandle(SQL_HANDLE_ENV, class->env);
+ ast_mutex_destroy(&class->lock);
+ ast_cond_destroy(&class->cond);
}
static int null_hash_fn(const void *obj, const int flags)
@@ -180,21 +198,23 @@ static int null_hash_fn(const void *obj, const int flags)
static void odbc_obj_destructor(void *data)
{
struct odbc_obj *obj = data;
- struct odbc_class *class = obj->parent;
- obj->parent = NULL;
+
odbc_obj_disconnect(obj);
- ao2_ref(class, -1);
}
-static void destroy_table_cache(struct odbc_cache_tables *table) {
+static void destroy_table_cache(struct odbc_cache_tables *table)
+{
struct odbc_cache_columns *col;
+
ast_debug(1, "Destroying table cache for %s\n", table->table);
+
AST_RWLIST_WRLOCK(&table->columns);
while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
ast_free(col);
}
AST_RWLIST_UNLOCK(&table->columns);
AST_RWLIST_HEAD_DESTROY(&table->columns);
+
ast_free(table);
}
@@ -370,18 +390,19 @@ SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT (*prepare_c
* We must therefore redo everything when we establish a new
* connection. */
stmt = prepare_cb(obj, data);
+ if (!stmt) {
+ return NULL;
+ }
- if (stmt) {
- res = SQLExecute(stmt);
- if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
- if (res == SQL_ERROR) {
- ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute");
- }
-
- ast_log(LOG_WARNING, "SQL Execute error %d!\n", res);
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- stmt = NULL;
+ res = SQLExecute(stmt);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
+ if (res == SQL_ERROR) {
+ ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute");
}
+
+ ast_log(LOG_WARNING, "SQL Execute error %d!\n", res);
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ stmt = NULL;
}
return stmt;
@@ -468,7 +489,7 @@ static int load_odbc_config(void)
struct ast_variable *v;
char *cat;
const char *dsn, *username, *password, *sanitysql;
- int enabled, bse, conntimeout, forcecommit, isolation;
+ int enabled, bse, conntimeout, forcecommit, isolation, maxconnections;
struct timeval ncache = { 0, 0 };
int preconnect = 0, res = 0;
struct ast_flags config_flags = { 0 };
@@ -495,6 +516,7 @@ static int load_odbc_config(void)
conntimeout = 10;
forcecommit = 0;
isolation = SQL_TXN_READ_COMMITTED;
+ maxconnections = 1;
for (v = ast_variable_browse(config, cat); v; v = v->next) {
if (!strcasecmp(v->name, "pooling") ||
!strncasecmp(v->name, "share", 5) ||
@@ -538,6 +560,11 @@ static int load_odbc_config(void)
ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
isolation = SQL_TXN_READ_COMMITTED;
}
+ } else if (!strcasecmp(v->name, "max_connections")) {
+ if (sscanf(v->value, "%30d", &maxconnections) != 1 || maxconnections < 1) {
+ ast_log(LOG_WARNING, "max_connections must be a positive integer\n");
+ maxconnections = 1;
+ }
}
}
@@ -563,6 +590,7 @@ static int load_odbc_config(void)
new->isolation = isolation;
new->conntimeout = conntimeout;
new->negative_connection_cache = ncache;
+ new->maxconnections = maxconnections;
if (cat)
ast_copy_string(new->name, cat, sizeof(new->name));
@@ -581,6 +609,9 @@ static int load_odbc_config(void)
break;
}
+ ast_mutex_init(&new->lock);
+ ast_cond_init(&new->cond, NULL);
+
odbc_register_class(new, preconnect);
ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
ao2_ref(new, -1);
@@ -641,6 +672,7 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c
ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn);
ast_cli(a->fd, " Last connection attempt: %s\n", timestr);
+ ast_cli(a->fd, " Number of active connections: %zd (out of %d)\n", class->connection_cnt, class->maxconnections);
ast_cli(a->fd, "\n");
}
ao2_ref(class, -1);
@@ -654,38 +686,47 @@ static struct ast_cli_entry cli_odbc[] = {
AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)")
};
-static int odbc_register_class(struct odbc_class *class, int preconnect)
+static void odbc_register_class(struct odbc_class *class, int preconnect)
{
struct odbc_obj *obj;
- if (class) {
- ao2_link(class_container, class);
- /* I still have a reference in the caller, so a deref is NOT missing here. */
-
- if (preconnect) {
- /* Request and release builds a connection */
- obj = ast_odbc_request_obj(class->name, 0);
- if (obj) {
- ast_odbc_release_obj(obj);
- }
- }
- return 0;
- } else {
- ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
- return -1;
+ ao2_link(class_container, class);
+ /* I still have a reference in the caller, so a deref is NOT missing here. */
+
+ if (!preconnect) {
+ return;
}
+
+ /* Request and release builds a connection */
+ obj = ast_odbc_request_obj(class->name, 0);
+ if (obj) {
+ ast_odbc_release_obj(obj);
+ }
+
+ return;
}
void ast_odbc_release_obj(struct odbc_obj *obj)
{
- ast_debug(2, "Releasing ODBC handle %p\n", obj);
+ struct odbc_class *class = obj->parent;
-#ifdef DEBUG_THREADS
- obj->file[0] = '\0';
- obj->function[0] = '\0';
- obj->lineno = 0;
-#endif
- ao2_ref(obj, -1);
+ ast_debug(2, "Releasing ODBC handle %p into pool\n", obj);
+
+ /* The odbc_obj only holds a reference to the class when it is
+ * actively being used. This guarantees no circular reference
+ * between odbc_class and odbc_obj. Since it is being released
+ * we also release our class reference. If a reload occurred before
+ * the class will go away automatically once all odbc_obj are
+ * released back.
+ */
+ obj->parent = NULL;
+
+ ast_mutex_lock(&class->lock);
+ AST_LIST_INSERT_HEAD(&class->connections, obj, list);
+ ast_cond_signal(&class->cond);
+ ast_mutex_unlock(&class->lock);
+
+ ao2_ref(class, -1);
}
int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
@@ -703,6 +744,50 @@ static int aoro2_class_cb(void *obj, void *arg, int flags)
return 0;
}
+/*
+ * \brief Determine if the connection has died.
+ *
+ * \param connection The connection to check
+ * \param class The ODBC class
+ * \retval 1 Yep, it's dead
+ * \retval 0 It's alive and well
+ */
+static int connection_dead(struct odbc_obj *connection, struct odbc_class *class)
+{
+ char *test_sql = "select 1";
+ SQLINTEGER dead;
+ SQLRETURN res;
+ SQLHSTMT stmt;
+
+ res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0);
+ if (SQL_SUCCEEDED(res)) {
+ return dead == SQL_CD_TRUE ? 1 : 0;
+ }
+
+ /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a
+ * probing query instead
+ */
+ res = SQLAllocHandle(SQL_HANDLE_STMT, connection->con, &stmt);
+ if (!SQL_SUCCEEDED(res)) {
+ return 1;
+ }
+
+ if (!ast_strlen_zero(class->sanitysql)) {
+ test_sql = class->sanitysql;
+ }
+
+ res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
+ if (!SQL_SUCCEEDED(res)) {
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ return 1;
+ }
+
+ res = SQLExecute(stmt);
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+
+ return SQL_SUCCEEDED(res) ? 0 : 1;
+}
+
struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
{
struct odbc_obj *obj = NULL;
@@ -713,17 +798,60 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
return NULL;
}
- /* XXX ODBC connection objects do not have shared ownership, so there is no reason
- * to use refcounted objects here.
- */
- obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
- /* Inherit reference from the ao2_callback from before */
- obj->parent = class;
- if (odbc_obj_connect(obj) == ODBC_FAIL) {
- ao2_ref(obj, -1);
- return NULL;
+ ast_mutex_lock(&class->lock);
+
+ while (!obj) {
+ obj = AST_LIST_REMOVE_HEAD(&class->connections, list);
+
+ if (!obj) {
+ if (class->connection_cnt < class->maxconnections) {
+ /* If no connection is immediately available establish a new
+ * one if allowed. If we try and fail we give up completely as
+ * we could go into an infinite loop otherwise.
+ */
+ obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
+ if (!obj) {
+ break;
+ }
+
+ obj->parent = ao2_bump(class);
+ if (odbc_obj_connect(obj) == ODBC_FAIL) {
+ ao2_ref(obj->parent, -1);
+ ao2_ref(obj, -1);
+ obj = NULL;
+ break;
+ }
+
+ class->connection_cnt++;
+ ast_debug(2, "Created ODBC handle %p on class '%s', new count is %zd\n", obj,
+ name, class->connection_cnt);
+ } else {
+ /* Otherwise if we're not allowed to create a new one we
+ * wait for another thread to give up the connection they
+ * own.
+ */
+ ast_cond_wait(&class->cond, &class->lock);
+ }
+ } else if (connection_dead(obj, class)) {
+ /* If the connection is dead try to grab another functional one from the
+ * pool instead of trying to resurrect this one.
+ */
+ ao2_ref(obj, -1);
+ obj = NULL;
+ class->connection_cnt--;
+ ast_debug(2, "ODBC handle %p dead - removing from class '%s', new count is %zd\n",
+ obj, name, class->connection_cnt);
+ } else {
+ /* We successfully grabbed a connection from the pool and all is well!
+ */
+ obj->parent = ao2_bump(class);
+ ast_debug(2, "Reusing ODBC handle %p from class '%s'\n", obj, name);
+ }
}
+ ast_mutex_unlock(&class->lock);
+ ao2_ref(class, -1);
+
return obj;
}
@@ -755,14 +883,6 @@ static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
obj->con = NULL;
res = SQLDisconnect(con);
- if (obj->parent) {
- if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
- ast_debug(3, "Disconnected %d from %s [%s](%p)\n", res, obj->parent->name, obj->parent->dsn, obj);
- } else {
- ast_debug(3, "res_odbc: %s [%s](%p) already disconnected\n", obj->parent->name, obj->parent->dsn, obj);
- }
- }
-
if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) == SQL_SUCCESS) {
ast_debug(3, "Database handle %p (connection %p) deallocated\n", obj, con);
} else {
diff --git a/res/res_srtp.c b/res/res_srtp.c
index 1e68f9675..0b1fb73e7 100644
--- a/res/res_srtp.c
+++ b/res/res_srtp.c
@@ -40,7 +40,11 @@
ASTERISK_REGISTER_FILE()
#include <srtp/srtp.h>
+#ifdef HAVE_OPENSSL
+#include <openssl/rand.h>
+#else
#include <srtp/crypto_kernel.h>
+#endif
#include "asterisk/lock.h"
#include "asterisk/sched.h"
@@ -305,7 +309,11 @@ static int ast_srtp_policy_set_master_key(struct ast_srtp_policy *policy, const
static int ast_srtp_get_random(unsigned char *key, size_t len)
{
+#ifdef HAVE_OPENSSL
+ return RAND_bytes(key, len) > 0 ? 0: -1;
+#else
return crypto_get_random(key, len) != err_status_ok ? -1: 0;
+#endif
}
static void ast_srtp_set_cb(struct ast_srtp *srtp, const struct ast_srtp_cb *cb, void *data)
diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json
index aafd231a1..9e8c7c3d4 100644
--- a/rest-api/api-docs/channels.json
+++ b/rest-api/api-docs/channels.json
@@ -128,6 +128,14 @@
"required": false,
"allowMultiple": false,
"dataType": "string"
+ },
+ {
+ "name": "formats",
+ "description": "The format name capability list to use if originator is not specified. Ex. \"ulaw,slin16\". Format names can be found with \"core show codecs\".",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
}
],
"errorResponses": [
@@ -196,6 +204,14 @@
"required": false,
"allowMultiple": false,
"dataType": "string"
+ },
+ {
+ "name": "formats",
+ "description": "The format name capability list to use if originator is not specified. Ex. \"ulaw,slin16\". Format names can be found with \"core show codecs\".",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
}
]
}
@@ -338,6 +354,14 @@
"required": false,
"allowMultiple": false,
"dataType": "string"
+ },
+ {
+ "name": "formats",
+ "description": "The format name capability list to use if originator is not specified. Ex. \"ulaw,slin16\". Format names can be found with \"core show codecs\".",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
}
],
"errorResponses": [