summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES26
-rw-r--r--Makefile102
-rw-r--r--channels/chan_rtp.c86
-rw-r--r--configs/samples/hep.conf.sample4
-rw-r--r--contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py32
-rw-r--r--include/asterisk/logger.h18
-rw-r--r--include/asterisk/parking.h11
-rw-r--r--include/asterisk/res_hep.h14
-rw-r--r--include/asterisk/res_pjsip.h4
-rw-r--r--include/asterisk/strings.h2
-rw-r--r--main/asterisk.c73
-rw-r--r--main/logger.c215
-rw-r--r--main/udptl.c12
-rw-r--r--res/res_hep.c37
-rw-r--r--res/res_hep.exports.in1
-rw-r--r--res/res_hep_pjsip.c63
-rw-r--r--res/res_hep_rtcp.c33
-rw-r--r--res/res_pjsip.c50
-rw-r--r--res/res_pjsip/pjsip_configuration.c71
-rw-r--r--res/res_pjsip/pjsip_distributor.c128
-rw-r--r--res/res_pjsip_dtmf_info.c7
-rw-r--r--res/res_pjsip_empty_info.c89
-rw-r--r--res/res_pjsip_one_touch_record_info.c9
-rw-r--r--res/res_sorcery_astdb.c57
-rw-r--r--utils/extconf.c3
25 files changed, 827 insertions, 320 deletions
diff --git a/CHANGES b/CHANGES
index a547fbc86..b6fedfcda 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
diff --git a/Makefile b/Makefile
index 7528f8374..b988c8ff6 100644
--- a/Makefile
+++ b/Makefile
@@ -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(&lthread, 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__