diff options
54 files changed, 1236 insertions, 124 deletions
@@ -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 @@ -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": [ |