diff options
39 files changed, 470 insertions, 96 deletions
@@ -26,6 +26,24 @@ res_pjsip into the "reg_server" field in the ps_contacts table to facilitate multi-server setups. +res_hep +------------------ + * Added a new option, 'uuid_type', that sets the preferred source of the Homer + correlation UUID. The valid options are: + - call-id: Use the PJSIP SIP Call-ID header value + - channel: Use the Asterisk channel name + The default value is 'call-id'. In the event that a HEP module cannot find a + valid value using the specified 'uuid_type', the module may fallback to a + more readily available source for the correlation UUID. + +app_confbridge +------------------ + * Added a bridge profile option called regcontext that allows you to + dynamically register the conference bridge name as an extension into + the specified context. This allows tracking down conferences on multi- + server installations via alternate means (DUNDI for example). By default + this feature is not used. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.8.0 to Asterisk 13.9.0 ------------ ------------------------------------------------------------------------------ diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 55b7b1240..991b3a307 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1253,9 +1253,17 @@ void conf_handle_second_active(struct confbridge_conference *conference) void conf_ended(struct confbridge_conference *conference) { + struct pbx_find_info q = { .stacklen = 0 }; + /* Called with a reference to conference */ ao2_unlink(conference_bridges, conference); send_conf_end_event(conference); + if (!ast_strlen_zero(conference->b_profile.regcontext) && + pbx_find_extension(NULL, NULL, &q, conference->b_profile.regcontext, + conference->name, 1, NULL, "", E_MATCH)) { + ast_context_remove_extension(conference->b_profile.regcontext, + conference->name, 1, NULL); + } ao2_lock(conference); conf_stop_record(conference); ao2_unlock(conference); @@ -1360,6 +1368,13 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen } send_conf_start_event(conference); + + if (!ast_strlen_zero(conference->b_profile.regcontext)) { + if (!ast_exists_extension(NULL, conference->b_profile.regcontext, conference->name, 1, NULL)) { + ast_add_extension(conference->b_profile.regcontext, 1, conference->name, 1, NULL, NULL, "Noop", NULL, NULL, "ConfBridge"); + } + } + ast_debug(1, "Created conference '%s' and linked to container.\n", conference_name); } diff --git a/apps/app_followme.c b/apps/app_followme.c index e5a5ee3c5..af6bb1039 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -66,6 +66,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis_channels.h" #include "asterisk/max_forwards.h" +#define REC_FORMAT "sln" + /*** DOCUMENTATION <application name="FollowMe" language="en_US"> <synopsis> @@ -1421,7 +1423,7 @@ static int app_exec(struct ast_channel *chan, const char *data) snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s", ast_config_AST_SPOOL_DIR, ast_channel_uniqueid(chan)); - if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, "sln", &duration, + if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, REC_FORMAT, &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) { goto outrun; } @@ -1522,7 +1524,18 @@ outrun: ast_free(nm); } if (!ast_strlen_zero(targs->namerecloc)) { - unlink(targs->namerecloc); + int ret; + char fn[PATH_MAX]; + + snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc, + REC_FORMAT); + ret = unlink(fn); + if (ret != 0) { + ast_log(LOG_NOTICE, "Failed to delete recorded name file %s: %d (%s)\n", + fn, errno, strerror(errno)); + } else { + ast_debug(2, "deleted recorded prompt %s.\n", fn); + } } ast_free((char *) targs->predial_callee); ast_party_connected_line_free(&targs->connected_in); diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index b8b1e2a9c..f5bb7eb57 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -317,6 +317,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") on a conference. </para></description> </configOption> + <configOption name="regcontext"> + <synopsis>The name of the context into which to register the name of the conference bridge as NoOP() at priority 1</synopsis> + <description><para> + When set this will cause the name of the created conference to be registered + into the named context at priority 1 with an operation of NoOP(). This can + then be used in other parts of the dialplan to test for the existence of a + specific conference bridge. + You should be aware that there are potential races between testing for the + existence of a bridge, and taking action upon that information, consider + for example two callers executing the check simultaniously, and then taking + special action as "first caller" into the bridge. The same for exiting, + directly after the check the bridge can be destroyed before the new caller + enters (creating a new bridge), for example, and the "first member" actions + could thus be missed. + </para></description> + </configOption> <configOption name="video_mode"> <synopsis>Sets how confbridge handles video distribution to the conference participants</synopsis> <description><para> @@ -1563,6 +1579,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, ast_cli(a->fd,"Max Members: No Limit\n"); } + ast_cli(a->fd,"Registration context: %s\n", b_profile.regcontext); + switch (b_profile.flags & (BRIDGE_OPT_VIDEO_SRC_LAST_MARKED | BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) { @@ -2128,6 +2146,7 @@ int conf_load_config(void) aco_option_register(&cfg_info, "record_file_append", ACO_EXACT, bridge_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_FILE_APPEND); aco_option_register(&cfg_info, "max_members", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, max_members)); aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file)); + aco_option_register(&cfg_info, "regcontext", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, regcontext)); aco_option_register(&cfg_info, "language", ACO_EXACT, bridge_types, "en", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, language)); aco_option_register_custom(&cfg_info, "^sound_", ACO_REGEX, bridge_types, NULL, sound_option_handler, 0); /* This option should only be used with the CONFBRIDGE dialplan function */ diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 8d2dffb1c..a1fa5a2b7 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -207,6 +207,7 @@ struct bridge_profile { unsigned int internal_sample_rate; /*!< The internal sample rate of the bridge. 0 when set to auto adjust mode. */ unsigned int mix_interval; /*!< The internal mixing interval used by the bridge. When set to 0 the bridgewill use a default interval. */ struct bridge_profile_sounds *sounds; + char regcontext[AST_MAX_CONTEXT]; }; /*! \brief The structure that represents a conference bridge */ diff --git a/configs/basic-pbx/asterisk.conf b/configs/basic-pbx/asterisk.conf index 576cc976b..ff66ceea7 100644 --- a/configs/basic-pbx/asterisk.conf +++ b/configs/basic-pbx/asterisk.conf @@ -1,26 +1,13 @@ -[directories] -astetcdir => /etc/asterisk -astmoddir => /usr/lib/asterisk/modules -astvarlibdir => /var/lib/asterisk -astdbdir => /var/lib/asterisk -astkeydir => /var/lib/asterisk -astdatadir => /var/lib/asterisk -astagidir => /var/lib/asterisk/agi-bin -astspooldir => /var/spool/asterisk -astrundir => /var/run/asterisk -astlogdir => /var/log/asterisk -astsbindir => /usr/sbin - [options] ; If we want to start Asterisk with a default verbosity for the verbose -; or debug logger channel types, then we use these settings. +; or debug logger channel types, then we use these settings (by default +; they are disabled). ;verbose = 5 -;debug = 5 +;debug = 2 ; User and group to run asterisk as. NOTE: This will require changes to ; directory and device permissions. -;runuser = asterisk ; The user to run as. -;rungroup = asterisk ; The group to run as. +;runuser = asterisk ; The user to run as. The default is root. +;rungroup = asterisk ; The group to run as. The default is root -defaultlanguage = en -documentation_language = en_US +;defaultlanguage = es diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index d0bdd6fd9..49208c31b 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -211,6 +211,8 @@ type=bridge ;language=en ; Set the language used for announcements to the conference. ; Default is en (English). +;regcontext=conferences ; The name of the context into which to register conference names as extensions. + ; All sounds in the conference are customizable using the bridge profile options below. ; Simply state the option followed by the filename or full path of the filename after ; the option. Example: sound_had_joined=conf-hasjoin This will play the conf-hasjoin diff --git a/configs/samples/hep.conf.sample b/configs/samples/hep.conf.sample index 40b17aa0e..6e409d151 100644 --- a/configs/samples/hep.conf.sample +++ b/configs/samples/hep.conf.sample @@ -13,4 +13,8 @@ capture_password = foo ; If specified, the authorization passsword capture_id = 1234 ; A unique integer identifier for this ; server. This ID will be embedded sent ; with each packet from this server. +uuid_type = call-id ; Specify the preferred source for the Homer + ; correlation UUID. Valid options are: + ; - 'call-id' for the PJSIP SIP Call-ID + ; - 'channel' for the Asterisk channel name @@ -663,6 +663,10 @@ PWLIB_LIBDIR PWLIB_INCDIR PWLIBDIR PTLIB_CONFIG +PYTHONDEV_LIBS +PYTHONDEV_CFLAGS +PYTHONDEV_INCLUDE +PYTHONDEV_LIB PJPROJECT_LIBS PJPROJECT_CFLAGS PG_CONFIG @@ -1416,6 +1420,8 @@ LIBEDIT_CFLAGS LIBEDIT_LIBS PJPROJECT_CFLAGS PJPROJECT_LIBS +PYTHONDEV_CFLAGS +PYTHONDEV_LIBS GMIME_CFLAGS GMIME_LIBS GTK2_CFLAGS @@ -2158,6 +2164,10 @@ Some influential environment variables: C compiler flags for PJPROJECT, overriding pkg-config PJPROJECT_LIBS linker flags for PJPROJECT, overriding pkg-config + PYTHONDEV_CFLAGS + C compiler flags for PYTHONDEV, overriding pkg-config + PYTHONDEV_LIBS + linker flags for PYTHONDEV, overriding pkg-config GMIME_CFLAGS C compiler flags for GMIME, overriding pkg-config GMIME_LIBS linker flags for GMIME, overriding pkg-config @@ -13602,7 +13612,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13648,7 +13658,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13672,7 +13682,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13717,7 +13727,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13741,7 +13751,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -17604,7 +17614,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_LEAK_SANITIZER=1 else - AST_LEAK_SANITIZER= + AST_LEAK_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } @@ -17636,7 +17646,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_UNDEFINED_SANITIZER=1 else - AST_UNDEFINED_SANITIZER= + AST_UNDEFINED_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } @@ -25172,6 +25182,97 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi + + + if test "x${PBX_PYTHONDEV}" != "x1" -a "${USE_PYTHONDEV}" != "no"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYTHONDEV" >&5 +$as_echo_n "checking for PYTHONDEV... " >&6; } + +if test -n "$PYTHONDEV_CFLAGS"; then + pkg_cv_PYTHONDEV_CFLAGS="$PYTHONDEV_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"python\""; } >&5 + ($PKG_CONFIG --exists --print-errors "python") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PYTHONDEV_CFLAGS=`$PKG_CONFIG --cflags "python" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PYTHONDEV_LIBS"; then + pkg_cv_PYTHONDEV_LIBS="$PYTHONDEV_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"python\""; } >&5 + ($PKG_CONFIG --exists --print-errors "python") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PYTHONDEV_LIBS=`$PKG_CONFIG --libs "python" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PYTHONDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "python" 2>&1` + else + PYTHONDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "python" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PYTHONDEV_PKG_ERRORS" >&5 + + + PBX_PYTHONDEV=0 + + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + PBX_PYTHONDEV=0 + + +else + PYTHONDEV_CFLAGS=$pkg_cv_PYTHONDEV_CFLAGS + PYTHONDEV_LIBS=$pkg_cv_PYTHONDEV_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + PBX_PYTHONDEV=1 + PYTHONDEV_INCLUDE="$PYTHONDEV_CFLAGS" + PYTHONDEV_LIB="$PYTHONDEV_LIBS" + +$as_echo "#define HAVE_PYTHONDEV 1" >>confdefs.h + + +fi + fi + + + if test "x${PBX_POPT}" != "x1" -a "${USE_POPT}" != "no"; then pbxlibdir="" # if --with-POPT=DIR has been specified, use it. diff --git a/configure.ac b/configure.ac index 7571f7fd5..f2e42ba1f 100644 --- a/configure.ac +++ b/configure.ac @@ -1116,7 +1116,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_LEAK_SANITIZER=1], - [AST_LEAK_SANITIZER=] + [AST_LEAK_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" @@ -1132,7 +1132,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_UNDEFINED_SANITIZER=1], - [AST_UNDEFINED_SANITIZER=] + [AST_UNDEFINED_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" @@ -2197,6 +2197,10 @@ if test "$USE_PJPROJECT" != "no" ; then fi fi +AC_SUBST([PYTHONDEV_LIB]) +AC_SUBST([PYTHONDEV_INCLUDE]) +AST_PKG_CONFIG_CHECK([PYTHONDEV], [python]) + AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h]) AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h]) diff --git a/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py b/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py new file mode 100644 index 000000000..76faf394c --- /dev/null +++ b/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py @@ -0,0 +1,32 @@ +"""ps_contacts add authenticate_qualify + +Revision ID: 6be31516058d +Revises: 81b01a191a46 +Create Date: 2016-05-03 14:57:12.538179 + +""" + +# revision identifiers, used by Alembic. +revision = '6be31516058d' +down_revision = '81b01a191a46' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_contacts', sa.Column('authenticate_qualify', yesno_values)) + + +def downgrade(): + op.drop_column('ps_contacts', 'authenticate_qualify') + diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 80780986a..a01131cc3 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -731,6 +731,9 @@ /* Define if your system has the PWLib libraries. */ #undef HAVE_PWLIB +/* Define if your system has the PYTHONDEV libraries. */ +#undef HAVE_PYTHONDEV + /* Define to 1 if you have the Radius Client library. */ #undef HAVE_RADIUS diff --git a/include/asterisk/res_hep.h b/include/asterisk/res_hep.h index 8839fd60a..bd0129eea 100644 --- a/include/asterisk/res_hep.h +++ b/include/asterisk/res_hep.h @@ -49,6 +49,11 @@ enum hepv3_capture_type { HEPV3_CAPTURE_TYPE_IAX = 0x10, }; +enum hep_uuid_type { + HEP_UUID_TYPE_CALL_ID = 0, + HEP_UUID_TYPE_CHANNEL, +}; + /*! \brief HEPv3 Capture Info */ struct hepv3_capture_info { /*! The source address of the packet */ @@ -104,6 +109,15 @@ struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t */ int hepv3_send_packet(struct hepv3_capture_info *capture_info); +/*! + * \brief Get the preferred UUID type + * + * \since 13.10.0 + * + * \retval The type of UUID the packet should use + */ +enum hep_uuid_type hepv3_get_uuid_type(void); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/config_options.c b/main/config_options.c index db99a441d..c8988c984 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -198,8 +198,8 @@ static int link_option_to_types(struct aco_info *info, struct aco_type **types, #ifdef AST_DEVMODE opt->doc_unavailable = 1; #endif -#endif } +#endif } /* The container(s) should hold the only ref to opt */ ao2_ref(opt, -1); diff --git a/main/file.c b/main/file.c index 7ce021340..1c51177c2 100644 --- a/main/file.c +++ b/main/file.c @@ -799,7 +799,7 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil /* As above, but for video. But here we don't have translators * so we must enforce a format. */ - struct ast_format_cap *tmp_cap; + struct ast_format_cap *nativeformats, *tmp_cap; char *buf; int buflen; int i, fd; @@ -810,16 +810,23 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil buflen = strlen(preflang) + strlen(filename) + 4; buf = ast_alloca(buflen); + ast_channel_lock(chan); + nativeformats = ao2_bump(ast_channel_nativeformats(chan)); + ast_channel_unlock(chan); + /* is the channel capable of video without translation ?*/ - if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO)) { + if (!ast_format_cap_has_type(nativeformats, AST_MEDIA_TYPE_VIDEO)) { + ao2_cleanup(nativeformats); return NULL; } if (!(tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ao2_cleanup(nativeformats); return NULL; } /* Video is supported, so see what video formats exist for this file */ if (!fileexists_core(filename, NULL, preflang, buf, buflen, tmp_cap)) { ao2_ref(tmp_cap, -1); + ao2_cleanup(nativeformats); return NULL; } @@ -828,7 +835,7 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil struct ast_format *format = ast_format_cap_get_format(tmp_cap, i); if ((ast_format_get_type(format) != AST_MEDIA_TYPE_VIDEO) || - !ast_format_cap_iscompatible(ast_channel_nativeformats(chan), tmp_cap)) { + !ast_format_cap_iscompatible(nativeformats, tmp_cap)) { ao2_ref(format, -1); continue; } @@ -837,12 +844,14 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil if (fd >= 0) { ao2_ref(format, -1); ao2_ref(tmp_cap, -1); + ao2_cleanup(nativeformats); return ast_channel_vstream(chan); } ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename); ao2_ref(format, -1); } ao2_ref(tmp_cap, -1); + ao2_cleanup(nativeformats); return NULL; } @@ -1097,8 +1106,10 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p fs = ast_openstream(chan, filename, preflang); if (!fs) { struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + ast_channel_lock(chan); ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), strerror(errno)); + ast_channel_unlock(chan); return -1; } @@ -1133,7 +1144,12 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p res = ast_playstream(fs); if (!res && vfs) res = ast_playstream(vfs); - ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default"); + + if (VERBOSITY_ATLEAST(3)) { + ast_channel_lock(chan); + ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default"); + ast_channel_unlock(chan); + } return res; } diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index fbca2ad9b..a91cd9f6b 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -86,6 +86,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <enum name="Reachable"/> <enum name="Created"/> <enum name="Removed"/> + <enum name="Updated"/> </enumlist> </parameter> <parameter name="AOR"> @@ -97,6 +98,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <parameter name="RoundtripUsec"> <para>The RTT measured during the last qualify.</para> </parameter> + <parameter name="UserAgent"> + <para>Content of the User-Agent header in REGISTER request</para> + </parameter> + <parameter name="RegExpire"> + <para>Absolute time that this contact is no longer valid after</para> + </parameter> </syntax> </managerEventInstance> </managerEvent> diff --git a/main/strings.c b/main/strings.c index 9e885ebc3..db78a6cd2 100644 --- a/main/strings.c +++ b/main/strings.c @@ -234,8 +234,8 @@ int ast_strings_match(const char *left, const char *op, const char *right) { char *internal_op = (char *)op; char *internal_right = (char *)right; - float left_num; - float right_num; + double left_num; + double right_num; int scan_numeric = 0; if (!(left && right)) { @@ -297,7 +297,7 @@ regex: } equals: - scan_numeric = (sscanf(left, "%f", &left_num) && sscanf(internal_right, "%f", &right_num)); + scan_numeric = (sscanf(left, "%lf", &left_num) && sscanf(internal_right, "%lf", &right_num)); if (internal_op[0] == '=') { if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) { diff --git a/makeopts.in b/makeopts.in index bfc965de4..9fa49bc04 100644 --- a/makeopts.in +++ b/makeopts.in @@ -243,6 +243,9 @@ PORTAUDIO_LIB=@PORTAUDIO_LIB@ PRI_INCLUDE=@PRI_INCLUDE@ PRI_LIB=@PRI_LIB@ +PYTHONDEV_INCLUDE=@PYTHONDEV_INCLUDE@ +PYTHONDEV_LIB=@PYTHONDEV_LIB@ + RESAMPLE_INCLUDE=@RESAMPLE_INCLUDE@ RESAMPLE_LIB=@RESAMPLE_LIB@ diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index a37b83146..a86f3129c 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -381,7 +381,7 @@ static int ari_bridges_play_helper(const char *args_media, return -1; } - if (ast_asprintf(playback_url, "/playback/%s", + if (ast_asprintf(playback_url, "/playbacks/%s", stasis_app_playback_get_id(playback)) == -1) { playback_url = NULL; ast_ari_response_alloc_failed(response); diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index f722802d8..9e2db9de6 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -524,7 +524,7 @@ static void ari_channels_handle_play( return; } - if (ast_asprintf(&playback_url, "/playback/%s", + if (ast_asprintf(&playback_url, "/playbacks/%s", stasis_app_playback_get_id(playback)) == -1) { playback_url = NULL; ast_ari_response_error( diff --git a/res/res_ari.c b/res/res_ari.c index f39db16cd..4a0a22d79 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -304,10 +304,11 @@ void ast_ari_response_alloc_failed(struct ast_ari_response *response) void ast_ari_response_created(struct ast_ari_response *response, const char *url, struct ast_json *message) { + RAII_VAR(struct stasis_rest_handlers *, root, get_root_handler(), ao2_cleanup); response->message = message; response->response_code = 201; response->response_text = "Created"; - ast_str_append(&response->headers, 0, "Location: %s\r\n", url); + ast_str_append(&response->headers, 0, "Location: /%s%s\r\n", root->path_segment, url); } static void add_allow_header(struct stasis_rest_handlers *handler, diff --git a/res/res_fax.c b/res/res_fax.c index 2fa64bc0f..6282b13d7 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -626,6 +626,8 @@ static const struct ast_datastore_info fax_datastore = { static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_details *details); static int fax_detect_attach(struct ast_channel *chan, int timeout, int flags); static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan); +static struct ast_fax_session *fax_v21_session_new (struct ast_channel *chan); + /*! \brief Copies fax detection and gateway framehooks during masquerades * @@ -2835,6 +2837,23 @@ static void destroy_gateway(void *data) ao2_cleanup(gateway->peer_write_format); } +static struct ast_fax_session *fax_v21_session_new (struct ast_channel *chan) { + struct ast_fax_session_details *v21_details; + struct ast_fax_session *v21_session; + + if (!chan || !(v21_details = session_details_new())) { + return NULL; + } + + v21_details->caps = AST_FAX_TECH_V21_DETECT; + if (!(v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { + ao2_ref(v21_details, -1); + return NULL; + } + + return v21_session; +} + /*! \brief Create a new fax gateway object. * \param chan the channel the gateway object will be attached to * \param details the fax session details @@ -2843,30 +2862,16 @@ static void destroy_gateway(void *data) static struct fax_gateway *fax_gateway_new(struct ast_channel *chan, struct ast_fax_session_details *details) { struct fax_gateway *gateway = ao2_alloc(sizeof(*gateway), destroy_gateway); - struct ast_fax_session_details *v21_details; if (!gateway) { return NULL; } - if (!(v21_details = session_details_new())) { + if (!(gateway->chan_v21_session = fax_v21_session_new(chan))) { + ast_log(LOG_ERROR, "Can't create V21 session on chan %s for T.38 gateway session\n", ast_channel_name(chan)); ao2_ref(gateway, -1); return NULL; } - v21_details->caps = AST_FAX_TECH_V21_DETECT; - if (!(gateway->chan_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { - ao2_ref(v21_details, -1); - ao2_ref(gateway, -1); - return NULL; - } - - if (!(gateway->peer_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { - ao2_ref(v21_details, -1); - ao2_ref(gateway, -1); - return NULL; - } - ao2_ref(v21_details, -1); - gateway->framehook = -1; details->caps = AST_FAX_TECH_GATEWAY; @@ -3360,6 +3365,11 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_channel_unlock(peer); gateway->bridged = 1; + if (!(gateway->peer_v21_session = fax_v21_session_new(peer))) { + ast_log(LOG_ERROR, "Can't create V21 session on chan %s for T.38 gateway session\n", ast_channel_name(peer)); + ast_framehook_detach(chan, gateway->framehook); + return f; + } } if (gateway->bridged && !ast_tvzero(gateway->timeout_start)) { @@ -3486,6 +3496,10 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d .disable_inheritance = 1, /* Masquerade inheritance is handled through the datastore fixup */ }; + if (global_fax_debug) { + details->option.debug = AST_FAX_OPTFLAG_TRUE; + } + ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "gateway operation started successfully"); ast_string_field_set(details, error, "NO_ERROR"); diff --git a/res/res_hep.c b/res/res_hep.c index 69a8ab391..723b27df8 100644 --- a/res/res_hep.c +++ b/res/res_hep.c @@ -60,6 +60,15 @@ </enumlist> </description> </configOption> + <configOption name="uuid_type" default="call-id"> + <synopsis>The preferred type of UUID to pass to Homer.</synopsis> + <description> + <enumlist> + <enum name="call-id"><para>Use the PJSIP Call-Id</para></enum> + <enum name="channel"><para>Use the Asterisk channel name</para></enum> + </enumlist> + </description> + </configOption> <configOption name="capture_address" default="192.168.1.1:9061"> <synopsis>The address and port of the Homer server to send packets to.</synopsis> </configOption> @@ -231,6 +240,7 @@ struct hep_generic { struct hepv3_global_config { unsigned int enabled; /*!< Whether or not sending is enabled */ unsigned int capture_id; /*!< Capture ID for this agent */ + enum hep_uuid_type uuid_type; /*!< The preferred type of the UUID */ AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(capture_address); /*!< Address to send to */ AST_STRING_FIELD(capture_password); /*!< Password for Homer server */ @@ -329,6 +339,25 @@ static void *module_config_alloc(void) return config; } +/*! \brief Handler for the uuid_type attribute */ +static int uuid_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct hepv3_global_config *global_config = obj; + + if (strcasecmp(var->name, "uuid_type")) { + return -1; + } + + if (!strcasecmp(var->value, "channel")) { + global_config->uuid_type = HEP_UUID_TYPE_CHANNEL; + } else if (!strcasecmp(var->value, "call-id")) { + global_config->uuid_type = HEP_UUID_TYPE_CALL_ID; + } else { + return -1; + } + return 0; +} + /*! \brief HEPv3 run-time data destructor */ static void hepv3_data_dtor(void *obj) { @@ -376,6 +405,13 @@ static void capture_info_dtor(void *obj) ast_free(info->payload); } +enum hep_uuid_type hepv3_get_uuid_type(void) +{ + RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup); + + return config->general->uuid_type; +} + struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len) { struct hepv3_capture_info *info; @@ -607,6 +643,7 @@ static int load_module(void) aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, DEFAULT_HEP_SERVER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_address)); aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password)); aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id)); + aco_option_register_custom(&cfg_info, "uuid_type", ACO_EXACT, global_options, "call-id", uuid_type_handler, 0); if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) { goto error; diff --git a/res/res_hep.exports.in b/res/res_hep.exports.in index d09d3f409..df0f2b4f7 100644 --- a/res/res_hep.exports.in +++ b/res/res_hep.exports.in @@ -2,6 +2,7 @@ global: LINKER_SYMBOL_PREFIX*hepv3_send_packet; LINKER_SYMBOL_PREFIX*hepv3_create_capture_info; + LINKER_SYMBOL_PREFIX*hepv3_get_uuid_type; local: *; }; diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index b5cf0b81e..caffd2563 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -51,13 +51,18 @@ static char *assign_uuid(const pj_str_t *call_id, const pj_str_t *local_tag, con RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup); pjsip_dialog *dlg; char *uuid = NULL; + enum hep_uuid_type uuid_type = hepv3_get_uuid_type(); - if ((dlg = pjsip_ua_find_dialog(call_id, local_tag, remote_tag, PJ_FALSE)) + if ((uuid_type == HEP_UUID_TYPE_CHANNEL) + && (dlg = pjsip_ua_find_dialog(call_id, local_tag, remote_tag, PJ_FALSE)) && (session = ast_sip_dialog_get_session(dlg)) && (session->channel)) { uuid = ast_strdup(ast_channel_name(session->channel)); - } else { + } + + /* If we couldn't get the channel or we never wanted it, default to the call-id */ + if (!uuid) { uuid = ast_malloc(pj_strlen(call_id) + 1); if (uuid) { diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 787512bbf..49a92539f 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -36,6 +36,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/res_hep.h" #include "asterisk/module.h" #include "asterisk/netsock2.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" #include "asterisk/stasis.h" #include "asterisk/rtp_engine.h" #include "asterisk/json.h" @@ -43,6 +45,35 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static struct stasis_subscription *stasis_rtp_subscription; +static char *assign_uuid(struct ast_json *json_channel) +{ + const char *channel_name = ast_json_string_get(ast_json_object_get(json_channel, "name")); + enum hep_uuid_type uuid_type = hepv3_get_uuid_type(); + char *uuid = NULL; + + if (!channel_name) { + return NULL; + } + + if (uuid_type == HEP_UUID_TYPE_CALL_ID && ast_begins_with(channel_name, "PJSIP")) { + struct ast_channel *chan = ast_channel_get_by_name(channel_name); + char buf[128]; + + if (chan && !ast_func_read(chan, "CHANNEL(pjsip,call-id)", buf, sizeof(buf))) { + uuid = ast_strdup(buf); + } + + ast_channel_cleanup(chan); + } + + /* If we couldn't get the call-id or didn't want it, just use the channel name */ + if (!uuid) { + uuid = ast_strdup(channel_name); + } + + return uuid; +} + static void rtcp_message_handler(struct stasis_message *message) { @@ -94,7 +125,7 @@ static void rtcp_message_handler(struct stasis_message *message) ast_sockaddr_parse(&capture_info->src_addr, ast_json_string_get(from), PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, ast_json_string_get(to), PARSE_PORT_REQUIRE); - capture_info->uuid = ast_strdup(ast_json_string_get(ast_json_object_get(json_channel, "name"))); + capture_info->uuid = assign_uuid(json_channel); if (!capture_info->uuid) { ao2_ref(capture_info, -1); return; diff --git a/res/res_pjsip.c b/res/res_pjsip.c index ae7155b6b..61d26302d 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1092,6 +1092,13 @@ If <literal>0</literal> no timeout. Time in fractional seconds. </para></description> </configOption> + <configOption name="authenticate_qualify" default="no"> + <synopsis>Authenticates a qualify request if needed</synopsis> + <description><para> + If true and a qualify request receives a challenge or authenticate response + authentication is attempted before declaring the contact available. + </para></description> + </configOption> <configOption name="outbound_proxy"> <synopsis>Outbound proxy used when sending OPTIONS request</synopsis> <description><para> diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index d2c087487..3a5afb6bc 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -378,6 +378,10 @@ static struct ast_sip_transport_state *find_or_create_temporary_state(struct ast new_state->type = transport->type; pjsip_tls_setting_default(&new_state->tls); +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + /* proto must be forced to 0 to enable all protocols otherwise only TLS will work */ + new_state->tls.proto = 0; +#endif new_state->tls.ciphers = new_state->ciphers; ao2_ref(new_state, +1); diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index db1d0794b..ef06456a7 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1121,6 +1121,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400); ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout)); + ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify)); ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index cbe955728..b7da81433 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -391,7 +391,7 @@ static void log_unidentified_request(pjsip_rx_data *rdata, unsigned int count, u " after %u tries in %.3f ms\n", from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, count, period / 1000.0); } else { - ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found", + ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found\n", from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf); } } diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index f832e6f78..b9339f60b 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1036,17 +1036,11 @@ int ast_sip_initialize_sorcery_qualify(void) return 0; } -static int qualify_and_schedule_cb(void *obj, void *arg, int flags) +static void qualify_and_schedule_contact(struct ast_sip_contact *contact) { - struct ast_sip_contact *contact = obj; - struct ast_sip_aor *aor = arg; int initial_interval; int max_time = ast_sip_get_max_initial_qualify_time(); - contact->qualify_frequency = aor->qualify_frequency; - contact->qualify_timeout = aor->qualify_timeout; - contact->authenticate_qualify = aor->authenticate_qualify; - /* Delay initial qualification by a random fraction of the specified interval */ if (max_time && max_time < contact->qualify_frequency) { initial_interval = max_time; @@ -1062,26 +1056,47 @@ static int qualify_and_schedule_cb(void *obj, void *arg, int flags) } else { update_contact_status(contact, UNKNOWN); } +} + +static int qualify_and_schedule_cb_with_aor(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_aor *aor = arg; + + contact->qualify_frequency = aor->qualify_frequency; + contact->qualify_timeout = aor->qualify_timeout; + contact->authenticate_qualify = aor->authenticate_qualify; + + qualify_and_schedule_contact(contact); + + return 0; +} + +static int qualify_and_schedule_cb_without_aor(void *obj, void *arg, int flags) +{ + qualify_and_schedule_contact((struct ast_sip_contact *) obj); return 0; } /*! * \internal - * \brief Qualify and schedule an endpoint's contacts + * \brief Qualify and schedule an aor's contacts * - * \details For the given endpoint retrieve its list of aors, qualify all - * contacts, and schedule for checks if configured. + * \details For the given aor check if it has permanent contacts, + * qualify all contacts and schedule for checks if configured. */ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) { struct ast_sip_aor *aor = obj; struct ao2_container *contacts; - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); - ao2_ref(contacts, -1); + if (aor->permanent_contacts) { + contacts = ast_sip_location_retrieve_aor_contacts(aor); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); + ao2_ref(contacts, -1); + } } return 0; @@ -1104,6 +1119,7 @@ static void qualify_and_schedule_all(void) { struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); struct ao2_container *aors; + struct ao2_container *contacts; if (!var) { return; @@ -1111,16 +1127,22 @@ static void qualify_and_schedule_all(void) aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); - ast_variables_destroy(var); - ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); - if (!aors) { - return; + if (aors) { + ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); + ao2_ref(aors, -1); } - ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); - ao2_ref(aors, -1); + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); + ao2_ref(contacts, -1); + } + + ast_variables_destroy(var); + } static int format_contact_status(void *obj, void *arg, int flags) @@ -1186,7 +1208,7 @@ static void aor_observer_modified(const void *obj) contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); ao2_ref(contacts, -1); } } diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c index ff46fd884..59e9738fd 100644 --- a/res/res_pjsip_authenticator_digest.c +++ b/res/res_pjsip_authenticator_digest.c @@ -206,9 +206,12 @@ static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsi RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup); char hash[33]; + /* + * Note you may be tempted to think why not include the port. The reason + * is that when using TCP the port can potentially differ from before. + */ ast_str_append(&str, 0, "%s", timestamp); ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name); - ast_str_append(&str, 0, ":%d", rdata->pkt_info.src_port); ast_str_append(&str, 0, ":%s", eid); ast_str_append(&str, 0, ":%s", realm); ast_md5_hash(hash, ast_str_buffer(str)); @@ -509,5 +512,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication .load = load_module, .unload = unload_module, .reload = reload_module, - .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, ); diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 7f4858af0..b1ffd2cc3 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -515,5 +515,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP IP endpoint ide .load = load_module, .reload = reload_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, ); diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c index dea5f4ae7..e018abd61 100644 --- a/res/res_pjsip_endpoint_identifier_user.c +++ b/res/res_pjsip_endpoint_identifier_user.c @@ -201,5 +201,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP username endpoi .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, ); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 8a40cce23..1ae3522d8 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1096,7 +1096,7 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE, "<%s:%s@%s%.*s%s:%d%s%s%s%s>", - (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip", + ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip", user, (type & PJSIP_TRANSPORT_IPV6) ? "[" : "", (int)local_addr.slen, diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 9aeefae29..a8144fc05 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -957,5 +957,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Suppo .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3, ); diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index e5de9f7bb..c6b5a1b33 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -97,7 +97,6 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; - RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy); void *object = NULL; @@ -113,7 +112,7 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc } if (!(object = ast_sorcery_alloc(sorcery, type, key)) || - ast_sorcery_objectset_apply(sorcery, object, objset)) { + ast_sorcery_objectset_apply(sorcery, object, existing)) { ao2_cleanup(object); return NULL; } diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 7fa3902ba..7349db62f 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -45,6 +45,13 @@ ifeq ($(SPECIAL_TARGETS),) CF := $(filter-out -I%,$(CF)) export CFLAGS += $(CF) export LDFLAGS += $(CC_LDFLAGS) + TARGETS := pjproject.symbols + ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),TEST_FRAMEWORK) + TARGETS += source/pjsip-apps/bin/pjsua-$(TARGET_NAME) + ifneq ($(PYTHONDEV_LIB),) + TARGETS += source/pjsip-apps/src/python/build/_pjsua.so + endif + endif else all install: endif @@ -95,12 +102,10 @@ source/pjlib/build/.pjlib-$(TARGET_NAME).depend: build.mak $(ECHO_PREFIX) "Making dependencies" +$(CMD_PREFIX) $(SUBMAKE) -C source dep - menuselect: ../../menuselect.makeopts ../../makeopts -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || : -$(CMD_PREFIX) rm -rf pjproject.symbols - source/pjlib/lib/libpj-$(TARGET_NAME).a: menuselect source/pjlib/build/.pjlib-$(TARGET_NAME).depend $(ECHO_PREFIX) Compiling libs +$(CMD_PREFIX) $(SUBMAKE) -C source lib $(REALLY_QUIET) @@ -117,17 +122,22 @@ source/pjsip-apps/src/python/build/_pjsua.so: source/pjlib/lib/libpj-$(TARGET_NA $(ECHO_PREFIX) Compiling python bindings $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; MAKE=$(MAKE) python setup.py build --build-platlib=./build $(REALLY_QUIET)) -_all: pjproject.symbols source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/src/python/build/_pjsua.so +_all: $(TARGETS) _install: _all - $(ECHO_PREFIX) Installing apps and python bindings @if [ ! -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject" ]; then \ $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject"; \ fi; +ifneq ($(findstring source/pjsip-apps/bin/pjsua-$(TARGET_NAME),$(TARGETS)),) + $(ECHO_PREFIX) Installing apps $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsua-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsua" $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsystest-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsystest" +endif +ifneq ($(findstring source/pjsip-apps/src/python/build/_pjsua.so,$(TARGETS)),) + $(ECHO_PREFIX) Installing python bindings $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/src/python/build/_pjsua.so "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" $(CMD_PREFIX) $(INSTALL) -m 644 source/pjsip-apps/src/python/build/pjsua.py "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" +endif uninstall: $(ECHO_PREFIX) Uninstalling apps and python bindings @@ -135,7 +145,7 @@ uninstall: clean: $(ECHO_PREFIX) Cleaning - -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || : + -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build ; rm -rf source/pjsip-apps/bin/* ) || : -$(CMD_PREFIX) rm -rf pjproject.symbols distclean: diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index 6b51c2f2a..d2e7d25a4 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -3,7 +3,7 @@ PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --disable-speex-codec --disable-speex-aec \ --disable-gsm-codec --disable-video --disable-v4l2 --disable-sound --disable-opencore-amr \ - --disable-ilbc-codec --without-libyuv --disable-g7221-codec + --disable-ilbc-codec --without-libyuv --disable-g7221-codec --disable-resample ifeq ($(shell uname -s),Linux) PJPROJECT_CONFIG_OPTS += --enable-epoll |