diff options
-rw-r--r-- | CHANGES | 26 | ||||
-rw-r--r-- | Makefile | 102 | ||||
-rw-r--r-- | channels/chan_rtp.c | 86 | ||||
-rw-r--r-- | configs/samples/hep.conf.sample | 4 | ||||
-rw-r--r-- | contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py | 32 | ||||
-rw-r--r-- | include/asterisk/logger.h | 18 | ||||
-rw-r--r-- | include/asterisk/parking.h | 11 | ||||
-rw-r--r-- | include/asterisk/res_hep.h | 14 | ||||
-rw-r--r-- | include/asterisk/res_pjsip.h | 4 | ||||
-rw-r--r-- | include/asterisk/strings.h | 2 | ||||
-rw-r--r-- | main/asterisk.c | 73 | ||||
-rw-r--r-- | main/logger.c | 215 | ||||
-rw-r--r-- | main/udptl.c | 12 | ||||
-rw-r--r-- | res/res_hep.c | 37 | ||||
-rw-r--r-- | res/res_hep.exports.in | 1 | ||||
-rw-r--r-- | res/res_hep_pjsip.c | 63 | ||||
-rw-r--r-- | res/res_hep_rtcp.c | 33 | ||||
-rw-r--r-- | res/res_pjsip.c | 50 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 71 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_distributor.c | 128 | ||||
-rw-r--r-- | res/res_pjsip_dtmf_info.c | 7 | ||||
-rw-r--r-- | res/res_pjsip_empty_info.c | 89 | ||||
-rw-r--r-- | res/res_pjsip_one_touch_record_info.c | 9 | ||||
-rw-r--r-- | res/res_sorcery_astdb.c | 57 | ||||
-rw-r--r-- | utils/extconf.c | 3 |
25 files changed, 827 insertions, 320 deletions
@@ -256,6 +256,12 @@ res_pjsip will be used instead. The new SIP resolver provides NAPTR support, improved SRV support, and AAAA record support. +res_pjsip_info_empty +-------------------- + * A new module that can respond to empty Content-Type INFO packets during call. + Some SBCs will terminate a call if their empty INFO packets are not responded + to within a predefined time. + res_pjsip_outbound_registration ------------------------------- * A new 'fatal_retry_interval' option has been added to outbound registration. @@ -268,6 +274,7 @@ res_pjsip_outbound_publish * Added a new multi_user option that when set to 'yes' allows a given configuration to be used for multiple users. + CEL Backends ------------------ @@ -313,6 +320,15 @@ res_fax res_pjsip ------------------ + * Endpoint IP Access Controls + Added new configuration Endpoint options: + "acl" - list of IP ACL section names in acl.conf + "deny" - List of IP addresses to deny access from + "permit" - List of IP addresses to permit access from + "contact_acl" - List of Contact ACL section names in acl.conf + "contact_deny" - List of Contact header addresses to deny + "contact_permit" - List of Contact header addresses to permit + * Added new status Updated to AMI event ContactStatus on update registration * Added "reg_server" to contacts. @@ -320,6 +336,16 @@ 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 @@ -824,60 +824,56 @@ install-logrotate: rm -f contrib/scripts/asterisk.logrotate.tmp config: - @if [ "${OSARCH}" = "linux-gnu" -o "${OSARCH}" = "kfreebsd-gnu" ]; then \ - if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ - ./build_tools/install_subst contrib/init.d/rc.redhat.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ - if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/chkconfig --add asterisk ; \ - fi ; \ - elif [ -f /etc/debian_version ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.debian.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - if [ ! -f "$(DESTDIR)/etc/default/asterisk" ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/default/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /usr/sbin/update-rc.d asterisk defaults 50 91 ; \ - fi ; \ - elif [ -f /etc/gentoo-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.gentoo.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/rc-update add asterisk default ; \ - fi ; \ - elif [ -f /etc/mandrake-release -o -f /etc/mandriva-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.mandriva.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ - if [ ! -f /etc/sysconfig/asterisk ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/chkconfig --add asterisk ; \ - fi ; \ - elif [ -f /etc/SuSE-release -o -f /etc/novell-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.suse.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - if [ ! -f /etc/sysconfig/asterisk ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/chkconfig --add asterisk ; \ - fi ; \ - elif [ -f /etc/arch-release -o -f /etc/arch-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.archlinux.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - elif [ -d "$(DESTDIR)/Library/LaunchDaemons" ]; then \ - if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist" ]; then \ - ./build_tools/install_subst contrib/init.d/org.asterisk.asterisk.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist"; \ - fi; \ - if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist" ]; then \ - ./build_tools/install_subst contrib/init.d/org.asterisk.muted.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist"; \ - fi; \ - elif [ -f /etc/slackware-version ]; then \ - echo "Slackware is not currently supported, although an init script does exist for it."; \ - else \ - echo "We could not install init scripts for your distribution." ; \ - fi \ + if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ + ./build_tools/install_subst contrib/init.d/rc.redhat.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ + if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/chkconfig --add asterisk ; \ + fi ; \ + elif [ -f /etc/debian_version ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.debian.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + if [ ! -f "$(DESTDIR)/etc/default/asterisk" ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/default/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /usr/sbin/update-rc.d asterisk defaults 50 91 ; \ + fi ; \ + elif [ -f /etc/gentoo-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.gentoo.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/rc-update add asterisk default ; \ + fi ; \ + elif [ -f /etc/mandrake-release -o -f /etc/mandriva-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.mandriva.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ + if [ ! -f /etc/sysconfig/asterisk ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/chkconfig --add asterisk ; \ + fi ; \ + elif [ -f /etc/SuSE-release -o -f /etc/novell-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.suse.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + if [ ! -f /etc/sysconfig/asterisk ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/chkconfig --add asterisk ; \ + fi ; \ + elif [ -f /etc/arch-release -o -f /etc/arch-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.archlinux.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + elif [ -d "$(DESTDIR)/Library/LaunchDaemons" ]; then \ + if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist" ]; then \ + ./build_tools/install_subst contrib/init.d/org.asterisk.asterisk.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist"; \ + fi; \ + if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist" ]; then \ + ./build_tools/install_subst contrib/init.d/org.asterisk.muted.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist"; \ + fi; \ + elif [ -f /etc/slackware-version ]; then \ + echo "Slackware is not currently supported, although an init script does exist for it."; \ else \ - echo "We could not install init scripts for your operating system." ; \ + echo "We could not install init scripts for your distribution." ; \ fi sounds: diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index 04eb0b1fe..56705b1f0 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -141,19 +141,32 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo parse = ast_strdupa(data); AST_NONSTANDARD_APP_ARGS(args, parse, '/'); - fmt = ast_format_cap_get_format(cap, 0); + if (ast_strlen_zero(args.type)) { + ast_log(LOG_ERROR, "Type is required for the 'MulticastRTP' channel\n"); + goto failure; + } - ast_sockaddr_setnull(&control_address); + if (ast_strlen_zero(args.destination)) { + ast_log(LOG_ERROR, "Destination is required for the 'MulticastRTP' channel\n"); + goto failure; + } + if (!ast_sockaddr_parse(&destination_address, args.destination, PARSE_PORT_REQUIRE)) { + ast_log(LOG_ERROR, "Destination address '%s' could not be parsed\n", + args.destination); + goto failure; + } - if (!ast_strlen_zero(args.control) && - !ast_sockaddr_parse(&control_address, args.control, PARSE_PORT_REQUIRE)) { + ast_sockaddr_setnull(&control_address); + if (!ast_strlen_zero(args.control) + && !ast_sockaddr_parse(&control_address, args.control, PARSE_PORT_REQUIRE)) { ast_log(LOG_ERROR, "Control address '%s' could not be parsed\n", args.control); goto failure; } - if (!ast_sockaddr_parse(&destination_address, args.destination, - PARSE_PORT_REQUIRE)) { - ast_log(LOG_ERROR, "Destination address '%s' could not be parsed\n", args.destination); + fmt = ast_format_cap_get_format(cap, 0); + if (!fmt) { + ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n", + args.destination); goto failure; } @@ -162,12 +175,17 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo goto failure; } - if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, args.type))) { - ast_log(LOG_ERROR, "Could not create RTP instance for sending media to '%s'\n", args.destination); + instance = ast_rtp_instance_new("multicast", NULL, &control_address, args.type); + if (!instance) { + ast_log(LOG_ERROR, + "Could not create '%s' multicast RTP instance for sending media to '%s'\n", + args.type, args.destination); goto failure; } - if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, requestor, 0, "MulticastRTP/%p", instance))) { + chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, + requestor, 0, "MulticastRTP/%p", instance); + if (!chan) { ast_rtp_instance_destroy(instance); goto failure; } @@ -216,40 +234,54 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form ); if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n"); goto failure; } parse = ast_strdupa(data); AST_NONSTANDARD_APP_ARGS(args, parse, '/'); - if (!ast_strlen_zero(args.format)) { - fmt = ast_format_cache_get(args.format); - } else { - fmt = ast_format_cap_get_format(cap, 0); - } - - if (!fmt) { - ast_log(LOG_ERROR, "No format specified for sending RTP to '%s'\n", args.destination); + if (ast_strlen_zero(args.destination)) { + ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n"); goto failure; } - - if (!ast_sockaddr_parse(&address, args.destination, - PARSE_PORT_REQUIRE)) { + if (!ast_sockaddr_parse(&address, args.destination, PARSE_PORT_REQUIRE)) { ast_log(LOG_ERROR, "Destination '%s' could not be parsed\n", args.destination); goto failure; } + if (!ast_strlen_zero(args.format)) { + fmt = ast_format_cache_get(args.format); + if (!fmt) { + ast_log(LOG_ERROR, "Format '%s' not found for sending RTP to '%s'\n", + args.format, args.destination); + goto failure; + } + } else { + fmt = ast_format_cap_get_format(cap, 0); + if (!fmt) { + ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n", + args.destination); + goto failure; + } + } + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!caps) { goto failure; } ast_ouraddrfor(&address, &local_address); - if (!(instance = ast_rtp_instance_new(args.engine, NULL, &local_address, NULL))) { - ast_log(LOG_ERROR, "Could not create RTP instance for sending media to '%s'\n", args.destination); + instance = ast_rtp_instance_new(args.engine, NULL, &local_address, NULL); + if (!instance) { + ast_log(LOG_ERROR, + "Could not create %s RTP instance for sending media to '%s'\n", + S_OR(args.engine, "default"), args.destination); goto failure; } - if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, requestor, 0, "UnicastRTP/%s-%p", args.destination, instance))) { + chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, + requestor, 0, "UnicastRTP/%s-%p", args.destination, instance); + if (!chan) { ast_rtp_instance_destroy(instance); goto failure; } @@ -268,9 +300,11 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form ast_channel_tech_pvt_set(chan, instance); - pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS", ast_sockaddr_stringify_addr(&local_address)); + pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS", + ast_sockaddr_stringify_addr(&local_address)); ast_rtp_instance_get_local_address(instance, &local_address); - pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT", ast_sockaddr_stringify_port(&local_address)); + pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT", + ast_sockaddr_stringify_port(&local_address)); ast_channel_unlock(chan); 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 diff --git a/contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py b/contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py new file mode 100644 index 000000000..e119b2aa4 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py @@ -0,0 +1,32 @@ +"""Add PJSIP Endpoint IP Access Control options + +Revision ID: d7e3c73eb2bf +Revises: 6be31516058d +Create Date: 2016-05-13 12:45:45.071871 + +""" + +# revision identifiers, used by Alembic. +revision = 'd7e3c73eb2bf' +down_revision = '6be31516058d' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('deny', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('permit', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('acl', sa.String(40))) + op.add_column('ps_endpoints', sa.Column('contact_deny', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('contact_permit', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('contact_acl', sa.String(40))) + + +def downgrade(): + op.drop_column('ps_endpoints', 'contact_acl') + op.drop_column('ps_endpoints', 'contact_permit') + op.drop_column('ps_endpoints', 'contact_deny') + op.drop_column('ps_endpoints', 'acl') + op.drop_column('ps_endpoints', 'permit') + op.drop_column('ps_endpoints', 'deny') diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index bf8ce6acf..9f9f671c0 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -195,11 +195,25 @@ int ast_unregister_verbose(void (*verboser)(const char *string)) attribute_warn_ void ast_console_puts(const char *string); /*! - * \brief log the string to the console, and all attached - * console clients + * \brief log the string to the console, and all attached console clients + * + * \param string The message to write to the console + * \param level The log level of the message + * * \version 1.6.1 added level parameter */ void ast_console_puts_mutable(const char *string, int level); + +/*! + * \brief log the string to the console, and all attached console clients + * \since 14.0.0 + * + * \param message The message to write to the console + * \param sublevel If the log level supports it, the sub-level of the message + * \param level The log level of the message + */ +void ast_console_puts_mutable_full(const char *message, int level, int sublevel); + void ast_console_toggle_mute(int fd, int silent); /*! diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h index 4c93c3b45..53dfe9320 100644 --- a/include/asterisk/parking.h +++ b/include/asterisk/parking.h @@ -211,12 +211,19 @@ int ast_parking_is_exten_park(const char *context, const char *exten); * \brief Park the bridge and/or callers that this channel is in * * \param parker The bridge_channel parking the bridge - * \param exten Optional. The extension the channel or bridge was parked at if the - * call succeeds. + * \param[out] exten Optional. The parking exten to access the parking lot. * \param length Optional. If \c exten is specified, the size of the buffer. * * \note This is safe to be called outside of the \ref AstBridging Bridging API. * + * \note The exten parameter was intended to return the extension the channel or + * bridge was parked at if the call succeeds. However, accessing that information + * is very difficult to do with the new asynchronous design. That information may + * not be available anywhere by the time this function currently returns. + * + * Only, chan_skinny is known to call this function and use the exten parameter + * for the phone display. + * * \retval 0 on success * \retval non-zero on error */ 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/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 05f8100cf..cf8c719d5 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -738,6 +738,10 @@ struct ast_sip_endpoint { unsigned int usereqphone; /*! Whether to pass through hold and unhold using re-invites with recvonly and sendrecv */ unsigned int moh_passthrough; + /* Access control list */ + struct ast_acl_list *acl; + /* Restrict what IPs are allowed in the Contact header (for registration) */ + struct ast_acl_list *contact_acl; }; /*! diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 0e2f69ba8..2ca75a69c 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -688,7 +688,7 @@ void ast_str_trim_blanks(struct ast_str *buf), if (!buf) { return; } - while (buf->__AST_STR_USED && buf->__AST_STR_STR[buf->__AST_STR_USED - 1] < 33) { + while (buf->__AST_STR_USED && ((unsigned char) buf->__AST_STR_STR[buf->__AST_STR_USED - 1]) < 33) { buf->__AST_STR_STR[--(buf->__AST_STR_USED)] = '\0'; } } diff --git a/main/asterisk.c b/main/asterisk.c index bf2206cd7..6cfbc1b33 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1257,14 +1257,15 @@ void ast_console_toggle_mute(int fd, int silent) /*! * \brief log the string to all attached network console clients */ -static void ast_network_puts_mutable(const char *string, int level) +static void ast_network_puts_mutable(const char *string, int level, int sublevel) { int x; for (x = 0; x < AST_MAX_CONNECTS; ++x) { if (consoles[x].fd < 0 || consoles[x].mute - || consoles[x].levels[level]) { + || consoles[x].levels[level] + || (level == __LOG_VERBOSE && consoles[x].option_verbose < sublevel)) { continue; } fdprint(consoles[x].p[1], string); @@ -1277,12 +1278,23 @@ static void ast_network_puts_mutable(const char *string, int level) */ void ast_console_puts_mutable(const char *string, int level) { + ast_console_puts_mutable_full(string, level, 0); +} + +static int console_print(const char *s); + +void ast_console_puts_mutable_full(const char *message, int level, int sublevel) +{ /* Send to the root console */ - fputs(string, stdout); - fflush(stdout); + console_print(message); + + /* Wake up a poll()ing console */ + if (ast_opt_console && consolethread != AST_PTHREADT_NULL) { + pthread_kill(consolethread, SIGURG); + } /* Send to any network console clients */ - ast_network_puts_mutable(string, level); + ast_network_puts_mutable(message, level, sublevel); } /*! @@ -1314,24 +1326,6 @@ void ast_console_puts(const char *string) ast_network_puts(string); } -static void network_verboser(const char *string) -{ - int x; - int verb_level; - - /* Send to any network console clients if client verbocity allows. */ - verb_level = VERBOSE_MAGIC2LEVEL(string); - for (x = 0; x < AST_MAX_CONNECTS; ++x) { - if (consoles[x].fd < 0 - || consoles[x].mute - || consoles[x].levels[__LOG_VERBOSE] - || consoles[x].option_verbose < verb_level) { - continue; - } - fdprint(consoles[x].p[1], string); - } -} - static pthread_t lthread; /*! @@ -1594,9 +1588,6 @@ static int ast_makesocket(void) ast_socket = -1; return -1; } - if (ast_register_verbose(network_verboser)) { - ast_log(LOG_WARNING, "Unable to register network verboser?\n"); - } if (ast_pthread_create_background(<hread, NULL, listener, NULL)) { ast_log(LOG_WARNING, "Unable to create listener thread.\n"); @@ -2118,7 +2109,7 @@ static int console_state_init(void *ptr) AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr); -static int console_print(const char *s, int local) +static int console_print(const char *s) { struct console_state_data *state = ast_threadstorage_get(&console_state, sizeof(*state)); @@ -2189,18 +2180,6 @@ static int console_print(const char *s, int local) return res; } -static void console_verboser(const char *s) -{ - if (!console_print(s, 1)) { - return; - } - - /* Wake up a poll()ing console */ - if (ast_opt_console && consolethread != AST_PTHREADT_NULL) { - pthread_kill(consolethread, SIGURG); - } -} - static int ast_all_zeros(const char *s) { while (*s) { @@ -2713,7 +2692,7 @@ static int ast_el_read_char(EditLine *editline, char *cp) } } - console_print(buf, 0); + console_print(buf); if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (res >= 2 && buf[res-2] == '\n'))) { *cp = CC_REFRESH; @@ -3786,10 +3765,6 @@ static void env_init(void) static void print_intro_message(const char *runuser, const char *rungroup) { if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) { - if (ast_register_verbose(console_verboser)) { - fprintf(stderr, "Unable to register console verboser?\n"); - return; - } WELCOME_MESSAGE; if (runuser) { ast_verbose("Running as user '%s'\n", runuser); @@ -4424,6 +4399,11 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou aco_init(); + if (init_logger()) { /* Start logging subsystem */ + printf("Failed: init_logger\n%s", term_quit()); + exit(1); + } + if (ast_bucket_init()) { printf("Failed: ast_bucket_init\n%s", term_quit()); exit(1); @@ -4466,11 +4446,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou srand((unsigned int) getpid() + (unsigned int) time(NULL)); initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool)); - if (init_logger()) { /* Start logging subsystem */ - printf("Failed: init_logger\n%s", term_quit()); - exit(1); - } - threadstorage_init(); if (ast_rtp_engine_init()) { diff --git a/main/logger.c b/main/logger.c index c9cf50e09..ae1e0bd8d 100644 --- a/main/logger.c +++ b/main/logger.c @@ -158,6 +158,7 @@ enum logmsgtypes { struct logmsg { enum logmsgtypes type; int level; + int sublevel; int line; int lwp; ast_callid callid; @@ -307,6 +308,52 @@ static struct logformatter logformatter_json = { .format_log = format_log_json }; +static int logger_add_verbose_magic(struct logmsg *logmsg, char *buf, size_t size) +{ + const char *p; + const char *fmt; + struct ast_str *prefixed; + signed char magic = logmsg->sublevel > 9 ? -10 : -logmsg->sublevel - 1; /* 0 => -1, 1 => -2, etc. Can't pass NUL, as it is EOS-delimiter */ + + /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */ + if (logmsg->sublevel < 0) { + if (!strncmp(logmsg->message, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) { + magic = -5; + } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) { + magic = -4; + } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) { + magic = -3; + } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) { + magic = -2; + } else { + magic = -1; + } + } + + if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE))) { + return -1; + } + + ast_str_reset(prefixed); + + /* for every newline found in the buffer add verbose prefix data */ + fmt = logmsg->message; + do { + if (!(p = strchr(fmt, '\n'))) { + p = strchr(fmt, '\0') - 1; + } + ++p; + + ast_str_append(&prefixed, 0, "%c", (char)magic); + ast_str_append_substr(&prefixed, 0, fmt, p - fmt); + fmt = p; + } while (p && *p); + + snprintf(buf, size, "%s", ast_str_buffer(prefixed)); + + return 0; +} + static int format_log_default(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size) { char call_identifier_str[13]; @@ -334,6 +381,14 @@ static int format_log_default(struct logchannel *chan, struct logmsg *msg, char { char linestr[32]; + /* + * Verbose messages are interpreted by console channels in their own + * special way + */ + if (msg->level == __LOG_VERBOSE) { + return logger_add_verbose_magic(msg, buf, size); + } + /* Turn the numeric line number into a string for colorization */ snprintf(linestr, sizeof(linestr), "%d", msg->line); @@ -1406,13 +1461,6 @@ static char *handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, stru } } -struct verb { - void (*verboser)(const char *string); - AST_LIST_ENTRY(verb) list; -}; - -static AST_RWLIST_HEAD_STATIC(verbosers, verb); - static struct ast_cli_entry cli_logger[] = { AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"), AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"), @@ -1433,60 +1481,13 @@ static struct sigaction handle_SIGXFSZ = { .sa_flags = SA_RESTART, }; -static char *logger_strip_verbose_magic(const char *message, int level) -{ - const char *begin, *end; - char *stripped_message, *dst; - char magic = -(level + 1); - - if (!(stripped_message = ast_malloc(strlen(message) + 1))) { - return NULL; - } - - begin = message; - dst = stripped_message; - do { - end = strchr(begin, magic); - if (end) { - size_t len = end - begin; - memcpy(dst, begin, len); - begin = end + 1; - dst += len; - } else { - strcpy(dst, begin); /* safe */ - break; - } - } while (1); - - return stripped_message; -} - /*! \brief Print a normal log message to the channels */ static void logger_print_normal(struct logmsg *logmsg) { struct logchannel *chan = NULL; char buf[BUFSIZ]; - struct verb *v = NULL; - char *tmpmsg; int level = 0; - if (logmsg->level == __LOG_VERBOSE) { - - /* Iterate through the list of verbosers and pass them the log message string */ - AST_RWLIST_RDLOCK(&verbosers); - AST_RWLIST_TRAVERSE(&verbosers, v, list) - v->verboser(logmsg->message); - AST_RWLIST_UNLOCK(&verbosers); - - level = VERBOSE_MAGIC2LEVEL(logmsg->message); - - tmpmsg = logger_strip_verbose_magic(logmsg->message, level); - if (tmpmsg) { - ast_string_field_set(logmsg, message, tmpmsg); - ast_free(tmpmsg); - } - } - AST_RWLIST_RDLOCK(&logchannels); if (!AST_RWLIST_EMPTY(&logchannels)) { AST_RWLIST_TRAVERSE(&logchannels, chan, list) { @@ -1523,13 +1524,8 @@ static void logger_print_normal(struct logmsg *logmsg) } break; case LOGTYPE_CONSOLE: - /* The Console already is a verboser as well */ - if (logmsg->level == __LOG_VERBOSE) { - continue; - } - if (!chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) { - ast_console_puts_mutable(buf, logmsg->level); + ast_console_puts_mutable_full(buf, logmsg->level, logmsg->sublevel); } break; case LOGTYPE_FILE: @@ -1723,7 +1719,6 @@ int init_logger(void) void close_logger(void) { struct logchannel *f = NULL; - struct verb *cur = NULL; ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger)); @@ -1735,14 +1730,9 @@ void close_logger(void) ast_cond_signal(&logcond); AST_LIST_UNLOCK(&logmsgs); - if (logthread != AST_PTHREADT_NULL) + if (logthread != AST_PTHREADT_NULL) { pthread_join(logthread, NULL); - - AST_RWLIST_WRLOCK(&verbosers); - while ((cur = AST_LIST_REMOVE_HEAD(&verbosers, list))) { - ast_free(cur); } - AST_RWLIST_UNLOCK(&verbosers); AST_RWLIST_WRLOCK(&logchannels); @@ -1894,7 +1884,7 @@ void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created) /*! * \brief send log messages to syslog and/or the console */ -static void __attribute__((format(printf, 6, 0))) ast_log_full(int level, const char *file, int line, const char *function, ast_callid callid, const char *fmt, va_list ap) +static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel, const char *file, int line, const char *function, ast_callid callid, const char *fmt, va_list ap) { struct logmsg *logmsg = NULL; struct ast_str *buf = NULL; @@ -1956,6 +1946,7 @@ static void __attribute__((format(printf, 6, 0))) ast_log_full(int level, const /* Copy over data */ logmsg->level = level; + logmsg->sublevel = sublevel; logmsg->line = line; ast_string_field_set(logmsg, level_name, levels[level]); ast_string_field_set(logmsg, file, file); @@ -1990,7 +1981,7 @@ void ast_log(int level, const char *file, int line, const char *function, const if (level == __LOG_VERBOSE) { __ast_verbose_ap(file, line, function, 0, callid, fmt, ap); } else { - ast_log_full(level, file, line, function, callid, fmt, ap); + ast_log_full(level, -1, file, line, function, callid, fmt, ap); } va_end(ap); } @@ -2014,7 +2005,7 @@ void ast_log_safe(int level, const char *file, int line, const char *function, c callid = ast_read_threadstorage_callid(); va_start(ap, fmt); - ast_log_full(level, file, line, function, callid, fmt, ap); + ast_log_full(level, -1, file, line, function, callid, fmt, ap); va_end(ap); /* Clear flag so the next allocation failure can be logged. */ @@ -2025,7 +2016,7 @@ void ast_log_callid(int level, const char *file, int line, const char *function, { va_list ap; va_start(ap, fmt); - ast_log_full(level, file, line, function, callid, fmt, ap); + ast_log_full(level, -1, file, line, function, callid, fmt, ap); va_end(ap); } @@ -2060,53 +2051,7 @@ void ast_log_backtrace(void) void __ast_verbose_ap(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, va_list ap) { - const char *p; - struct ast_str *prefixed, *buf; - int res = 0; - signed char magic = level > 9 ? -10 : -level - 1; /* 0 => -1, 1 => -2, etc. Can't pass NUL, as it is EOS-delimiter */ - - /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */ - if (level < 0) { - if (!strncmp(fmt, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) { - magic = -5; - } else if (!strncmp(fmt, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) { - magic = -4; - } else if (!strncmp(fmt, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) { - magic = -3; - } else if (!strncmp(fmt, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) { - magic = -2; - } else { - magic = -1; - } - } - - if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)) || - !(buf = ast_str_thread_get(&verbose_build_buf, VERBOSE_BUF_INIT_SIZE))) { - return; - } - - res = ast_str_set_va(&buf, 0, fmt, ap); - /* If the build failed then we can drop this allocated message */ - if (res == AST_DYNSTR_BUILD_FAILED) { - return; - } - - ast_str_reset(prefixed); - - /* for every newline found in the buffer add verbose prefix data */ - fmt = ast_str_buffer(buf); - do { - if (!(p = strchr(fmt, '\n'))) { - p = strchr(fmt, '\0') - 1; - } - ++p; - - ast_str_append(&prefixed, 0, "%c", (char)magic); - ast_str_append_substr(&prefixed, 0, fmt, p - fmt); - fmt = p; - } while (p && *p); - - ast_log_callid(__LOG_VERBOSE, file, line, func, callid, "%s", ast_str_buffer(prefixed)); + ast_log_full(__LOG_VERBOSE, level, file, line, func, callid, fmt, ap); } void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...) @@ -2271,40 +2216,6 @@ void ast_verb_console_set(int verb_level) ast_verb_update(); } -int ast_register_verbose(void (*v)(const char *string)) -{ - struct verb *verb; - - if (!(verb = ast_malloc(sizeof(*verb)))) - return -1; - - verb->verboser = v; - - AST_RWLIST_WRLOCK(&verbosers); - AST_RWLIST_INSERT_HEAD(&verbosers, verb, list); - AST_RWLIST_UNLOCK(&verbosers); - - return 0; -} - -int ast_unregister_verbose(void (*v)(const char *string)) -{ - struct verb *cur; - - AST_RWLIST_WRLOCK(&verbosers); - AST_RWLIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) { - if (cur->verboser == v) { - AST_RWLIST_REMOVE_CURRENT(list); - ast_free(cur); - break; - } - } - AST_RWLIST_TRAVERSE_SAFE_END; - AST_RWLIST_UNLOCK(&verbosers); - - return cur ? 0 : -1; -} - static void update_logchannels(void) { struct logchannel *cur; diff --git a/main/udptl.c b/main/udptl.c index a0f533fd0..e543b4e8e 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -769,6 +769,18 @@ struct ast_frame *ast_udptl_read(struct ast_udptl *udptl) return &ast_null_frame; } + /* + * If early media isn't turned on for the channel driver, it's going to + * drop this frame. By that time though, udptl has already incremented + * the expected sequence number so if the CPE re-sends, the second frame + * will be dropped as a dup even though the first frame never went through. + * So we drop the frame here if the channel isn't up. 'tag' is set by the + * channel drivers on T38_ENABLED or T38_PEER_REINVITE. + */ + if (udptl->tag == NULL) { + return &ast_null_frame; + } + if (udptl->nat) { /* Send to whoever sent to us */ if (ast_sockaddr_cmp(&udptl->them, &addr)) { diff --git a/res/res_hep.c b/res/res_hep.c index e831fff02..45201359d 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 87d68e36d..0cc54c237 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) { @@ -77,13 +82,35 @@ 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; } - pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); + /* 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 { + 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); + } + } pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3); cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg); @@ -115,17 +142,39 @@ 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) { return PJ_SUCCESS; } - if (rdata->tp_info.transport->addr_len) { - pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); + if (!rdata->pkt_info.src_addr_len) { + return PJ_SUCCESS; } - if (rdata->pkt_info.src_addr_len) { - pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3); + 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 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); + } else { + snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } } uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag); diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 25aed1520..8643d4db6 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -36,6 +36,8 @@ ASTERISK_REGISTER_FILE() #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_REGISTER_FILE() 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 a3b2d081d..c06b67ecf 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -849,6 +849,56 @@ channel is hung up. By default this option is set to 0, which means do not check. </para></description> </configOption> + <configOption name="acl"> + <synopsis>List of IP ACL section names in acl.conf</synopsis> + <description><para> + This matches sections configured in <literal>acl.conf</literal>. The value is + defined as a list of comma-delimited section names. + </para></description> + </configOption> + <configOption name="deny"> + <synopsis>List of IP addresses to deny access from</synopsis> + <description><para> + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + </para></description> + </configOption> + <configOption name="permit"> + <synopsis>List of IP addresses to permit access from</synopsis> + <description><para> + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + </para></description> + </configOption> + <configOption name="contact_acl"> + <synopsis>List of Contact ACL section names in acl.conf</synopsis> + <description><para> + This matches sections configured in <literal>acl.conf</literal>. The value is + defined as a list of comma-delimited section names. + </para></description> + </configOption> + <configOption name="contact_deny"> + <synopsis>List of Contact header addresses to deny</synopsis> + <description><para> + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + </para></description> + </configOption> + <configOption name="contact_permit"> + <synopsis>List of Contact header addresses to permit</synopsis> + <description><para> + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + </para></description> + </configOption> </configObject> <configObject name="auth"> <synopsis>Authentication type</synopsis> diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index c370ab75f..8b6fe61d8 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -262,6 +262,65 @@ static const struct ast_sorcery_observer endpoint_observers = { .deleted = endpoint_deleted_observer, }; +static int endpoint_acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_endpoint *endpoint = obj; + int error = 0; + int ignore; + + if (ast_strlen_zero(var->value)) return 0; + + if (!strncmp(var->name, "contact_", 8)) { + ast_append_acl(var->name + 8, var->value, &endpoint->contact_acl, &error, &ignore); + } else { + ast_append_acl(var->name, var->value, &endpoint->acl, &error, &ignore); + } + + return error; +} + +static int acl_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + struct ast_acl_list *acl_list; + struct ast_acl *first_acl; + + if (endpoint && !ast_acl_list_is_empty(acl_list=endpoint->acl)) { + AST_LIST_LOCK(acl_list); + first_acl = AST_LIST_FIRST(acl_list); + if (ast_strlen_zero(first_acl->name)) { + *buf = "deny/permit"; + } else { + *buf = first_acl->name; + } + AST_LIST_UNLOCK(acl_list); + } + + *buf = ast_strdup(*buf); + return 0; +} + +static int contact_acl_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + struct ast_acl_list *acl_list; + struct ast_acl *first_acl; + + if (endpoint && !ast_acl_list_is_empty(acl_list=endpoint->contact_acl)) { + AST_LIST_LOCK(acl_list); + first_acl = AST_LIST_FIRST(acl_list); + if (ast_strlen_zero(first_acl->name)) { + *buf = "deny/permit"; + } else { + *buf = first_acl->name; + } + AST_LIST_UNLOCK(acl_list); + } + + *buf = ast_strdup(*buf); + return 0; +} + static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -272,8 +331,8 @@ static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, endpoint->dtmf = AST_SIP_DTMF_INBAND; } else if (!strcasecmp(var->value, "info")) { endpoint->dtmf = AST_SIP_DTMF_INFO; - } else if (!strcasecmp(var->value, "auto")) { - endpoint->dtmf = AST_SIP_DTMF_AUTO; + } else if (!strcasecmp(var->value, "auto")) { + endpoint->dtmf = AST_SIP_DTMF_AUTO; } else if (!strcasecmp(var->value, "none")) { endpoint->dtmf = AST_SIP_DTMF_NONE; } else { @@ -295,7 +354,7 @@ static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf) case AST_SIP_DTMF_INFO : *buf = "info"; break; case AST_SIP_DTMF_AUTO : - *buf = "auto"; break; + *buf = "auto"; break; default: *buf = "none"; } @@ -1760,6 +1819,12 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, message_context)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, accountcode)); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "deny", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "permit", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "acl", "", endpoint_acl_handler, acl_to_str, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_deny", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index b7da81433..2ab954eb0 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -21,6 +21,7 @@ #include <pjsip.h> #include "asterisk/res_pjsip.h" +#include "asterisk/acl.h" #include "include/res_pjsip_private.h" #include "asterisk/taskprocessor.h" #include "asterisk/threadpool.h" @@ -230,20 +231,33 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG || pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || rdata->msg_info.to->tag.slen != 0) { - return pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag, + dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag, remote_tag, PJ_TRUE); + if (dlg) { + return dlg; + } } - /* Incoming CANCEL without a to-tag can't use same method for finding the - * dialog. Instead, we have to find the matching INVITE transaction and - * then get the dialog from the transaction + /* + * There may still be a matching dialog if this is + * 1) an incoming CANCEL request without a to-tag + * 2) an incoming response to a dialog-creating request. */ - pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS, - pjsip_get_invite_method(), rdata); + if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { + /* CANCEL requests will need to match the INVITE we initially received. Any + * other request type will either have been matched already or is not in + * dialog + */ + pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS, + pjsip_get_invite_method(), rdata); + } else { + pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAC, + &rdata->msg_info.cseq->method, rdata); + } tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); if (!tsx) { - ast_log(LOG_ERROR, "Could not find matching INVITE transaction for CANCEL request\n"); + ast_debug(3, "Could not find matching transaction for %s\n", rdata->msg_info.info); return NULL; } @@ -380,19 +394,21 @@ struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void) return artificial_endpoint; } -static void log_unidentified_request(pjsip_rx_data *rdata, unsigned int count, unsigned int period) +static void log_failed_request(pjsip_rx_data *rdata, char *msg, unsigned int count, unsigned int period) { char from_buf[PJSIP_MAX_URL_SIZE]; char callid_buf[PJSIP_MAX_URL_SIZE]; + char method_buf[PJSIP_MAX_URL_SIZE]; pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.from->uri, from_buf, PJSIP_MAX_URL_SIZE); ast_copy_pj_str(callid_buf, &rdata->msg_info.cid->id, PJSIP_MAX_URL_SIZE); + ast_copy_pj_str(method_buf, &rdata->msg_info.msg->line.req.method.name, PJSIP_MAX_URL_SIZE); if (count) { - ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found" + ast_log(LOG_NOTICE, "Request '%s' from '%s' failed for '%s:%d' (callid: %s) - %s" " 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); + method_buf, from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, msg, count, period / 1000.0); } else { - 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); + ast_log(LOG_NOTICE, "Request '%s' from '%s' failed for '%s:%d' (callid: %s) - %s\n", + method_buf, from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, msg); } } @@ -405,7 +421,7 @@ static void check_endpoint(pjsip_rx_data *rdata, struct unidentified_request *un unid->count++; if (ms < (unidentified_period * 1000) && unid->count >= unidentified_count) { - log_unidentified_request(rdata, unid->count, ms); + log_failed_request(rdata, "No matching endpoint found", unid->count, ms); ast_sip_report_invalid_endpoint(name, rdata); } ao2_unlock(unid); @@ -479,7 +495,7 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) ao2_ref(unid, -1); ao2_unlock(unidentified_requests); } else { - log_unidentified_request(rdata, 0, 0); + log_failed_request(rdata, "No matching endpoint found", 0, 0); ast_sip_report_invalid_endpoint(name, rdata); } } @@ -487,6 +503,79 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) return PJ_FALSE; } +static int apply_endpoint_acl(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint) +{ + struct ast_sockaddr addr; + + if (ast_acl_list_is_empty(endpoint->acl)) { + return 0; + } + + memset(&addr, 0, sizeof(addr)); + ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID); + ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port); + + if (ast_apply_acl(endpoint->acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) { + log_failed_request(rdata, "Not match Endpoint ACL", 0, 0); + ast_sip_report_failed_acl(endpoint, rdata, "not_match_endpoint_acl"); + return 1; + } + return 0; +} + +static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs) +{ + pjsip_sip_uri *sip_uri; + char host[256]; + + if (!contact || contact->star) { + *addrs = NULL; + return 0; + } + if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) { + *addrs = NULL; + return 0; + } + sip_uri = pjsip_uri_get_uri(contact->uri); + ast_copy_pj_str(host, &sip_uri->host, sizeof(host)); + return ast_sockaddr_resolve(addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC); +} + +static int apply_endpoint_contact_acl(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint) +{ + int num_contact_addrs; + int forbidden = 0; + struct ast_sockaddr *contact_addrs; + int i; + pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; + + if (ast_acl_list_is_empty(endpoint->contact_acl)) { + return 0; + } + + while ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) { + num_contact_addrs = extract_contact_addr(contact, &contact_addrs); + if (num_contact_addrs <= 0) { + continue; + } + for (i = 0; i < num_contact_addrs; ++i) { + if (ast_apply_acl(endpoint->contact_acl, &contact_addrs[i], "SIP Contact ACL: ") != AST_SENSE_ALLOW) { + log_failed_request(rdata, "Not match Endpoint Contact ACL", 0, 0); + ast_sip_report_failed_acl(endpoint, rdata, "not_match_endpoint_contact_acl"); + forbidden = 1; + break; + } + } + ast_free(contact_addrs); + if (forbidden) { + /* No use checking other contacts if we already have failed ACL check */ + break; + } + } + + return forbidden; +} + static pj_bool_t authenticate(pjsip_rx_data *rdata) { RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup); @@ -494,6 +583,15 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) ast_assert(endpoint != NULL); + if (endpoint!=artificial_endpoint) { + if (apply_endpoint_acl(rdata, endpoint) || apply_endpoint_contact_acl(rdata, endpoint)) { + if (!is_ack) { + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); + } + return PJ_TRUE; + } + } + if (!is_ack && ast_sip_requires_authentication(endpoint, rdata)) { pjsip_tx_data *tdata; struct unidentified_request *unid; @@ -515,10 +613,12 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) pjsip_tx_data_dec_ref(tdata); return PJ_FALSE; case AST_SIP_AUTHENTICATION_FAILED: + log_failed_request(rdata, "Failed to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); return PJ_TRUE; case AST_SIP_AUTHENTICATION_ERROR: + log_failed_request(rdata, "Error to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); pjsip_tx_data_dec_ref(tdata); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); diff --git a/res/res_pjsip_dtmf_info.c b/res/res_pjsip_dtmf_info.c index 47ccd1ae5..e534f3e27 100644 --- a/res/res_pjsip_dtmf_info.c +++ b/res/res_pjsip_dtmf_info.c @@ -103,13 +103,13 @@ static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pj if (!body || !body->len) { /* need to return 200 OK on empty body */ send_response(session, rdata, 200); - return 0; + return 1; } res = body->print_body(body, buf, body->len); if (res < 0) { send_response(session, rdata, 500); - return 0; + return 1; } buf[res] = '\0'; @@ -150,11 +150,12 @@ static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pj } send_response(session, rdata, event ? 200 : 500); - return event ? 0 : -1; + return 1; } static struct ast_sip_session_supplement dtmf_info_supplement = { .method = "INFO", + .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST, .incoming_request = dtmf_info_incoming_request, }; diff --git a/res/res_pjsip_empty_info.c b/res/res_pjsip_empty_info.c new file mode 100644 index 000000000..09109ba2c --- /dev/null +++ b/res/res_pjsip_empty_info.c @@ -0,0 +1,89 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Bradley Latus <brad.latus@gmail.com> + * + * 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. + */ + +/*** MODULEINFO + <depend>pjproject</depend> + <depend>res_pjsip</depend> + <depend>res_pjsip_session</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include <pjsip.h> +#include <pjsip_ua.h> + +#include "asterisk/res_pjsip.h" +#include "asterisk/res_pjsip_session.h" +#include "asterisk/module.h" + +static void send_response(struct ast_sip_session *session, + struct pjsip_rx_data *rdata, int code) +{ + pjsip_tx_data *tdata; + pjsip_dialog *dlg = session->inv_session->dlg; + + if (pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata) == PJ_SUCCESS) { + struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); + pjsip_dlg_send_response(dlg, tsx, tdata); + } +} + +static int empty_info_incoming_request(struct ast_sip_session *session, + struct pjsip_rx_data *rdata) +{ + if (!rdata->msg_info.ctype) { + /* Need to return 200 OK on empty body */ + /* Some SBCs use empty INFO as a KEEPALIVE */ + send_response(session, rdata, 200); + return 1; + } + + /* Let another module respond */ + return 0; + +} + +static struct ast_sip_session_supplement empty_info_supplement = { + .method = "INFO", + .priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST, + .incoming_request = empty_info_incoming_request, +}; + +static int load_module(void) +{ + CHECK_PJSIP_SESSION_MODULE_LOADED(); + + ast_sip_session_register_supplement(&empty_info_supplement); + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + ast_sip_session_unregister_supplement(&empty_info_supplement); + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Empty INFO Support", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_APP_DEPEND, +); diff --git a/res/res_pjsip_one_touch_record_info.c b/res/res_pjsip_one_touch_record_info.c index 30dfcaabf..2d53fd48e 100644 --- a/res/res_pjsip_one_touch_record_info.c +++ b/res/res_pjsip_one_touch_record_info.c @@ -72,13 +72,13 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip if (!session->channel) { send_response(session, 481, rdata); - return 0; + return 1; } /* Is this endpoint configured with One Touch Recording? */ if (!session->endpoint->info.recording.enabled || ast_strlen_zero(feature)) { send_response(session, 403, rdata); - return 0; + return 1; } ast_channel_lock(session->channel); @@ -87,7 +87,7 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip if (feature_res || ast_strlen_zero(feature_code)) { send_response(session, 403, rdata); - return 0; + return 1; } for (digit = feature_code; *digit; ++digit) { @@ -97,11 +97,12 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip send_response(session, 200, rdata); - return 0; + return 1; } static struct ast_sip_session_supplement info_supplement = { .method = "INFO", + .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST, .incoming_request = handle_incoming_request, }; diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index dcfaba528..79db66808 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -79,6 +79,58 @@ static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, v return ast_db_put(family, ast_sorcery_object_get_id(object), value); } +/*! \brief Internal helper function which returns a filtered objectset. + * + * The following are filtered out of the objectset: + * \li Fields that are not registered with sorcery. + * + * \param objectset Objectset to filter. + * \param sorcery The sorcery instance that is requesting an objectset. + * \param type The object type + * + * \return The filtered objectset + */ +static struct ast_variable *sorcery_astdb_filter_objectset(struct ast_variable *objectset, const struct ast_sorcery *sorcery, + const char *type) +{ + struct ast_variable *previous = NULL, *field = objectset; + struct ast_sorcery_object_type *object_type; + + object_type = ast_sorcery_get_object_type(sorcery, type); + if (!object_type) { + ast_log(LOG_WARNING, "Unknown sorcery object type %s. Expect errors\n", type); + return objectset; + } + + while (field) { + struct ast_variable *removed; + + if (ast_sorcery_is_object_field_registered(object_type, field->name)) { + previous = field; + field = field->next; + continue; + } + + ast_debug(1, "Filtering out astdb field '%s' from retrieval\n", field->name); + + if (previous) { + previous->next = field->next; + } else { + objectset = field->next; + } + + removed = field; + field = field->next; + removed->next = NULL; + + ast_variables_destroy(removed); + } + + ao2_cleanup(object_type); + + return objectset; +} + /*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects) { @@ -103,10 +155,13 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc if (!(json = ast_json_load_string(entry->data, &error))) { return NULL; } + if (ast_json_to_ast_variables(json, &existing) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) { return NULL; } + existing = sorcery_astdb_filter_objectset(existing, sorcery, type); + if (fields && !ast_variable_lists_match(existing, fields, 0)) { continue; } @@ -148,6 +203,7 @@ static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void * if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &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, id)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { ast_debug(3, "Failed to retrieve object '%s' from astdb\n", id); @@ -260,6 +316,7 @@ static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void continue; } else 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)) { regfree(&expression); diff --git a/utils/extconf.c b/utils/extconf.c index 4eaea3c2d..48053aed6 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -120,9 +120,6 @@ void ast_queue_log(const char *queuename, const char *callid, const char *agent, /* IN CONFLICT: void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2))); */ -int ast_register_verbose(void (*verboser)(const char *string)); -int ast_unregister_verbose(void (*verboser)(const char *string)); - void ast_console_puts(const char *string); #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__ |