diff options
35 files changed, 604 insertions, 943 deletions
diff --git a/apps/app_minivm.c b/apps/app_minivm.c index 6b1e8bb83..dcf0ee2fa 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -1254,7 +1254,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu struct ast_channel *chan = NULL; char *fromaddress; char *fromemail; - int res; + int res = -1; if (!str1 || !str2) { return -1; diff --git a/apps/app_record.c b/apps/app_record.c index 104daa51e..d1cdeabce 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -139,6 +139,12 @@ enum { OPTION_NO_TRUNCATE = (1 << 9), }; +enum dtmf_response { + RESPONSE_NO_MATCH = 0, + RESPONSE_OPERATOR, + RESPONSE_DTMF, +}; + AST_APP_OPTIONS(app_opts,{ AST_APP_OPTION('a', OPTION_APPEND), AST_APP_OPTION('k', OPTION_KEEP), @@ -162,24 +168,22 @@ AST_APP_OPTIONS(app_opts,{ * \param dtmf_integer the integer value of the DTMF key received * \param terminator key currently set to be pressed for normal termination * - * \retval 0 do not exit - * \retval -1 do exit + * \returns One of enum dtmf_response */ -static int record_dtmf_response(struct ast_channel *chan, struct ast_flags *flags, int dtmf_integer, int terminator) +static enum dtmf_response record_dtmf_response(struct ast_channel *chan, + struct ast_flags *flags, int dtmf_integer, int terminator) { if ((dtmf_integer == OPERATOR_KEY) && (ast_test_flag(flags, OPTION_OPERATOR_EXIT))) { - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "OPERATOR"); - return -1; + return RESPONSE_OPERATOR; } if ((dtmf_integer == terminator) || (ast_test_flag(flags, OPTION_ANY_TERMINATE))) { - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "DTMF"); - return -1; + return RESPONSE_DTMF; } - return 0; + return RESPONSE_NO_MATCH; } static int create_destination_directory(const char *path) @@ -248,6 +252,7 @@ static int record_exec(struct ast_channel *chan, const char *data) ); int ms; struct timeval start; + const char *status_response = "ERROR"; /* The next few lines of code parse out the filename and header from the input string */ if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */ @@ -345,7 +350,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (res) { ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan)); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; goto out; } @@ -381,7 +386,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (create_destination_directory(tmp)) { ast_log(LOG_WARNING, "Could not create directory for file %s\n", args.filename); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; goto out; } @@ -390,7 +395,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (!s) { ast_log(LOG_WARNING, "Could not create file %s\n", args.filename); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; goto out; } @@ -425,7 +430,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (res) { ast_log(LOG_WARNING, "Problem writing frame\n"); ast_frfree(f); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; break; } @@ -441,7 +446,7 @@ static int record_exec(struct ast_channel *chan, const char *data) /* Ended happily with silence */ ast_frfree(f); gotsilence = 1; - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "SILENCE"); + status_response = "SILENCE"; break; } } @@ -450,12 +455,26 @@ static int record_exec(struct ast_channel *chan, const char *data) if (res) { ast_log(LOG_WARNING, "Problem writing frame\n"); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; ast_frfree(f); break; } } else if (f->frametype == AST_FRAME_DTMF) { - if (record_dtmf_response(chan, &flags, f->subclass.integer, terminator)) { + enum dtmf_response rc = + record_dtmf_response(chan, &flags, f->subclass.integer, terminator); + switch(rc) { + case RESPONSE_NO_MATCH: + break; + case RESPONSE_OPERATOR: + status_response = "OPERATOR"; + ast_debug(1, "Got OPERATOR\n"); + break; + case RESPONSE_DTMF: + status_response = "DTMF"; + ast_debug(1, "Got DTMF\n"); + break; + } + if (rc != RESPONSE_NO_MATCH) { ast_frfree(f); break; } @@ -465,13 +484,13 @@ static int record_exec(struct ast_channel *chan, const char *data) if (maxduration > 0 && !ms) { gottimeout = 1; - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT"); + status_response = "TIMEOUT"; } if (!f) { ast_debug(1, "Got hangup\n"); res = -1; - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "HANGUP"); + status_response = "HANGUP"; if (!ast_test_flag(&flags, OPTION_KEEP)) { ast_filedelete(args.filename, NULL); } @@ -506,6 +525,9 @@ out: if (sildet) { ast_dsp_free(sildet); } + + pbx_builtin_setvar_helper(chan, "RECORD_STATUS", status_response); + return res; } diff --git a/autoconf/ast_gcc_attribute.m4 b/autoconf/ast_gcc_attribute.m4 index 4ade81404..b1972bedf 100644 --- a/autoconf/ast_gcc_attribute.m4 +++ b/autoconf/ast_gcc_attribute.m4 @@ -7,6 +7,7 @@ AC_MSG_CHECKING(for compiler 'attribute $1' support) saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" m4_ifval([$4],$4=0) +ax_cv_have_func_attribute_$1=0 if test "x$2" = "x" then @@ -15,6 +16,7 @@ AC_COMPILE_IFELSE( [])], AC_MSG_RESULT(yes) m4_ifval([$4],$4=1) + ax_cv_have_func_attribute_$1=1 AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]), AC_MSG_RESULT(no) ) @@ -24,6 +26,7 @@ AC_COMPILE_IFELSE( [])], AC_MSG_RESULT(yes) m4_ifval([$4],$4=1) + ax_cv_have_func_attribute_$1=1 AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]), AC_MSG_RESULT(no) ) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5efff7eca..c48801756 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -583,7 +583,19 @@ static int answer(void *data) pjsip_inv_dec_ref(session->inv_session); #endif - return (status == PJ_SUCCESS) ? 0 : -1; + if (status != PJ_SUCCESS) { + char err[PJ_ERR_MSG_SIZE]; + + pj_strerror(status, err, sizeof(err)); + ast_log(LOG_WARNING,"Cannot answer '%s': %s\n", + ast_channel_name(session->channel), err); + /* + * Return this value so we can distinguish between this + * failure and the threadpool synchronous push failing. + */ + return -2; + } + return 0; } /*! \brief Function called by core when we should answer a PJSIP session */ @@ -591,6 +603,7 @@ static int chan_pjsip_answer(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); struct ast_sip_session *session; + int res; if (ast_channel_state(ast) == AST_STATE_UP) { return 0; @@ -611,11 +624,15 @@ static int chan_pjsip_answer(struct ast_channel *ast) can occur between this thread and bridging (specifically when native bridging attempts to do direct media) */ ast_channel_unlock(ast); - if (ast_sip_push_task_synchronous(session->serializer, answer, session)) { - ast_log(LOG_WARNING, "Unable to push answer task to the threadpool. Cannot answer call\n"); + res = ast_sip_push_task_synchronous(session->serializer, answer, session); + if (res) { + if (res == -1) { + ast_log(LOG_ERROR,"Cannot answer '%s': Unable to push answer task to the threadpool.\n", + ast_channel_name(session->channel)); #ifdef HAVE_PJSIP_INV_SESSION_REF - pjsip_inv_dec_ref(session->inv_session); + pjsip_inv_dec_ref(session->inv_session); #endif + } ao2_ref(session, -1); ast_channel_lock(ast); return -1; diff --git a/configs/samples/ast_debug_tools.conf.sample b/configs/samples/ast_debug_tools.conf.sample index f26626b20..1c4827f91 100644 --- a/configs/samples/ast_debug_tools.conf.sample +++ b/configs/samples/ast_debug_tools.conf.sample @@ -20,6 +20,12 @@ # anyway. COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt)) +# The directory to contain output files and work directories. +# For output from existing core files, the default is the +# directory that the core file is found in. For core files +# produced from a running process, the default is /tmp. +OUTPUTDIR=/some/directory + # Date command for the "running" coredump and tarballs. # DATEFORMAT will be executed to get the timestamp. # Don't put quotes around the format string or they'll be @@ -17912,6 +17912,7 @@ $as_echo_n "checking for compiler 'attribute pure' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_pure=0 if test "x" = "x" then @@ -17930,6 +17931,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_pure=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_pure 1 @@ -17957,6 +17959,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_pure=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_pure 1 @@ -17980,6 +17983,7 @@ $as_echo_n "checking for compiler 'attribute malloc' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_malloc=0 if test "x" = "x" then @@ -17998,6 +18002,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_malloc=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_malloc 1 @@ -18025,6 +18030,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_malloc=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_malloc 1 @@ -18048,6 +18054,7 @@ $as_echo_n "checking for compiler 'attribute const' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_const=0 if test "x" = "x" then @@ -18066,6 +18073,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_const=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_const 1 @@ -18093,6 +18101,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_const=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_const 1 @@ -18116,6 +18125,7 @@ $as_echo_n "checking for compiler 'attribute unused' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_unused=0 if test "x" = "x" then @@ -18134,6 +18144,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_unused=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_unused 1 @@ -18161,6 +18172,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_unused=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_unused 1 @@ -18184,6 +18196,7 @@ $as_echo_n "checking for compiler 'attribute always_inline' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_always_inline=0 if test "x" = "x" then @@ -18202,6 +18215,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_always_inline=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_always_inline 1 @@ -18229,6 +18243,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_always_inline=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_always_inline 1 @@ -18252,6 +18267,7 @@ $as_echo_n "checking for compiler 'attribute deprecated' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_deprecated=0 if test "x" = "x" then @@ -18270,6 +18286,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_deprecated=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_deprecated 1 @@ -18297,6 +18314,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_deprecated=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_deprecated 1 @@ -18320,6 +18338,7 @@ $as_echo_n "checking for compiler 'attribute sentinel' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_sentinel=0 if test "x" = "x" then @@ -18338,6 +18357,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_sentinel=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_sentinel 1 @@ -18365,6 +18385,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_sentinel=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_sentinel 1 @@ -18388,6 +18409,7 @@ $as_echo_n "checking for compiler 'attribute warn_unused_result' support... " >& saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_warn_unused_result=0 if test "x" = "x" then @@ -18406,6 +18428,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_warn_unused_result=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_warn_unused_result 1 @@ -18433,6 +18456,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_warn_unused_result=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_warn_unused_result 1 @@ -18456,6 +18480,7 @@ $as_echo_n "checking for compiler 'attribute may_alias' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_may_alias=0 if test "x" = "x" then @@ -18474,6 +18499,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_may_alias=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_may_alias 1 @@ -18501,6 +18527,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_may_alias=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_may_alias 1 @@ -18524,6 +18551,7 @@ $as_echo_n "checking for compiler 'attribute constructor' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_constructor=0 if test "x" = "x" then @@ -18542,6 +18570,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_constructor=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_constructor 1 @@ -18569,6 +18598,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_constructor=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_constructor 1 @@ -18586,12 +18616,17 @@ fi CFLAGS="$saved_CFLAGS" +if test "$ax_cv_have_func_attribute_constructor" != "1"; then + as_fn_error $? "*** Function constructor attribute is not supported by your compiler." "$LINENO" 5 +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute destructor' support" >&5 $as_echo_n "checking for compiler 'attribute destructor' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_destructor=0 if test "x" = "x" then @@ -18610,6 +18645,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_destructor=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_destructor 1 @@ -18637,6 +18673,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_destructor=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_destructor 1 @@ -18654,12 +18691,16 @@ fi CFLAGS="$saved_CFLAGS" +if test "$ax_cv_have_func_attribute_destructor" != "1"; then + as_fn_error $? "*** Function destructor attribute is not supported by your compiler." "$LINENO" 5 +fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute noreturn' support" >&5 $as_echo_n "checking for compiler 'attribute noreturn' support... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" +ax_cv_have_func_attribute_noreturn=0 if test "xnoreturn" = "x" then @@ -18678,6 +18719,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_noreturn=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_noreturn 1 @@ -18705,6 +18747,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + ax_cv_have_func_attribute_noreturn=1 cat >>confdefs.h <<_ACEOF #define HAVE_ATTRIBUTE_noreturn 1 diff --git a/configure.ac b/configure.ac index da0400516..30ff4ac31 100644 --- a/configure.ac +++ b/configure.ac @@ -1122,7 +1122,14 @@ AST_GCC_ATTRIBUTE(sentinel) AST_GCC_ATTRIBUTE(warn_unused_result) AST_GCC_ATTRIBUTE(may_alias) AST_GCC_ATTRIBUTE(constructor) +if test "$ax_cv_have_func_attribute_constructor" != "1"; then + AC_MSG_ERROR([*** Function constructor attribute is not supported by your compiler.]) +fi + AST_GCC_ATTRIBUTE(destructor) +if test "$ax_cv_have_func_attribute_destructor" != "1"; then + AC_MSG_ERROR([*** Function destructor attribute is not supported by your compiler.]) +fi AST_GCC_ATTRIBUTE(noreturn,noreturn) AC_MSG_CHECKING(for -fsanitize=address support) diff --git a/contrib/scripts/ast_coredumper b/contrib/scripts/ast_coredumper index 9b01a4239..884ede71f 100755 --- a/contrib/scripts/ast_coredumper +++ b/contrib/scripts/ast_coredumper @@ -15,7 +15,7 @@ SYNOPSIS $prog [ --help ] [ --running | --RUNNING ] [ --latest ] [ --tarball-coredumps ] [ --delete-coredumps-after ] [ --tarball-results ] [ --delete-results-after ] - [ --tarball-uniqueid="<uniqueid>" ] + [ --tarball-config ] [ --tarball-uniqueid="<uniqueid>" ] [ --no-default-search ] [ --append-coredumps ] [ --asterisk-bin="path" ] [ <coredump> | <pattern> ... ] @@ -51,7 +51,8 @@ DESCRIPTION Create a coredump from the running asterisk instance and process it along with any other coredumps found (if any). WARNING: This WILL interrupt call processing. You will be - asked to confirm. + asked to confirm. The coredump will be written to /tmp if + $OUTPUTDIR is not defined. --RUNNING Same as --running but without the confirmation prompt. @@ -69,10 +70,11 @@ DESCRIPTION /usr/sbin/asterisk, /usr/lib(64)/libasterisk* and /usr/lib(64)/asterisk as those files are needed to properly examine the coredump. The file will be named - /tmp/asterisk.<timestamp>.coredumps.tar.gz or - /tmp/asterisk-<uniqueid>.coredumps.tar.gz if + $OUTPUTDIR/asterisk.<timestamp>.coredumps.tar.gz or + $OUTPUTDIR/asterisk-<uniqueid>.coredumps.tar.gz if --tarball-uniqueid was specified. WARNING: This file could 1gb in size! + Mutually exclusive with --tartball-results --delete-coredumps-after Deletes all processed coredumps regardless of whether @@ -81,7 +83,8 @@ DESCRIPTION --tarball-results Creates a gzipped tarball of all result files produced. The tarball name will be: - /tmp/asterisk.<timestamp>.results.tar.gz + $OUTPUTDIR/asterisk.<timestamp>.results.tar.gz + Mutually exclusive with --tartball-coredumps --delete-results-after Deletes all processed results regardless of whether @@ -89,6 +92,10 @@ DESCRIPTION to use this option unless you have also specified --tarball-results. + --tarball-config + Adds the contents of /etc/asterisk to the tarball created + with --tarball-coredumps or --tarball-results. + --tarball-uniqueid="<uniqueid>" Normally DATEFORMAT is used to make the tarballs unique but you can use your own unique id in the tarball names @@ -130,6 +137,10 @@ DESCRIPTION NOTES You must be root to use $prog. + $OUTPUTDIR can be read from the current environment or from the + ast_debug_tools.conf file described below. If not specified, + work products are placed in the same directory as the core file. + The script relies on not only bash, but also recent GNU date and gdb with python support. *BSD operating systems may require installation of the 'coreutils' and 'devel/gdb' packagess and minor @@ -166,6 +177,12 @@ FILES # anyway. COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]\$(hostname)!(*.txt)) + # The directory to contain output files and work directories. + # For output from existing core files, the default is the + # directory that the core file is found in. For core files + # produced from a running process, the default is /tmp. + OUTPUTDIR=/some/directory + # Date command for the "running" coredump and tarballs. # DATEFORMAT will be executed to get the timestamp. # Don't put quotes around the format string or they'll be @@ -227,6 +244,13 @@ if [ -z "$GDB" ] ; then exit 1 fi +if [ -n "$OUTPUTDIR" ] ; then + if [ ! -d "$OUTPUTDIR" ] ; then + echo "OUTPUTDIR $OUTPUTDIR doesn't exists or is not a directory" + exit 1 + fi +fi + if [ ${#COREDUMPS[@]} -eq 0 ] ; then COREDUMPS+=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt)) fi @@ -326,6 +350,10 @@ fi # Timestamp to use for output files df=${tarball_uniqueid:-$(${DATEFORMAT})} +if [ -z "$asterisk_bin" ]; then + asterisk_bin=$(which asterisk) +fi + if $running || $RUNNING ; then # We need to go through some gyrations to find the pid of the running # MAIN asterisk process and not someone or something running asterisk -r. @@ -351,9 +379,9 @@ if $running || $RUNNING ; then read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer fi if [[ "$answer" =~ ^[Yy] ]] ; then - cf="/tmp/core-asterisk-running-$df" + cf="${OUTPUTDIR:-/tmp}/core-asterisk-running-$df" echo "Dumping running asterisk process to $cf" - ${GDB} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1 + ${GDB} ${asterisk_bin} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1 COREDUMPS+=("$cf") else echo "Skipping dump of running process" @@ -370,20 +398,22 @@ fi # and save them to /tmp/.gdbinit ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:` -tail -n +${ss} $0 >/tmp/.ast_coredumper.gdbinit +tail -n +${ss} $0 >${OUTPUTDIR:-/tmp}/.ast_coredumper.gdbinit # Now iterate over the coredumps and dump the debugging info for i in ${!COREDUMPS[@]} ; do cf=${COREDUMPS[$i]} echo "Processing $cf" - if [ -z "$asterisk_bin" ]; then - asterisk_bin=$(which asterisk) - fi - ${GDB} -n --batch -q --ex "source /tmp/.ast_coredumper.gdbinit" "$asterisk_bin" "$cf" 2>/dev/null | ( + + cfdir=`dirname ${cf}` + cfname=`basename ${cf}` + outputdir=${OUTPUTDIR:-${cfdir}} + + ${GDB} -n --batch -q --ex "source ${OUTPUTDIR:-/tmp}/.ast_coredumper.gdbinit" "$asterisk_bin" "$cf" 2>/dev/null | ( of=/dev/null while IFS= read line ; do if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then - of=${cf}-${BASH_REMATCH[1]} + of=${outputdir}/${cfname}-${BASH_REMATCH[1]} of=${of//:/-} rm -f "$of" echo "Creating $of" @@ -391,50 +421,58 @@ for i in ${!COREDUMPS[@]} ; do echo -e $"$line" >> "$of" done ) -done -if $tarball_coredumps ; then - tf=/tmp/asterisk-$df.coredumps.tar.gz - echo "Creating $tf" - dest=/tmp/asterisk-$df - rm -rf $dest 2>/dev/null || : - libdir=usr/lib - [ -d /usr/lib64 ] && libdir+=64 - mkdir -p $dest/tmp $dest/$libdir/asterisk $dest/etc $dest/usr/sbin - for i in ${!COREDUMPS[@]} ; do - ln -s "${COREDUMPS[@]}" $dest/"${COREDUMPS[@]}" - cp "${COREDUMPS[@]}"*.txt $dest/tmp/ - done - cp /etc/os-release $dest/etc/ - cp -a /$libdir/libasterisk* $dest/$libdir/ - cp -a /$libdir/asterisk/* $dest/$libdir/asterisk/ - cp -a /usr/sbin/asterisk $dest/usr/sbin - rm -rf $tf - tar -chzf $tf --transform="s/^[.]/$df/" -C $dest . - rm -rf $dest - echo "Created $tf" -fi + if $tarball_coredumps ; then + cfname=${cfname//:/-} + tf=${outputdir}/${cfname}.tar.gz + echo "Creating ${tf}" -if $delete_coredumps_after ; then - for i in ${!COREDUMPS[@]} ; do - rm -rf "${COREDUMPS[$i]}" - done -fi + dest=${outputdir}/${cfname}.output + rm -rf ${dest} 2>/dev/null || : -if $tarball_results ; then - tf=/tmp/asterisk-$df-results.tar - echo "Creating $tf.gz" - for i in ${!COREDUMPS[@]} ; do - tar -uvf $tf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt 2>/dev/null - done - gzip $tf -fi + libdir=usr/lib + [ -d /usr/lib64 ] && libdir+=64 + mkdir -p ${dest}/tmp ${dest}/${libdir}/asterisk ${dest}/etc ${dest}/usr/sbin -if $delete_results_after ; then - for i in ${!COREDUMPS[@]} ; do - rm -rf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt - done -fi + ln -s ${cf} ${dest}/tmp/${cfname} + cp ${outputdir}/${cfname}*.txt ${dest}/tmp/ + cp /etc/os-release ${dest}/etc/ + if $tarball_config ; then + cp -a /etc/asterisk ${dest}/etc/ + fi + cp -a /${libdir}/libasterisk* ${dest}/${libdir}/ + cp -a /${libdir}/asterisk/* ${dest}/${libdir}/asterisk/ + cp -a /usr/sbin/asterisk ${dest}/usr/sbin + rm -rf ${tf} + tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} . + rm -rf ${dest} + echo "Created $tf" + elif $tarball_results ; then + cfname=${cfname//:/-} + tf=${outputdir}/${cfname}.tar.gz + echo "Creating ${tf}" + + dest=${outputdir}/${cfname}.output + rm -rf ${dest} 2>/dev/null || : + mkdir -p ${dest} + cp ${outputdir}/${cfname}*.txt ${dest}/ + if $tarball_config ; then + mkdir -p ${dest}/etc + cp -a /etc/asterisk ${dest}/etc/ + fi + tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} . + rm -rf ${dest} + echo "Created $tf" + fi + +if $delete_coredumps_after ; then + rm -rf "${cf}" + fi + + if $delete_results_after ; then + rm -rf "${cf//:/-}"-{brief,full,thread1,locks}.txt + fi +done exit @@ -463,6 +501,9 @@ class DumpAsteriskCommand(gdb.Command): try: gdb.execute("p $_siginfo", from_tty) gdb.execute("info signal $_siginfo.si_signo") + except: + pass + try: gdb.execute("thread apply 1 bt full", from_tty) except: pass @@ -470,6 +511,9 @@ class DumpAsteriskCommand(gdb.Command): try: gdb.execute("p $_siginfo", from_tty) gdb.execute("info signal $_siginfo.si_signo") + except: + pass + try: gdb.execute("thread apply all bt", from_tty) except: pass @@ -477,6 +521,9 @@ class DumpAsteriskCommand(gdb.Command): try: gdb.execute("p $_siginfo", from_tty) gdb.execute("info signal $_siginfo.si_signo") + except: + pass + try: gdb.execute("thread apply all bt full", from_tty) except: pass @@ -484,6 +531,9 @@ class DumpAsteriskCommand(gdb.Command): try: gdb.execute("p $_siginfo", from_tty) gdb.execute("info signal $_siginfo.si_signo") + except: + pass + try: gdb.execute("show_locks", from_tty) except: pass diff --git a/include/asterisk/doxygen/asterisk-git-howto.h b/include/asterisk/doxygen/asterisk-git-howto.h deleted file mode 100644 index 1ecce15c0..000000000 --- a/include/asterisk/doxygen/asterisk-git-howto.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2009, Digium, Inc. - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! - * \file - */ - -/*! - * \page AsteriskGitHowto How to setup a local GIT mirror of the Asterisk SVN repository - * - * <hr> - * - * \section Introduction Introduction - * This document will instruct you how to setup a local git mirror of the - * Asterisk SVN repository. - * - * Why would you want that? for starters, it's a fast repository browser - * and works well even when offline. More on why and why not at 'Pros and Cons' - * in the end of this document. - * <hr> - * - * \section Setup Setup - * - * Make sure you have the package - * - \verbatim - git-svn - \endverbatim - * - * installed. It is part of the standard git distribution and included in - * any recent Linux distribution. - * - * Next, get the files from this repository: - * - \verbatim - git clone http://git.tzafrir.org.il/git/asterisk-tools.git - \endverbatim - * - * Which will create the subdirectory 'asterisk-tools' under your working - * directory. For the purpose of this HOWTO I assume that you will later - * download Asterisk under the same directory. - * - * Now let's get Asterisk: - * - \verbatim - git svn clone -s http://svn.digium.com/svn/asterisk - \endverbatim - * - * This will download the whole /trunk , /tags and /branches hirarchies - * to a new git repository under asterisk/ . - * This will take a L O N G time. In the order of magnitude of a - * day. If it stops in the middle: - * - \verbatim - # cd asterisk; git svn fetch --fetch-all - \endverbatim - * - * All commands as of this point are run from the newly-created subdirectory - * 'asterisk' - * - \verbatim - cd asterisk - \endverbatim - * - * Next make your repository more compact: - * - * \note FIXME: I now get a .git subdirectory of the size of 135MB. This seems - * overly large considering what I got a few monthes ago. - * - \verbatim - git repack -a - \endverbatim - * - * Now fix the menuselect bits. One possible venue is to use submodules. - * This would require setting a separate menuselect repository . And - * fixing the submodule references in every new tag to point to the right - * place. I gave up at this stage, and instead reimplememented menuselect - * - \verbatim - cp -a ../asterisk-tools/menuselect menuselect - make -C menuselect dummies - chmod +x menuselect/menuselect - \endverbatim - * - * Next thing to do is ignore generated files. .gitignore is somewhat - * like svn:ignore . Though it is possible to use one at the top - * directory. Hence I decided to make it ignore itself as well: - * - \verbatim - cp ../asterisk-tools/asterisk_gitignore .gitignore - \endverbatim - * - * Now let's generate tags that will point to the tags/* branches. - * e.g. tag 'v1.4.8' will point to the head of branch tags/1.4.8 . - * If you don't like the extra 'v', just edit the sed command. - * - \verbatim - ../asterisk-tools/update_tags - \endverbatim - * - * Example configuration (refer to menuselect/menuselelct for more - * information). For instance: res_snmp breaks building 1.4 from git: - * - \verbatim - echo 'exclude res_snmp' >build_tools/conf - \endverbatim - * - * <hr> - * - * \section Update Update - * The main Asterisk repository tends to get new commits occasionally. I - * suppose you want those updates in your local copy. The following command - * should normally be done from the master branch. If you actually use branches, - * it is recommended to switch to it beforehand: - * - \verbatim - git checkout master - \endverbatim - * - * Next, get all updates. - * <hr> - * - * \section Usage Usage - * - * If you use git from the command-line, it is highly recommended to enable - * programmable bash completion. The git command-line is way more complex - * than svn, but the completion makes it usable: - * - * - \verbatim - asterisk$ git show v1.2.28<tab><tab> - v1.2.28 v1.2.28.1 - - asterisk$ git show v1.2.28:c<tab><tab> - callerid.c channel.c cli.c coef_out.h contrib/ - cdr/ channels/ codecs/ config.c cryptostub.c - cdr.c chanvars.c coef_in.h configs/ cygwin/ - - asterisk$ git svn<tab><tab> - clone fetch log set-tree - commit-diff find-rev propget show-externals - create-ignore info proplist show-ignore - dcommit init rebase - - asterisk$ git svn rebase --f - --fetch-all --follow-parent - \endverbatim - * - * Some useful commands: - * - \verbatim - git svn rebase --fetch-all # pull updates from upstream - man git-FOO # documentation for 'git FOO' - # <tree> is any place on graph of branches: HEAD, name of a branch or - # a tag, commit ID, and some others - git show <tree> # The top commit in this tree (log + diff) - git show <tree>:directory # directory listing - git show <tree>:some/file # get that file - git log <tree> # commit log up to that point - git branch # shows local branches and in which one you are - git branch -r # List remote branches. Such are SVN ones. - \endverbatim - * - * For more information, see the man page gittutorial as well as - * \arg http://git-scm.com/documentation - * - \verbatim - git svn rebase --fetch-all - \endverbatim - * - * <hr> - * - * \section ProsAndCons Pros and Cons - * - * \subsection TheGood The Good - * - * Working off-line: - * If you want to be able to use 'svn log' and 'svn diff' to a different - * branch, now you can. - * - * Efficient repository browser: - * With git you can effectively browse commit logs and working copies of - * various branches. In fact, using it merely as a logs and versions - * browser can be useful on its own. - * - * Branches really work: - * With SVN merging a branch is complicated. Partially because lack of - * separate merge tracking.With git you don't need the extra svnmerge: - * changes that don't collide with your branch merge in a quick merge - * operation. - * - * \subsection Limitations Limitations - * - * svn:externals : - * does not really work well with git-svn (and similar systems: svk, - * bzr-svn and hg-svn). Git has something called submodules that allows - * emulating the basic functionality of svn:externals, but is not as - * transparent. - * - * Commiting: - * Not sure how safe it is to commit from such a copy. In most places I - * see that it is not recommended to commit directly from git-svn. OTOH, - * git has some tools that make it easy to prepare a patch set out of a - * branch (e.g. git format-patch). - * - * IIRC there are also some issues for git-svn with https certificate - * authentication in the first place. - * - * Tags: - * /tags are branches. SVN tags are really branches that we pretend not - * to change. And in fact in Asterisk we practically do change. But see - * workaround below to generate tags from the tag branches. - * - * /team branches:: - * At least with git 1.5.x you can't easily follow all the team branches. - * This is due to a bug in their handling of wildcards in branches - * description. I believe this has been resolved in 1.6 but I didn't get - * to test that. Even if it will, it will require an extra step of manual - * editing. - * - * <hr> - */ diff --git a/include/asterisk/doxygen/commits.h b/include/asterisk/doxygen/commits.h deleted file mode 100644 index 032bfc5f4..000000000 --- a/include/asterisk/doxygen/commits.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2009, Digium, Inc. - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! - * \file - */ - -/*! - * \page CommitMessages Guidelines for Commit Messages - * - * <hr> - * - * \section CommitMsgFormatting Commit Message Formatting - * - * The following illustrates the basic outline for commit messages: - * - * \verbatim - * <One-liner summary of changes> - * - * <Empty Line> - * - * <Verbose description of the changes> - * - * <Empty Line> - * - * <Special Tags> - * \endverbatim - * - * Some commit history viewers treat the first line of commit messages as the - * summary for the commit. So, an effort should be made to format our commit - * messages in that fashion. The verbose description may contain multiple - * paragraphs, itemized lists, etc. Always end the first sentence (and any - * subsequent sentences) with punctuation. - * - * Commit messages should be wrapped at 80 %columns. - * - * \note For trivial commits, such as "fix the build", or "fix spelling mistake", - * the verbose description may not be necessary. - * - * <hr> - * - * \section CommitMsgTags Special Tags for Commit Messages - * - * \subsection MantisTags Mantis (https://issues.asterisk.org/) - * - * To have a commit noted in an issue, use a tag of the form: - * \arg (issue #1234) - * - * To have a commit automatically close an issue, use a tag of the form: - * \arg (closes issue #1234) - * - * When making a commit for a mantis issue, it is easiest to use the - * provided commit %message template functionality. It will format the - * special tags appropriately, and will also include information about who - * reported the issue, which patches are being applied, and who did testing. - * - * Assuming that you have bug marshal access (and if you have commit access, - * it is pretty safe to assume that you do), you will find the commit %message - * template section directly below the issue details section and above the - * issue relationships section. You will have to click the '+' next to - * "Commit message template" to make the contents of the section visible. - * - * Here is an example of what the template will generate for you: - * - * \verbatim - * (closes issue #1234) - * Reported by: SomeGuy - * Patches: - * fix_bug_1234.diff uploaded by SomeDeveloper (license 5678) - * \endverbatim - * - * If the patch being committed was written by the person doing the commit, - * and is not available to reference as an upload to the issue, there is no - * need to include something like "fixed by me", as that will be the default - * assumption when a specific patch is not referenced. - * - * \subsection ReviewBoardTags Review Board (https://reviewboard.asterisk.org/) - * - * To have a commit set a review request as submitted, include the full URL - * to the review request. For example: - * \arg Review: %https://reviewboard.asterisk.org/r/95/ - * - * \note The trailing slash in the review URL is required. - * - * <hr> - * - * \section CommitMsgSvnmerge Commit Messages with svnmerge - * - * When using the svnmerge tool for merging changes between branches, use the - * commit %message generated by svnmerge. The '-f' option to svnmerge allows - * you to specify a file for svnmerge to write out a commit %message to. The - * '-F' option to svn commit allows you to specify a file that contains the - * commit %message. - * - * If you are using the expect script wrappers for svnmerge from repotools, - * a commit %message is automatically placed in the file '../merge.msg'. - * - * For more detailed information about working with branches and merging, - * see the following page on %asterisk.org: - * \arg https://wiki.asterisk.org/wiki/display/AST/Subversion+Usage - */ diff --git a/include/asterisk/doxygen/releases.h b/include/asterisk/doxygen/releases.h deleted file mode 100644 index d1b33ffd2..000000000 --- a/include/asterisk/doxygen/releases.h +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2009, Digium, Inc. - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! - * \file - */ - -/*! - * \page ReleaseStatus Asterisk Release Status - * - * \section warranty Warranty - * The following warranty applies to all open source releases of Asterisk: - * - * NO WARRANTY - * - * BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY - * FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN - * OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES - * PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED - * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS - * TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE - * PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, - * REPAIR OR CORRECTION. - - * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR - * REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, - * INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING - * OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED - * TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY - * YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER - * PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * \section releasestatustypes Release Status Types - * - * Release management is a essentially an agreement between the development - * community and the %user community on what kind of updates can be expected - * for Asterisk releases, and what types of changes these updates will contain. - * Once these policies are established, the development community works very - * hard to adhere to them. However, the development community does reserve - * the right to make exceptions to these rules for special cases as the need - * arises. - * - * Asterisk releases are in various states of maintenance. The states are - * defined here: - * - * \arg <b>None</b> - This release series is receiving no updates whatsoever. - * \arg <b>Security-Only</b> - This release series is receiving updates, but - * only to address security issues. Security issues found and fixed in - * this release series will be accompanied by a published security advisory - * from the Asterisk project. - * \arg <b>Full-Support</b> - This release series is receiving updates for all - * types of bugs. - * \arg <b>Full-Development</b> - Changes in this part of Asterisk include bug - * fixes, as well as new %features and architectural improvements. - * - * \section AsteriskReleases Asterisk Maintenance Levels - * - * \htmlonly - * <table border="1"> - * <tr> - * <td><b>Name</b></td> - * <td><b>SVN Branch</b></td> - * <td><b>Status</b></td> - * <td><b>Notes</b></td> - * </tr> - * <tr> - * <td>Asterisk 1.0</td> - * <td>/branches/1.0</td> - * <td>None</td> - * </tr> - * <tr> - * <td>Asterisk 1.2</td> - * <td>/branches/1.2</td> - * <td>Security-Only</td> - * </tr> - * <tr> - * <td>Asterisk 1.4</td> - * <td>/branches/1.4</td> - * <td>Full-Support</td> - * </tr> - * <tr> - * <td>Asterisk 1.6.0</td> - * <td>/branches/1.6.0</td> - * <td>Full-Support</td> - * </tr> - * <tr> - * <td>Asterisk 1.6.1</td> - * <td>/branches/1.6.1</td> - * <td>Full-Support</td> - * <td>Still in beta</td> - * </tr> - * <tr> - * <td>Asterisk trunk</td> - * <td>/trunk</td> - * <td>Full-Development</td> - * <td>No releases are made directly from trunk.</td> - * </tr> - * </table> - * \endhtmlonly - * - * For more information on how and when Asterisk releases are made, see the - * release policies page: - * \arg \ref ReleasePolicies - */ - -/*! - * \page ReleasePolicies Asterisk Release and Commit Policies - * - * \section releasestatus Asterisk Release Status - * - * For more information on the current status of each Asterisk release series, - * please see the Asterisk Release Status page: - * - * \arg \ref ReleaseStatus - * - * <hr> - * - * \section commitmonitoring Commit Monitoring - * - * To monitor commits to Asterisk and related projects, visit - * <a href="http://lists.digium.com/">http://lists.digium.com</a>. The Digium - * mailing list server hosts a %number of mailing lists for commits. - * - * <hr> - * - * \section ast10policy Asterisk 1.0 - * - * \subsection svnbranch SVN Branch - * - * \arg /branches/1.0 - * - * \subsection ast10releases Release and Commit Policy - * No more releases of Asterisk 1.0 will be made for any reason. - * - * No commits should be made to the Asterisk 1.0 branch. - * - * <hr> - * - * \section ast12policy Asterisk 1.2 - * - * \subsection svnbranch SVN Branch - * - * \arg /branches/1.2 - * - * \subsection ast12releases Release and Commit Policy - * - * There will be no more scheduled releases of Asterisk 1.2. - * - * Commits to the Asterisk 1.2 branch should only address security issues or - * regressions introduced by previous security fixes. For a security issue, the - * commit should be accompanied by an - * <a href="http://downloads.asterisk.org/pub/security/">Asterisk Security Advisory</a> - * and an immediate release. When a commit goes in to fix a regression, the previous - * security advisory that is related to the change that introduced the bug should get - * updated to indicate that there is an updated version of the fix. A release should - * be made immediately for these regression fixes, as well. - * - * \subsection ast12releasenumbers Release Numbering - * - * - 1.2.X - a release that contains new security fixes - * - 1.2.X.Y - a release that contains fixes to the security patches released in - * version 1.2.X - * - * <hr> - * - * \section ast14policy Asterisk 1.4 - * - * \subsection svnbranch SVN Branch - * - * \arg /branches/1.4 - * - * \subsection ast14releases Release and Commit Policy - * - * Asterisk 1.4 is receiving regular bug fix release updates. An attempt is made to - * make releases of every four to six weeks. Since this release series is receiving - * changes for all types of bugs, the number of changes in a single release can be - * significant. 1.4.X releases go through a release candidate testing cycle to help - * catch any regressions that may have been introduced. - * - * Commits to Asterisk 1.4 must be to address bugs only. No new %features should be - * introduced into Asterisk 1.4 to reduce the %number of changes to this established - * release series. The only exceptions to this %rule are for cases where something - * that may be considered a feature is needed to address a bug or security issue. - * - * \subsection ast14releasenumbers Release Numbering - * - * - 1.4.X - a release that contains new bug fixes to the 1.4 release series - * - 1.4.X.Y - a release that contains very few changes on top of 1.4.X. This - * may be for a security patch, or for a regression introduced in 1.4.X. - * - * <hr> - * - * \section ast16policy Asterisk 1.6 - * - * \subsection svnbranch SVN Branch - * - * \arg /branches/1.6.* - * - * \subsection ast16releases Release and Commit Policy - * - * Asterisk 1.6 is managed in a different way than previous Asterisk release series. - * From a high level, it was inspired by the release model used for Linux 2.6. - * The intended time frame for 1.6.X releases is every 2 or 3 months. Each 1.6.X - * release gets its own branch. The 1.6.X branches are branches off of trunk. - * Once the branch is created, it only receives bug fixes. Each 1.6.X release goes - * through a beta and release candidate testing cycle. - * - * After a 1.6.X release is published, it will be maintained until 1.6.[X + 3] is - * released. While a 1.6.X release branch is still maintained, it will receive only - * bug fixes. Periodic maintenance releases will be made and labeled as 1.6.X.Y. - * 1.6.X.Y releases should go through a release candidate test cycle before being - * published. - * - * For now, all previous 1.6 release will be maintained for security issues. Once - * we have more 1.6 releases to deal with, this part of the policy will likely change. - * - * For some history on the motivations for Asterisk 1.6 release management, see the - * first two sections of this - * <a href="http://lists.digium.com/pipermail/asterisk-dev/2007-October/030083.html">mailing list post</a>. - * - * \subsection ast16releasenumbers Release Numbering - * - * - 1.6.X - a release that includes new functionality - * - 1.6.X.Y - a release that contains fixes for bugs or security issues identified - * in the 1.6.X release series. - * - * <hr> - * - * \section asttrunk Asterisk Trunk - * - * \subsection svnbranch SVN Branch - * - * \arg /trunk - * - * \subsection asttrunkpolicy Release and Commit Policy - * - * No releases are ever made directly from Asterisk trunk. - * - * Asterisk trunk is used as the main development area for upcoming Asterisk 1.6 - * releases. Commits to Asterisk trunk are not limited. They can be bug fixes, - * new %features, and architectural improvements. However, for larger sets - * of changes, developers should work with the Asterisk project leaders to - * schedule them for inclusion. Care is taken not to include too many invasive - * sets of changes for each new Asterisk 1.6 release. - * - * No changes should go into Asterisk trunk that are not ready to go into a - * release. While the upcoming release will go through a beta and release - * candidate test cycle, code should not be in trunk until the code has been - * tested and reviewed such that there is reasonable belief that the code - * is ready to go. - * - * <hr> - * - * \section astteam Asterisk Team Branches - * - * \subsection svnbranch SVN Branch - * - * \arg /team/<developername> - * - * \subsection astteampolicy Release and Commit Policy - * - * The Asterisk subversion repository has a special directory called "team" - * where developers can make their own personal development branches. This is - * where new %features, bug fixes, and architectural improvements are developed - * while they are in %progress. - * - * Just about anything goes as far as commits to this area goes. However, - * developers should keep in mind that anything committed here, as well as - * anywhere else on Digium's SVN server, falls under the contributor license - * agreement. - * - * In addition to each developer having their own space for working on projects, - * there is also a team/group folder where %group development efforts take place. - * - * Finally, in each developer folder, there is a folder called "private". This - * is where developers can create branches for working on things that they are - * not ready for the whole world to see. - */ diff --git a/include/asterisk/doxygen/reviewboard.h b/include/asterisk/doxygen/reviewboard.h deleted file mode 100644 index 59ab852bd..000000000 --- a/include/asterisk/doxygen/reviewboard.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -* Asterisk -- An open source telephony toolkit. -* -* Copyright (C) 1999 - 2009, Digium, Inc. -* -* See http://www.asterisk.org for more information about -* the Asterisk project. Please do not directly contact -* any of the maintainers of this project for assistance; -* the project provides a web site, mailing lists and IRC -* channels for your use. -* -* This program is free software, distributed under the terms of -* the GNU General Public License Version 2. See the LICENSE file -* at the top of the source tree. -*/ - -/*! -* \file -*/ - -/*! - * \page Reviewboard Reviewboard Usage and Guidelines - * - * <hr> - * - * \section ReviewboardGuidelines Usage Guidelines - * - * Mantis (https://issues.asterisk.org) and Reviewboard (https://reviewboard.asterisk.org) - * are both utilities that the Asterisk development community uses to help - * track and review code being written for Asterisk. Since both systems - * are used for posting patches, it is worth discussing when it is appropriate - * to use reviewboard and when not. - * - * Here are the situations in which it is appropriate to post code to reviewboard: - * - A committer has a patch that they would like to get some feedback on before - * merging into one of the main branches. - * - A committer or bug marshal has requested a contributor to post their patch - * from Mantis on reviewboard to aid in the review process. This typically - * happens with complex code contributions where reviewboard can help aid in - * providing feedback. - * - * We do encourage all interested parties to participate in the review process. - * However, aside from the cases mentioned above, we prefer that all code - * submissions first go through Mantis. - * - * \note It is acceptable for a committer to post patches to reviewboard before - * they are complete to get some feedback on the approach being taken. However, - * if the code is not yet ready to be merged, it \b must be documented as such. - * A review request with a patch proposed for merging should have documented - * testing and should not have blatant coding guidelines violations. Lack of - * these things is careless and shows disrespect for those reviewing your code. - * - * <hr> - * - * \section ReviewboardPosting Posting Code to Reviewboard - * - * \subsection postreview Using post-review - * - * The easiest way to post a patch to reviewboard is by using the - * post-review tool. We have post-review in our repotools svn repository. - * - * \verbatim - * $ svn co http://svn.digium.com/svn/repotools - * \endverbatim - * - * Essentially, post-review is a script that will take the output of "svn - * diff" and create a review request out of it for you. So, once you have - * a working copy with the changes you expect in the output of "svn diff", - * you just run the following command: - * - * \verbatim - * $ post-review - * \endverbatim - * - * If it complains about not knowing which reviewboard server to use, add - * the server option: - * - * \verbatim - * $ post-review --server=https://reviewboard.asterisk.org - * \endverbatim - * - * \subsection postreviewnewfiles Dealing with New Files - * - * I have one final note about an oddity with using post-review. If you - * maintain your code in a team branch, and the new code includes new - * files, there are some additional steps you must take to get post-review - * to behave properly. - * - * You would start by getting your changes applied to a trunk working copy: - * - * \verbatim - * $ cd .../trunk - * \endverbatim - * - * Then, apply the changes from your branch: - * - * \verbatim - * $ svn merge .../trunk .../team/group/my_new_code - * \endverbatim - * - * Now, the code is merged into your working copy. However, for a new - * file, subversion treats it as a copy of existing content and not new - * content, so new files don't show up in "svn diff" at this point. To get - * it to show up in the diff, use the following commands so svn treats it - * as new content and publishes it in the diff: - * - * \verbatim - * $ svn revert my_new_file.c - * $ svn add my_new_file.c - * \endverbatim - * - * Now, it should work, and you can run "post-review" as usual. - * - * \subsection postreviewupdate Updating Patch on Existing Review Request - * - * Most of the time, a patch on reviewboard will require multiple iterations - * before other sign off on it being ready to be merged. To update the diff - * for an existing review request, you can use post-review and the -r option. - * Apply the current version of the diff to a working copy as described above, - * and then run the following command: - * - * \verbatim - * $ post-review -r <review request number> - * \endverbatim - */ diff --git a/include/asterisk/doxyref.h b/include/asterisk/doxyref.h index 55500230d..14ebb4b83 100644 --- a/include/asterisk/doxyref.h +++ b/include/asterisk/doxyref.h @@ -33,12 +33,6 @@ * * \section devpolicy Development and Release Policies * \arg \ref CodeGuide : The must-read document for all developers - * \arg \ref CommitMessages : Information on formatting and special tags for commit messages - * \arg \ref ReleaseStatus : The current support level for various Asterisk releases - * \arg \ref ReleasePolicies : Asterisk Release and Commit Policies - * \arg \ref Reviewboard : Reviewboard Usage and Guidelines - * \arg \ref MantisWorkflow : Workflow Guidelines for Asterisk Open Source Issue Tracker - * \arg \ref AsteriskGitHowto : How to setup a local GIT mirror of the Asterisk SVN repository * \arg \ref AstCREDITS : A Thank You to contributors (unfortunately out of date) * * \section apisandinterfaces Asterisk APIs and Interfaces diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h index d8e7d063b..83d5d4f78 100644 --- a/include/asterisk/http_websocket.h +++ b/include/asterisk/http_websocket.h @@ -344,6 +344,15 @@ AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), { errno AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_remote_address, (struct ast_websocket *session), {return NULL;}); /*! + * \brief Get the local address for a WebSocket connection session. + * + * \retval ast_sockaddr Local address + * + * \since 13.19.0 + */ +AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_local_address, (struct ast_websocket *session), {return NULL;}); + +/*! * \brief Get whether the WebSocket session is using a secure transport or not. * * \retval 0 if unsecure diff --git a/include/asterisk/optional_api.h b/include/asterisk/optional_api.h index 394aed0e4..8d1498ca9 100644 --- a/include/asterisk/optional_api.h +++ b/include/asterisk/optional_api.h @@ -107,10 +107,6 @@ #if defined(OPTIONAL_API) -#if !defined(HAVE_ATTRIBUTE_constructor) || !defined(HAVE_ATTRIBUTE_constructor) -#error OPTIONAL_API requires compiler constructor/destructor support -#endif - /*! * \internal * \brief Function pointer to an optional API function. diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h index 0cb434766..73ed06078 100644 --- a/include/asterisk/sorcery.h +++ b/include/asterisk/sorcery.h @@ -312,6 +312,14 @@ struct ast_sorcery_wizard { /*! \brief Callback for closing a wizard */ void (*close)(void *data); + + /*! \brief Optional callback for retrieving multiple objects by matching their id with a prefix */ + void (*retrieve_prefix)(const struct ast_sorcery *sorcery, + void *data, + const char *type, + struct ao2_container *objects, + const char *prefix, + const size_t prefix_len); }; /*! \brief Interface for a sorcery object type observer */ @@ -364,9 +372,20 @@ int ast_sorcery_init(void); int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module); /*! + * \brief Register a sorcery wizard + * + * \param interface Pointer to a wizard interface + * \param module Pointer to the module implementing the interface + * + * \retval 0 success + * \retval -1 failure + */ +int __ast_sorcery_wizard_register_with_prefix(const struct ast_sorcery_wizard *interface, struct ast_module *module); + +/*! * \brief See \ref __ast_sorcery_wizard_register() */ -#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register(interface, ast_module_info ? ast_module_info->self : NULL) +#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register_with_prefix(interface, ast_module_info ? ast_module_info->self : NULL) /*! * \brief Unregister a sorcery wizard @@ -1218,6 +1237,22 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex); /*! + * \brief Retrieve multiple objects whose id begins with the specified prefix + * \since 13.19.0 + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object to retrieve + * \param prefix Object id prefix + * \param prefix_len The length of prefix in bytes + * + * \retval non-NULL if error occurs + * \retval NULL success + * + * \note The prefix is matched in a case sensitive manner. + */ +struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len); + +/*! * \brief Update an object * * \param sorcery Pointer to a sorcery structure diff --git a/main/aoc.c b/main/aoc.c index d63fbdf15..707dbb00f 100644 --- a/main/aoc.c +++ b/main/aoc.c @@ -1861,7 +1861,10 @@ static void aoc_publish_blob(struct ast_channel *chan, struct stasis_message_typ msg = stasis_message_create(msg_type, aoc_event); ao2_ref(aoc_event, -1); - stasis_publish(ast_manager_get_topic(), msg); + if (msg) { + stasis_publish(ast_manager_get_topic(), msg); + ao2_ref(msg, -1); + } } static struct ast_manager_event_blob *aoc_to_ami(struct stasis_message *message, diff --git a/main/audiohook.c b/main/audiohook.c index 869cb750e..cb3c4bcb3 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -947,7 +947,9 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st * rely on actual media being present to do things. */ if (!middle_frame->data.ptr) { - ast_frfree(middle_frame); + if (middle_frame != start_frame) { + ast_frfree(middle_frame); + } return start_frame; } diff --git a/main/plc.c b/main/plc.c index 1f0206920..4421e7a0c 100644 --- a/main/plc.c +++ b/main/plc.c @@ -98,7 +98,7 @@ static void normalise_history(plc_state_t *s) if (s->buf_ptr == 0) return; memcpy(tmp, s->history, sizeof(int16_t)*s->buf_ptr); - memcpy(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr)); + memmove(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr)); memcpy(s->history + PLC_HISTORY_LEN - s->buf_ptr, tmp, sizeof(int16_t) * s->buf_ptr); s->buf_ptr = 0; } diff --git a/main/sorcery.c b/main/sorcery.c index 1bdf2c2f8..cb0aff538 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -544,6 +544,27 @@ static void sorcery_internal_wizard_destructor(void *obj) int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module) { + struct ast_sorcery_wizard compat = { + .name = interface->name, + .open = interface->open, + .load = interface->load, + .reload = interface->reload, + .create = interface->create, + .retrieve_id = interface->retrieve_id, + .retrieve_regex = interface->retrieve_regex, + .retrieve_fields = interface->retrieve_fields, + .retrieve_multiple = interface->retrieve_multiple, + .update = interface->update, + .delete = interface->delete, + .close = interface->close, + .retrieve_prefix = NULL, + }; + + return __ast_sorcery_wizard_register_with_prefix(&compat, module); +} + +int __ast_sorcery_wizard_register_with_prefix(const struct ast_sorcery_wizard *interface, struct ast_module *module) +{ struct ast_sorcery_internal_wizard *wizard; int res = -1; @@ -1982,6 +2003,36 @@ struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *so return objects; } +struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len) +{ + RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); + struct ao2_container *objects; + int i; + + if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) { + return NULL; + } + + AST_VECTOR_RW_RDLOCK(&object_type->wizards); + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + struct ast_sorcery_object_wizard *wizard = + AST_VECTOR_GET(&object_type->wizards, i); + + if (!wizard->wizard->callbacks.retrieve_prefix) { + continue; + } + + wizard->wizard->callbacks.retrieve_prefix(sorcery, wizard->data, object_type->name, objects, prefix, prefix_len); + + if (wizard->caching && ao2_container_count(objects)) { + break; + } + } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); + + return objects; +} + /*! \brief Internal function which returns if the wizard has created the object */ static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details) { diff --git a/res/res_fax.c b/res/res_fax.c index 666c2d997..6e4451b67 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -4563,12 +4563,7 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat unsigned int gwtimeout; if (sscanf(timeout, "%30u", &gwtimeout) == 1) { - if (gwtimeout >= 0) { - details->gateway_timeout = gwtimeout * 1000; - } else { - ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", - cmd, data); - } + details->gateway_timeout = gwtimeout * 1000; } else { ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", timeout, data); } @@ -4607,13 +4602,7 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat if (details->faxdetect_id < 0) { if (timeout) { if (sscanf(timeout, "%30u", &fdtimeout) == 1) { - if (fdtimeout >= 0) { - fdtimeout *= 1000; - } else { - ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", - cmd, data); - fdtimeout = 0; - } + fdtimeout *= 1000; } else { ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", timeout, data); diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index 1614b4319..1d99fcc17 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -91,35 +91,44 @@ static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) pjsip_cid_hdr *cid_hdr; pjsip_from_hdr *from_hdr; pjsip_to_hdr *to_hdr; - pjsip_tpmgr_fla2_param prm; capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start)); if (!capture_info) { return PJ_SUCCESS; } - /* Attempt to determine what IP address will we send this packet out of */ - pjsip_tpmgr_fla2_param_default(&prm); - prm.tp_type = tdata->tp_info.transport->key.type; - pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); - prm.local_if = PJ_TRUE; + if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) { + pjsip_tpmgr_fla2_param prm; - /* If we can't get the local address use what we have already */ - if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { - pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); - } else { - if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { - snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + /* Attempt to determine what IP address will we send this packet out of */ + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = tdata->tp_info.transport->key.type; + pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); + prm.local_if = PJ_TRUE; + + /* If we can't get the local address use what we have already */ + if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { + pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } else { - snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { + snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } else { + snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } } + } else { + /* For reliable transports they can only ever come from the transport + * local address. + */ + pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } + pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3); cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg); @@ -152,7 +161,6 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) char remote_buf[256]; char *uuid; struct hepv3_capture_info *capture_info; - pjsip_tpmgr_fla2_param prm; capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len); if (!capture_info) { @@ -164,27 +172,33 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) } pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3); - /* Attempt to determine what IP address we probably received this packet on */ - pjsip_tpmgr_fla2_param_default(&prm); - prm.tp_type = rdata->tp_info.transport->key.type; - pj_strset2(&prm.dst_host, rdata->pkt_info.src_name); - prm.local_if = PJ_TRUE; + if (!(rdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) { + pjsip_tpmgr_fla2_param prm; - /* If we can't get the local address use what we have already */ - if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) { - pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); - } else { - if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { - snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + /* Attempt to determine what IP address we probably received this packet on */ + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = rdata->tp_info.transport->key.type; + pj_strset2(&prm.dst_host, rdata->pkt_info.src_name); + prm.local_if = PJ_TRUE; + + /* If we can't get the local address use what we have already */ + if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) { + pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } else { - snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { + snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } else { + snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } } + } else { + pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag); diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 2baccc052..75a6eba64 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -87,18 +87,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") /*! \brief Structure definition for session */ struct ast_websocket { - FILE *f; /*!< Pointer to the file instance used for writing and reading */ - int fd; /*!< File descriptor for the session, only used for polling */ - struct ast_sockaddr address; /*!< Address of the remote client */ - enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */ - size_t payload_len; /*!< Length of the payload */ - char *payload; /*!< Pointer to the payload */ - size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */ - int timeout; /*!< The timeout for operations on the socket */ - unsigned int secure:1; /*!< Bit to indicate that the transport is secure */ - unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */ - unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */ - struct websocket_client *client; /*!< Client object when connected as a client websocket */ + FILE *f; /*!< Pointer to the file instance used for writing and reading */ + int fd; /*!< File descriptor for the session, only used for polling */ + struct ast_sockaddr remote_address; /*!< Address of the remote client */ + struct ast_sockaddr local_address; /*!< Our local address */ + enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */ + size_t payload_len; /*!< Length of the payload */ + char *payload; /*!< Pointer to the payload */ + size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */ + int timeout; /*!< The timeout for operations on the socket */ + unsigned int secure:1; /*!< Bit to indicate that the transport is secure */ + unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */ + unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */ + struct websocket_client *client; /*!< Client object when connected as a client websocket */ }; /*! \brief Hashing function for protocols */ @@ -183,7 +184,7 @@ static void session_destroy_fn(void *obj) if (session->f) { fclose(session->f); ast_verb(2, "WebSocket connection %s '%s' closed\n", session->client ? "to" : "from", - ast_sockaddr_stringify(&session->address)); + ast_sockaddr_stringify(&session->remote_address)); } } @@ -316,7 +317,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, ui fclose(session->f); session->f = NULL; ast_verb(2, "WebSocket connection %s '%s' forcefully closed due to fatal write error\n", - session->client ? "to" : "from", ast_sockaddr_stringify(&session->address)); + session->client ? "to" : "from", ast_sockaddr_stringify(&session->remote_address)); } ao2_unlock(session); @@ -429,7 +430,12 @@ int AST_OPTIONAL_API_NAME(ast_websocket_fd)(struct ast_websocket *session) struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_remote_address)(struct ast_websocket *session) { - return &session->address; + return &session->remote_address; +} + +struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_local_address)(struct ast_websocket *session) +{ + return &session->local_address; } int AST_OPTIONAL_API_NAME(ast_websocket_is_secure)(struct ast_websocket *session) @@ -890,12 +896,22 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan return 0; } + /* Get our local address for the connected socket */ + if (ast_getsockname(ser->fd, &session->local_address)) { + ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to get local address\n", + ast_sockaddr_stringify(&ser->remote_address)); + websocket_bad_request(ser); + ao2_ref(session, -1); + ao2_ref(protocol_handler, -1); + return 0; + } + ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol ? : "", version); /* Populate the session with all the needed details */ session->f = ser->f; session->fd = ser->fd; - ast_sockaddr_copy(&session->address, &ser->remote_address); + ast_sockaddr_copy(&session->remote_address, &ser->remote_address); session->opcode = -1; session->reconstruct = DEFAULT_RECONSTRUCTION_CEILING; session->secure = ser->ssl ? 1 : 0; @@ -1350,7 +1366,7 @@ static enum ast_websocket_result websocket_client_connect(struct ast_websocket * ws->f = ws->client->ser->f; ws->fd = ws->client->ser->fd; ws->secure = ws->client->ser->ssl ? 1 : 0; - ast_sockaddr_copy(&ws->address, &ws->client->ser->remote_address); + ast_sockaddr_copy(&ws->remote_address, &ws->client->ser->remote_address); return WS_OK; } diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 81234d695..d2e7b2b69 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -368,7 +368,7 @@ static int contact_acl_to_str(const void *obj, const intptr_t *args, char **buf) static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; - enum ast_sip_dtmf_mode dtmf = ast_sip_str_to_dtmf(var->value); + int dtmf = ast_sip_str_to_dtmf(var->value); if (dtmf == -1) { return -1; diff --git a/res/res_pjsip_endpoint_identifier_anonymous.c b/res/res_pjsip_endpoint_identifier_anonymous.c index b93133824..2a47cbe3f 100644 --- a/res/res_pjsip_endpoint_identifier_anonymous.c +++ b/res/res_pjsip_endpoint_identifier_anonymous.c @@ -56,9 +56,11 @@ static int find_transport_state_in_use(void *obj, void *arg, int flags) return 0; } +#define DOMAIN_NAME_LEN 255 + static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) { - char domain_name[64], id[AST_UUID_STR_LEN]; + char domain_name[DOMAIN_NAME_LEN + 1]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); @@ -70,6 +72,8 @@ static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) } if (!ast_sip_get_disable_multi_domain()) { + char id[sizeof("anonymous@") + DOMAIN_NAME_LEN]; + /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "anonymous@%s", domain_name); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c index 30da062ed..b79dcb59b 100644 --- a/res/res_pjsip_endpoint_identifier_user.c +++ b/res/res_pjsip_endpoint_identifier_user.c @@ -74,10 +74,12 @@ static int find_transport_state_in_use(void *obj, void *arg, int flags) return 0; } +#define DOMAIN_NAME_LEN 255 +#define USERNAME_LEN 255 + static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoint_name, char *domain_name) { - char id[AST_UUID_STR_LEN]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); @@ -85,6 +87,8 @@ static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoi RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (!ast_sip_get_disable_multi_domain()) { + char id[DOMAIN_NAME_LEN + USERNAME_LEN + sizeof("@")]; + /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { @@ -116,8 +120,8 @@ static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoi static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) { - char username[64]; - char domain[64]; + char username[USERNAME_LEN + 1]; + char domain[DOMAIN_NAME_LEN + 1]; struct ast_sip_endpoint *endpoint; if (get_from_header(rdata, username, sizeof(username), domain, sizeof(domain))) { @@ -149,7 +153,7 @@ static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) static struct ast_sip_endpoint *auth_username_identify(pjsip_rx_data *rdata) { - char username[64], realm[64]; + char username[USERNAME_LEN + 1], realm[DOMAIN_NAME_LEN + 1]; struct ast_sip_endpoint *endpoint; pjsip_authorization_hdr *auth_header = NULL; diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index c04594fee..b874a4de3 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -203,27 +203,25 @@ static int transport_create(void *data) ast_debug(4, "Creating websocket transport for %s:%s\n", newtransport->transport.type_name, ws_addr_str); + newtransport->transport.info = (char *) pj_pool_alloc(newtransport->transport.pool, + strlen(newtransport->transport.type_name) + strlen(ws_addr_str) + sizeof(" to ")); + sprintf(newtransport->transport.info, "%s to %s", newtransport->transport.type_name, ws_addr_str); + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr); if (newtransport->transport.key.rem_addr.addr.sa_family == pj_AF_INET6()) { newtransport->transport.key.type = transport_type_wss_ipv6; - newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN); - pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET6_ADDRSTRLEN, 0); } else { newtransport->transport.key.type = transport_type_wss; - newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET_ADDRSTRLEN); - pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET_ADDRSTRLEN, 0); } newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr); - pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr); - - newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr); - newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr); + ws_addr_str = ast_sockaddr_stringify(ast_websocket_local_address(newtransport->ws_session)); + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.local_addr); + pj_strdup2(pool, &newtransport->transport.local_name.host, ast_sockaddr_stringify_host(ast_websocket_local_address(newtransport->ws_session))); + newtransport->transport.local_name.port = ast_sockaddr_port(ast_websocket_local_address(newtransport->ws_session)); newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type); - newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64); - newtransport->transport.dir = PJSIP_TP_DIR_INCOMING; newtransport->transport.tpmgr = tpmgr; newtransport->transport.send_msg = &ws_send_msg; diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index 1aec0be95..fee857525 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -46,6 +46,7 @@ static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, vo static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object); static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_astdb_close(void *data); @@ -58,6 +59,7 @@ static struct ast_sorcery_wizard astdb_object_wizard = { .retrieve_fields = sorcery_astdb_retrieve_fields, .retrieve_multiple = sorcery_astdb_retrieve_multiple, .retrieve_regex = sorcery_astdb_retrieve_regex, + .retrieve_prefix = sorcery_astdb_retrieve_prefix, .update = sorcery_astdb_update, .delete = sorcery_astdb_delete, .close = sorcery_astdb_close, @@ -329,6 +331,42 @@ static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void regfree(&expression); } +static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + const char *family_prefix = data; + size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */ + char family[family_len + 1]; + char tree[prefix_len + sizeof("%")]; + RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); + struct ast_db_entry *entry; + + snprintf(tree, sizeof(tree), "%.*s%%", (int) prefix_len, prefix); + snprintf(family, sizeof(family), "%s/%s", family_prefix, type); + + if (!(entries = ast_db_gettree(family, tree))) { + return; + } + + for (entry = entries; entry; entry = entry->next) { + /* The key in the entry includes the family, so we need to strip it out */ + const char *key = entry->key + family_len + 2; + RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + struct ast_json_error error; + RAII_VAR(void *, object, NULL, ao2_cleanup); + RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); + + if (!(json = ast_json_load_string(entry->data, &error)) + || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) + || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) + || !(object = ast_sorcery_alloc(sorcery, type, key)) + || ast_sorcery_objectset_apply(sorcery, object, objset)) { + return; + } + + ao2_link(objects, object); + } +} + static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object) { const char *prefix = data; diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c index 7fd7e769a..b02000eab 100644 --- a/res/res_sorcery_config.c +++ b/res/res_sorcery_config.c @@ -73,6 +73,12 @@ struct sorcery_config_fields_cmp_params { /*! \brief Regular expression for checking object id */ regex_t *regex; + /*! \brief Prefix for matching object id */ + const char *prefix; + + /*! \brief Prefix length in bytes for matching object id */ + const size_t prefix_len; + /*! \brief Optional container to put object into */ struct ao2_container *container; }; @@ -85,6 +91,7 @@ static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, v static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len); static void sorcery_config_close(void *data); static struct ast_sorcery_wizard config_object_wizard = { @@ -96,6 +103,7 @@ static struct ast_sorcery_wizard config_object_wizard = { .retrieve_fields = sorcery_config_retrieve_fields, .retrieve_multiple = sorcery_config_retrieve_multiple, .retrieve_regex = sorcery_config_retrieve_regex, + .retrieve_prefix = sorcery_config_retrieve_prefix, .close = sorcery_config_close, }; @@ -120,6 +128,11 @@ static int sorcery_config_fields_cmp(void *obj, void *arg, int flags) ao2_link(params->container, obj); } return 0; + } else if (params->prefix) { + if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) { + ao2_link(params->container, obj); + } + return 0; } else if (params->fields && (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) || (!ast_variable_lists_match(objset, params->fields, 0)))) { @@ -208,6 +221,24 @@ static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, voi regfree(&expression); } +static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + struct sorcery_config *config = data; + RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup); + struct sorcery_config_fields_cmp_params params = { + .sorcery = sorcery, + .container = objects, + .prefix = prefix, + .prefix_len = prefix_len, + }; + + if (!config_objects) { + return; + } + + ao2_callback(config_objects, OBJ_NODATA | OBJ_MULTIPLE, sorcery_config_fields_cmp, ¶ms); +} + /*! \brief Internal function which determines if criteria has been met for considering an object set applicable */ static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria) { diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c index b2f05591b..a05f05d9e 100644 --- a/res/res_sorcery_memory.c +++ b/res/res_sorcery_memory.c @@ -48,6 +48,7 @@ static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, v static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object); static int sorcery_memory_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_memory_close(void *data); @@ -60,6 +61,7 @@ static struct ast_sorcery_wizard memory_object_wizard = { .retrieve_fields = sorcery_memory_retrieve_fields, .retrieve_multiple = sorcery_memory_retrieve_multiple, .retrieve_regex = sorcery_memory_retrieve_regex, + .retrieve_prefix = sorcery_memory_retrieve_prefix, .update = sorcery_memory_update, .delete = sorcery_memory_delete, .close = sorcery_memory_close, @@ -76,6 +78,12 @@ struct sorcery_memory_fields_cmp_params { /*! \brief Regular expression for checking object id */ regex_t *regex; + /*! \brief Prefix for matching object id */ + const char *prefix; + + /*! \brief Prefix length in bytes for matching object id */ + const size_t prefix_len; + /*! \brief Optional container to put object into */ struct ao2_container *container; }; @@ -127,6 +135,11 @@ static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags) ao2_link(params->container, obj); } return 0; + } else if (params->prefix) { + if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) { + ao2_link(params->container, obj); + } + return 0; } else if (params->fields && (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) || (!ast_variable_lists_match(objset, params->fields, 0)))) { @@ -200,6 +213,18 @@ static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, voi regfree(&expression); } +static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + struct sorcery_memory_fields_cmp_params params = { + .sorcery = sorcery, + .container = objects, + .prefix = prefix, + .prefix_len = prefix_len, + }; + + ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms); +} + static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object) { RAII_VAR(void *, existing, NULL, ao2_cleanup); diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index bf2347ccd..30e6ef04b 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -185,6 +185,10 @@ struct sorcery_memory_cache_fields_cmp_params { const struct ast_variable *fields; /*! \brief Regular expression for checking object id */ regex_t *regex; + /*! \brief Prefix for matching object id */ + const char *prefix; + /*! \brief Prefix length in bytes for matching object id */ + const size_t prefix_len; /*! \brief Optional container to put object into */ struct ao2_container *container; }; @@ -201,6 +205,8 @@ static void sorcery_memory_cache_retrieve_multiple(const struct ast_sorcery *sor struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_memory_cache_close(void *data); @@ -216,6 +222,7 @@ static struct ast_sorcery_wizard memory_cache_object_wizard = { .retrieve_fields = sorcery_memory_cache_retrieve_fields, .retrieve_multiple = sorcery_memory_cache_retrieve_multiple, .retrieve_regex = sorcery_memory_cache_retrieve_regex, + .retrieve_prefix = sorcery_memory_cache_retrieve_prefix, .close = sorcery_memory_cache_close, }; @@ -1253,6 +1260,11 @@ static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags) ao2_link(params->container, cached->object); } return 0; + } else if (params->prefix) { + if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) { + ao2_link(params->container, cached->object); + } + return 0; } else if (params->fields && (!ast_variable_lists_match(cached->objectset, params->fields, 0))) { /* If we can't turn the object into an object set OR if differences exist between the fields @@ -1378,6 +1390,40 @@ static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcer /*! * \internal + * \brief Callback function to retrieve multiple objects whose id matches a prefix + * + * \param sorcery The sorcery instance + * \param data The sorcery memory cache + * \param type The type of the object to retrieve + * \param objects Container to place the objects into + * \param prefix Prefix to match against the object id + */ +static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + struct sorcery_memory_cache *cache = data; + struct sorcery_memory_cache_fields_cmp_params params = { + .sorcery = sorcery, + .cache = cache, + .container = objects, + .prefix = prefix, + .prefix_len = prefix_len, + }; + + if (is_passthru_update() || !cache->full_backend_cache) { + return; + } + + memory_cache_full_update(sorcery, type, cache); + ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, ¶ms); + + if (ao2_container_count(objects)) { + memory_cache_stale_check(sorcery, cache); + } +} + +/*! + * \internal * \brief Callback function to finish configuring the memory cache * * \param data The sorcery memory cache diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index 138d6ea95..1c52eb90f 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -59,6 +59,8 @@ static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object); static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_realtime_close(void *data); @@ -71,6 +73,7 @@ static struct ast_sorcery_wizard realtime_object_wizard = { .retrieve_fields = sorcery_realtime_retrieve_fields, .retrieve_multiple = sorcery_realtime_retrieve_multiple, .retrieve_regex = sorcery_realtime_retrieve_regex, + .retrieve_prefix = sorcery_realtime_retrieve_prefix, .update = sorcery_realtime_update, .delete = sorcery_realtime_delete, .close = sorcery_realtime_close, @@ -262,6 +265,23 @@ static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, v sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields); } +static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + char field[strlen(UUID_FIELD) + 6], value[prefix_len + 2]; + RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy); + + if (prefix_len) { + snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); + snprintf(value, sizeof(value), "%.*s%%", (int) prefix_len, prefix); + if (!(fields = ast_variable_new(field, value, ""))) { + return; + } + } + + sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields); +} + static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object) { struct sorcery_config *config = data; diff --git a/res/snmp/agent.c b/res/snmp/agent.c index 9d1528dde..7cd895559 100644 --- a/res/snmp/agent.c +++ b/res/snmp/agent.c @@ -63,6 +63,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> +#if !defined(RONLY) && defined(NETSNMP_OLDAPI_RONLY) +#define RONLY NETSNMP_OLDAPI_RONLY +#endif + #include "asterisk/paths.h" /* need ast_config_AST_SOCKET */ #include "asterisk/channel.h" #include "asterisk/logger.h" diff --git a/tests/test_logger.c b/tests/test_logger.c index bf809ba54..08585a6b8 100644 --- a/tests/test_logger.c +++ b/tests/test_logger.c @@ -192,7 +192,7 @@ static char *handle_cli_performance_test(struct ast_cli_entry *e, int cmd, struc static char *handle_cli_queue_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - unsigned int level; + int level; int current_queue_limit; unsigned int x; struct timeval start, end; @@ -222,7 +222,7 @@ static char *handle_cli_queue_test(struct ast_cli_entry *e, int cmd, struct ast_ ast_cli(a->fd, "Test: Failed, could not register level 'queuetest'.\n"); return CLI_SUCCESS; } - ast_cli(a->fd, "Test: got level %u for 'queuetest'.\n", level); + ast_cli(a->fd, "Test: got level %d for 'queuetest'.\n", level); if (ast_logger_create_channel(tmppath, "queuetest") != AST_LOGGER_SUCCESS) { ast_cli(a->fd, "Test: Unable to create logger channel '%s'\n", tmppath); diff --git a/tests/test_pbx.c b/tests/test_pbx.c index acf7484c1..df6b88dc8 100644 --- a/tests/test_pbx.c +++ b/tests/test_pbx.c @@ -39,6 +39,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/test.h" +#include <signal.h> + /*! * If we determine that we really need * to be able to register more than 10 |