aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--BSDmakefile11
-rw-r--r--CHANGES17
-rw-r--r--Makefile2
-rw-r--r--UPGRADE.txt11
-rw-r--r--addons/ooh323c/src/ooSocket.h5
-rw-r--r--addons/ooh323c/src/oochannels.c24
-rw-r--r--addons/res_config_mysql.c2
-rw-r--r--apps/app_adsiprog.c6
-rw-r--r--apps/app_celgenuserevent.c3
-rw-r--r--apps/app_chanspy.c2
-rw-r--r--apps/app_dial.c3
-rw-r--r--apps/app_festival.c13
-rw-r--r--apps/app_followme.c1
-rw-r--r--apps/app_getcpeid.c6
-rw-r--r--apps/app_meetme.c6
-rw-r--r--apps/app_osplookup.c8
-rw-r--r--apps/app_queue.c5
-rw-r--r--apps/app_readexten.c2
-rw-r--r--apps/app_speech_utils.c6
-rw-r--r--apps/app_stack.c6
-rw-r--r--apps/app_voicemail.c13
-rw-r--r--cdr/cdr_adaptive_odbc.c3
-rw-r--r--cdr/cdr_odbc.c3
-rw-r--r--cel/cel_odbc.c (renamed from cel/cel_adaptive_odbc.c)57
-rw-r--r--channels/chan_agent.c2
-rw-r--r--channels/chan_dahdi.c52
-rw-r--r--channels/chan_iax2.c114
-rw-r--r--channels/chan_local.c32
-rw-r--r--channels/chan_mgcp.c5
-rw-r--r--channels/chan_misdn.c105
-rw-r--r--channels/chan_multicast_rtp.c10
-rw-r--r--channels/chan_phone.c80
-rw-r--r--channels/chan_sip.c606
-rw-r--r--channels/chan_usbradio.c161
-rw-r--r--channels/console_video.c239
-rw-r--r--channels/sig_analog.c10
-rw-r--r--channels/sig_analog.h2
-rw-r--r--channels/sig_pri.c69
-rw-r--r--channels/sig_pri.h6
-rw-r--r--channels/sip/config_parser.c12
-rw-r--r--channels/sip/include/sip.h14
-rw-r--r--configs/cdr.conf.sample31
-rw-r--r--configs/cel.conf.sample15
-rw-r--r--configs/cel_custom.conf.sample12
-rw-r--r--configs/cel_odbc.conf.sample (renamed from configs/cel_adaptive_odbc.conf.sample)2
-rw-r--r--configs/iax.conf.sample9
-rw-r--r--configs/manager.conf.sample18
-rw-r--r--configs/res_curl.conf.sample8
-rw-r--r--configs/res_stun_monitor.conf.sample22
-rw-r--r--configs/say.conf.sample115
-rw-r--r--configs/sip.conf.sample55
-rwxr-xr-xconfigure154
-rw-r--r--configure.ac80
-rw-r--r--doc/tex/asterisk.tex6
-rw-r--r--doc/tex/channelvariables.tex23
-rw-r--r--doc/tex/partymanip.tex325
-rw-r--r--doc/tex/sounds.tex80
-rw-r--r--formats/format_wav.c69
-rw-r--r--funcs/func_aes.c6
-rw-r--r--funcs/func_channel.c9
-rw-r--r--funcs/func_odbc.c6
-rw-r--r--include/asterisk/astobj2.h4
-rw-r--r--include/asterisk/autoconfig.h.in17
-rw-r--r--include/asterisk/calendar.h2
-rw-r--r--include/asterisk/ccss.h19
-rw-r--r--include/asterisk/cel.h7
-rw-r--r--include/asterisk/channel.h38
-rw-r--r--include/asterisk/cli.h4
-rw-r--r--include/asterisk/compiler.h6
-rw-r--r--include/asterisk/event_defs.h4
-rw-r--r--include/asterisk/module.h5
-rw-r--r--include/asterisk/netsock2.h20
-rw-r--r--include/asterisk/pbx.h8
-rw-r--r--include/asterisk/poll-compat.h22
-rw-r--r--include/asterisk/res_srtp.h1
-rw-r--r--include/asterisk/sched.h10
-rw-r--r--include/asterisk/select.h110
-rw-r--r--include/asterisk/translate.h8
-rw-r--r--include/asterisk/unaligned.h2
-rw-r--r--keys/freeworlddialup.pub6
-rw-r--r--keys/iaxtel.pub6
-rw-r--r--main/asterisk.c46
-rw-r--r--main/ccss.c49
-rw-r--r--main/cdr.c39
-rw-r--r--main/cel.c6
-rw-r--r--main/channel.c14
-rw-r--r--main/cli.c43
-rw-r--r--main/config.c2
-rw-r--r--main/features.c89
-rw-r--r--main/loader.c20
-rw-r--r--main/manager.c33
-rw-r--r--main/netsock2.c16
-rw-r--r--main/pbx.c57
-rw-r--r--main/poll.c196
-rw-r--r--main/rtp_engine.c4
-rw-r--r--main/sched.c2
-rw-r--r--main/stun.c7
-rw-r--r--main/translate.c295
-rw-r--r--main/utils.c16
-rw-r--r--makeopts.in1
-rw-r--r--pbx/pbx_config.c34
-rw-r--r--pbx/pbx_dundi.c1
-rw-r--r--pbx/pbx_loopback.c1
-rw-r--r--pbx/pbx_realtime.c4
-rw-r--r--pbx/pbx_spool.c15
-rw-r--r--res/res_ais.c20
-rw-r--r--res/res_calendar.c22
-rw-r--r--res/res_calendar_caldav.c14
-rw-r--r--res/res_calendar_ews.c82
-rw-r--r--res/res_calendar_icalendar.c8
-rw-r--r--res/res_config_odbc.c2
-rw-r--r--res/res_config_pgsql.c16
-rw-r--r--res/res_fax.c128
-rw-r--r--res/res_jabber.c23
-rw-r--r--res/res_musiconhold.c124
-rw-r--r--res/res_odbc.c3
-rw-r--r--res/res_pktccops.c35
-rw-r--r--res/res_rtp_asterisk.c21
-rw-r--r--res/res_srtp.c96
-rw-r--r--res/res_stun_monitor.c311
-rw-r--r--tests/test_poll.c253
121 files changed, 4013 insertions, 1213 deletions
diff --git a/BSDmakefile b/BSDmakefile
new file mode 100644
index 000000000..de6fc9c4c
--- /dev/null
+++ b/BSDmakefile
@@ -0,0 +1,11 @@
+# This is a convenience script for systems on which BSD make is the default,
+# such that typing 'make' will do what people expect, instead of producing an
+# error (due to incompatibilities between BSD make and GNU make).
+
+.include "makeopts"
+
+all::
+ $(MAKE)
+
+$(.TARGETS)::
+ $(MAKE) $(.TARGETS)
diff --git a/CHANGES b/CHANGES
index c4fd00ec2..2f63402fb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -73,6 +73,11 @@ SIP Changes
RTP has been outfitted with the same abilities.
* Added support for setting the Max-Forwards: header in SIP requests. Setting is
available in device configurations as well as in the dial plan.
+ * Addition of the 'subscribe_network_change' option for turning on and off
+ res_stun_monitor module support in chan_sip.
+ * Addition of the 'auth_options_requests' option for turning on and off
+ authentication for OPTIONS requests in chan_sip.
+
IAX2 Changes
-----------
@@ -82,6 +87,9 @@ IAX2 Changes
encryption is being used. This interoperates with the SIP SRTP implementation
so that a secure SIP call can be bridged to a secure IAX call when the
dialplan requires bridged channels to be "secure".
+ * Addition of the 'subscribe_network_change' option for turning on and off
+ res_stun_monitor module support in chan_iax.
+
MGCP Changes
------------
@@ -535,6 +543,10 @@ Miscellaneous
* The UNISTIM channel driver (chan_unistim) has been updated to support devices that
have less than 3 lines on the LCD.
* Realtime now supports database failover. See the sample extconfig.conf for details.
+ * The addition of improved translation path building for wideband codecs. Sample
+ rate changes during translation are now avoided unless absolutely necessary.
+ * The addition of the res_stun_monitor module for monitoring and reacting to network
+ changes while behind a NAT.
CLI Changes
-----------
@@ -550,6 +562,7 @@ CLI Changes
manager.conf.
* Added 'all' keyword to the CLI command "channel request hangup" so that you can send
the channel hangup request to all channels.
+ * Added a "core reload" CLI command that executes a global reload of Asterisk.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 1.6.1 to Asterisk 1.6.2 -------------
@@ -1091,10 +1104,6 @@ SIP changes
option is enabled, Asterisk will watch for a CNG tone in the incoming audio
for a received call. If it is detected, the channel will jump to the
'fax' extension in the dialplan.
- * Improved NAT and STUN support.
- chan_sip now can use port numbers in bindaddr, externip and externhost
- options, as well as contact a STUN server to detect its external address
- for the SIP socket. See sip.conf.sample, 'NAT' section.
* The default SIP useragent= identifier now includes the Asterisk version
* A new option, match_auth_username in sip.conf changes the matching of incoming requests.
If set, and the incoming request carries authentication info,
diff --git a/Makefile b/Makefile
index 30df890ca..d0f02a3d8 100644
--- a/Makefile
+++ b/Makefile
@@ -606,8 +606,6 @@ bininstall: _all installdirs $(SUBDIRS_INSTALL)
$(INSTALL) -m 644 doc/core-*.xml $(DESTDIR)$(ASTDATADIR)/documentation
$(INSTALL) -m 644 doc/appdocsxml.dtd $(DESTDIR)$(ASTDATADIR)/documentation
- $(INSTALL) -m 644 keys/iaxtel.pub $(DESTDIR)$(ASTDATADIR)/keys
- $(INSTALL) -m 644 keys/freeworlddialup.pub $(DESTDIR)$(ASTDATADIR)/keys
$(INSTALL) -m 644 doc/asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8
$(INSTALL) -m 644 contrib/scripts/astgenkey.8 $(DESTDIR)$(ASTMANDIR)/man8
$(INSTALL) -m 644 contrib/scripts/autosupport.8 $(DESTDIR)$(ASTMANDIR)/man8
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 677fdb7c2..9889a55e6 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -20,6 +20,9 @@
From 1.6.2 to 1.8:
+* The default value for the alwaysauthreject option in sip.conf has been changed
+ from "no" to "yes".
+
* The behavior of the 'parkedcallstimeout' has changed slightly. The formulation
of the extension name that a timed out parked call is delivered to when this
option is set to 'no' was modified such that instead of converting '/' to '0',
@@ -106,6 +109,14 @@ From 1.6.2 to 1.8:
482 Loop Detected response. The dialplan will just continue from where it
left off.
+* The 'stunaddr' option has been removed from chan_sip. This feature did not
+ behave as expected, had no correct use case, and was not RFC compliant. The
+ removal of this feature will hopefully be followed by a correct RFC compliant
+ STUN implementation in chan_sip in the future.
+
+* The default value for the pedantic option in sip.conf has been changed
+ from "no" to "yes".
+
From 1.6.1 to 1.6.2:
* SIP no longer sends the 183 progress message for early media by
diff --git a/addons/ooh323c/src/ooSocket.h b/addons/ooh323c/src/ooSocket.h
index dff1c8a16..73492cc60 100644
--- a/addons/ooh323c/src/ooSocket.h
+++ b/addons/ooh323c/src/ooSocket.h
@@ -23,6 +23,7 @@
#define _OOSOCKET_H_
#include "asterisk/poll-compat.h"
+#include "asterisk/compiler.h"
#ifdef _WIN32_WCE
#include <winsock.h>
@@ -329,9 +330,9 @@ EXTERN int ooSocketSendTo(OOSOCKET socket, const ASN1OCTET* pdata,
* returns.
* @return Completion status of operation: 0 (ASN_OK) = success,
* negative return value is error.
- */
+ */
EXTERN int ooSocketSelect(int nfds, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds, struct timeval * timeout);
+ fd_set *exceptfds, struct timeval * timeout) attribute_deprecated;
EXTERN int ooSocketPoll(struct pollfd *pfds, int nfds, int timeout);
diff --git a/addons/ooh323c/src/oochannels.c b/addons/ooh323c/src/oochannels.c
index 446b56a27..c4ac24871 100644
--- a/addons/ooh323c/src/oochannels.c
+++ b/addons/ooh323c/src/oochannels.c
@@ -15,6 +15,7 @@
*****************************************************************************/
#include "asterisk.h"
#include "asterisk/lock.h"
+#include "asterisk/poll-compat.h"
#include "ooports.h"
#include "oochannels.h"
@@ -1980,22 +1981,12 @@ int ooStopMonitorCalls()
OOBOOL ooChannelsIsConnectionOK(OOH323CallData *call, OOSOCKET sock)
{
- struct timeval to;
- fd_set readfds;
- int ret = 0, nfds=0;
+ struct timeval to = { .tv_usec = 500 };
+ struct pollfd pfds = { .fd = sock, .events = POLLIN };
+ int ret = 0;
- to.tv_sec = 0;
- to.tv_usec = 500;
- FD_ZERO(&readfds);
+ ret = ast_poll2(&pfds, 1, &to);
- FD_SET(sock, &readfds);
- if(nfds < (int)sock)
- nfds = (int)sock;
-
- nfds++;
-
- ret = ooSocketSelect(nfds, &readfds, NULL, NULL, &to);
-
if(ret == -1)
{
OOTRACEERR3("Error in select ...broken pipe check(%s, %s)\n",
@@ -2003,9 +1994,8 @@ OOBOOL ooChannelsIsConnectionOK(OOH323CallData *call, OOSOCKET sock)
return FALSE;
}
- if(FD_ISSET(sock, &readfds))
- {
- char buf[2];
+ if (pfds.events & POLLIN) {
+ char buf[2];
if(ooSocketRecvPeek(sock, (ASN1OCTET*) buf, 2) == 0)
{
OOTRACEWARN3("Broken pipe detected. (%s, %s)", call->callType,
diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c
index e770452fd..1ba522485 100644
--- a/addons/res_config_mysql.c
+++ b/addons/res_config_mysql.c
@@ -307,7 +307,7 @@ static char *decode_chunk(char *chunk)
char *orig = chunk;
for (; *chunk; chunk++) {
if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
- sscanf(chunk + 1, "%02hhd", chunk);
+ sscanf(chunk + 1, "%02hhX", chunk);
memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
}
}
diff --git a/apps/app_adsiprog.c b/apps/app_adsiprog.c
index 8af1473d1..c138f0429 100644
--- a/apps/app_adsiprog.c
+++ b/apps/app_adsiprog.c
@@ -1591,4 +1591,8 @@ static int load_module(void)
return AST_MODULE_LOAD_SUCCESS;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk ADSI Programming Application");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk ADSI Programming Application",
+ .load = load_module,
+ .unload = unload_module,
+ .nonoptreq = "res_adsi",
+ );
diff --git a/apps/app_celgenuserevent.c b/apps/app_celgenuserevent.c
index da1c246ef..b1701ba23 100644
--- a/apps/app_celgenuserevent.c
+++ b/apps/app_celgenuserevent.c
@@ -41,6 +41,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<parameter name="event-name" required="true">
<argument name="event-name" required="true">
</argument>
+ <argument name="extra" required="false">
+ <para>Extra text to be included with the event.</para>
+ </argument>
</parameter>
</syntax>
<description>
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 96748e667..f1b509c63 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -927,7 +927,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
}
if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
if (!ast_test_flag(flags, OPTION_NOTECH)) {
- if (ast_fileexists(peer_name, NULL, NULL) != -1) {
+ if (ast_fileexists(peer_name, NULL, NULL) > 0) {
res = ast_streamfile(chan, peer_name, chan->language);
if (!res) {
res = ast_waitstream(chan, "");
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 60bf7b424..0f7b4880d 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -2611,8 +2611,9 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
sentringing = 0;
ast_indicate(chan, -1);
}
- /* Be sure no generators are left on it */
+ /* Be sure no generators are left on it and reset the visible indication */
ast_deactivate_generator(chan);
+ chan->visible_indication = 0;
/* Make sure channels are compatible */
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
diff --git a/apps/app_festival.c b/apps/app_festival.c
index c547cfc6b..ef8827adb 100644
--- a/apps/app_festival.c
+++ b/apps/app_festival.c
@@ -49,6 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
+#include "asterisk/endian.h"
#define FESTIVAL_CONFIG "festival.conf"
#define MAXLEN 180
@@ -127,7 +128,7 @@ static char *socket_receive_file_to_buff(int fd, int *size)
static int send_waveform_to_fd(char *waveform, int length, int fd)
{
int res;
-#ifdef __PPC__
+#if __BYTE_ORDER == __BIG_ENDIAN
int x;
char c;
#endif
@@ -142,20 +143,20 @@ static int send_waveform_to_fd(char *waveform, int length, int fd)
ast_close_fds_above_n(0);
if (ast_opt_high_priority)
ast_set_priority(0);
-#ifdef __PPC__
+#if __BYTE_ORDER == __BIG_ENDIAN
for (x = 0; x < length; x += 2) {
c = *(waveform + x + 1);
*(waveform + x + 1) = *(waveform + x);
*(waveform + x) = c;
}
#endif
-
- if (write(fd, waveform, length) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
+
+ if (write(0, waveform, length) < 0) {
+ /* Cannot log -- all FDs are already closed */
}
close(fd);
- exit(0);
+ _exit(0);
}
static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys)
diff --git a/apps/app_followme.c b/apps/app_followme.c
index fcab992d3..b17d5252b 100644
--- a/apps/app_followme.c
+++ b/apps/app_followme.c
@@ -51,7 +51,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
-#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
diff --git a/apps/app_getcpeid.c b/apps/app_getcpeid.c
index 93df1623a..220708156 100644
--- a/apps/app_getcpeid.c
+++ b/apps/app_getcpeid.c
@@ -132,4 +132,8 @@ static int load_module(void)
return ast_register_application_xml(app, cpeid_exec);
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get ADSI CPE ID");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Get ADSI CPE ID",
+ .load = load_module,
+ .unload = unload_module,
+ .nonoptreq = "res_adsi",
+ );
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index 85bb0a645..2f64a9b78 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -2782,6 +2782,9 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
if (!ast_streamfile(chan, "minutes", chan->language))
ast_waitstream(chan, "");
+ if (musiconhold) {
+ conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
+ }
announcement_played = 1;
}
}
@@ -2853,6 +2856,9 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
res = ast_streamfile(chan, user->warning_sound, chan->language);
res = ast_waitstream(chan, "");
}
+ if (musiconhold) {
+ conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
+ }
}
}
if (user->warning_freq) {
diff --git a/apps/app_osplookup.c b/apps/app_osplookup.c
index ea20cee77..239d6d501 100644
--- a/apps/app_osplookup.c
+++ b/apps/app_osplookup.c
@@ -1493,6 +1493,7 @@ static int osp_lookup(
char callingnum[OSP_SIZE_NORSTR];
char callednum[OSP_SIZE_NORSTR];
char destination[OSP_SIZE_NORSTR];
+ char* tmp;
unsigned int tokenlen;
char token[OSP_SIZE_TOKSTR];
char src[OSP_SIZE_NORSTR];
@@ -1565,6 +1566,11 @@ static int osp_lookup(
}
}
+ ast_copy_string(callednum, called, sizeof(callednum));
+ if((tmp = strchr(callednum, ';')) != NULL) {
+ *tmp = '\0';
+ }
+
callidnum = 0;
callids[0] = NULL;
for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
@@ -1605,7 +1611,7 @@ static int osp_lookup(
dev,
calling ? calling : "",
OSPC_NFORMAT_E164,
- called,
+ callednum,
OSPC_NFORMAT_E164,
NULL,
callidnum,
diff --git a/apps/app_queue.c b/apps/app_queue.c
index ccdee7fb3..57cbc0b63 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -57,7 +57,7 @@
*/
/*** MODULEINFO
- <depend>res_monitor</depend>
+ <use>res_monitor</use>
***/
#include "asterisk.h"
@@ -8186,7 +8186,7 @@ static int load_module(void)
static int reload(void)
{
- struct ast_flags mask = {AST_FLAGS_ALL,};
+ struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
ast_unload_realtime("queue_members");
reload_handler(1, &mask, NULL);
return 0;
@@ -8197,5 +8197,6 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
+ .nonoptreq = "res_monitor",
);
diff --git a/apps/app_readexten.c b/apps/app_readexten.c
index 8049fc949..5e8159b35 100644
--- a/apps/app_readexten.c
+++ b/apps/app_readexten.c
@@ -232,7 +232,7 @@ static int readexten_exec(struct ast_channel *chan, const char *data)
if (res < 1) { /* timeout expired or hangup */
if (ast_check_hangup(chan)) {
status = "HANGUP";
- } else {
+ } else if (x == 0) {
pbx_builtin_setvar_helper(chan, arglist.variable, "t");
status = "TIMEOUT";
}
diff --git a/apps/app_speech_utils.c b/apps/app_speech_utils.c
index 60af43640..0323f7c47 100644
--- a/apps/app_speech_utils.c
+++ b/apps/app_speech_utils.c
@@ -955,4 +955,8 @@ static int load_module(void)
return res;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialplan Speech Applications");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Dialplan Speech Applications",
+ .load = load_module,
+ .unload = unload_module,
+ .nonoptreq = "res_speech",
+ );
diff --git a/apps/app_stack.c b/apps/app_stack.c
index dcf13a00d..29c37a20b 100644
--- a/apps/app_stack.c
+++ b/apps/app_stack.c
@@ -704,4 +704,8 @@ static int load_module(void)
return 0;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialplan subroutines (Gosub, Return, etc)");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Dialplan subroutines (Gosub, Return, etc)",
+ .load = load_module,
+ .unload = unload_module,
+ .nonoptreq = "res_agi",
+ );
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index 4ff67e371..8f0a5bd82 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -38,7 +38,8 @@
*/
/*** MODULEINFO
- <depend>res_smdi</depend>
+ <use>res_adsi</use>
+ <use>res_smdi</use>
***/
/*** MAKEOPTS
@@ -1492,11 +1493,12 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
}
value = strstr(tmp, ",");
if (!value) {
- ast_log(AST_LOG_WARNING, "variable has bad format.\n");
- break;
+ new = alloca(strlen(newpassword)+1);
+ sprintf(new, "%s", newpassword);
+ } else {
+ new = alloca((strlen(value) + strlen(newpassword) + 1));
+ sprintf(new, "%s%s", newpassword, value);
}
- new = alloca((strlen(value) + strlen(newpassword) + 1));
- sprintf(new, "%s%s", newpassword, value);
if (!(cat = ast_category_get(cfg, category))) {
ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
break;
@@ -13085,4 +13087,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
.load = load_module,
.unload = unload_module,
.reload = reload,
+ .nonoptreq = "res_adsi,res_smdi",
);
diff --git a/cdr/cdr_adaptive_odbc.c b/cdr/cdr_adaptive_odbc.c
index 857ad726a..f0b0e99bf 100644
--- a/cdr/cdr_adaptive_odbc.c
+++ b/cdr/cdr_adaptive_odbc.c
@@ -25,8 +25,7 @@
*/
/*** MODULEINFO
- <depend>generic_odbc</depend>
- <depend>ltdl</depend>
+ <depend>res_odbc</depend>
***/
#include "asterisk.h"
diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c
index ab4a1455d..f77d60b2c 100644
--- a/cdr/cdr_odbc.c
+++ b/cdr/cdr_odbc.c
@@ -29,8 +29,7 @@
*/
/*** MODULEINFO
- <depend>generic_odbc</depend>
- <depend>ltdl</depend>
+ <depend>res_odbc</depend>
***/
#include "asterisk.h"
diff --git a/cel/cel_adaptive_odbc.c b/cel/cel_odbc.c
index f5bd4a3c8..0a33fb4ad 100644
--- a/cel/cel_adaptive_odbc.c
+++ b/cel/cel_odbc.c
@@ -4,7 +4,7 @@
* Copyright (C) 2008 Digium
*
* Adapted from cdr_adaptive_odbc:
- * Tilghman Lesher <cdr_adaptive_odbc__v1@the-tilghman.com>
+ * Tilghman Lesher <tlesher AT digium DOT com>
* by Steve Murphy
*
* See http://www.asterisk.org for more information about
@@ -20,15 +20,14 @@
/*! \file
*
- * \brief Adaptive ODBC CEL backend
+ * \brief ODBC CEL backend
*
- * \author Tilghman Lesher <cdr_adaptive_odbc__v1@the-tilghman.com>
+ * \author Tilghman Lesher <tlesher AT digium DOT com>
* \ingroup cel_drivers
*/
/*** MODULEINFO
- <depend>generic_odbc</depend>
- <depend>ltdl</depend>
+ <depend>res_odbc</depend>
***/
#include "asterisk.h"
@@ -50,7 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cel.h"
#include "asterisk/module.h"
-#define CONFIG "cel_adaptive_odbc.conf"
+#define CONFIG "cel_odbc.conf"
static struct ast_event_sub *event_sub = NULL;
/* Optimization to reduce number of memory allocations */
@@ -99,7 +98,7 @@ static int load_config(void)
cfg = ast_config_load(CONFIG, config_flags);
if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Unable to load " CONFIG ". No adaptive ODBC CEL records!\n");
+ ast_log(LOG_WARNING, "Unable to load " CONFIG ". No ODBC CEL records!\n");
return -1;
}
@@ -161,7 +160,7 @@ static int load_config(void)
ast_copy_string(tableptr->connection, connection, lenconnection + 1);
ast_copy_string(tableptr->table, table, lentable + 1);
- ast_verb(3, "Found adaptive CEL table %s@%s.\n", tableptr->table, tableptr->connection);
+ ast_verb(3, "Found CEL table %s@%s.\n", tableptr->table, tableptr->connection);
/* Check for filters first */
for (var = ast_variable_browse(cfg, catg); var; var = var->next) {
@@ -382,7 +381,7 @@ static void odbc_log(const struct ast_event *event, void *userdata)
/* No need to check the connection now; we'll handle any failure in prepare_and_execute */
if (!(obj = ast_odbc_request_obj(tableptr->connection, 0))) {
- ast_log(LOG_WARNING, "cel_adaptive_odbc: Unable to retrieve database handle for '%s:%s'. CEL failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
+ ast_log(LOG_WARNING, "Unable to retrieve database handle for '%s:%s'. CEL failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
continue;
}
@@ -572,7 +571,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
}
break;
case SQL_INTEGER:
- {
+ if (ast_strlen_zero(colptr)) {
+ continue;
+ } else {
int integer = 0;
if (strcasecmp(entry->name, "eventtype") == 0) {
integer = (int) record.event_type;
@@ -589,7 +590,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
}
break;
case SQL_BIGINT:
- {
+ if (ast_strlen_zero(colptr)) {
+ continue;
+ } else {
long long integer = 0;
if (strcasecmp(entry->name, "eventtype") == 0) {
integer = (long long) record.event_type;
@@ -606,7 +609,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
}
break;
case SQL_SMALLINT:
- {
+ if (ast_strlen_zero(colptr)) {
+ continue;
+ } else {
short integer = 0;
if (strcasecmp(entry->name, "eventtype") == 0) {
integer = (short) record.event_type;
@@ -623,7 +628,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
}
break;
case SQL_TINYINT:
- {
+ if (ast_strlen_zero(colptr)) {
+ continue;
+ } else {
char integer = 0;
if (strcasecmp(entry->name, "eventtype") == 0) {
integer = (char) record.event_type;
@@ -640,7 +647,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
}
break;
case SQL_BIT:
- {
+ if (ast_strlen_zero(colptr)) {
+ continue;
+ } else {
char integer = 0;
if (strcasecmp(entry->name, "eventtype") == 0) {
integer = (char) record.event_type;
@@ -660,7 +669,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
break;
case SQL_NUMERIC:
case SQL_DECIMAL:
- {
+ if (ast_strlen_zero(colptr)) {
+ continue;
+ } else {
double number = 0.0;
if (strcasecmp(entry->name, "eventtype") == 0) {
number = (double)record.event_type;
@@ -679,7 +690,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
case SQL_FLOAT:
case SQL_REAL:
case SQL_DOUBLE:
- {
+ if (ast_strlen_zero(colptr)) {
+ continue;
+ } else {
double number = 0.0;
if (strcasecmp(entry->name, "eventtype") == 0) {
number = (double) record.event_type;
@@ -717,7 +730,7 @@ static void odbc_log(const struct ast_event *event, void *userdata)
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
}
if (rows == 0) {
- ast_log(LOG_WARNING, "cel_adaptive_odbc: Insert failed on '%s:%s'. CEL failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
+ ast_log(LOG_WARNING, "Insert failed on '%s:%s'. CEL failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
}
early_release:
ast_odbc_release_obj(obj);
@@ -742,9 +755,9 @@ static int unload_module(void)
event_sub = ast_event_unsubscribe(event_sub);
}
if (AST_RWLIST_WRLOCK(&odbc_tables)) {
- event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "Adaptive ODBC CEL backend", NULL, AST_EVENT_IE_END);
+ event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "ODBC CEL backend", NULL, AST_EVENT_IE_END);
if (!event_sub) {
- ast_log(LOG_ERROR, "cel_adaptive_odbc: Unable to subscribe to CEL events\n");
+ ast_log(LOG_ERROR, "Unable to subscribe to CEL events\n");
}
ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n");
return -1;
@@ -763,9 +776,9 @@ static int load_module(void)
}
load_config();
AST_RWLIST_UNLOCK(&odbc_tables);
- event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "Adaptive ODBC CEL backend", NULL, AST_EVENT_IE_END);
+ event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "ODBC CEL backend", NULL, AST_EVENT_IE_END);
if (!event_sub) {
- ast_log(LOG_ERROR, "cel_odbc: Unable to subscribe to CEL events\n");
+ ast_log(LOG_ERROR, "Unable to subscribe to CEL events\n");
}
return AST_MODULE_LOAD_SUCCESS;
}
@@ -783,7 +796,7 @@ static int reload(void)
return AST_MODULE_LOAD_SUCCESS;
}
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Adaptive ODBC CEL backend",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ODBC CEL backend",
.load = load_module,
.unload = unload_module,
.reload = reload,
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index b8e142d04..37a6688d7 100644
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -32,6 +32,7 @@
*/
/*** MODULEINFO
<depend>chan_local</depend>
+ <depend>res_monitor</depend>
***/
#include "asterisk.h"
@@ -2484,4 +2485,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Agent Proxy Channel",
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+ .nonoptreq = "res_monitor,chan_local",
);
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index df03a5805..364c85d04 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -38,7 +38,7 @@
*/
/*** MODULEINFO
- <depend>res_smdi</depend>
+ <use>res_smdi</use>
<depend>dahdi</depend>
<depend>tonezone</depend>
<use>pri</use>
@@ -2887,6 +2887,7 @@ static void my_pri_fixup_chans(void *chan_old, void *chan_new)
/* More stuff to transfer to the new channel. */
new_chan->law = old_chan->law;
+ strcpy(new_chan->dialstring, old_chan->dialstring);
}
#endif /* defined(HAVE_PRI) */
@@ -3111,7 +3112,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
if (pri->pvts[idx]->owner
#if defined(HAVE_PRI_SERVICE_MESSAGES)
/* Out-of-service B channels are "in-use". */
- && pri->pvts[idx]->service_status
+ || pri->pvts[idx]->service_status
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
) {
++in_use;
@@ -13708,25 +13709,36 @@ static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
ast_cli(a->fd, "No PRI running on span %d\n", span);
return CLI_SUCCESS;
}
+
+ /* Set debug level in libpri */
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
- if (pris[span-1].pri.dchans[x]) {
- if (level == 1) {
- pri_set_debug(pris[span-1].pri.dchans[x], SIG_PRI_DEBUG_NORMAL);
- ast_cli(a->fd, "Enabled debugging on span %d\n", span);
- } else if (level == 0) {
- pri_set_debug(pris[span-1].pri.dchans[x], 0);
- /* close the file if it's set */
- ast_mutex_lock(&pridebugfdlock);
- close(pridebugfd);
- pridebugfd = -1;
- ast_cli(a->fd, "PRI debug output to file disabled\n");
- ast_mutex_unlock(&pridebugfdlock);
- } else {
- pri_set_debug(pris[span-1].pri.dchans[x], SIG_PRI_DEBUG_INTENSE);
- ast_cli(a->fd, "Enabled debugging on span %d\n", span);
+ if (pris[span - 1].pri.dchans[x]) {
+ switch (level) {
+ case 0:
+ pri_set_debug(pris[span - 1].pri.dchans[x], 0);
+ break;
+ case 1:
+ pri_set_debug(pris[span - 1].pri.dchans[x], SIG_PRI_DEBUG_NORMAL);
+ break;
+ default:
+ pri_set_debug(pris[span - 1].pri.dchans[x], SIG_PRI_DEBUG_INTENSE);
+ break;
}
}
}
+ if (level == 0) {
+ /* Close the debugging file if it's set */
+ ast_mutex_lock(&pridebugfdlock);
+ if (0 <= pridebugfd) {
+ close(pridebugfd);
+ pridebugfd = -1;
+ ast_cli(a->fd, "Disabled PRI debug output to file '%s'\n",
+ pridebugfilename);
+ }
+ ast_mutex_unlock(&pridebugfdlock);
+ }
+ pris[span - 1].pri.debug = (level) ? 1 : 0;
+ ast_cli(a->fd, "%s debugging on span %d\n", (level) ? "Enabled" : "Disabled", span);
return CLI_SUCCESS;
}
#endif /* defined(HAVE_PRI) */
@@ -13943,7 +13955,7 @@ static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_
int x;
int span;
int count=0;
- int debug=0;
+ int debug;
switch (cmd) {
case CLI_INIT:
@@ -13959,7 +13971,6 @@ static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_
for (span = 0; span < NUM_SPANS; span++) {
if (pris[span].pri.pri) {
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
- debug = 0;
if (pris[span].pri.dchans[x]) {
debug = pri_get_debug(pris[span].pri.dchans[x]);
ast_cli(a->fd, "Span %d: Debug: %s\tIntense: %s\n", span+1, (debug&PRI_DEBUG_Q931_STATE)? "Yes" : "No" ,(debug&PRI_DEBUG_Q921_RAW)? "Yes" : "No" );
@@ -13975,7 +13986,7 @@ static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_
ast_mutex_unlock(&pridebugfdlock);
if (!count)
- ast_cli(a->fd, "No debug set or no PRI running\n");
+ ast_cli(a->fd, "No PRI running\n");
return CLI_SUCCESS;
}
#endif /* defined(HAVE_PRI) */
@@ -17915,4 +17926,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, tdesc,
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+ .nonoptreq = "res_smdi",
);
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 5bb6b2c59..b05adaa1a 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -268,6 +268,9 @@ static char default_parkinglot[AST_MAX_CONTEXT];
static char language[MAX_LANGUAGE] = "";
static char regcontext[AST_MAX_CONTEXT] = "";
+static struct ast_event_sub *network_change_event_subscription; /*!< subscription id for network change events */
+static int network_change_event_sched_id = -1;
+
static int maxauthreq = 3;
static int max_retries = 4;
static int ping_time = 21;
@@ -355,6 +358,8 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
static struct io_context *io;
static struct ast_sched_thread *sched;
+#define DONT_RESCHEDULE -2
+
static format_t iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH;
static int iaxdebug = 0;
@@ -1177,6 +1182,8 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat
static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *datalen);
static int iax2_transfer(struct ast_channel *c, const char *dest);
static int iax2_write(struct ast_channel *c, struct ast_frame *f);
+static int iax2_sched_add(struct ast_sched_thread *st, int when, ast_sched_cb callback, const void *data);
+
static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now);
static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
@@ -1201,6 +1208,7 @@ static void build_rand_pad(unsigned char *buf, ssize_t len);
static struct callno_entry *get_unused_callno(int trunk, int validated);
static int replace_callno(const void *obj);
static void sched_delay_remove(struct sockaddr_in *sin, struct callno_entry *callno_entry);
+static void network_change_event_cb(const struct ast_event *, void *);
static const struct ast_channel_tech iax2_tech = {
.type = "IAX2",
@@ -1236,6 +1244,47 @@ static void mwi_event_cb(const struct ast_event *event, void *userdata)
* is time to send MWI, since it is only sent with a REGACK. */
}
+static void network_change_event_subscribe(void)
+{
+ if (!network_change_event_subscription) {
+ network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
+ network_change_event_cb,
+ "SIP Network Change ",
+ NULL,
+ AST_EVENT_IE_END);
+ }
+}
+
+static void network_change_event_unsubscribe(void)
+{
+ if (network_change_event_subscription) {
+ network_change_event_subscription = ast_event_unsubscribe(network_change_event_subscription);
+ }
+}
+
+static int network_change_event_sched_cb(const void *data)
+{
+ struct iax2_registry *reg;
+ network_change_event_sched_id = -1;
+ AST_LIST_LOCK(&registrations);
+ AST_LIST_TRAVERSE(&registrations, reg, entry) {
+ iax2_do_register(reg);
+ }
+ AST_LIST_UNLOCK(&registrations);
+
+ return 0;
+}
+
+static void network_change_event_cb(const struct ast_event *event, void *userdata)
+{
+ ast_debug(1, "IAX, got a network change event, renewing all IAX registrations.\n");
+ if (network_change_event_sched_id == -1) {
+ network_change_event_sched_id = iax2_sched_add(sched, 1000, network_change_event_sched_cb, NULL);
+ }
+
+}
+
+
/*! \brief Send manager event at call setup to link between Asterisk channel name
and IAX2 call identifiers */
static void iax2_ami_channelupdate(struct chan_iax2_pvt *pvt)
@@ -1246,7 +1295,6 @@ static void iax2_ami_channelupdate(struct chan_iax2_pvt *pvt)
pvt->callno, pvt->peercallno, pvt->peer ? pvt->peer : "");
}
-
static struct ast_datastore_info iax2_variable_datastore_info = {
.type = "IAX2_VARIABLE",
.duplicate = iax2_dup_variable_datastore,
@@ -1427,10 +1475,9 @@ static void __send_ping(const void *data)
if (iaxs[callno]) {
if (iaxs[callno]->peercallno) {
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
- iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
- } else {
- /* I am the schedule, so I'm allowed to do this */
- iaxs[callno]->pingid = -1;
+ if (iaxs[callno]->pingid != DONT_RESCHEDULE) {
+ iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
+ }
}
} else {
ast_debug(1, "I was supposed to send a PING with callno %d, but no such call exists.\n", callno);
@@ -1441,9 +1488,16 @@ static void __send_ping(const void *data)
static int send_ping(const void *data)
{
+ int callno = (long) data;
+ ast_mutex_lock(&iaxsl[callno]);
+ if (iaxs[callno] && iaxs[callno]->pingid != DONT_RESCHEDULE) {
+ iaxs[callno]->pingid = -1;
+ }
+ ast_mutex_unlock(&iaxsl[callno]);
+
#ifdef SCHED_MULTITHREADED
if (schedule_action(__send_ping, data))
-#endif
+#endif
__send_ping(data);
return 0;
@@ -1488,10 +1542,9 @@ static void __send_lagrq(const void *data)
if (iaxs[callno]) {
if (iaxs[callno]->peercallno) {
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
- iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
- } else {
- /* I am the schedule, so I'm allowed to do this */
- iaxs[callno]->lagid = -1;
+ if (iaxs[callno]->lagid != DONT_RESCHEDULE) {
+ iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
+ }
}
} else {
ast_debug(1, "I was supposed to send a LAGRQ with callno %d, but no such call exists.\n", callno);
@@ -1502,11 +1555,17 @@ static void __send_lagrq(const void *data)
static int send_lagrq(const void *data)
{
+ int callno = (long) data;
+ ast_mutex_lock(&iaxsl[callno]);
+ if (iaxs[callno] && iaxs[callno]->lagid != DONT_RESCHEDULE) {
+ iaxs[callno]->lagid = -1;
+ }
+ ast_mutex_unlock(&iaxsl[callno]);
+
#ifdef SCHED_MULTITHREADED
if (schedule_action(__send_lagrq, data))
-#endif
+#endif
__send_lagrq(data);
-
return 0;
}
@@ -1688,7 +1747,9 @@ static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
}
/* No more pings or lagrq's */
AST_SCHED_DEL_SPINLOCK(ast_sched_thread_get_context(sched), pvt->pingid, &iaxsl[pvt->callno]);
+ pvt->pingid = DONT_RESCHEDULE;
AST_SCHED_DEL_SPINLOCK(ast_sched_thread_get_context(sched), pvt->lagid, &iaxsl[pvt->callno]);
+ pvt->lagid = DONT_RESCHEDULE;
ast_sched_thread_del(sched, pvt->autoid);
ast_sched_thread_del(sched, pvt->authid);
ast_sched_thread_del(sched, pvt->initid);
@@ -6986,13 +7047,14 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
astman_append(s,
"Event: RegistryEntry\r\n"
+ "%s"
"Host: %s\r\n"
"DNSmanager: %s\r\n"
"Username: %s\r\n"
"Perceived: %s\r\n"
"Refresh: %d\r\n"
"State: %s\r\n"
- "\r\n", host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived,
+ "\r\n", idtext, host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived,
reg->refresh, regstate2str(reg->regstate));
total++;
@@ -10428,6 +10490,7 @@ retryowner:
/* No authentication required, let them in */
memset(&ied1, 0, sizeof(ied1));
iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
+ iax_ie_append_versioned_uint64(&ied1, IAX_IE_FORMAT2, 0, format);
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
if (strcmp(iaxs[fr->callno]->exten, "TBD")) {
ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
@@ -10893,6 +10956,7 @@ retryowner2:
/* Authentication received */
memset(&ied1, 0, sizeof(ied1));
iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
+ iax_ie_append_versioned_uint64(&ied1, IAX_IE_FORMAT2, 0, format);
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
if (strcmp(iaxs[fr->callno]->exten, "TBD")) {
ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
@@ -12779,7 +12843,8 @@ static int set_config(const char *config_file, int reload)
int format;
int portno = IAX_DEFAULT_PORTNO;
int x;
- int mtuv;
+ int mtuv;
+ int subscribe_network_change = 1;
struct iax2_user *user;
struct iax2_peer *peer;
struct ast_netsock *ns;
@@ -13097,6 +13162,14 @@ static int set_config(const char *config_file, int reload)
if (add_calltoken_ignore(v->value)) {
ast_log(LOG_WARNING, "Invalid calltokenoptional address range - '%s' line %d\n", v->value, v->lineno);
}
+ } else if (!strcasecmp(v->name, "subscribe_network_change_event")) {
+ if (ast_true(v->value)) {
+ subscribe_network_change = 1;
+ } else if (ast_false(v->value)) {
+ subscribe_network_change = 0;
+ } else {
+ ast_log(LOG_WARNING, "subscribe_network_change_event value %s is not valid at line %d.\n", v->value, v->lineno);
+ }
} else if (!strcasecmp(v->name, "shrinkcallerid")) {
if (ast_true(v->value)) {
ast_set_flag64((&globalflags), IAX_SHRINKCALLERID);
@@ -13109,7 +13182,13 @@ static int set_config(const char *config_file, int reload)
/* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
v = v->next;
}
-
+
+ if (subscribe_network_change) {
+ network_change_event_subscribe();
+ } else {
+ network_change_event_unsubscribe();
+ }
+
if (defaultsockfd < 0) {
if (!(ns = ast_netsock_bind(netsock, io, "0.0.0.0", portno, qos.tos, qos.cos, socket_read, NULL))) {
ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
@@ -14050,6 +14129,8 @@ static int __unload_module(void)
struct ast_context *con;
int x;
+ network_change_event_unsubscribe();
+
ast_manager_unregister("IAXpeers");
ast_manager_unregister("IAXpeerlist");
ast_manager_unregister("IAXnetstats");
@@ -14530,6 +14611,8 @@ static int load_module(void)
ast_realtime_require_field("iaxpeers", "name", RQ_CHAR, 10, "ipaddr", RQ_CHAR, 15, "port", RQ_UINTEGER2, 5, "regseconds", RQ_UINTEGER2, 6, SENTINEL);
+ network_change_event_subscribe();
+
return AST_MODULE_LOAD_SUCCESS;
}
@@ -14538,4 +14621,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Inter Asterisk eXchan
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+ .nonoptreq = "res_crypto",
);
diff --git a/channels/chan_local.c b/channels/chan_local.c
index d1f66f8dd..aebca441a 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -409,6 +409,38 @@ static void check_bridge(struct local_pvt *p)
p->chan->audiohooks = p->owner->audiohooks;
p->owner->audiohooks = audiohooks_swapper;
}
+
+ /* If any Caller ID was set, preserve it after masquerade like above. We must check
+ * to see if Caller ID was set because otherwise we'll mistakingly copy info not
+ * set from the dialplan and will overwrite the real channel Caller ID. The reason
+ * for this whole preswapping action is because the Caller ID is set on the channel
+ * thread (which is the to be masqueraded away local channel) before both local
+ * channels are optimized away.
+ */
+ if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid
+ || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid
+ || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) {
+ struct ast_party_caller tmp;
+ tmp = p->owner->caller;
+ p->owner->caller = p->chan->_bridge->caller;
+ p->chan->_bridge->caller = tmp;
+ }
+ if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid
+ || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid
+ || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) {
+ struct ast_party_redirecting tmp;
+ tmp = p->owner->redirecting;
+ p->owner->redirecting = p->chan->_bridge->redirecting;
+ p->chan->_bridge->redirecting = tmp;
+ }
+ if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) {
+ struct ast_party_dialed tmp;
+ tmp = p->owner->dialed;
+ p->owner->dialed = p->chan->_bridge->dialed;
+ p->chan->_bridge->dialed = tmp;
+ }
+
+
ast_app_group_update(p->chan, p->owner);
ast_channel_masquerade(p->owner, p->chan->_bridge);
ast_set_flag(p, LOCAL_ALREADY_MASQED);
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 485b39aad..2f953a9ae 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -30,7 +30,7 @@
*/
/*** MODULEINFO
- <depend>res_pktccops</depend>
+ <use>res_pktccops</use>
***/
#include "asterisk.h"
@@ -3580,7 +3580,7 @@ static int find_and_retrans(struct mgcp_subchannel *sub, struct mgcp_request *re
if (sscanf(req->identifier, "%30d", &seqno) != 1) {
seqno = 0;
}
- for (cur = sub->parent->parent->responses, next = cur->next; cur; cur = next, next = cur->next) {
+ for (cur = sub->parent->parent->responses, next = cur ? cur->next : NULL; cur; cur = next, next = cur ? cur->next : NULL) {
if (now - cur->whensent > RESPONSE_TIMEOUT) {
/* Delete this entry */
if (prev)
@@ -4915,4 +4915,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Media Gateway Control
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+ .nonoptreq = "res_pktccops",
);
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 8b31ed23a..d326e1511 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -6011,7 +6011,7 @@ static int read_config(struct chan_list *ch)
* \param ast Current Asterisk channel
* \param id Party id information to send to the other side
* \param source Why are we sending this update
- * \param cid_tag Caller ID tag to set in the connected line
+ * \param cid_tag User tag to apply to the party id.
*
* \return Nothing
*/
@@ -6036,6 +6036,61 @@ static void misdn_queue_connected_line_update(struct ast_channel *ast, const str
/*!
* \internal
+ * \brief Update the caller id party on this channel.
+ *
+ * \param ast Current Asterisk channel
+ * \param id Remote party id information to update.
+ * \param cid_tag User tag to apply to the party id.
+ *
+ * \return Nothing
+ */
+static void misdn_update_caller_id(struct ast_channel *ast, const struct misdn_party_id *id, char *cid_tag)
+{
+ struct ast_party_caller caller;
+ struct ast_set_party_caller update_caller;
+
+ memset(&update_caller, 0, sizeof(update_caller));
+ update_caller.id.number = 1;
+ update_caller.ani.number = 1;
+
+ ast_channel_lock(ast);
+ ast_party_caller_set_init(&caller, &ast->caller);
+
+ caller.id.number.valid = 1;
+ caller.id.number.str = (char *) id->number;
+ caller.id.number.plan = misdn_to_ast_ton(id->number_type)
+ | misdn_to_ast_plan(id->number_plan);
+ caller.id.number.presentation = misdn_to_ast_pres(id->presentation)
+ | misdn_to_ast_screen(id->screening);
+
+ caller.ani.number = caller.id.number;
+
+ caller.id.tag = cid_tag;
+ caller.ani.tag = cid_tag;
+
+ ast_channel_set_caller_event(ast, &caller, &update_caller);
+ ast_channel_unlock(ast);
+}
+
+/*!
+ * \internal
+ * \brief Update the remote party id information.
+ *
+ * \param ast Current Asterisk channel
+ * \param id Remote party id information to update.
+ * \param source Why are we sending this update
+ * \param cid_tag User tag to apply to the party id.
+ *
+ * \return Nothing
+ */
+static void misdn_update_remote_party(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source, char *cid_tag)
+{
+ misdn_update_caller_id(ast, id, cid_tag);
+ misdn_queue_connected_line_update(ast, id, source, cid_tag);
+}
+
+/*!
+ * \internal
* \brief Get the connected line information out of the Asterisk channel.
*
* \param ast Current Asterisk channel
@@ -7160,15 +7215,14 @@ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame
static struct ast_frame *misdn_read(struct ast_channel *ast)
{
struct chan_list *tmp;
- fd_set rrfs;
- struct timeval tv = { 0, 20000 };
int len, t;
+ struct pollfd pfd = { .fd = -1, .events = POLLIN };
if (!ast) {
chan_misdn_log(1, 0, "misdn_read called without ast\n");
return NULL;
}
- if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
+ if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
return NULL;
}
@@ -7178,21 +7232,18 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
return NULL;
}
- FD_ZERO(&rrfs);
- FD_SET(tmp->pipe[0], &rrfs);
-
- t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv);
- if (!t) {
- chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
- len = 160;
- }
+ pfd.fd = tmp->pipe[0];
+ t = ast_poll(&pfd, 1, 20);
if (t < 0) {
- chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n", strerror(errno));
+ chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
return NULL;
}
- if (FD_ISSET(tmp->pipe[0], &rrfs)) {
+ if (!t) {
+ chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
+ len = 160;
+ } else if (pfd.revents & POLLIN) {
len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));
if (len <= 0) {
@@ -9161,7 +9212,7 @@ static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel
* The consequences if we wind up sending two updates is benign.
* The other end will think that it got transferred twice.
*/
- misdn_queue_connected_line_update(ch->ast, &party_id,
+ misdn_update_remote_party(ch->ast, &party_id,
(bc->fac_in.u.EctInform.Status == 0 /* alerting */)
? AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
: AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
@@ -10233,7 +10284,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
/* Update the connected line information on the other channel */
- misdn_queue_connected_line_update(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, bc->incoming_cid_tag);
+ misdn_update_remote_party(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, bc->incoming_cid_tag);
}
ch->l3id = bc->l3_id;
@@ -10456,25 +10507,21 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
ast_queue_frame(ch->ast, &frame);
}
} else {
- fd_set wrfs;
- struct timeval tv = { 0, 0 };
+ struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
int t;
- FD_ZERO(&wrfs);
- FD_SET(ch->pipe[1], &wrfs);
+ t = ast_poll(&pfd, 1, 0);
- t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
- if (!t) {
- chan_misdn_log(9, bc->port, "Select Timed out\n");
+ if (t < 0) {
+ chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
break;
}
-
- if (t < 0) {
- chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
+ if (!t) {
+ chan_misdn_log(9, bc->port, "poll() timed out\n");
break;
}
- if (FD_ISSET(ch->pipe[1], &wrfs)) {
+ if (pfd.revents & POLLOUT) {
chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
@@ -10636,7 +10683,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
if (bc->redirecting.to_changed) {
bc->redirecting.to_changed = 0;
if (ch && ch->ast) {
- misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
+ misdn_update_remote_party(ch->ast, &bc->redirecting.to,
AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, bc->incoming_cid_tag);
}
}
@@ -10645,7 +10692,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
if (bc->redirecting.to_changed) {
bc->redirecting.to_changed = 0;
if (ch && ch->ast) {
- misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
+ misdn_update_remote_party(ch->ast, &bc->redirecting.to,
AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
}
}
diff --git a/channels/chan_multicast_rtp.c b/channels/chan_multicast_rtp.c
index e3414d2f3..93f46473f 100644
--- a/channels/chan_multicast_rtp.c
+++ b/channels/chan_multicast_rtp.c
@@ -126,11 +126,6 @@ static struct ast_channel *multicast_rtp_request(const char *type, format_t form
}
*destination++ = '\0';
- if (!ast_sockaddr_parse(&destination_address, destination,
- PARSE_PORT_REQUIRE)) {
- goto failure;
- }
-
if ((control = strchr(destination, '/'))) {
*control++ = '\0';
if (!ast_sockaddr_parse(&control_address, control,
@@ -139,6 +134,11 @@ static struct ast_channel *multicast_rtp_request(const char *type, format_t form
}
}
+ if (!ast_sockaddr_parse(&destination_address, destination,
+ PARSE_PORT_REQUIRE)) {
+ goto failure;
+ }
+
if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, multicast_type))) {
goto failure;
}
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index 48da10fd6..531b95cb5 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -1017,12 +1017,12 @@ static void phone_check_exception(struct phone_pvt *i)
static void *do_monitor(void *data)
{
- fd_set rfds, efds;
- int n, res;
+ struct pollfd *fds = NULL;
+ int nfds = 0, inuse_fds = 0, res;
struct phone_pvt *i;
int tonepos = 0;
/* The tone we're playing this round */
- struct timeval wait = {0,0};
+ struct timeval tv = { 0, 0 };
int dotone;
/* This thread monitors all the frame relay interfaces which are not yet in use
(and thus do not have a separate thread) indefinitely */
@@ -1036,33 +1036,38 @@ static void *do_monitor(void *data)
}
/* Build the stuff we're going to select on, that is the socket of every
phone_pvt that does not have an associated owner channel */
- n = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&efds);
i = iflist;
dotone = 0;
- while (i) {
- if (FD_ISSET(i->fd, &rfds))
- ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
+ inuse_fds = 0;
+ for (i = iflist; i; i = i->next) {
if (!i->owner) {
/* This needs to be watched, as it lacks an owner */
- FD_SET(i->fd, &rfds);
- FD_SET(i->fd, &efds);
- if (i->fd > n)
- n = i->fd;
+ if (inuse_fds == nfds) {
+ void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
+ if (!tmp) {
+ /* Avoid leaking */
+ continue;
+ }
+ fds = tmp;
+ nfds++;
+ }
+ fds[inuse_fds].fd = i->fd;
+ fds[inuse_fds].events = POLLIN | POLLERR;
+ fds[inuse_fds].revents = 0;
+ inuse_fds++;
+
if (i->dialtone && i->mode != MODE_SIGMA) {
/* Remember we're going to have to come back and play
more dialtones */
- if (ast_tvzero(wait)) {
+ if (ast_tvzero(tv)) {
/* If we're due for a dialtone, play one */
- if (write(i->fd, DialTone + tonepos, 240) != 240)
+ if (write(i->fd, DialTone + tonepos, 240) != 240) {
ast_log(LOG_WARNING, "Dial tone write error\n");
+ }
}
dotone++;
}
}
-
- i = i->next;
}
/* Okay, now that we know what to do, release the interface lock */
ast_mutex_unlock(&iflock);
@@ -1071,26 +1076,28 @@ static void *do_monitor(void *data)
if (dotone && i && i->mode != MODE_SIGMA) {
/* If we're ready to recycle the time, set it to 30 ms */
tonepos += 240;
- if (tonepos >= sizeof(DialTone))
- tonepos = 0;
- if (ast_tvzero(wait)) {
- wait = ast_tv(30000, 0);
+ if (tonepos >= sizeof(DialTone)) {
+ tonepos = 0;
}
- res = ast_select(n + 1, &rfds, NULL, &efds, &wait);
+ if (ast_tvzero(tv)) {
+ tv = ast_tv(0, 30000);
+ }
+ res = ast_poll2(fds, inuse_fds, &tv);
} else {
- res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
- wait = ast_tv(0,0);
+ res = ast_poll(fds, inuse_fds, -1);
+ tv = ast_tv(0, 0);
tonepos = 0;
}
/* Okay, select has finished. Let's see what happened. */
if (res < 0) {
- ast_debug(1, "select return %d: %s\n", res, strerror(errno));
+ ast_debug(1, "poll returned %d: %s\n", res, strerror(errno));
continue;
}
/* If there are no fd's changed, just continue, it's probably time
to play some more dialtones */
- if (!res)
+ if (!res) {
continue;
+ }
/* Alright, lock the interface list again, and let's look and see what has
happened */
if (ast_mutex_lock(&iflock)) {
@@ -1098,15 +1105,27 @@ static void *do_monitor(void *data)
continue;
}
- i = iflist;
- for(; i; i=i->next) {
- if (FD_ISSET(i->fd, &rfds)) {
+ for (i = iflist; i; i = i->next) {
+ int j;
+ /* Find the record */
+ for (j = 0; j < inuse_fds; j++) {
+ if (fds[j].fd == i->fd) {
+ break;
+ }
+ }
+
+ /* Not found? */
+ if (j == inuse_fds) {
+ continue;
+ }
+
+ if (fds[j].revents & POLLIN) {
if (i->owner) {
continue;
}
phone_mini_packet(i);
}
- if (FD_ISSET(i->fd, &efds)) {
+ if (fds[j].revents & POLLERR) {
if (i->owner) {
continue;
}
@@ -1116,7 +1135,6 @@ static void *do_monitor(void *data)
ast_mutex_unlock(&iflock);
}
return NULL;
-
}
static int restart_monitor()
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 47dc2610d..805b372ad 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -162,6 +162,7 @@
*/
/*** MODULEINFO
+ <depend>res_crypto</depend>
<depend>chan_local</depend>
***/
@@ -259,7 +260,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/translate.h"
#include "asterisk/ast_version.h"
#include "asterisk/event.h"
-#include "asterisk/stun.h"
#include "asterisk/cel.h"
#include "asterisk/data.h"
#include "asterisk/aoc.h"
@@ -762,6 +762,9 @@ static int regobjs = 0; /*!< Registry objects */
static struct ast_flags global_flags[3] = {{0}}; /*!< global SIP_ flags */
static int global_t38_maxdatagram; /*!< global T.38 FaxMaxDatagram override */
+static struct ast_event_sub *network_change_event_subscription; /*!< subscription id for network change events */
+static int network_change_event_sched_id = -1;
+
static char used_context[AST_MAX_CONTEXT]; /*!< name of automatically created context for unloading */
AST_MUTEX_DEFINE_STATIC(netlock);
@@ -1142,9 +1145,6 @@ static struct ast_sockaddr internip;
* hostname is stored in externhost, and the hostname->IP mapping
* is refreshed every 'externrefresh' seconds;
*
- * + with "stunaddr = host[:port]" we run queries every externrefresh seconds
- * to the specified server, and store the result in externaddr.
- *
* Other variables (externhost, externexpire, externrefresh) are used
* to support the above functions.
*/
@@ -1154,7 +1154,6 @@ static struct ast_sockaddr media_address; /*!< External RTP IP address if we are
static char externhost[MAXHOSTNAMELEN]; /*!< External host name */
static time_t externexpire; /*!< Expiration counter for re-resolving external host name in dynamic DNS */
static int externrefresh = 10; /*!< Refresh timer for DNS-based external address (dyndns) */
-static struct sockaddr_in stunaddr; /*!< stun server address */
static uint16_t externtcpport; /*!< external tcp port */
static uint16_t externtlsport; /*!< external tls port */
@@ -1334,6 +1333,7 @@ static int sip_poke_peer(struct sip_peer *peer, int force);
static void sip_poke_all_peers(void);
static void sip_peer_hold(struct sip_pvt *p, int hold);
static void mwi_event_cb(const struct ast_event *, void *);
+static void network_change_event_cb(const struct ast_event *, void *);
/*--- Applications, functions, CLI and manager command helpers */
static const char *sip_nat_mode(const struct sip_pvt *p);
@@ -1512,7 +1512,7 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
static int handle_request_message(struct sip_pvt *p, struct sip_request *req);
static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e);
static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
-static int handle_request_options(struct sip_pvt *p, struct sip_request *req);
+static int handle_request_options(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *nounlock);
static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e);
static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno, int *nounlock);
@@ -2622,6 +2622,32 @@ cleanup:
return NULL;
}
+/* this func is used with ao2_callback to unlink/delete all marked
+ peers */
+static int peer_is_marked(void *peerobj, void *arg, int flags)
+{
+ struct sip_peer *peer = peerobj;
+ return peer->the_mark ? CMP_MATCH : 0;
+}
+
+
+/* \brief Unlink all marked peers from ao2 containers */
+static void unlink_marked_peers_from_tables(void)
+{
+ ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
+ "initiating callback to remove marked peers");
+ ao2_t_callback(peers_by_ip, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
+ "initiating callback to remove marked peers");
+}
+
+/* \brief Unlink single peer from all ao2 containers */
+static void unlink_peer_from_tables(struct sip_peer *peer)
+{
+ ao2_t_unlink(peers, peer, "ao2_unlink of peer from peers table");
+ if (!ast_sockaddr_isnull(&peer->addr)) {
+ ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table");
+ }
+}
/*!
* helper functions to unreference various types of objects.
@@ -3112,14 +3138,13 @@ static void build_via(struct sip_pvt *p)
static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us, struct sip_pvt *p)
{
struct ast_sockaddr theirs;
- struct sockaddr_in externaddr_sin;
/* Set want_remap to non-zero if we want to remap 'us' to an externally
* reachable IP address and port. This is done if:
* 1. we have a localaddr list (containing 'internal' addresses marked
* as 'deny', so ast_apply_ha() will return AST_SENSE_DENY on them,
* and AST_SENSE_ALLOW on 'external' ones);
- * 2. either stunaddr or externaddr is set, so we know what to use as the
+ * 2. externaddr is set, so we know what to use as the
* externally visible address;
* 3. the remote address, 'them', is external;
* 4. the address returned by ast_ouraddrfor() is 'internal' (AST_SENSE_DENY
@@ -3141,22 +3166,16 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
}
} else {
want_remap = localaddr &&
- !(ast_sockaddr_isnull(&externaddr) && stunaddr.sin_addr.s_addr) &&
+ !ast_sockaddr_isnull(&externaddr) &&
ast_apply_ha(localaddr, &theirs) == AST_SENSE_ALLOW ;
}
if (want_remap &&
(!sip_cfg.matchexternaddrlocally || !ast_apply_ha(localaddr, us)) ) {
- /* if we used externhost or stun, see if it is time to refresh the info */
+ /* if we used externhost, see if it is time to refresh the info */
if (externexpire && time(NULL) >= externexpire) {
- if (stunaddr.sin_addr.s_addr) {
- ast_sockaddr_to_sin(&externaddr, &externaddr_sin);
- ast_stun_request(sipsock, &stunaddr, NULL, &externaddr_sin);
- } else {
- if (ast_sockaddr_resolve_first(&externaddr, externhost, 0)) {
- ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost);
- }
- externexpire = time(NULL);
+ if (ast_sockaddr_resolve_first(&externaddr, externhost, 0)) {
+ ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost);
}
externexpire = time(NULL) + externrefresh;
}
@@ -3182,9 +3201,6 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka
break;
}
}
- else {
- ast_log(LOG_WARNING, "stun failed\n");
- }
ast_debug(1, "Target address %s is not local, substituting externaddr\n",
ast_sockaddr_stringify(them));
} else if (p) {
@@ -3341,7 +3357,6 @@ static int retrans_pkt(const void *data)
append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data->str);
xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
- sip_pvt_unlock(pkt->owner);
/* If there was no error during the network transmission, schedule the next retransmission,
* but if the next retransmission is going to be beyond our timeout period, mark the packet's
@@ -3353,6 +3368,7 @@ static int retrans_pkt(const void *data)
pkt->retrans_stop = 1;
reschedule = diff;
}
+ sip_pvt_unlock(pkt->owner);
return reschedule;
}
}
@@ -3584,10 +3600,6 @@ static int __sip_autodestruct(const void *data)
}
}
- if (p->relatedpeer) {
- p->relatedpeer = unref_peer(p->relatedpeer, "__sip_autodestruct: unref peer p->relatedpeer"); /* Remove link to peer. If it's realtime, make sure it's gone from memory) */
- }
-
/* Reset schedule ID */
p->autokillid = -1;
@@ -4774,7 +4786,7 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
- ast_rtp_instance_set_qos(dialog->rtp, global_tos_audio, 0, "SIP RTP");
+ ast_rtp_instance_set_qos(dialog->rtp, global_tos_audio, global_cos_audio, "SIP RTP");
do_setnat(dialog);
@@ -5255,8 +5267,7 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
if (p->owner) {
if (lockowner)
ast_channel_lock(p->owner);
- if (option_debug)
- ast_log(LOG_DEBUG, "Detaching from %s\n", p->owner->name);
+ ast_debug(1, "Detaching from %s\n", p->owner->name);
p->owner->tech_pvt = NULL;
/* Make sure that the channel knows its backend is going away */
p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
@@ -5823,12 +5834,10 @@ static int sip_hangup(struct ast_channel *ast)
if (!p->alreadygone && p->initreq.data && !ast_strlen_zero(p->initreq.data->str)) {
if (needcancel) { /* Outgoing call, not up */
if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- /* stop retransmitting an INVITE that has not received a response */
/* if we can't send right now, mark it pending */
if (p->invitestate == INV_CALLING) {
/* We can't send anything in CALLING state */
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- __sip_pretend_ack(p);
/* Do we need a timer here if we don't hear from them at all? Yes we do or else we will get hung dialogs and those are no fun. */
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
append_history(p, "DELAY", "Not sending cancel, waiting for timeout");
@@ -6416,7 +6425,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
* just says they are waiting to get AOC-E before completely tearing
* the call down. Since SIP does not support this at the moment go
* ahead and terminate the call here to avoid an unnecessary timeout. */
- ast_log(LOG_DEBUG, "AOC-E termination request received on %s. This is not yet supported on sip. Continue with hangup \n", p->owner->name);
+ ast_debug(1, "AOC-E termination request received on %s. This is not yet supported on sip. Continue with hangup \n", p->owner->name);
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
}
break;
@@ -6882,8 +6891,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
f = ast_dsp_process(p->owner, p->dsp, f);
if (f && f->frametype == AST_FRAME_DTMF) {
if (f->subclass.integer == 'f') {
- if (option_debug)
- ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", ast->name);
+ ast_debug(1, "Fax CNG detected on %s\n", ast->name);
*faxdetect = 1;
/* If we only needed this DSP for fax detection purposes we can just drop it now */
if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
@@ -7046,6 +7054,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
char *sent_by, *branch;
const char *cseq = get_header(req, "Cseq");
unsigned int seqno;
+
/* get branch parameter from initial Request that started this dialog */
get_viabranch(ast_strdupa(get_header(req, "Via")), &sent_by, &branch);
/* only store the branch if it begins with the magic prefix "z9hG4bK", otherwise
@@ -7060,7 +7069,8 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
if (!ast_strlen_zero(cseq) && (sscanf(cseq, "%30u", &seqno) == 1)) {
p->init_icseq = seqno;
}
- set_socket_transport(&p->socket, req->socket.type); /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
+ /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
+ set_socket_transport(&p->socket, req->socket.type);
} else {
set_socket_transport(&p->socket, SIP_TRANSPORT_UDP);
}
@@ -7193,7 +7203,10 @@ enum match_req_res {
*/
static enum match_req_res match_req_to_dialog(struct sip_pvt *sip_pvt_ptr, struct match_req_args *arg)
{
- const char *init_ruri = REQ_OFFSET_TO_STR(&sip_pvt_ptr->initreq, rlPart2);
+ const char *init_ruri = NULL;
+ if (sip_pvt_ptr->initreq.headers) {
+ init_ruri = REQ_OFFSET_TO_STR(&sip_pvt_ptr->initreq, rlPart2);
+ }
/*
* Match Tags and call-id to Dialog
@@ -7252,8 +7265,8 @@ static enum match_req_res match_req_to_dialog(struct sip_pvt *sip_pvt_ptr, struc
if ((arg->method != SIP_RESPONSE) && /* must be a Request */
ast_strlen_zero(arg->totag) && /* must not have a totag */
(sip_pvt_ptr->init_icseq == arg->seqno) && /* the cseq must be the same as this dialogs initial cseq */
- !ast_strlen_zero(sip_pvt_ptr->initviabranch)) { /* The dialog must have started with a RFC3261 compliant branch tag */
-
+ !ast_strlen_zero(sip_pvt_ptr->initviabranch) && /* The dialog must have started with a RFC3261 compliant branch tag */
+ init_ruri) { /* the dialog must have an initial request uri associated with it */
/* This Request matches all the criteria required for Loop/Merge detection.
* Now we must go down the path of comparing VIA's and RURIs. */
if (ast_strlen_zero(arg->viabranch) ||
@@ -8106,8 +8119,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
break;
}
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED.");
+ ast_debug(3, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED.");
}
@@ -8291,11 +8303,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
break;
}
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Processing media-level (%s) SDP %c=%s... %s\n",
- (audio == TRUE)? "audio" : (video == TRUE)? "video" : "image",
- type, value,
- (processed == TRUE)? "OK." : "UNSUPPORTED.");
+ ast_debug(3, "Processing media-level (%s) SDP %c=%s... %s\n",
+ (audio == TRUE)? "audio" : (video == TRUE)? "video" : "image",
+ type, value,
+ (processed == TRUE)? "OK." : "UNSUPPORTED.");
}
}
@@ -8471,10 +8482,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
if (udptlportno > 0) {
if (ast_test_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP) && ast_test_flag(&p->flags[1], SIP_PAGE2_UDPTL_DESTINATION)) {
ast_rtp_instance_get_remote_address(p->rtp, isa);
- if (!ast_sockaddr_isnull(isa)) {
- if (debug) {
- ast_log(LOG_DEBUG, "Peer T.38 UDPTL is set behind NAT and with destination, destination address now %s\n", ast_sockaddr_stringify(isa));
- }
+ if (!ast_sockaddr_isnull(isa) && debug) {
+ ast_debug(1, "Peer T.38 UDPTL is set behind NAT and with destination, destination address now %s\n", ast_sockaddr_stringify(isa));
}
}
ast_sockaddr_set_port(isa, udptlportno);
@@ -8548,7 +8557,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_set_write_format(p->owner, p->owner->writeformat);
}
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && !ast_sockaddr_isnull(sa) && (!sendonly || sendonly == -1)) {
+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && (!ast_sockaddr_isnull(sa) || !ast_sockaddr_isnull(vsa) || !ast_sockaddr_isnull(tsa) || !ast_sockaddr_isnull(isa)) && (!sendonly || sendonly == -1)) {
ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
/* Activate a re-invite */
ast_queue_frame(p->owner, &ast_null_frame);
@@ -8564,7 +8573,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
if (sip_cfg.notifyhold)
sip_peer_hold(p, FALSE);
ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); /* Clear both flags */
- } else if (ast_sockaddr_isnull(sa) || (sendonly && sendonly != -1)) {
+ } else if ((ast_sockaddr_isnull(sa) && ast_sockaddr_isnull(vsa) && ast_sockaddr_isnull(tsa) && ast_sockaddr_isnull(isa)) || (sendonly && sendonly != -1)) {
int already_on_hold = ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD);
ast_queue_control_data(p->owner, AST_CONTROL_HOLD,
S_OR(p->mohsuggest, NULL),
@@ -8750,8 +8759,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(p->rtp), codec_n);
if (!format.asterisk_format || !format.code) /* non-codec or not found */
continue;
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting framing for %s to %ld\n", ast_getformatname(format.code), framing);
+ ast_debug(1, "Setting framing for %s to %ld\n", ast_getformatname(format.code), framing);
ast_codec_pref_setsize(pref, format.code, framing);
}
ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, pref);
@@ -9003,6 +9011,20 @@ static int process_sdp_a_image(const char *a, struct sip_pvt *p)
return found;
}
+/*! \brief Add "Supported" header to sip message. Since some options may
+ * be disabled in the config, the sip_pvt must be inspected to determine what
+ * is supported for this dialog. */
+static int add_supported_header(struct sip_pvt *pvt, struct sip_request *req)
+{
+ int res;
+ if (st_get_mode(pvt) != SESSION_TIMER_MODE_REFUSE) {
+ res = add_header(req, "Supported", "replaces, timer");
+ } else {
+ res = add_header(req, "Supported", "replaces");
+ }
+ return res;
+}
+
/*! \brief Add header to SIP message */
static int add_header(struct sip_request *req, const char *var, const char *value)
{
@@ -9035,8 +9057,16 @@ static int add_header_max_forwards(struct sip_pvt *dialog, struct sip_request *r
char clen[10];
const char *max = NULL;
+ /* deadlock avoidance */
+ while (dialog->owner && ast_channel_trylock(dialog->owner)) {
+ sip_pvt_unlock(dialog);
+ usleep(1);
+ sip_pvt_lock(dialog);
+ }
+
if (dialog->owner) {
max = pbx_builtin_getvar_helper(dialog->owner, "SIP_MAX_FORWARDS");
+ ast_channel_unlock(dialog->owner);
}
/* The channel variable overrides the peer/channel value */
@@ -9436,14 +9466,13 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
if (!ast_strlen_zero(global_useragent))
add_header(resp, "Server", global_useragent);
add_header(resp, "Allow", ALLOWED_METHODS);
- add_header(resp, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, resp);
/* If this is an invite, add Session-Timers related headers if the feature is active for this session */
if (p->method == SIP_INVITE && p->stimer && p->stimer->st_active == TRUE && p->stimer->st_active_peer_ua == TRUE) {
char se_hdr[256];
snprintf(se_hdr, sizeof(se_hdr), "%d;refresher=%s", p->stimer->st_interval,
strefresher2str(p->stimer->st_ref));
- add_header(resp, "Require", "timer");
add_header(resp, "Session-Expires", se_hdr);
}
@@ -10259,6 +10288,8 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
struct ast_sockaddr *taddr, struct ast_sockaddr *dest,
struct ast_sockaddr *vdest, struct ast_sockaddr *tdest)
{
+ int use_externip = 0;
+
/* First, get our address */
ast_rtp_instance_get_local_address(p->rtp, addr);
if (p->vrtp) {
@@ -10268,6 +10299,11 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
ast_rtp_instance_get_local_address(p->trtp, taddr);
}
+ /* If our real IP differs from the local address returned by the RTP engine, use it. */
+ /* The premise is that if we are already using that IP to communicate with the client, */
+ /* we should be using it for RTP too. */
+ use_externip = ast_sockaddr_cmp_addr(&p->ourip, addr);
+
/* Now, try to figure out where we want them to send data */
/* Is this a re-invite to move the media out, then use the original offer from caller */
if (!ast_sockaddr_isnull(&p->redirip)) { /* If we have a redirection IP, use it */
@@ -10286,7 +10322,7 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
*/
ast_sockaddr_copy(dest,
!ast_sockaddr_isnull(&media_address) ? &media_address :
- !ast_sockaddr_is_any(addr) ? addr :
+ !ast_sockaddr_is_any(addr) && !use_externip ? addr :
&p->ourip);
ast_sockaddr_set_port(dest, ast_sockaddr_port(addr));
}
@@ -10309,7 +10345,7 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
*/
ast_sockaddr_copy(vdest,
!ast_sockaddr_isnull(&media_address) ? &media_address :
- !ast_sockaddr_is_any(vaddr) ? vaddr :
+ !ast_sockaddr_is_any(vaddr) && !use_externip ? vaddr :
&p->ourip);
ast_sockaddr_set_port(vdest, ast_sockaddr_port(vaddr));
}
@@ -10333,7 +10369,7 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
*/
ast_sockaddr_copy(tdest,
!ast_sockaddr_isnull(&media_address) ? &media_address :
- !ast_sockaddr_is_any(taddr) ? taddr :
+ !ast_sockaddr_is_any(taddr) && !use_externip ? taddr :
&p->ourip);
ast_sockaddr_set_port(tdest, ast_sockaddr_port(taddr));
}
@@ -10909,7 +10945,7 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old
reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1);
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
if (sipdebug) {
if (oldsdp == TRUE)
add_header(&req, "X-asterisk-Info", "SIP re-invite (Session-Timers)");
@@ -11305,7 +11341,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
}
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
if (p->options && p->options->addsipheaders && p->owner) {
struct ast_channel *chan = p->owner; /* The owner channel */
@@ -11645,23 +11681,32 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
ast_channel_unlock(caller);
caller = ast_channel_unref(caller);
}
+
+ /* We create a fake call-id which the phone will send back in an INVITE
+ Replaces header which we can grab and do some magic with. */
+ if (sip_cfg.pedanticsipchecking) {
+ ast_str_append(tmp, 0, "<dialog id=\"%s\" call-id=\"pickup-%s\" local-tag=\"%s\" remote-tag=\"%s\" direction=\"recipient\">\n",
+ exten, p->callid, p->theirtag, p->tag);
+ } else {
+ ast_str_append(tmp, 0, "<dialog id=\"%s\" call-id=\"pickup-%s\" direction=\"recipient\">\n",
+ exten, p->callid);
+ }
+ ast_str_append(tmp, 0,
+ "<remote>\n"
+ /* See the limitations of this above. Luckily the phone seems to still be
+ happy when these values are not correct. */
+ "<identity display=\"%s\">%s</identity>\n"
+ "<target uri=\"%s\"/>\n"
+ "</remote>\n"
+ "<local>\n"
+ "<identity>%s</identity>\n"
+ "<target uri=\"%s\"/>\n"
+ "</local>\n",
+ local_display, local_target, local_target, mto, mto);
+ } else {
+ ast_str_append(tmp, 0, "<dialog id=\"%s\" direction=\"recipient\">\n", exten);
}
- /* We create a fake call-id which the phone will send back in an INVITE
- Replaces header which we can grab and do some magic with. */
- ast_str_append(tmp, 0,
- "<dialog id=\"%s\" call-id=\"pickup-%s\" direction=\"recipient\">\n"
- "<remote>\n"
- /* See the limitations of this above. Luckily the phone seems to still be
- happy when these values are not correct. */
- "<identity display=\"%s\">%s</identity>\n"
- "<target uri=\"%s\"/>\n"
- "</remote>\n"
- "<local>\n"
- "<identity>%s</identity>\n"
- "<target uri=\"%s\"/>\n"
- "</local>\n",
- exten, p->callid, local_display, local_target, local_target, mto, mto);
} else {
ast_str_append(tmp, 0, "<dialog id=\"%s\">", exten);
}
@@ -11857,7 +11902,7 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *messa
add_header(&req, "Subscription-state", terminate ? "terminated;reason=noresource" : "active");
add_header(&req, "Content-Type", "message/sipfrag;version=2.0");
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
snprintf(tmp, sizeof(tmp), "SIP/2.0 %s\r\n", message);
add_content(&req, tmp);
@@ -11966,7 +12011,7 @@ static void update_connectedline(struct sip_pvt *p, const void *data, size_t dat
reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1);
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
add_rpid(&req, p);
add_sdp(&req, p, FALSE, TRUE, FALSE);
@@ -11999,7 +12044,7 @@ static void update_connectedline(struct sip_pvt *p, const void *data, size_t dat
send_response(p, &resp, XMIT_UNRELIABLE, 0);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
} else {
- ast_log(LOG_DEBUG, "Unable able to send update to '%s' in state '%s'\n", p->owner->name, ast_state2str(p->owner->_state));
+ ast_debug(1, "Unable able to send update to '%s' in state '%s'\n", p->owner->name, ast_state2str(p->owner->_state));
}
} else {
ast_set_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND);
@@ -12456,7 +12501,7 @@ static int transmit_refer(struct sip_pvt *p, const char *dest)
add_header(&req, "Refer-To", referto);
add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+ add_supported_header(p, &req);
if (!ast_strlen_zero(p->our_contact)) {
add_header(&req, "Referred-By", p->our_contact);
}
@@ -12652,7 +12697,6 @@ static int expire_register(const void *data)
peer->expire = -1;
peer->portinuri = 0;
- memset(&peer->addr, 0, sizeof(peer->addr));
destroy_association(peer); /* remove registration data from storage */
set_socket_transport(&peer->socket, peer->default_outbound_transport);
@@ -12675,12 +12719,13 @@ static int expire_register(const void *data)
if (peer->selfdestruct ||
ast_test_flag(&peer->flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
- ao2_t_unlink(peers, peer, "ao2_unlink of peer from peers table");
- if (!ast_sockaddr_isnull(&peer->addr)) {
- ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table");
- }
+ unlink_peer_from_tables(peer);
}
+ /* Only clear the addr after we check for destruction. The addr must remain
+ * in order to unlink from the peers_by_ip container correctly */
+ memset(&peer->addr, 0, sizeof(peer->addr));
+
unref_peer(peer, "removing peer ref for expire_register");
return 0;
@@ -13411,6 +13456,39 @@ static void mwi_event_cb(const struct ast_event *event, void *userdata)
ao2_unlock(peer);
}
+static void network_change_event_subscribe(void)
+{
+ if (!network_change_event_subscription) {
+ network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
+ network_change_event_cb,
+ "SIP Network Change ",
+ NULL, AST_EVENT_IE_END);
+ }
+}
+
+static void network_change_event_unsubscribe(void)
+{
+ if (network_change_event_subscription) {
+ network_change_event_subscription = ast_event_unsubscribe(network_change_event_subscription);
+ }
+}
+
+static int network_change_event_sched_cb(const void *data)
+{
+ network_change_event_sched_id = -1;
+ sip_send_all_registers();
+ sip_send_all_mwi_subscriptions();
+ return 0;
+}
+
+static void network_change_event_cb(const struct ast_event *event, void *userdata)
+{
+ ast_debug(1, "SIP, got a network change event, renewing all SIP registrations.\n");
+ if (network_change_event_sched_id == -1) {
+ network_change_event_sched_id = ast_sched_add(sched, 1000, network_change_event_sched_cb, NULL);
+ }
+}
+
/*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
\note If you add an "hint" priority to the extension in the dial plan,
you will get notifications on device state changes */
@@ -14623,7 +14701,7 @@ static int get_also_info(struct sip_pvt *p, struct sip_request *oreq)
* address and port in the SIP headers without the need for STUN.
* The address part is also reused for the media sessions.
* Note that ast_sip_ouraddrfor() still rewrites p->ourip
- * if you specify externaddr/seternaddr/stunaddr.
+ * if you specify externaddr/seternaddr/.
*/
static attribute_unused void check_via_response(struct sip_pvt *p, struct sip_request *req)
{
@@ -15790,14 +15868,6 @@ static int dialog_needdestroy(void *dialogobj, void *arg, int flags)
return 0;
}
-/* this func is used with ao2_callback to unlink/delete all marked
- peers */
-static int peer_is_marked(void *peerobj, void *arg, int flags)
-{
- struct sip_peer *peer = peerobj;
- return peer->the_mark ? CMP_MATCH : 0;
-}
-
/*! \brief Remove temporary realtime objects from memory (CLI) */
/*! \todo XXXX Propably needs an overhaul after removal of the devices */
static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -15900,8 +15970,7 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli
}
ao2_iterator_destroy(&i);
if (pruned) {
- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
- "initiating callback to remove marked peers");
+ unlink_marked_peers_from_tables();
ast_cli(a->fd, "%d peers pruned.\n", pruned);
} else
ast_cli(a->fd, "No peers found to prune.\n");
@@ -16740,6 +16809,10 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
ast_cli(a->fd, "\n\nGlobal Settings:\n");
ast_cli(a->fd, "----------------\n");
ast_cli(a->fd, " UDP Bindaddress: %s\n", ast_sockaddr_stringify(&bindaddr));
+ if (ast_sockaddr_is_ipv6(&bindaddr) && ast_sockaddr_is_any(&bindaddr)) {
+ ast_cli(a->fd, " ** Additional Info:\n");
+ ast_cli(a->fd, " [::] may include IPv4 in addition to IPv6, if such a feature is enabled in the OS.\n");
+ }
ast_cli(a->fd, " TCP SIP Bindaddress: %s\n",
sip_cfg.tcp_enabled != FALSE ?
ast_sockaddr_stringify(&sip_tcp_desc.local_address) :
@@ -16814,8 +16887,6 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
msg = "Disabled, no localnet list";
else if (ast_sockaddr_isnull(&externaddr))
msg = "Disabled";
- else if (stunaddr.sin_addr.s_addr != 0)
- msg = "Enabled using STUN";
else if (!ast_strlen_zero(externhost))
msg = "Enabled using externhost";
else
@@ -16835,8 +16906,6 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
ast_strdupa(ast_sockaddr_stringify_addr(&d->netmask)));
}
}
- ast_cli(a->fd, " STUN server: %s:%d\n", ast_inet_ntoa(stunaddr.sin_addr), ntohs(stunaddr.sin_port));
-
ast_cli(a->fd, "\nGlobal Signalling Settings:\n");
ast_cli(a->fd, "---------------------------\n");
ast_cli(a->fd, " Codecs: ");
@@ -18415,7 +18484,11 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char
}
}
-/*! \brief Check pending actions on SIP call */
+/*! \brief Check pending actions on SIP call
+ *
+ * \note both sip_pvt and sip_pvt's owner channel (if present)
+ * must be locked for this function.
+ */
static void check_pendings(struct sip_pvt *p)
{
if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
@@ -18430,6 +18503,9 @@ static void check_pendings(struct sip_pvt *p)
if (p->pendinginvite)
return;
+ if (p->owner) {
+ ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+ }
/* Perhaps there is an SD change INVITE outstanding */
transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
}
@@ -18455,12 +18531,21 @@ static void check_pendings(struct sip_pvt *p)
static int sip_reinvite_retry(const void *data)
{
struct sip_pvt *p = (struct sip_pvt *) data;
+ struct ast_channel *owner;
sip_pvt_lock(p); /* called from schedule thread which requires a lock */
+ while ((owner = p->owner) && ast_channel_trylock(owner)) {
+ sip_pvt_unlock(p);
+ usleep(1);
+ sip_pvt_lock(p);
+ }
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
p->waitid = -1;
check_pendings(p);
sip_pvt_unlock(p);
+ if (owner) {
+ ast_channel_unlock(owner);
+ }
dialog_unref(p, "unref the dialog ptr from sip_reinvite_retry, because it held a dialog ptr");
return 0;
}
@@ -18825,7 +18910,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
/* Check for Session-Timers related headers */
if (st_get_mode(p) != SESSION_TIMER_MODE_REFUSE && p->outgoing_call == TRUE && !reinvite) {
p_hdrval = (char*)get_header(req, "Session-Expires");
- if (!ast_strlen_zero(p_hdrval)) {
+ if (!ast_strlen_zero(p_hdrval)) {
/* UAS supports Session-Timers */
enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO;
int tmp_st_interval = 0;
@@ -19189,6 +19274,23 @@ static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest,
ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
}
break;
+ default:
+ /* We should treat unrecognized 9xx as 900. 400 is actually
+ specified as a possible response, but any 4-6xx is
+ theoretically possible. */
+
+ if (resp < 299) { /* 1xx cases don't get here */
+ ast_log(LOG_WARNING, "SIP transfer to %s had unxpected 2xx response (%d), confusion is possible. \n", p->refer->refer_to, resp);
+ } else {
+ ast_log(LOG_WARNING, "SIP transfer to %s with response (%d). \n", p->refer->refer_to, resp);
+ }
+
+ p->refer->status = REFER_FAILED;
+ pvt_set_needdestroy(p, "received failure response");
+ if (p->owner) {
+ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ }
+ break;
}
}
@@ -19505,6 +19607,8 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
need to hang around for something more "definitive" */
if (resp != 100)
handle_response_peerpoke(p, resp, req);
+ } else if (sipmethod == SIP_REFER && resp >= 200) {
+ handle_response_refer(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_PUBLISH) {
/* SIP PUBLISH transcends this morass of doodoo and instead
* we just always call the response handler. Good gravy!
@@ -19541,18 +19645,12 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
}
break;
- case 202: /* Transfer accepted */
- if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- break;
case 401: /* Not www-authorized on SIP method */
case 407: /* Proxy auth required */
if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, seqno);
else if (sipmethod == SIP_NOTIFY)
handle_response_notify(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
else if (sipmethod == SIP_SUBSCRIBE)
handle_response_subscribe(p, resp, rest, req, seqno);
else if (p->registry && sipmethod == SIP_REGISTER)
@@ -19625,8 +19723,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
case 481: /* Call leg does not exist */
if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, seqno);
- } else if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_SUBSCRIBE) {
handle_response_subscribe(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_BYE) {
@@ -19668,16 +19764,9 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
}
if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
else
ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", ast_sockaddr_stringify(&p->sa), msg);
break;
- case 603: /* Declined transfer */
- if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- }
/* Fallthrough */
default:
if ((resp >= 300) && (resp < 700)) {
@@ -19720,10 +19809,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
case 410: /* Gone */
case 400: /* Bad Request */
case 500: /* Server error */
- if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- } else if (sipmethod == SIP_SUBSCRIBE) {
+ if (sipmethod == SIP_SUBSCRIBE) {
handle_response_subscribe(p, resp, rest, req, seqno);
break;
}
@@ -19821,15 +19907,9 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
;
}
break;
- case 202: /* Transfer accepted */
- if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- break;
case 401: /* www-auth */
case 407:
- if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_INVITE)
+ if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, seqno);
else if (sipmethod == SIP_BYE) {
if (p->authtries == MAX_AUTHTRIES || do_proxy_auth(p, req, resp, sipmethod, 0)) {
@@ -19851,15 +19931,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
case 501: /* Not Implemented */
if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
break;
- case 603: /* Declined transfer */
- if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- }
- /* Fallthrough */
default: /* Errors without handlers */
if ((resp >= 100) && (resp < 200)) {
if (sipmethod == SIP_INVITE) { /* re-invite */
@@ -20307,18 +20379,8 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
*sep++ = '\0'; /* Response string */
respcode = atoi(code);
switch (respcode) {
- case 100: /* Trying: */
- case 101: /* dialog establishment */
- /* Don't do anything yet */
- success = -1; /* Wait */
- break;
- case 183: /* Ringing: */
- /* Don't do anything yet */
- success = -1; /* Wait */
- break;
case 200: /* OK: The new call is up, hangup this call */
/* Hangup the call that we are replacing */
- success = -1; /* Wait */
break;
case 301: /* Moved permenantly */
case 302: /* Moved temporarily */
@@ -20326,13 +20388,24 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
success = FALSE;
break;
case 503: /* Service Unavailable: The new call failed */
- /* Cancel transfer, continue the call */
+ case 603: /* Declined: Not accepted */
+ /* Cancel transfer, continue the current call */
success = FALSE;
break;
- case 603: /* Declined: Not accepted */
+ case 0: /* Parse error */
/* Cancel transfer, continue the current call */
+ ast_log(LOG_NOTICE, "Error parsing sipfrag in NOTIFY in response to REFER.\n");
success = FALSE;
break;
+ default:
+ if (respcode < 200) {
+ /* ignore provisional responses */
+ success = -1;
+ } else {
+ ast_log(LOG_NOTICE, "Got unknown code '%d' in NOTIFY in response to REFER.\n", respcode);
+ success = FALSE;
+ }
+ break;
}
if (success == FALSE) {
ast_log(LOG_NOTICE, "Transfer failed. Sorry. Nothing further to do with this call\n");
@@ -20398,26 +20471,39 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
/*! \brief Handle incoming OPTIONS request
An OPTIONS request should be answered like an INVITE from the same UA, including SDP
*/
-static int handle_request_options(struct sip_pvt *p, struct sip_request *req)
+static int handle_request_options(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e)
{
int res;
- /*! XXX get_destination assumes we're already authenticated. This means that a request from
- a known device (peer) will end up in the wrong context if this is out-of-dialog.
- However, we want to handle OPTIONS as light as possible, so we might want to have
- a configuration option whether we care or not. Some devices use this for testing
- capabilities, which means that we need to match device to answer with proper
- capabilities (including SDP).
- \todo Fix handle_request_options device handling with optional authentication
- (this needs to be fixed in 1.4 as well)
- */
-
if (p->lastinvite) {
/* if this is a request in an active dialog, just confirm that the dialog exists. */
transmit_response_with_allow(p, "200 OK", req, 0);
return 0;
}
+ if (sip_cfg.auth_options_requests) {
+ /* Do authentication if this OPTIONS request began the dialog */
+ copy_request(&p->initreq, req);
+ set_pvt_allowed_methods(p, req);
+ res = check_user(p, req, SIP_OPTIONS, e, XMIT_UNRELIABLE, addr);
+ if (res == AUTH_CHALLENGE_SENT) {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ return 0;
+ }
+ if (res < 0) { /* Something failed in authentication */
+ if (res == AUTH_FAKE_AUTH) {
+ ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+ transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE);
+ } else {
+ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+ transmit_response(p, "403 Forbidden", req);
+ }
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ return 0;
+ }
+ }
+
+ /* must go through authentication before getting here */
res = (get_destination(p, req, NULL) == SIP_GET_DEST_EXTEN_FOUND ? 0 : -1);
build_contact(p);
@@ -20887,7 +20973,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
struct sip_pvt *subscription = NULL;
replace_id += 7; /* Worst case we are looking at \0 */
- if ((subscription = get_sip_pvt_byid_locked(replace_id, NULL, NULL)) == NULL) {
+ if ((subscription = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) {
ast_log(LOG_NOTICE, "Unable to find subscription with call-id: %s\n", replace_id);
transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
error = 1;
@@ -21192,10 +21278,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
}
/* Session-Timers */
- if (p->sipoptions & SIP_OPT_TIMER) {
+ if ((p->sipoptions & SIP_OPT_TIMER) && !ast_strlen_zero(get_header(req, "Session-Expires"))) {
/* The UAC has requested session-timers for this session. Negotiate
the session refresh interval and who will be the refresher */
- ast_debug(2, "Incoming INVITE with 'timer' option enabled\n");
+ ast_debug(2, "Incoming INVITE with 'timer' option supported and \"Session-Expires\" header.\n");
/* Allocate Session-Timers struct w/in the dialog */
if (!p->stimer)
@@ -21203,17 +21289,15 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
/* Parse the Session-Expires header */
p_uac_se_hdr = get_header(req, "Session-Expires");
- if (!ast_strlen_zero(p_uac_se_hdr)) {
- rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref);
- if (rtn != 0) {
- transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
- p->invitestate = INV_COMPLETED;
- if (!p->lastinvite) {
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- res = -1;
- goto request_invite_cleanup;
+ rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref);
+ if (rtn != 0) {
+ transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
+ p->invitestate = INV_COMPLETED;
+ if (!p->lastinvite) {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
+ res = -1;
+ goto request_invite_cleanup;
}
/* Parse the Min-SE header */
@@ -21650,7 +21734,7 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *
ast_do_masquerade(target.chan1);
- ast_channel_lock(transferer); /* the transferer pvt is expected to remain locked on return */
+ sip_pvt_lock(transferer); /* the transferer pvt is expected to remain locked on return */
ast_indicate(target.chan1, AST_CONTROL_UNHOLD);
@@ -22839,7 +22923,6 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
int firststate = AST_EXTENSION_REMOVED;
struct sip_peer *authpeer = NULL;
const char *eventheader = get_header(req, "Event"); /* Get Event package name */
- const char *acceptheader = get_header(req, "Accept");
int resubscribe = (p->subscribed != NONE);
char *temp, *event;
struct ao2_iterator i;
@@ -22970,51 +23053,93 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
if (!strcmp(event, "presence") || !strcmp(event, "dialog")) { /* Presence, RFC 3842 */
unsigned int pidf_xml;
+ const char *accept;
+ int start = 0;
+ enum subscriptiontype subscribed = NONE;
+ const char *unknown_acceptheader = NULL;
if (authpeer) /* We do not need the authpeer any more */
unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 2)");
/* Header from Xten Eye-beam Accept: multipart/related, application/rlmi+xml, application/pidf+xml, application/xpidf+xml */
+ accept = __get_header(req, "Accept", &start);
+ while ((subscribed == NONE) && !ast_strlen_zero(accept)) {
+ pidf_xml = strstr(accept, "application/pidf+xml") ? 1 : 0;
+
+ /* Older versions of Polycom firmware will claim pidf+xml, but really
+ * they only support xpidf+xml. */
+ if (pidf_xml && strstr(p->useragent, "Polycom")) {
+ subscribed = XPIDF_XML;
+ } else if (pidf_xml) {
+ subscribed = PIDF_XML; /* RFC 3863 format */
+ } else if (strstr(accept, "application/dialog-info+xml")) {
+ subscribed = DIALOG_INFO_XML;
+ /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
+ } else if (strstr(accept, "application/cpim-pidf+xml")) {
+ subscribed = CPIM_PIDF_XML; /* RFC 3863 format */
+ } else if (strstr(accept, "application/xpidf+xml")) {
+ subscribed = XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
+ } else {
+ unknown_acceptheader = accept;
+ }
+ /* check to see if there is another Accept header present */
+ accept = __get_header(req, "Accept", &start);
+ }
- pidf_xml = strstr(acceptheader, "application/pidf+xml") ? 1 : 0;
-
- /* Older versions of Polycom firmware will claim pidf+xml, but really
- * they only support xpidf+xml. */
- if (pidf_xml && strstr(p->useragent, "Polycom")) {
- p->subscribed = XPIDF_XML;
- } else if (pidf_xml) {
- p->subscribed = PIDF_XML; /* RFC 3863 format */
- } else if (strstr(acceptheader, "application/dialog-info+xml")) {
- p->subscribed = DIALOG_INFO_XML;
- /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
- } else if (strstr(acceptheader, "application/cpim-pidf+xml")) {
- p->subscribed = CPIM_PIDF_XML; /* RFC 3863 format */
- } else if (strstr(acceptheader, "application/xpidf+xml")) {
- p->subscribed = XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
- } else if (ast_strlen_zero(acceptheader)) {
+ if (!start) {
if (p->subscribed == NONE) { /* if the subscribed field is not already set, and there is no accept header... */
transmit_response(p, "489 Bad Event", req);
-
- ast_log(LOG_WARNING, "SUBSCRIBE failure: no Accept header: pvt: stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
+ ast_log(LOG_WARNING,"SUBSCRIBE failure: no Accept header: pvt: "
+ "stateid: %d, laststate: %d, dialogver: %d, subscribecont: "
+ "'%s', subscribeuri: '%s'\n",
+ p->stateid,
+ p->laststate,
+ p->dialogver,
+ p->subscribecontext,
+ p->subscribeuri);
pvt_set_needdestroy(p, "no Accept header");
return 0;
}
/* if p->subscribed is non-zero, then accept is not obligatory; according to rfc 3265 section 3.1.3, at least.
so, we'll just let it ride, keeping the value from a previous subscription, and not abort the subscription */
- } else {
+ } else if (subscribed == NONE) {
/* Can't find a format for events that we know about */
char mybuf[200];
- snprintf(mybuf, sizeof(mybuf), "489 Bad Event (format %s)", acceptheader);
+ if (!ast_strlen_zero(unknown_acceptheader)) {
+ snprintf(mybuf, sizeof(mybuf), "489 Bad Event (format %s)", unknown_acceptheader);
+ } else {
+ snprintf(mybuf, sizeof(mybuf), "489 Bad Event");
+ }
transmit_response(p, mybuf, req);
-
- ast_log(LOG_WARNING, "SUBSCRIBE failure: unrecognized format: '%s' pvt: subscribed: %d, stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- acceptheader, (int)p->subscribed, p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
+ ast_log(LOG_WARNING,"SUBSCRIBE failure: unrecognized format:"
+ "'%s' pvt: subscribed: %d, stateid: %d, laststate: %d,"
+ "dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
+ unknown_acceptheader,
+ (int)p->subscribed,
+ p->stateid,
+ p->laststate,
+ p->dialogver,
+ p->subscribecontext,
+ p->subscribeuri);
pvt_set_needdestroy(p, "unrecognized format");
return 0;
+ } else {
+ p->subscribed = subscribed;
}
} else if (!strcmp(event, "message-summary")) {
- if (!ast_strlen_zero(acceptheader) && strcmp(acceptheader, "application/simple-message-summary")) {
+ int start = 0;
+ int found_supported = 0;
+ const char *acceptheader;
+
+ acceptheader = __get_header(req, "Accept", &start);
+ while (!found_supported && !ast_strlen_zero(acceptheader)) {
+ found_supported = strcmp(acceptheader, "application/simple-message-summary") ? 0 : 1;
+ if (!found_supported && (option_debug > 2)) {
+ ast_log(LOG_DEBUG, "Received SIP mailbox subscription for unknown format: %s\n", acceptheader);
+ }
+ acceptheader = __get_header(req, "Accept", &start);
+ }
+ if (start && !found_supported) {
/* Format requested that we do not support */
transmit_response(p, "406 Not Acceptable", req);
ast_debug(2, "Received SIP mailbox subscription for unknown format: %s\n", acceptheader);
@@ -23296,8 +23421,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as
return 0;
}
if (p->ocseq && (p->ocseq < seqno)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
+ ast_debug(1, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
return -1;
} else {
char causevar[256], causeval[256];
@@ -23404,7 +23528,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as
/* Handle various incoming SIP methods in requests */
switch (p->method) {
case SIP_OPTIONS:
- res = handle_request_options(p, req);
+ res = handle_request_options(p, req, addr, e);
break;
case SIP_INVITE:
res = handle_request_invite(p, req, debug, seqno, addr, recount, e, nounlock);
@@ -23489,9 +23613,7 @@ static void process_request_queue(struct sip_pvt *p, int *recount, int *nounlock
while ((req = AST_LIST_REMOVE_HEAD(&p->request_queue, next))) {
if (handle_incoming(p, req, &p->recv, recount, nounlock) == -1) {
/* Request failed */
- if (option_debug) {
- ast_log(LOG_DEBUG, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
- }
+ ast_debug(1, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
}
ast_free(req);
}
@@ -24478,7 +24600,7 @@ enum st_mode st_get_mode(struct sip_pvt *p)
static int sip_poke_noanswer(const void *data)
{
struct sip_peer *peer = (struct sip_peer *)data;
-
+
peer->pokeexpire = -1;
if (peer->lastms > -1) {
@@ -24497,9 +24619,12 @@ static int sip_poke_noanswer(const void *data)
peer->call = dialog_unref(peer->call, "unref dialog peer->call");
/* peer->call = sip_destroy(peer->call);*/
}
-
- peer->lastms = -1;
- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+
+ /* Don't send a devstate change if nothing changed. */
+ if (peer->lastms > -1) {
+ peer->lastms = -1;
+ ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+ }
/* Try again quickly */
AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched,
@@ -25343,6 +25468,8 @@ static void set_peer_defaults(struct sip_peer *peer)
peer->timer_b = global_timer_b;
clear_peer_mailboxes(peer);
peer->disallowed_methods = sip_cfg.disallowed_methods;
+ peer->transports = default_transports;
+ peer->default_outbound_transport = default_primary_transport;
}
/*! \brief Create temporary peer (used in autocreatepeer mode) */
@@ -25497,6 +25624,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
/* If we have realm authentication information, remove them (reload) */
clear_realm_authentication(peer->auth);
peer->auth = NULL;
+ /* clear the transport information. We will detect if a default value is required after parsing the config */
peer->default_outbound_transport = 0;
peer->transports = 0;
@@ -26100,8 +26228,8 @@ static int reload_config(enum channelreloadreason reason)
int auto_sip_domains = FALSE;
struct ast_sockaddr old_bindaddr = bindaddr;
int registry_count = 0, peer_count = 0, timerb_set = 0, timert1_set = 0;
+ int subscribe_network_change = 1;
time_t run_start, run_end;
- struct sockaddr_in externaddr_sin;
int bindport = 0;
run_start = time(0);
@@ -26204,7 +26332,6 @@ static int reload_config(enum channelreloadreason reason)
/* Reset IP addresses */
ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0);
- memset(&stunaddr, 0, sizeof(stunaddr));
memset(&internip, 0, sizeof(internip));
/* Free memory for local network address mask */
@@ -26245,6 +26372,7 @@ static int reload_config(enum channelreloadreason reason)
sip_cfg.notifyhold = FALSE; /*!< Keep track of hold status for a peer */
sip_cfg.directrtpsetup = FALSE; /* Experimental feature, disabled by default */
sip_cfg.alwaysauthreject = DEFAULT_ALWAYSAUTHREJECT;
+ sip_cfg.auth_options_requests = DEFAULT_AUTH_OPTIONS;
sip_cfg.allowsubscribe = FALSE;
sip_cfg.disallowed_methods = SIP_UNKNOWN;
sip_cfg.contact_ha = NULL; /* Reset the contact ACL */
@@ -26485,6 +26613,10 @@ static int reload_config(enum channelreloadreason reason)
}
} else if (!strcasecmp(v->name, "alwaysauthreject")) {
sip_cfg.alwaysauthreject = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "auth_options_requests")) {
+ if (ast_true(v->value)) {
+ sip_cfg.auth_options_requests = 1;
+ }
} else if (!strcasecmp(v->name, "mohinterpret")) {
ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret));
} else if (!strcasecmp(v->name, "mohsuggest")) {
@@ -26590,12 +26722,6 @@ static int reload_config(enum channelreloadreason reason)
}
} else if (!strcasecmp(v->name, "registerattempts")) {
global_regattempts_max = atoi(v->value);
- } else if (!strcasecmp(v->name, "stunaddr")) {
- stunaddr.sin_port = htons(3478);
- if (ast_parse_arg(v->value, PARSE_INADDR, &stunaddr)) {
- ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value);
- }
- externexpire = time(NULL);
} else if (!strcasecmp(v->name, "bindaddr") || !strcasecmp(v->name, "udpbindaddr")) {
if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
@@ -26803,11 +26929,25 @@ static int reload_config(enum channelreloadreason reason)
ast_log(LOG_WARNING, "'%s' is not a valid maxforwards value at line %d. Using default.\n", v->value, v->lineno);
sip_cfg.default_max_forwards = DEFAULT_MAX_FORWARDS;
}
+ } else if (!strcasecmp(v->name, "subscribe_network_change_event")) {
+ if (ast_true(v->value)) {
+ subscribe_network_change = 1;
+ } else if (ast_false(v->value)) {
+ subscribe_network_change = 0;
+ } else {
+ ast_log(LOG_WARNING, "subscribe_network_change_event value %s is not valid at line %d.\n", v->value, v->lineno);
+ }
} else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
}
}
+ if (subscribe_network_change) {
+ network_change_event_subscribe();
+ } else {
+ network_change_event_unsubscribe();
+ }
+
if (global_t1 < global_t1min) {
ast_log(LOG_WARNING, "'t1min' (%d) cannot be greater than 't1timer' (%d). Resetting 't1timer' to the value of 't1min'\n", global_t1min, global_t1);
global_t1 = global_t1min;
@@ -26895,15 +27035,8 @@ static int reload_config(enum channelreloadreason reason)
ast_set_qos(sipsock, global_tos_sip, global_cos_sip, "SIP");
}
}
- }
- if (stunaddr.sin_addr.s_addr != 0) {
- ast_debug(1, "stun to %s:%d\n",
- ast_inet_ntoa(stunaddr.sin_addr) , ntohs(stunaddr.sin_port));
- ast_sockaddr_to_sin(&externaddr, &externaddr_sin);
- ast_stun_request(sipsock, &stunaddr,
- NULL, &externaddr_sin);
- ast_debug(1, "STUN sees us at %s\n",
- ast_sockaddr_stringify(&externaddr));
+ } else {
+ ast_set_qos(sipsock, global_tos_sip, global_cos_sip, "SIP");
}
ast_mutex_unlock(&netlock);
@@ -27060,10 +27193,10 @@ static int reload_config(enum channelreloadreason reason)
char temp[MAXHOSTNAMELEN];
/* First our default IP address */
- if (!ast_sockaddr_isnull(&bindaddr)) {
+ if (!ast_sockaddr_isnull(&bindaddr) && !ast_sockaddr_is_any(&bindaddr)) {
add_sip_domain(ast_sockaddr_stringify_addr(&bindaddr),
SIP_DOMAIN_AUTO, NULL);
- } else if (!ast_sockaddr_isnull(&internip)) {
+ } else if (!ast_sockaddr_isnull(&internip) && !ast_sockaddr_is_any(&internip)) {
/* Our internal IP address, if configured */
add_sip_domain(ast_sockaddr_stringify_addr(&internip),
SIP_DOMAIN_AUTO, NULL);
@@ -27490,7 +27623,7 @@ static int sip_removeheader(struct ast_channel *chan, const char *data)
if (strncasecmp(ast_var_name(newvariable), "SIPADDHEADER", strlen("SIPADDHEADER")) == 0) {
if (removeall || (!strncasecmp(ast_var_value(newvariable),inbuf,strlen(inbuf)))) {
if (sipdebug)
- ast_log(LOG_DEBUG,"removing SIP Header \"%s\" as %s\n",
+ ast_debug(1,"removing SIP Header \"%s\" as %s\n",
ast_var_value(newvariable),
ast_var_name(newvariable));
AST_LIST_REMOVE_CURRENT(entries);
@@ -27671,6 +27804,12 @@ static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struc
}
}
+ /* For now, when we receive an INVITE just take the first successful crypto line */
+ if ((*srtp)->crypto && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+ ast_debug(3, "We've already processed a crypto attribute, skipping '%s'\n", a);
+ return FALSE;
+ }
+
if (!(*srtp)->crypto && !((*srtp)->crypto = sdp_crypto_setup())) {
return FALSE;
}
@@ -27694,9 +27833,8 @@ static int sip_do_reload(enum channelreloadreason reason)
start_poke = time(0);
/* Prune peers who still are supposed to be deleted */
- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
- "callback to remove marked peers");
-
+ unlink_marked_peers_from_tables();
+
ast_debug(4, "--------------- Done destroying pruned peers\n");
/* Send qualify (OPTIONS) to all peers */
@@ -27767,7 +27905,7 @@ static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr,
return 1;
}
if (addrs_cnt > 1) {
- ast_log(LOG_DEBUG, "Multiple addresses, using the first one only\n");
+ ast_debug(1, "Multiple addresses, using the first one only\n");
}
ast_sockaddr_copy(addr, &addrs[0]);
@@ -28314,6 +28452,7 @@ static int load_module(void)
sip_register_tests();
+ network_change_event_subscribe();
return AST_MODULE_LOAD_SUCCESS;
}
@@ -28326,6 +28465,8 @@ static int unload_module(void)
struct ast_context *con;
struct ao2_iterator i;
+ network_change_event_unsubscribe();
+
ast_sched_dump(sched);
/* First, take us out of the channel type list */
@@ -28466,4 +28607,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Session Initiation Pr
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
+ .nonoptreq = "res_crypto,chan_local",
);
diff --git a/channels/chan_usbradio.c b/channels/chan_usbradio.c
index b5867f5a4..eca7760ab 100644
--- a/channels/chan_usbradio.c
+++ b/channels/chan_usbradio.c
@@ -644,7 +644,7 @@ static struct chan_usbradio_pvt usbradio_default = {
/* DECLARE FUNCTION PROTOTYPES */
-static void store_txtoctype(struct chan_usbradio_pvt *o, char *s);
+static void store_txtoctype(struct chan_usbradio_pvt *o, const char *s);
static int hidhdwconfig(struct chan_usbradio_pvt *o);
static int set_txctcss_level(struct chan_usbradio_pvt *o);
static void pmrdump(struct chan_usbradio_pvt *o);
@@ -1119,8 +1119,7 @@ static void *hidthread(void *arg)
struct usb_device *usb_dev;
struct usb_dev_handle *usb_handle;
struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
- struct timeval to;
- fd_set rfds;
+ struct pollfd pfd = { .events = POLLIN };
usb_dev = hid_device_init(o->devstr);
if (usb_dev == NULL) {
@@ -1156,63 +1155,49 @@ static void *hidthread(void *arg)
traceusb1(("hidthread: Starting normally on %s!!\n",o->name));
lastrx = 0;
// popen
- while(!o->stophid)
- {
- to.tv_sec = 0;
- to.tv_usec = 50000; // maw sph
+ while (!o->stophid) {
+ pfd.fd = o->pttkick[0];
+ pfd.revents = 0;
- FD_ZERO(&rfds);
- FD_SET(o->pttkick[0],&rfds);
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(o->pttkick[0] + 1, &rfds, NULL, NULL, &to);
+ res = ast_poll(&pfd, 1, 50);
if (res < 0) {
- ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
+ ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
usleep(10000);
continue;
}
- if (FD_ISSET(o->pttkick[0],&rfds))
- {
+ if (pfd.revents & POLLIN) {
char c;
- if (read(o->pttkick[0],&c,1) < 0) {
+ if (read(o->pttkick[0], &c, 1) < 0) {
ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
}
}
- if(o->wanteeprom)
- {
+ if (o->wanteeprom) {
ast_mutex_lock(&o->eepromlock);
- if (o->eepromctl == 1) /* to read */
- {
+ if (o->eepromctl == 1) { /* to read */
/* if CS okay */
- if (!get_eeprom(usb_handle,o->eeprom))
- {
- if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC)
- {
- ast_log(LOG_NOTICE,"UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n",o->name);
- }
- else
- {
+ if (!get_eeprom(usb_handle, o->eeprom)) {
+ if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC) {
+ ast_log(LOG_NOTICE, "UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n", o->name);
+ } else {
o->rxmixerset = o->eeprom[EEPROM_RXMIXERSET];
- o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
+ o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
o->txmixbset = o->eeprom[EEPROM_TXMIXBSET];
- memcpy(&o->rxvoiceadj,&o->eeprom[EEPROM_RXVOICEADJ],sizeof(float));
- memcpy(&o->rxctcssadj,&o->eeprom[EEPROM_RXCTCSSADJ],sizeof(float));
+ memcpy(&o->rxvoiceadj, &o->eeprom[EEPROM_RXVOICEADJ], sizeof(float));
+ memcpy(&o->rxctcssadj, &o->eeprom[EEPROM_RXCTCSSADJ], sizeof(float));
o->txctcssadj = o->eeprom[EEPROM_TXCTCSSADJ];
o->rxsquelchadj = o->eeprom[EEPROM_RXSQUELCHADJ];
ast_log(LOG_NOTICE,"EEPROM Loaded on channel %s\n",o->name);
}
- }
- else
- {
- ast_log(LOG_NOTICE,"USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n",o->name);
+ } else {
+ ast_log(LOG_NOTICE, "USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n", o->name);
}
hid_set_outputs(usb_handle,bufsave);
- }
- if (o->eepromctl == 2) /* to write */
- {
+ }
+ if (o->eepromctl == 2) { /* to write */
put_eeprom(usb_handle,o->eeprom);
hid_set_outputs(usb_handle,bufsave);
- ast_log(LOG_NOTICE,"USB Parameters written to EEPROM on %s\n",o->name);
+ ast_log(LOG_NOTICE, "USB Parameters written to EEPROM on %s\n", o->name);
}
o->eepromctl = 0;
ast_mutex_unlock(&o->eepromlock);
@@ -1220,38 +1205,43 @@ static void *hidthread(void *arg)
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
hid_get_inputs(usb_handle,buf);
keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor);
- if (keyed != o->rxhidsq)
- {
- if(o->debuglevel)printf("chan_usbradio() hidthread: update rxhidsq = %d\n",keyed);
+ if (keyed != o->rxhidsq) {
+ if (o->debuglevel) {
+ printf("chan_usbradio() hidthread: update rxhidsq = %d\n", keyed);
+ }
o->rxhidsq=keyed;
}
/* if change in tx state as controlled by xpmr */
- txtmp=o->pmrChan->txPttOut;
-
- if (o->lasttx != txtmp)
- {
- o->pmrChan->txPttHid=o->lasttx = txtmp;
- if(o->debuglevel)printf("hidthread: tx set to %d\n",txtmp);
- buf[o->hid_gpio_loc] = 0;
- if (!o->invertptt)
- {
- if (txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
+ txtmp = o->pmrChan->txPttOut;
+
+ if (o->lasttx != txtmp) {
+ o->pmrChan->txPttHid = o->lasttx = txtmp;
+ if (o->debuglevel) {
+ ast_debug(0, "hidthread: tx set to %d\n", txtmp);
}
- else
- {
- if (!txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
+ buf[o->hid_gpio_loc] = 0;
+ if (!o->invertptt) {
+ if (txtmp) {
+ buf[o->hid_gpio_loc] = o->hid_io_ptt;
+ }
+ } else {
+ if (!txtmp) {
+ buf[o->hid_gpio_loc] = o->hid_io_ptt;
+ }
}
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
- memcpy(bufsave,buf,sizeof(buf));
- hid_set_outputs(usb_handle,buf);
+ memcpy(bufsave, buf, sizeof(buf));
+ hid_set_outputs(usb_handle, buf);
}
time(&o->lasthidtime);
}
buf[o->hid_gpio_loc] = 0;
- if (o->invertptt) buf[o->hid_gpio_loc] = o->hid_io_ptt;
+ if (o->invertptt) {
+ buf[o->hid_gpio_loc] = o->hid_io_ptt;
+ }
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
- hid_set_outputs(usb_handle,buf);
+ hid_set_outputs(usb_handle, buf);
pthread_exit(0);
}
@@ -1452,37 +1442,29 @@ static void *sound_thread(void *arg)
*/
read(o->sounddev, ign, sizeof(ign));
for (;;) {
- fd_set rfds, wfds;
- int maxfd, res;
-
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_SET(o->sndcmd[0], &rfds);
- maxfd = o->sndcmd[0]; /* pipe from the main process */
- if (o->cursound > -1 && o->sounddev < 0)
+ struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev } };
+ int res;
+
+ if (o->cursound > -1 && o->sounddev < 0) {
setformat(o, O_RDWR); /* need the channel, try to reopen */
- else if (o->cursound == -1 && o->owner == NULL)
- {
+ } else if (o->cursound == -1 && o->owner == NULL) {
setformat(o, O_CLOSE); /* can close */
}
if (o->sounddev > -1) {
if (!o->owner) { /* no one owns the audio, so we must drain it */
- FD_SET(o->sounddev, &rfds);
- maxfd = MAX(o->sounddev, maxfd);
+ pfd[1].events = POLLIN;
}
if (o->cursound > -1) {
- FD_SET(o->sounddev, &wfds);
- maxfd = MAX(o->sounddev, maxfd);
+ pfd[1].events |= POLLOUT;
}
}
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
+ res = ast_poll(pfd, o->sounddev > -1 ? 2 : 1, -1);
if (res < 1) {
- ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
+ ast_log(LOG_WARNING, "poll failed: %s\n", strerror(errno));
sleep(1);
continue;
}
- if (FD_ISSET(o->sndcmd[0], &rfds)) {
+ if (pfd[0].revents & POLLIN) {
/* read which sound to play from the pipe */
int i, what = -1;
@@ -1495,14 +1477,17 @@ static void *sound_thread(void *arg)
break;
}
}
- if (sounds[i].ind == -1)
+ if (sounds[i].ind == -1) {
ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
+ }
}
if (o->sounddev > -1) {
- if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */
+ if (pfd[1].revents & POLLIN) { /* read and ignore errors */
read(o->sounddev, ign, sizeof(ign));
- if (FD_ISSET(o->sounddev, &wfds))
+ }
+ if (pfd[1].revents & POLLOUT) {
send_sound(o);
+ }
}
}
return NULL; /* Never reached */
@@ -2697,7 +2682,7 @@ static void store_callerid(struct chan_usbradio_pvt *o, char *s)
}
#endif
-static void store_rxdemod(struct chan_usbradio_pvt *o, char *s)
+static void store_rxdemod(struct chan_usbradio_pvt *o, const char *s)
{
if (!strcasecmp(s,"no")){
o->rxdemod = RX_AUDIO_NONE;
@@ -2716,7 +2701,7 @@ static void store_rxdemod(struct chan_usbradio_pvt *o, char *s)
}
-static void store_txmixa(struct chan_usbradio_pvt *o, char *s)
+static void store_txmixa(struct chan_usbradio_pvt *o, const char *s)
{
if (!strcasecmp(s,"no")){
o->txmixa = TX_OUT_OFF;
@@ -2740,7 +2725,7 @@ static void store_txmixa(struct chan_usbradio_pvt *o, char *s)
//ast_log(LOG_WARNING, "set txmixa = %s\n", s);
}
-static void store_txmixb(struct chan_usbradio_pvt *o, char *s)
+static void store_txmixb(struct chan_usbradio_pvt *o, const char *s)
{
if (!strcasecmp(s,"no")){
o->txmixb = TX_OUT_OFF;
@@ -2765,7 +2750,7 @@ static void store_txmixb(struct chan_usbradio_pvt *o, char *s)
}
/*
*/
-static void store_rxcdtype(struct chan_usbradio_pvt *o, char *s)
+static void store_rxcdtype(struct chan_usbradio_pvt *o, const char *s)
{
if (!strcasecmp(s,"no")){
o->rxcdtype = CD_IGNORE;
@@ -2790,7 +2775,7 @@ static void store_rxcdtype(struct chan_usbradio_pvt *o, char *s)
}
/*
*/
-static void store_rxsdtype(struct chan_usbradio_pvt *o, char *s)
+static void store_rxsdtype(struct chan_usbradio_pvt *o, const char *s)
{
if (!strcasecmp(s,"no") || !strcasecmp(s,"SD_IGNORE")){
o->rxsdtype = SD_IGNORE;
@@ -2812,7 +2797,7 @@ static void store_rxsdtype(struct chan_usbradio_pvt *o, char *s)
}
/*
*/
-static void store_rxgain(struct chan_usbradio_pvt *o, char *s)
+static void store_rxgain(struct chan_usbradio_pvt *o, const char *s)
{
float f;
sscanf(s, "%30f", &f);
@@ -2821,7 +2806,7 @@ static void store_rxgain(struct chan_usbradio_pvt *o, char *s)
}
/*
*/
-static void store_rxvoiceadj(struct chan_usbradio_pvt *o, char *s)
+static void store_rxvoiceadj(struct chan_usbradio_pvt *o, const char *s)
{
float f;
sscanf(s, "%30f", &f);
@@ -2830,7 +2815,7 @@ static void store_rxvoiceadj(struct chan_usbradio_pvt *o, char *s)
}
/*
*/
-static void store_rxctcssadj(struct chan_usbradio_pvt *o, char *s)
+static void store_rxctcssadj(struct chan_usbradio_pvt *o, const char *s)
{
float f;
sscanf(s, "%30f", &f);
@@ -2839,7 +2824,7 @@ static void store_rxctcssadj(struct chan_usbradio_pvt *o, char *s)
}
/*
*/
-static void store_txtoctype(struct chan_usbradio_pvt *o, char *s)
+static void store_txtoctype(struct chan_usbradio_pvt *o, const char *s)
{
if (!strcasecmp(s,"no") || !strcasecmp(s,"TOC_NONE")){
o->txtoctype = TOC_NONE;
diff --git a/channels/console_video.c b/channels/console_video.c
index 88bf807d5..c26ac983f 100644
--- a/channels/console_video.c
+++ b/channels/console_video.c
@@ -234,34 +234,34 @@ struct video_out_desc {
* and contain all configurtion info.
*/
struct video_desc {
- char codec_name[64]; /* the codec we use */
+ char codec_name[64]; /* the codec we use */
- int stayopen; /* set if gui starts manually */
- pthread_t vthread; /* video thread */
- ast_mutex_t dec_lock; /* sync decoder and video thread */
- int shutdown; /* set to shutdown vthread */
- struct ast_channel *owner; /* owner channel */
+ int stayopen; /* set if gui starts manually */
+ pthread_t vthread; /* video thread */
+ ast_mutex_t dec_lock; /* sync decoder and video thread */
+ int shutdown; /* set to shutdown vthread */
+ struct ast_channel *owner; /* owner channel */
- struct fbuf_t enc_in; /* encoder input buffer, allocated in video_out_init() */
+ struct fbuf_t enc_in; /* encoder input buffer, allocated in video_out_init() */
- char keypad_file[256]; /* image for the keypad */
- char keypad_font[256]; /* font for the keypad */
+ char keypad_file[256]; /* image for the keypad */
+ char keypad_font[256]; /* font for the keypad */
- char sdl_videodriver[256];
+ char sdl_videodriver[256];
- struct fbuf_t rem_dpy; /* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */
- struct fbuf_t loc_dpy; /* display local source, no buffer (managed by SDL in bmp[1]) */
+ struct fbuf_t rem_dpy; /* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */
+ struct fbuf_t loc_dpy; /* display local source, no buffer (managed by SDL in bmp[1]) */
/* geometry of the thumbnails for all video sources. */
- struct fbuf_t src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */
+ struct fbuf_t src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */
- int frame_freeze; /* flag to freeze the incoming frame */
+ int frame_freeze; /* flag to freeze the incoming frame */
/* local information for grabbers, codecs, gui */
- struct gui_info *gui;
- struct video_dec_desc *in; /* remote video descriptor */
- struct video_out_desc out; /* local video descriptor */
+ struct gui_info *gui;
+ struct video_dec_desc *in; /* remote video descriptor */
+ struct video_out_desc out; /* local video descriptor */
};
static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
@@ -387,8 +387,9 @@ static struct fbuf_t *grabber_read(struct video_device *dev, int fps)
*/
static void grabber_move(struct video_device *dev, int dx, int dy)
{
- if (dev->grabber && dev->grabber->move)
- dev->grabber->move(dev->grabber_data, dx, dy);
+ if (dev->grabber && dev->grabber->move) {
+ dev->grabber->move(dev->grabber_data, dx, dy);
+ }
}
/*
@@ -508,33 +509,32 @@ static int video_out_init(struct video_desc *env)
/* now setup the parameters for the encoder.
* XXX should be codec-specific
*/
- {
- AVCodecContext *enc_ctx = avcodec_alloc_context();
- v->enc_ctx = enc_ctx;
- enc_ctx->pix_fmt = enc_in->pix_fmt;
- enc_ctx->width = enc_in->w;
- enc_ctx->height = enc_in->h;
- /* XXX rtp_callback ?
- * rtp_mode so ffmpeg inserts as many start codes as possible.
- */
- enc_ctx->rtp_mode = 1;
- enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
- enc_ctx->bit_rate = v->bitrate;
- enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
- enc_ctx->qmin = v->qmin; /* should be configured */
- enc_ctx->time_base = (AVRational){1, v->fps};
- enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
-
- v->enc->enc_init(v->enc_ctx);
-
- if (avcodec_open(enc_ctx, v->codec) < 0) {
- ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n",
- codec);
- av_free(enc_ctx);
- v->enc_ctx = NULL;
- return video_out_uninit(env);
+ {
+ AVCodecContext *enc_ctx = avcodec_alloc_context();
+ v->enc_ctx = enc_ctx;
+ enc_ctx->pix_fmt = enc_in->pix_fmt;
+ enc_ctx->width = enc_in->w;
+ enc_ctx->height = enc_in->h;
+ /* XXX rtp_callback ?
+ * rtp_mode so ffmpeg inserts as many start codes as possible.
+ */
+ enc_ctx->rtp_mode = 1;
+ enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
+ enc_ctx->bit_rate = v->bitrate;
+ enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
+ enc_ctx->qmin = v->qmin; /* should be configured */
+ enc_ctx->time_base = (AVRational){1, v->fps};
+ enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
+
+ v->enc->enc_init(v->enc_ctx);
+
+ if (avcodec_open(enc_ctx, v->codec) < 0) {
+ ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n", codec);
+ av_free(enc_ctx);
+ v->enc_ctx = NULL;
+ return video_out_uninit(env);
+ }
}
- }
/*
* Allocate enough for the encoded bitstream. As we are compressing,
* we hope that the output is never larger than the input size.
@@ -637,9 +637,9 @@ static void my_scale(struct fbuf_t *in, AVPicture *p_in,
p_in = fill_pict(in, &my_p_in);
if (p_out == NULL)
p_out = fill_pict(out, &my_p_out);
-
- /*if win_w is different from zero then we must change
- the size of the scaled buffer (the position is already
+
+ /*if win_w is different from zero then we must change
+ the size of the scaled buffer (the position is already
encoded into the out parameter)*/
if (out->win_w) { /* picture in picture enabled */
eff_w=out->win_w;
@@ -650,26 +650,26 @@ static void my_scale(struct fbuf_t *in, AVPicture *p_in,
img_convert(p_out, out->pix_fmt,
p_in, in->pix_fmt, in->w, in->h);
#else /* XXX replacement */
- {
- struct SwsContext *convert_ctx;
-
- convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
- eff_w, eff_h, out->pix_fmt,
- SWS_BICUBIC, NULL, NULL, NULL);
- if (convert_ctx == NULL) {
- ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
- return;
+ {
+ struct SwsContext *convert_ctx;
+
+ convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
+ eff_w, eff_h, out->pix_fmt,
+ SWS_BICUBIC, NULL, NULL, NULL);
+ if (convert_ctx == NULL) {
+ ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
+ return;
+ }
+ if (0)
+ ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
+ in->pix_fmt, in->w, in->h, out->pix_fmt, eff_w, eff_h);
+ sws_scale(convert_ctx,
+ p_in->data, p_in->linesize,
+ in->w, in->h, /* src slice */
+ p_out->data, p_out->linesize);
+
+ sws_freeContext(convert_ctx);
}
- if (0)
- ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
- in->pix_fmt, in->w, in->h, out->pix_fmt, eff_w, eff_h);
- sws_scale(convert_ctx,
- p_in->data, p_in->linesize,
- in->w, in->h, /* src slice */
- p_out->data, p_out->linesize);
-
- sws_freeContext(convert_ctx);
- }
#endif /* XXX replacement */
}
@@ -873,18 +873,20 @@ static void *video_thread(void *arg)
}
}
sdl_setup(env);
- if (!ast_strlen_zero(save_display))
+ if (!ast_strlen_zero(save_display)) {
setenv("DISPLAY", save_display, 1);
+ }
ast_mutex_init(&env->dec_lock); /* used to sync decoder and renderer */
if (grabber_open(&env->out)) {
ast_log(LOG_WARNING, "cannot open local video source\n");
- }
+ }
- if (env->out.device_num)
+ if (env->out.device_num) {
env->out.devices[env->out.device_primary].status_index |= IS_PRIMARY | IS_SECONDARY;
-
+ }
+
/* even if no device is connected, we must call video_out_init,
* as some of the data structures it initializes are
* used in get_video_frames()
@@ -893,14 +895,14 @@ static void *video_thread(void *arg)
/* Writes intial status of the sources. */
if (env->gui) {
- for (i = 0; i < env->out.device_num; i++) {
- print_message(env->gui->thumb_bd_array[i].board,
- src_msgs[env->out.devices[i].status_index]);
- }
+ for (i = 0; i < env->out.device_num; i++) {
+ print_message(env->gui->thumb_bd_array[i].board,
+ src_msgs[env->out.devices[i].status_index]);
+ }
}
for (;;) {
- struct timeval t = { 0, 50000 }; /* XXX 20 times/sec */
+ struct timespec t = { 0, 50000000 }; /* XXX 20 times/sec */
struct ast_frame *p, *f;
struct ast_channel *chan;
int fd;
@@ -908,13 +910,14 @@ static void *video_thread(void *arg)
/* determine if video format changed */
if (count++ % 10 == 0) {
- if (env->out.sendvideo && env->out.devices)
- sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps",
+ if (env->out.sendvideo && env->out.devices) {
+ snprintf(buf, sizeof(buf), "%s %s %dx%d @@ %dfps %dkbps",
env->out.devices[env->out.device_primary].name, env->codec_name,
env->enc_in.w, env->enc_in.h,
- env->out.fps, env->out.bitrate/1000);
- else
- sprintf(buf, "hold");
+ env->out.fps, env->out.bitrate / 1000);
+ } else {
+ sprintf(buf, "hold");
+ }
caption = buf;
}
@@ -923,36 +926,36 @@ static void *video_thread(void *arg)
* otherwise the drag will not work */
if (env->gui)
eventhandler(env, caption);
-
+
/* sleep for a while */
- ast_select(0, NULL, NULL, NULL, &t);
+ nanosleep(&t, NULL);
if (env->in) {
- struct video_dec_desc *v = env->in;
-
- /*
- * While there is something to display, call the decoder and free
- * the buffer, possibly enabling the receiver to store new data.
- */
- while (v->dec_in_dpy) {
- struct fbuf_t *tmp = v->dec_in_dpy; /* store current pointer */
-
- /* decode the frame, but show it only if not frozen */
- if (v->d_callbacks->dec_run(v, tmp) && !env->frame_freeze)
- show_frame(env, WIN_REMOTE);
- tmp->used = 0; /* mark buffer as free */
- tmp->ebit = 0;
- ast_mutex_lock(&env->dec_lock);
- if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN]) /* advance to next, circular */
- v->dec_in_dpy = &v->dec_in[0];
-
- if (v->dec_in_cur == NULL) /* receiver was idle, enable it... */
- v->dec_in_cur = tmp; /* using the slot just freed */
- else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
- v->dec_in_dpy = NULL; /* nothing more to display */
- ast_mutex_unlock(&env->dec_lock);
+ struct video_dec_desc *v = env->in;
+
+ /*
+ * While there is something to display, call the decoder and free
+ * the buffer, possibly enabling the receiver to store new data.
+ */
+ while (v->dec_in_dpy) {
+ struct fbuf_t *tmp = v->dec_in_dpy; /* store current pointer */
+
+ /* decode the frame, but show it only if not frozen */
+ if (v->d_callbacks->dec_run(v, tmp) && !env->frame_freeze)
+ show_frame(env, WIN_REMOTE);
+ tmp->used = 0; /* mark buffer as free */
+ tmp->ebit = 0;
+ ast_mutex_lock(&env->dec_lock);
+ if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN]) /* advance to next, circular */
+ v->dec_in_dpy = &v->dec_in[0];
+
+ if (v->dec_in_cur == NULL) /* receiver was idle, enable it... */
+ v->dec_in_cur = tmp; /* using the slot just freed */
+ else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
+ v->dec_in_dpy = NULL; /* nothing more to display */
+ ast_mutex_unlock(&env->dec_lock);
+ }
}
- }
if (env->shutdown)
break;
@@ -988,7 +991,7 @@ static void *video_thread(void *arg)
for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
if (write(fd, &blah, l) != l)
ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n",
- chan->name, f->frametype, f->subclass, strerror(errno));
+ chan->name, f->frametype, f->subclass, strerror(errno));
}
}
ast_channel_unlock(chan);
@@ -1194,13 +1197,13 @@ int console_video_cli(struct video_desc *env, const char *var, int fd)
if (env == NULL)
return 1; /* unrecognised */
- if (!strcasecmp(var, "videodevice")) {
+ if (!strcasecmp(var, "videodevice")) {
ast_cli(fd, "videodevice is [%s]\n", env->out.devices[env->out.device_primary].name);
- } else if (!strcasecmp(var, "videocodec")) {
+ } else if (!strcasecmp(var, "videocodec")) {
ast_cli(fd, "videocodec is [%s]\n", env->codec_name);
- } else if (!strcasecmp(var, "sendvideo")) {
+ } else if (!strcasecmp(var, "sendvideo")) {
ast_cli(fd, "sendvideo is [%s]\n", env->out.sendvideo ? "on" : "off");
- } else if (!strcasecmp(var, "video_size")) {
+ } else if (!strcasecmp(var, "video_size")) {
int in_w = 0, in_h = 0;
if (env->in) {
in_w = env->in->dec_out.w;
@@ -1212,22 +1215,22 @@ int console_video_cli(struct video_desc *env, const char *var, int fd)
env->loc_dpy.w, env->loc_dpy.h,
env->rem_dpy.w, env->rem_dpy.h,
in_w, in_h);
- } else if (!strcasecmp(var, "bitrate")) {
+ } else if (!strcasecmp(var, "bitrate")) {
ast_cli(fd, "bitrate is [%d]\n", env->out.bitrate);
- } else if (!strcasecmp(var, "qmin")) {
+ } else if (!strcasecmp(var, "qmin")) {
ast_cli(fd, "qmin is [%d]\n", env->out.qmin);
- } else if (!strcasecmp(var, "fps")) {
+ } else if (!strcasecmp(var, "fps")) {
ast_cli(fd, "fps is [%d]\n", env->out.fps);
- } else if (!strcasecmp(var, "startgui")) {
+ } else if (!strcasecmp(var, "startgui")) {
env->stayopen = 1;
console_video_start(env, NULL);
- } else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
+ } else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
env->stayopen = 0;
if (env->gui && env->owner)
ast_cli_command(-1, "console hangup");
else /* not in a call */
console_video_uninit(env);
- } else {
+ } else {
return 1; /* unrecognised */
}
return 0; /* recognised */
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 762169f87..90e8628e8 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -2471,7 +2471,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", analog_event2str(res), res, p->channel, index);
if (res & (ANALOG_EVENT_PULSEDIGIT | ANALOG_EVENT_DTMFUP)) {
- analog_set_pulsedial(p, (res & ANALOG_EVENT_PULSEDIGIT));
+ analog_set_pulsedial(p, (res & ANALOG_EVENT_PULSEDIGIT) ? 1 : 0);
ast_debug(1, "Detected %sdigit '%c'\n", (res & ANALOG_EVENT_PULSEDIGIT) ? "pulse ": "", res & 0xff);
analog_confmute(p, 0);
p->subs[index].f.frametype = AST_FRAME_DTMF_END;
@@ -3581,11 +3581,9 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
}
break;
case ANALOG_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
- ast_log(LOG_NOTICE,
- "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
- i->channel);
- return i->chan_pvt;
- break;
+ ast_log(LOG_NOTICE, "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
+ i->channel);
+ return i->chan_pvt;
case ANALOG_EVENT_NEONMWI_ACTIVE:
analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_ACTIVE);
break;
diff --git a/channels/sig_analog.h b/channels/sig_analog.h
index ff62ed52d..d88e622e7 100644
--- a/channels/sig_analog.h
+++ b/channels/sig_analog.h
@@ -271,6 +271,7 @@ struct analog_pvt {
unsigned int transfer:1;
unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */
unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */
+ unsigned int callwaitingcallerid:1;
const struct ast_channel_tech *chan_tech;
/*!
* \brief TRUE if distinctive rings are to be detected.
@@ -287,7 +288,6 @@ struct analog_pvt {
int polarityonanswerdelay;
int stripmsd;
enum analog_cid_start cid_start;
- int callwaitingcallerid;
char mohsuggest[MAX_MUSICCLASS];
char cid_num[AST_MAX_EXTENSION];
char cid_name[AST_MAX_EXTENSION];
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index 6878d81e8..c75badd66 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -4176,36 +4176,36 @@ static void *pri_dchannel(void *vpri)
}
}
/* Start with reasonable max */
- lowest = ast_tv(60, 0);
+ if (doidling || pri->resetting) {
+ /*
+ * Make sure we stop at least once per second if we're
+ * monitoring idle channels
+ */
+ lowest = ast_tv(1, 0);
+ } else {
+ /* Don't poll for more than 60 seconds */
+ lowest = ast_tv(60, 0);
+ }
for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
- /* Find lowest available d-channel */
- if (!pri->dchans[i])
+ if (!pri->dchans[i]) {
+ /* We scanned all D channels on this span. */
break;
- if ((next = pri_schedule_next(pri->dchans[i]))) {
+ }
+ next = pri_schedule_next(pri->dchans[i]);
+ if (next) {
/* We need relative time here */
tv = ast_tvsub(*next, ast_tvnow());
if (tv.tv_sec < 0) {
- tv = ast_tv(0,0);
+ /*
+ * A timer has already expired.
+ * By definition zero time is the lowest so we can quit early.
+ */
+ lowest = ast_tv(0, 0);
+ break;
}
- if (doidling || pri->resetting) {
- if (tv.tv_sec > 1) {
- tv = ast_tv(1, 0);
- }
- } else {
- if (tv.tv_sec > 60) {
- tv = ast_tv(60, 0);
- }
+ if (ast_tvcmp(tv, lowest) < 0) {
+ lowest = tv;
}
- } else if (doidling || pri->resetting) {
- /* Make sure we stop at least once per second if we're
- monitoring idle channels */
- tv = ast_tv(1,0);
- } else {
- /* Don't poll for more than 60 seconds */
- tv = ast_tv(60, 0);
- }
- if (!i || ast_tvcmp(tv, lowest) < 0) {
- lowest = tv;
}
}
ast_mutex_unlock(&pri->lock);
@@ -4243,8 +4243,10 @@ static void *pri_dchannel(void *vpri)
ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
if (e) {
- if (pri->debug)
- pri_dump_event(pri->dchans[which], e);
+ if (pri->debug) {
+ ast_verbose("Span: %d Processing event: %s\n",
+ pri->span, pri_event2str(e->e));
+ }
if (e->e != PRI_EVENT_DCHAN_DOWN) {
if (!(pri->dchanavail[which] & DCHAN_UP)) {
@@ -5917,7 +5919,20 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i
l = NULL;
n = NULL;
if (!p->hidecallerid) {
- l = ast->connected.id.number.valid ? ast->connected.id.number.str : NULL;
+ if (ast->connected.id.number.valid) {
+ /* If we get to the end of this loop without breaking, there's no
+ * calleridnum. This is done instead of testing for "unknown" or
+ * the thousands of other ways that the calleridnum could be
+ * invalid. */
+ for (l = ast->connected.id.number.str; l && *l; l++) {
+ if (strchr("0123456789", *l)) {
+ l = ast->connected.id.number.str;
+ break;
+ }
+ }
+ } else {
+ l = NULL;
+ }
if (!p->hidecalleridname) {
n = ast->connected.id.name.valid ? ast->connected.id.name.str : NULL;
}
@@ -6316,7 +6331,7 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
case AST_CONTROL_PROGRESS:
ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
sig_pri_set_digital(p, 0); /* Digital-only calls isn't allowing any inband progress messages */
- if (!p->progress && p->pri && !p->outgoing && !p->no_b_channel) {
+ if (!p->progress && !p->alerting && p->pri && !p->outgoing && !p->no_b_channel) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
#ifdef HAVE_PRI_PROG_W_CAUSE
diff --git a/channels/sig_pri.h b/channels/sig_pri.h
index f57d8f700..98b05b9ca 100644
--- a/channels/sig_pri.h
+++ b/channels/sig_pri.h
@@ -295,8 +295,8 @@ struct sig_pri_span {
int fds[SIG_PRI_NUM_DCHANS]; /*!< FD's for d-channels */
#if defined(HAVE_PRI_AOC_EVENTS)
- int aoc_passthrough_flag; /*!< Represents what AOC messages (S,D,E) are allowed to pass-through */
- int aoce_delayhangup:1; /*!< defines whether the aoce_delayhangup option is enabled or not */
+ int aoc_passthrough_flag; /*!< Represents what AOC messages (S,D,E) are allowed to pass-through */
+ unsigned int aoce_delayhangup:1; /*!< defines whether the aoce_delayhangup option is enabled or not */
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_SERVICE_MESSAGES)
@@ -389,7 +389,7 @@ struct sig_pri_span {
int num_call_waiting_calls;
#endif /* defined(HAVE_PRI_CALL_WAITING) */
int dchanavail[SIG_PRI_NUM_DCHANS]; /*!< Whether each channel is available */
- int debug; /*!< set to true if to dump PRI event info (tested but never set) */
+ int debug; /*!< set to true if to dump PRI event info */
int span; /*!< span number put into user output messages */
int resetting; /*!< true if span is being reset/restarted */
int resetpos; /*!< current position during a reset (-1 if not started) */
diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c
index 659e8cecc..0ab9ed769 100644
--- a/channels/sip/config_parser.c
+++ b/channels/sip/config_parser.c
@@ -661,16 +661,18 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum s
else
line = *hostname;
- if ((port = strrchr(line, ':'))) {
- *port++ = '\0';
+ if (ast_sockaddr_split_hostport(line, hostname, &port, 0) == 0) {
+ ast_log(LOG_WARNING, "Cannot parse host '%s' on line %d of sip.conf.\n",
+ line, lineno);
+ return -1;
+ }
+ if (port) {
if (!sscanf(port, "%5u", portnum)) {
ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", port, lineno);
port = NULL;
}
- }
-
- if (!port) {
+ } else {
if (*transport & SIP_TRANSPORT_TLS) {
*portnum = STANDARD_TLS_PORT;
} else {
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 0e207ca23..2bd1bc75f 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -154,14 +154,6 @@
*/
#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH"
-/*! \brief SIP Extensions we support
- * \note This should be generated based on the previous array
- * in combination with settings.
- *
- * \todo We should not have "timer" if it's disabled in the configuration file.
- */
-#define SUPPORTED_EXTENSIONS "replaces, timer"
-
/*! \brief Standard SIP unsecure port for UDP and TCP from RFC 3261. DO NOT CHANGE THIS */
#define STANDARD_SIP_PORT 5060
/*! \brief Standard SIP TLS port from RFC 3261. DO NOT CHANGE THIS */
@@ -209,12 +201,13 @@
#define DEFAULT_DOMAINSASREALM FALSE /*!< Use the domain option to guess the realm for registration and invite requests */
#define DEFAULT_NOTIFYRINGING TRUE /*!< Notify devicestate system on ringing state */
#define DEFAULT_NOTIFYCID DISABLED /*!< Include CID with ringing notifications */
-#define DEFAULT_PEDANTIC FALSE /*!< Avoid following SIP standards for dialog matching */
+#define DEFAULT_PEDANTIC TRUE /*!< Follow SIP standards for dialog matching */
#define DEFAULT_AUTOCREATEPEER FALSE /*!< Don't create peers automagically */
#define DEFAULT_MATCHEXTERNADDRLOCALLY FALSE /*!< Match extern IP locally default setting */
#define DEFAULT_QUALIFY FALSE /*!< Don't monitor devices */
#define DEFAULT_CALLEVENTS FALSE /*!< Extra manager SIP call events */
-#define DEFAULT_ALWAYSAUTHREJECT FALSE /*!< Don't reject authentication requests always */
+#define DEFAULT_ALWAYSAUTHREJECT TRUE /*!< Don't reject authentication requests always */
+#define DEFAULT_AUTH_OPTIONS FALSE
#define DEFAULT_REGEXTENONQUALIFY FALSE
#define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */
#define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */
@@ -682,6 +675,7 @@ struct sip_settings {
int srvlookup; /*!< SRV Lookup on or off. Default is on */
int allowguest; /*!< allow unauthenticated peers to connect? */
int alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */
+ int auth_options_requests; /*!< Authenticate OPTIONS requests */
int compactheaders; /*!< send compact sip headers */
int allow_external_domains; /*!< Accept calls to external SIP domains? */
int callevents; /*!< Whether we send manager events or not */
diff --git a/configs/cdr.conf.sample b/configs/cdr.conf.sample
index 3866ab1fa..b0c38c6cf 100644
--- a/configs/cdr.conf.sample
+++ b/configs/cdr.conf.sample
@@ -29,6 +29,22 @@
; channel.)
;unanswered = no
+; Normally, CDR's are not closed out until after all extensions are finished
+; executing. By enabling this option, the CDR will be ended before executing
+; the "h" extension so that CDR values such as "end" and "billsec" may be
+; retrieved inside of of this extension. The default value is "no".
+;endbeforehexten=no
+
+; Normally, the 'billsec' field logged to the backends (text files or databases)
+; is simply the end time (hangup time) minus the answer time in seconds. Internally,
+; asterisk stores the time in terms of microseconds and seconds. By setting
+; initiatedseconds to 'yes', you can force asterisk to report any seconds
+; that were initiated (a sort of round up method). Technically, this is
+; when the microsecond part of the end time is greater than the microsecond
+; part of the answer time, then the billsec time is incremented one second.
+; The default value is "no".
+;initiatedseconds=no
+
; Define the CDR batch mode, where instead of posting the CDR at the end of
; every call, the data will be stored in a buffer to help alleviate load on the
; asterisk server. Default is "no".
@@ -65,21 +81,6 @@
; is "yes".
;safeshutdown=yes
-; Normally, CDR's are not closed out until after all extensions are finished
-; executing. By enabling this option, the CDR will be ended before executing
-; the "h" extension so that CDR values such as "end" and "billsec" may be
-; retrieved inside of of this extension.
-;endbeforehexten=no
-
-; Normally, the 'billsec' field logged to the backends (text files or databases)
-; is simply the end time (hangup time) minus the answer time in seconds. Internally,
-; asterisk stores the time in terms of microseconds and seconds. By setting
-; initiatedseconds to 'yes', you can force asterisk to report any seconds
-; that were initiated (a sort of round up method). Technically, this is
-; when the microsecond part of the end time is greater than the microsecond
-; part of the answer time, then the billsec time is incremented one second.
-;initiatedseconds=no
-
;
;
; CHOOSING A CDR "BACKEND" (what kind of output to generate)
diff --git a/configs/cel.conf.sample b/configs/cel.conf.sample
index e99a34897..dba886604 100644
--- a/configs/cel.conf.sample
+++ b/configs/cel.conf.sample
@@ -90,7 +90,6 @@ events=APP_START,CHAN_START,CHAN_END,ANSWER,HANGUP,BRIDGE_START,BRIDGE_END
;
; Asterisk Manager Interface (AMI) CEL Backend
;
-
[manager]
; AMI Backend Activation
@@ -100,5 +99,17 @@ events=APP_START,CHAN_START,CHAN_END,ANSWER,HANGUP,BRIDGE_START,BRIDGE_END
;
; Accepted values: yes and no
; Default value: no
-
;enabled=yes
+
+;
+; RADIUS CEL Backend
+;
+[radius]
+;
+; Log date/time in GMT
+;usegmtime=yes
+;
+; Set this to the location of the radiusclient-ng configuration file
+; The default is /etc/radiusclient-ng/radiusclient.conf
+;radiuscfg => /usr/local/etc/radiusclient-ng/radiusclient.conf
+;
diff --git a/configs/cel_custom.conf.sample b/configs/cel_custom.conf.sample
index 4c5fbb093..37491a48b 100644
--- a/configs/cel_custom.conf.sample
+++ b/configs/cel_custom.conf.sample
@@ -17,5 +17,15 @@
; in the cel-custom directory under your Asterisk logs directory.
;
+;
+; Within a mapping, use the CALLERID() and CHANNEL() functions to retrieve
+; details from the CEL event. There are also a few variables created by this
+; module that can be used in a mapping:
+;
+; eventtype - The name of the CEL event.
+; eventtime - The timestamp of the CEL event.
+; eventextra - Extra data included with this CEL event, typically along with
+; an event of type USER_DEFINED from CELGenUserEvent().
+;
[mappings]
-;Master.csv => "${eventtype}","${eventtime}","${CALLERID(name)}","${CALLERID(num)}","${CALLERID(ANI)}","${CALLERID(RDNIS)}","${CALLERID(DNID)}","${CHANNEL(exten)}","${CHANNEL(context)}","${CHANNEL(channame)}","${CHANNEL(appname)}","${CHANNEL(appdata)}","${CHANNEL(amaflags)}","${CHANNEL(accountcode)}","${CHANNEL(uniqueid)}","${CHANNEL(linkedid)}","${CHANNEL(peer)}","${CHANNEL(userfield)}"
+;Master.csv => ${CSV_QUOTE(${eventtype})},${CSV_QUOTE(${eventtime})},${CSV_QUOTE(${CALLERID(name)})},${CSV_QUOTE(${CALLERID(num)})},${CSV_QUOTE(${CALLERID(ANI)})},${CSV_QUOTE(${CALLERID(RDNIS)})},${CSV_QUOTE(${CALLERID(DNID)})},${CSV_QUOTE(${CHANNEL(exten)})},${CSV_QUOTE(${CHANNEL(context)})},${CSV_QUOTE(${CHANNEL(channame)})},${CSV_QUOTE(${CHANNEL(appname)})},${CSV_QUOTE(${CHANNEL(appdata)})},${CSV_QUOTE(${CHANNEL(amaflags)})},${CSV_QUOTE(${CHANNEL(accountcode)})},${CSV_QUOTE(${CHANNEL(uniqueid)})},${CSV_QUOTE(${CHANNEL(linkedid)})},${CSV_QUOTE(${CHANNEL(peer)})},${CSV_QUOTE(${CHANNEL(userfield)})},${CSV_QUOTE(${eventextra})}
diff --git a/configs/cel_adaptive_odbc.conf.sample b/configs/cel_odbc.conf.sample
index 01702d192..5f21326df 100644
--- a/configs/cel_adaptive_odbc.conf.sample
+++ b/configs/cel_odbc.conf.sample
@@ -61,7 +61,7 @@
; peeraccount
; uniqueid
; linkedid
-; amaflag (an int)
+; amaflags (an int)
; userfield
; peer
diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample
index b516d4b85..73ae78afb 100644
--- a/configs/iax.conf.sample
+++ b/configs/iax.conf.sample
@@ -244,6 +244,15 @@ forcejitterbuffer=no
;
;register => FWDNumber:passwd@iax.fwdnet.net
;
+; Through the use of the res_stun_monitor module, Asterisk has the ability to detect when the
+; perceived external network address has changed. When the stun_monitor is installed and
+; configured, chan_iax will renew all outbound registrations when the monitor detects any sort
+; of network change has occurred. By default this option is enabled, but only takes effect once
+; res_stun_monitor is configured. If res_stun_monitor is enabled and you wish to not
+; generate all outbound registrations on a network change, use the option below to disable
+; this feature.
+;
+; subscribe_network_change_event = yes ; on by default
;
; You can disable authentication debugging to reduce the amount of
; debugging traffic.
diff --git a/configs/manager.conf.sample b/configs/manager.conf.sample
index bfa13430c..253a3ffa4 100644
--- a/configs/manager.conf.sample
+++ b/configs/manager.conf.sample
@@ -23,15 +23,8 @@
[general]
enabled = no
;webenabled = yes
-port = 5038
-
-;httptimeout = 60
-; a) httptimeout sets the Max-Age of the http cookie
-; b) httptimeout is the amount of time the webserver waits
-; on a action=waitevent request (actually its httptimeout-10)
-; c) httptimeout is also the amount of time the webserver keeps
-; a http session alive after completing a successful action
+port = 5038
bindaddr = 0.0.0.0
; Parameters that control AMI over TLS. ("enabled" must be set too).
@@ -69,6 +62,15 @@ bindaddr = 0.0.0.0
; debug = on ; enable some debugging info in AMI messages (default off).
; Also accessible through the "manager debug" CLI command.
+
+;httptimeout = 60
+; a) httptimeout sets the Max-Age of the http cookie
+; b) httptimeout is the amount of time the webserver waits
+; on a action=waitevent request (actually its httptimeout-10)
+; c) httptimeout is also the amount of time the webserver keeps
+; a http session alive after completing a successful action
+
+
;[mark]
;secret = mysecret
;deny=0.0.0.0/0.0.0.0
diff --git a/configs/res_curl.conf.sample b/configs/res_curl.conf.sample
new file mode 100644
index 000000000..2cc92dcbd
--- /dev/null
+++ b/configs/res_curl.conf.sample
@@ -0,0 +1,8 @@
+;
+; CURLOPT global settings (mostly set for realtime)
+;
+[globals]
+;proxy=myproxy.example.com
+;proxytype=http
+;proxyport=8001
+;proxyuserpwd=asterisk:asteriskrocks
diff --git a/configs/res_stun_monitor.conf.sample b/configs/res_stun_monitor.conf.sample
new file mode 100644
index 000000000..9237799c5
--- /dev/null
+++ b/configs/res_stun_monitor.conf.sample
@@ -0,0 +1,22 @@
+;
+; Configuration file for the res_stun_monitor module
+;
+; The res_stun_monitor module sends STUN requests to a configured STUN server
+; periodically. If the monitor detects a change in the external ip or port
+; provided by the STUN server an event is sent out internally within Asterisk
+; to alert all listeners to that event of the change.
+
+; The current default listeners for the netork change event include chan_sip
+; and chan_iax. Both of these channel drivers by default react to this event
+; by renewing all outbound registrations. This allows the endpoints Asterisk
+; is registering with to become aware of the address change and know the new
+; location.
+;
+[general]
+;
+; ---- STUN Server configuration ---
+; Setting the 'stunaddr' option to a valid address enables the stun monitor.
+;
+; stunaddr = mystunserver.com ; address of the stun server to query.
+; stunrefresh = 30 ; number of seconds between stun refreshes. default is 30
+;
diff --git a/configs/say.conf.sample b/configs/say.conf.sample
index 670e3944e..6285dbe1e 100644
--- a/configs/say.conf.sample
+++ b/configs/say.conf.sample
@@ -86,16 +86,23 @@ mode=old ; method for playing numbers and dates
; the 'SAY' variable contains YYYYMMDDHHmm.ss-dow-doy
; these rule map the strftime attributes.
_date:Y:. => num:${SAY:0:4} ; year, 19xx
- _date:[Bb]:. => digits/mon-$[${SAY:4:2}-1] ; month name, 0..11
+ _date:[Bbh]:. => digits/mon-$[${SAY:4:2}-1] ; month name, 0..11
_date:[Aa]:. => digits/day-${SAY:16:1} ; day of week
_date:[de]:. => num:${SAY:6:2} ; day of month
- _date:[hH]:. => num:${SAY:8:2} ; hour
+ _date:[H]:. => digits/oh, num:${SAY:8:2} ; hour (oh one, oh two, ..., oh nine, ten, eleven, ..., twenty-three)
_date:[I]:. => num:$[${SAY:8:2} % 12] ; hour 0-12
_date:[M]:. => num:${SAY:10:2} ; minute
; XXX too bad the '?' function does not remove the quotes
; _date:[pP]:. => digits/$[ ${SAY:10:2} > 12 ? "p-m" :: "a-m"] ; am pm
_date:[pP]:. => digits/p-m ; am pm
_date:[S]:. => num:${SAY:13:2} ; seconds
+ _date:[Ii]:. => num:$[${SAY:8:2} % 12] ; hour 0-12
+ _date:[k]:. => num:${SAY:8:2} ; hour (one, two. three, ...,twenty three
+ _date:[m]:. => num:${SAY:4:2} ; month number
+ _date:[Q]:. => date:dby ;incompleat ; "today", "yesterday" or ABdY
+ _date:[q]:. => date:dby ;incompleat ; "" (for today), "yesterday", weekday, or ABdY
+ _date:[R]:. => date:HM${SAY} ; 24 hour time, including minute
+ _date:[T]:. => date:HMS${SAY} ; 24 hour, minure, seconds
[en-base](!)
_[n]um:0. => num:${SAY:1}
@@ -106,16 +113,25 @@ mode=old ; method for playing numbers and dates
_[n]um:X00 => num:${SAY:0:1}, digits/hundred
_[n]um:XXX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:X000 => num:${SAY:0:1}, digits/thousand
_[n]um:XXXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
_[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}
+ _[n]um:X000000 => num:${SAY:0:1}, digits/million
_[n]um:XXXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/million
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/million
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}
+ _[n]um:X000000000 => num:${SAY:0:1}, digits/billion
_[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}
+ _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion
_[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}
+ _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion
_[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}
; enumeration
@@ -123,7 +139,8 @@ mode=old ; method for playing numbers and dates
_e[n]um:1X => digits/h-${SAY}
_e[n]um:[2-9]0 => digits/h-${SAY}
_e[n]um:[2-9][1-9] => num:${SAY:0:1}0, digits/h-${SAY:1}
- _e[n]um:[1-9]XX => num:${SAY:0:1}, digits/hundred, enum:${SAY:1}
+ _e[n]um:[1-9]00 => num:${SAY:0:1}, digits/h-hundred
+ _e[n]um:[1-9]XX => num:${SAY:0:1}, digits/h-hundred, enum:${SAY:1}
[en_GB](date-base,digit-base,en-base)
_[n]um:XXX => num:${SAY:0:1}, digits/hundred, vm-and, num:${SAY:1}
@@ -139,16 +156,31 @@ mode=old ; method for playing numbers and dates
_[n]um:[2-9]00 => num:${SAY:0:1}, digits/hundred
_[n]um:[2-9]XX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:1000 => digits/thousand
_[n]um:1XXX => digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => num:${SAY:0:1}, digits/thousands
_[n]um:[2-9]XXX => num:${SAY:0:1}, digits/thousands, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousands
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousands, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousands
_[n]um:XXXXXX => num:${SAY:0:3}, digits/thousands, num:${SAY:3}
+ _[n]um:1000000 => num:${SAY:0:1}, digits/million
_[n]um:1XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:[2-9]000000 => num:${SAY:0:1}, digits/millions
_[n]um:[2-9]XXXXXX => num:${SAY:0:1}, digits/millions, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/millions
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}
+ _[n]um:X000000000 => num:${SAY:0:1}, digits/billion
+ _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}
+ _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion
+ _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}
+ _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion
+ _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}
+
_datetime::. => date:AdBY 'digits/at' IMp:${SAY}
_date::. => date:AdBY:${SAY}
_time::. => date:IMp:${SAY}
@@ -168,14 +200,23 @@ mode=old ; method for playing numbers and dates
_[n]um:1XX => digits/ein, digits/hundred, num:${SAY:1}
_[n]um:[2-9]00 => digits/${SAY:0:1}, digits/hundred
_[n]um:[2-9]XX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}
+
+ _[n]um:1000 => digits/ein, digits/thousand
_[n]um:1XXX => digits/ein, digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => digits/${SAY:0:1}, digits/thousand
_[n]um:[2-9]XXX => digits/${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
- _[n]um:X00XXX => digits/${SAY:0:1}, digits/hundred, digits/thousand, num:${SAY:3}
- _[n]um:XXXXXX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
+ _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:1}
+
+ _[n]um:1000000 => digits/eine, digits/million
_[n]um:1XXXXXX => digits/eine, digits/million, num:${SAY:1}
+ _[n]um:[2-9]000000 => digits/${SAY:0:1}, digits/millions
_[n]um:[2-9]XXXXXX => digits/${SAY:0:1}, digits/millions, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/millions
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}
_datetime::. => date:AdBY 'digits/at' IMp:${SAY}
@@ -191,16 +232,25 @@ mode=old ; method for playing numbers and dates
_[n]um:[3-9][1-9] => digits/${SAY:0:1}0, num:${SAY:1}
_[n]um:XXX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:X000 => num:${SAY:0:1}, digits/thousand
_[n]um:XXXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
_[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}
+ _[n]um:X000000 => num:${SAY:0:1}, digits/million
_[n]um:XXXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/million
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/million
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}
+ _[n]um:X000000000 => num:${SAY:0:1}, digits/billion
_[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}
+ _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion
_[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}
+ _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion
_[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}
_datetime::. => date:YBdA k 'ora' M 'perc':${SAY}
@@ -222,14 +272,22 @@ mode=old ; method for playing numbers and dates
_[n]um:[2-9]00 => num:${SAY:0:1}, digits/hundred
_[n]um:[2-9]XX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}
+ _[n]um:1000 => digits/thousand
_[n]um:1XXX => digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => num:${SAY:0:1}, digits/thousand
_[n]um:[2-9]XXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
_[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
_[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}
+ _[n]um:1000000 => num:${SAY:0:1}, digits/million
_[n]um:1XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:[2-9]000000 => num:${SAY:0:1}, digits/million
_[n]um:[2-9]XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/million
_[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/million
_[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}
_datetime::. => date:AdBY 'digits/at' H 'hours' M 'perc':${SAY}
@@ -276,3 +334,50 @@ mode=old ; method for playing numbers and dates
_date::. => date:Ad 'letters/d' B 'letters/d' Y:${SAY}
_time::. => date:HMp:${SAY}
+[da](date-base,digit-base)
+ _[n]um:0. => num:${SAY:1}
+ _[n]um:X => digits/${SAY}
+ _[n]um:1X => digits/${SAY}
+ _[n]um:[2-9]0 => digits/${SAY}
+ _[n]um:[2-9][1-9] => digits/${SAY:1}-and, digits/${SAY:0:1}0
+ _[n]um:100 => digits/1N, digits/hundred
+ _[n]um:1XX => digits/1N, digits/hundred, num:${SAY:1}
+ _[n]um:[2-9]00 => digits/${SAY:0:1}, digits/hundred
+ _[n]um:[2-9]XX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}
+
+ _[n]um:1000 => digits/1N, digits/thousand
+ _[n]um:1XXX => digits/1N, digits/thousand, num:${SAY:1}
+ _[n]um:[2-9]000 => digits/${SAY:0:1}, digits/thousand
+ _[n]um:[2-9]XXX => digits/${SAY:0:1}, digits/thousand, num:${SAY:1}
+ _[n]um:XX000 => num:${SAY:0:2}, digits/thousand
+ _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}
+ _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand
+ _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}
+
+ _[n]um:X000000 => digits/${SAY:0:1}, digits/million
+ _[n]um:XXXXXXX => digits/${SAY:0:1}, digits/million, num:${SAY:1}
+ _[n]um:XX000000 => num:${SAY:0:2}, digits/millions
+ _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}
+ _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions
+ _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}
+
+ _[n]um:X000000000 => num:${SAY:0:1}, digits/billion
+ _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}
+ _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion
+ _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}
+ _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion
+ _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}
+
+ _datetime::. => date:AdBY 'digits/at' kM:${SAY}
+ _date::. => date:AdBY:${SAY}
+ _time::. => date:HM:${SAY}
+
+ ; enumeration
+ _e[n]um:X => digits/h-${SAY}
+ _e[n]um:1X => digits/h-${SAY}
+ _e[n]um:[2-9]0 => digits/h-${SAY}
+ _e[n]um:[2-9][1-9] => digits/${SAY:1}-and, digits/h-${SAY:0:1}0
+ _e[n]um:100 => digits/1N, digits/h-hundred
+ _e[n]um:1XX => digits/1N, digits/h-hundred, enum:${SAY:1}
+ _e[n]um:[2-9]00 => num:${SAY:0:1}, digits/h-hundred
+ _e[n]um:[2-9]XX => num:${SAY:0:1}, digits/h-hundred, enum:${SAY:1}
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index 01fd29b00..320895669 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -144,6 +144,8 @@ allowoverlap=no ; Disable overlap dialing support. (Default is y
; d) Listen on the IPv4 and IPv6 wildcards. Example: bindaddr=::
; (You can choose independently for UDP, TCP, and TLS, by specifying different values for
; "udpbindaddr", "tcpbindaddr", and "tlsbindaddr".)
+; (Note that using bindaddr=:: will show only a single IPv6 socket in netstat.
+; IPv4 is supported at the same time using IPv4-mapped IPv6 addresses.)
;
; You may optionally add a port number. (The default is port 5060 for UDP and TCP, 5061
; for TLS).
@@ -213,7 +215,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;pedantic=yes ; Enable checking of tags in headers,
; international character conversions in URIs
; and multiline formatted headers for strict
- ; SIP compatibility (defaults to "no")
+ ; SIP compatibility (defaults to "yes")
; See qos.tex or Quality of Service section of asterisk.pdf for a description of these parameters.
;tos_sip=cs3 ; Sets TOS for SIP packets.
@@ -253,6 +255,18 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; Message-Account in the MWI notify message
; defaults to "asterisk"
+; Codec negotiation
+;
+; When Asterisk is receiving a call, the codec will initially be set to the
+; first codec in the allowed codecs defined for the user receiving the call
+; that the caller also indicates that it supports. But, after the caller
+; starts sending RTP, Asterisk will switch to using whatever codec the caller
+; is sending.
+;
+; When Asterisk is placing a call, the codec used will be the first codec in
+; the allowed codecs that the callee indicates that it supports. Asterisk will
+; *not* switch to whatever codec the callee is sending.
+;
;preferred_codec_only=yes ; Respond to a SIP invite with the single most preferred codec
; rather than advertising all joint codec capabilities. This
; limits the other side's codec choice to exactly what we prefer.
@@ -354,6 +368,10 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; instead of letting the requester know whether there was
; a matching user or peer for their request. This reduces
; the ability of an attacker to scan for valid SIP usernames.
+ ; This option is set to "yes" by default.
+
+;auth_options_requests = yes ; Enabling this option will authenticate OPTIONS requests just like
+ ; INVITE requests are. By default this option is disabled.
;g726nonstandard = yes ; If the peer negotiates G726-32 audio, use AAL2 packing
; order instead of RFC3551 packing order (this is required
@@ -364,6 +382,10 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;outboundproxy=proxy.provider.domain:8080 ; send outbound signaling to this proxy, not directly to the devices
;outboundproxy=proxy.provider.domain,force ; Send ALL outbound signalling to proxy, ignoring route: headers
;outboundproxy=tls://proxy.provider.domain ; same as '=proxy.provider.domain' except we try to connect with tls
+;outboundproxy=192.0.2.1 ; IPv4 address literal (default port is 5060)
+;outboundproxy=2001:db8::1 ; IPv6 address literal (default port is 5060)
+;outboundproxy=192.168.0.2.1:5062 ; IPv4 address literal with explicit port
+;outboundproxy=[2001:db8::1]:5062 ; IPv6 address literal with explicit port
; ; (could also be tcp,udp) - defining transports on the proxy line only
; ; applies for the global proxy, otherwise use the transport= option
;matchexternaddrlocally = yes ; Only substitute the externaddr or externhost setting if it matches
@@ -720,31 +742,18 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; externhost=foo.dyndns.net ; refreshed periodically
; externrefresh=180 ; change the refresh interval
;
-; c. "stunaddr = stun.server[:port]" queries the STUN server specified
-; as an argument to obtain the external address/port.
-; Queries are also sent periodically every "externrefresh" seconds
-; (as a side effect, sending the query also acts as a keepalive for
-; the state entry on the nat box):
-;
-; stunaddr = foo.stun.com:3478
-; externrefresh = 15
-;
-; NOTE: STUN is only implemented for IPv4.
-;
; Note that at the moment all these mechanism work only for the SIP socket.
-; The IP address discovered with externaddr/externhost/STUN is reused for
+; The IP address discovered with externaddr/externhost is reused for
; media sessions as well, but the port numbers are not remapped so you
; may still experience problems.
;
; NOTE 1: in some cases, NAT boxes will use different port numbers in
; the internal<->external mapping. In these cases, the "externaddr" and
-; "externhost" might not help you configure addresses properly, and you
-; really need to use STUN.
+; "externhost" might not help you configure addresses properly.
;
; NOTE 2: when using "externaddr" or "externhost", the address part is
-; also used as the external address for media sessions. Even if you
-; use "stunaddr", STUN queries will be sent only from the SIP port,
-; not from media sockets. Thus, the port information in the SDP may be wrong!
+; also used as the external address for media sessions. Thus, the port
+; information in the SDP may be wrong!
;
; In addition to the above, Asterisk has an additional "nat" parameter to
; address NAT-related issues in incoming SIP or media sessions.
@@ -776,6 +785,16 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; can not be set per-user or per-peer.
;
; media_address = 172.16.42.1
+;
+; Through the use of the res_stun_monitor module, Asterisk has the ability to detect when the
+; perceived external network address has changed. When the stun_monitor is installed and
+; configured, chan_sip will renew all outbound registrations when the monitor detects any sort
+; of network change has occurred. By default this option is enabled, but only takes effect once
+; res_stun_monitor is configured. If res_stun_monitor is enabled and you wish to not
+; generate all outbound registrations on a network change, use the option below to disable
+; this feature.
+;
+; subscribe_network_change_event = yes ; on by default
;----------------------------------- MEDIA HANDLING --------------------------------
; By default, Asterisk tries to re-invite media streams to an optimal path. If there's
diff --git a/configure b/configure
index 655adc785..a192c5674 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.ac Revision: 279658 .
+# From configure.ac Revision: 285161 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.65 for asterisk trunk.
#
@@ -4674,6 +4674,9 @@ case "${host_os}" in
$as_echo "#define AST_POLL_COMPAT 1" >>confdefs.h
+
+$as_echo "#define _DARWIN_UNLIMITED_SELECT 1" >>confdefs.h
+
;;
*)
@@ -13930,7 +13933,7 @@ fi
done
-for ac_func in asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap ntohll newlocale putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl
+for ac_func in asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii memchr memmove memset mkdir munmap ntohll newlocale ppoll putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -14844,6 +14847,95 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can increase the maximum select-able file descriptor" >&5
+$as_echo_n "checking if we can increase the maximum select-able file descriptor... " >&6; }
+if test "$cross_compiling" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compile" >&5
+$as_echo "cross-compile" >&6; }
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main ()
+{
+
+ struct rlimit rlim = { FD_SETSIZE * 2, FD_SETSIZE * 2 };
+ int fd0, fd1;
+ struct timeval tv = { 0, };
+ struct ast_fdset { long fds_bits[1024]; } fds = { { 0, } };
+ if (setrlimit(RLIMIT_NOFILE, &rlim)) { exit(1); }
+ if ((fd0 = open("/dev/null", O_RDONLY)) < 0) { exit(1); }
+ if (dup2(fd0, (fd1 = FD_SETSIZE + 1)) < 0) { exit(1); }
+ FD_SET(fd0, (fd_set *) &fds);
+ FD_SET(fd1, (fd_set *) &fds);
+ if (select(FD_SETSIZE + 2, (fd_set *) &fds, NULL, NULL, &tv) < 0) { exit(1); }
+ exit(0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_VARIABLE_FDSET 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+if test "${ac_cv_have_variable_fdset}x" = "0x"; then
+ if test "$cross_compiling" = yes; then :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot run test program while cross compiling
+See \`config.log' for more details." "$LINENO" 5; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+if (getuid() != 0) { exit(1); }
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define CONFIGURE_RAN_AS_ROOT 1" >>confdefs.h
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute pure' support" >&5
$as_echo_n "checking for compiler 'attribute pure' support... " >&6; }
@@ -26148,6 +26240,64 @@ fi
+if test "$PBX_SRTP" = "1";
+then
+ saved_libs="${LIBS}"
+ saved_ldflags="${LDFLAGS}"
+ saved_cflags="${CFLAGS}"
+ LIBS="${LIBS} ${SRTP_LIB}"
+ LDFLAGS="${LDFLAGS} -shared -fPIC"
+ CFLAGS="${CFLAGS} ${SRTP_INCLUDE}"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the ability of -lsrtp to be linked in a shared object" >&5
+$as_echo_n "checking for the ability of -lsrtp to be linked in a shared object... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <srtp/srtp.h>
+int
+main ()
+{
+srtp_init();
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ***" >&5
+$as_echo "$as_me: ***" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: *** libsrtp could not be linked as a shared object" >&5
+$as_echo "$as_me: *** libsrtp could not be linked as a shared object" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: *** try compiling libsrtp manually and configuring with" >&5
+$as_echo "$as_me: *** try compiling libsrtp manually and configuring with" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: *** ./configure CFLAGS=-fPIC --prefix=/usr" >&5
+$as_echo "$as_me: *** ./configure CFLAGS=-fPIC --prefix=/usr" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: *** replacing /usr with the prefix of your choice" >&5
+$as_echo "$as_me: *** replacing /usr with the prefix of your choice" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ***" >&5
+$as_echo "$as_me: ***" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: *** If you do not need SRTP support re-run configure" >&5
+$as_echo "$as_me: *** If you do not need SRTP support re-run configure" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: *** with the --without-srtp option." >&5
+$as_echo "$as_me: *** with the --without-srtp option." >&6;}
+ exit 1
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="${saved_libs}"
+ LDFLAGS="${saved_ldflags}"
+ CFLAGS="${saved_cflags}"
+fi
+
if test "x${PBX_GMIME}" != "x1" -a "${USE_GMIME}" != "no"; then
PBX_GMIME=0
diff --git a/configure.ac b/configure.ac
index dfc45a5e8..afd997092 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,6 +60,7 @@ case "${host_os}" in
;;
darwin*)
AC_DEFINE([AST_POLL_COMPAT], 1, [Define to 1 if internal poll should be used.])
+ AC_DEFINE([_DARWIN_UNLIMITED_SELECT], 1, [Define to 1 if running on Darwin.])
;;
*)
AC_PREFIX_DEFAULT([/usr])
@@ -463,7 +464,7 @@ AC_FUNC_STRNLEN
AC_FUNC_STRTOD
AC_FUNC_UTIME_NULL
AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap ntohll newlocale putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl])
+AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii memchr memmove memset mkdir munmap ntohll newlocale ppoll putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl])
# NOTE: we use AC_CHECK_LIB to get -lm into the arguments for later checks,
# so that AC_CHECK_FUNCS can detect functions in that library.
@@ -738,6 +739,48 @@ AC_RUN_IFELSE(
AC_MSG_RESULT(unknown)
)
+AC_MSG_CHECKING(if we can increase the maximum select-able file descriptor)
+AC_RUN_IFELSE(
+AC_LANG_PROGRAM([
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+], [[
+ struct rlimit rlim = { FD_SETSIZE * 2, FD_SETSIZE * 2 };
+ int fd0, fd1;
+ struct timeval tv = { 0, };
+ struct ast_fdset { long fds_bits[[1024]]; } fds = { { 0, } };
+ if (setrlimit(RLIMIT_NOFILE, &rlim)) { exit(1); }
+ if ((fd0 = open("/dev/null", O_RDONLY)) < 0) { exit(1); }
+ if (dup2(fd0, (fd1 = FD_SETSIZE + 1)) < 0) { exit(1); }
+ FD_SET(fd0, (fd_set *) &fds);
+ FD_SET(fd1, (fd_set *) &fds);
+ if (select(FD_SETSIZE + 2, (fd_set *) &fds, NULL, NULL, &tv) < 0) { exit(1); }
+ exit(0)]]),
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_VARIABLE_FDSET], 1, [Define to 1 if your system can support larger than default select bitmasks.]),
+ AC_MSG_RESULT(no),
+ AC_MSG_RESULT(cross-compile)
+)
+
+if test "${ac_cv_have_variable_fdset}x" = "0x"; then
+ AC_RUN_IFELSE(
+ AC_LANG_PROGRAM([
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+], [if (getuid() != 0) { exit(1); }]),
+ AC_DEFINE([CONFIGURE_RAN_AS_ROOT], 1, [Some configure tests will unexpectedly fail if configure is run by a non-root user. These may be able to be tested at runtime.]))
+fi
+
AST_GCC_ATTRIBUTE(pure)
AST_GCC_ATTRIBUTE(malloc)
AST_GCC_ATTRIBUTE(const)
@@ -1807,6 +1850,41 @@ fi
AST_EXT_LIB_CHECK([SRTP], [srtp], [srtp_init], [srtp/srtp.h])
+if test "$PBX_SRTP" = "1";
+then
+ saved_libs="${LIBS}"
+ saved_ldflags="${LDFLAGS}"
+ saved_cflags="${CFLAGS}"
+ LIBS="${LIBS} ${SRTP_LIB}"
+ LDFLAGS="${LDFLAGS} -shared -fPIC"
+ CFLAGS="${CFLAGS} ${SRTP_INCLUDE}"
+ AC_MSG_CHECKING(for the ability of -lsrtp to be linked in a shared object)
+ AC_LINK_IFELSE(
+ [
+ AC_LANG_PROGRAM(
+ [#include <srtp/srtp.h>],
+ [srtp_init();]
+ )
+ ],
+ [ AC_MSG_RESULT(yes) ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_NOTICE(***)
+ AC_MSG_NOTICE(*** libsrtp could not be linked as a shared object)
+ AC_MSG_NOTICE(*** try compiling libsrtp manually and configuring with)
+ AC_MSG_NOTICE(*** ./configure CFLAGS=-fPIC --prefix=/usr)
+ AC_MSG_NOTICE(*** replacing /usr with the prefix of your choice)
+ AC_MSG_NOTICE(***)
+ AC_MSG_NOTICE(*** If you do not need SRTP support re-run configure)
+ AC_MSG_NOTICE(*** with the --without-srtp option.)
+ exit 1
+ ]
+ )
+ LIBS="${saved_libs}"
+ LDFLAGS="${saved_ldflags}"
+ CFLAGS="${saved_cflags}"
+fi
+
AST_EXT_TOOL_CHECK([GMIME], [gmime-config], [], [], [#include <gmime/gmime.h>], [gboolean q = g_mime_check_version(0,0,0);])
AST_EXT_LIB_CHECK([HOARD], [hoard], [malloc], [])
diff --git a/doc/tex/asterisk.tex b/doc/tex/asterisk.tex
index 4934d14fc..38d58bdef 100644
--- a/doc/tex/asterisk.tex
+++ b/doc/tex/asterisk.tex
@@ -151,12 +151,18 @@ reference purposes.
\chapter{Secure Calls}
\input{secure-calls.tex}
+\chapter{Manipulating Party ID Information}
+ \input{partymanip.tex}
+
\chapter{Call Completion Supplementary Services}
\input{ccss.tex}
\chapter{Packet Loss Concealment}
\input{plc.tex}
+\chapter{Sounds Packages}
+ \input{sounds.tex}
+
\chapter{Development}
\section{Backtrace}
\input{backtrace.tex}
diff --git a/doc/tex/channelvariables.tex b/doc/tex/channelvariables.tex
index 07f887269..a493e05fb 100644
--- a/doc/tex/channelvariables.tex
+++ b/doc/tex/channelvariables.tex
@@ -1044,10 +1044,23 @@ ${OSPINAUDIOQOS} The inbound call leg audio QoS string.
${OSPOUTAUDIOQOS} The outbound call leg audio QoS string.
\end{verbatim}
-\subsection{Connected line digit manipulation}
+\subsection{Digit manipulation}
\begin{verbatim}
-${CONNECTED_LINE_SEND_CALLEE_MACRO} Macro to call before sending a connected line update to the callee
-${CONNECTED_LINE_SEND_CALLEE_MACRO_ARGS} Arguments to pass to ${CONNECTED_LINE_SEND_CALLEE_MACRO}
-${CONNECTED_LINE_SEND_CALLER_MACRO} Macro to call before sending a connected line update to the caller
-${CONNECTED_LINE_SEND_CALLER_MACRO_ARGS} Arguments to pass to ${CONNECTED_LINE_SEND_CALLER_MACRO}
+${REDIRECTING_SEND_CALLEE_MACRO}
+ Macro to call before sending a redirecting update to the callee
+${REDIRECTING_SEND_CALLEE_MACRO_ARGS}
+ Arguments to pass to ${REDIRECTING_SEND_CALLEE_MACRO}
+${REDIRECTING_SEND_CALLER_MACRO}
+ Macro to call before sending a redirecting update to the caller
+${REDIRECTING_SEND_CALLER_MACRO_ARGS}
+ Arguments to pass to ${REDIRECTING_SEND_CALLER_MACRO}
+
+${CONNECTED_LINE_SEND_CALLEE_MACRO}
+ Macro to call before sending a connected line update to the callee
+${CONNECTED_LINE_SEND_CALLEE_MACRO_ARGS}
+ Arguments to pass to ${CONNECTED_LINE_SEND_CALLEE_MACRO}
+${CONNECTED_LINE_SEND_CALLER_MACRO}
+ Macro to call before sending a connected line update to the caller
+${CONNECTED_LINE_SEND_CALLER_MACRO_ARGS}
+ Arguments to pass to ${CONNECTED_LINE_SEND_CALLER_MACRO}
\end{verbatim}
diff --git a/doc/tex/partymanip.tex b/doc/tex/partymanip.tex
new file mode 100644
index 000000000..2ca05569f
--- /dev/null
+++ b/doc/tex/partymanip.tex
@@ -0,0 +1,325 @@
+\section{Introduction}
+
+This chapter aims to explain how to use some of the features available to
+manipulate party ID information. It will not delve into specific channel
+configuration options described in the respective sample configuration
+files. The party ID information can consist of Caller ID, Connected Line
+ID, redirecting to party ID information, and redirecting from party ID
+information. Meticulous control is needed particularly when
+interoperating between different channel technologies.
+
+\begin{itemize}
+
+\item Caller ID: The Caller ID information describes who is originating a
+call.
+
+\item Connected Line ID: The Connected Line ID information describes who
+is connected to the other end of a call while a call is established.
+Unlike Caller ID, the connected line information can change over the life
+of a call when call transfers are performed. The connected line
+information can also change in either direction because either end could
+transfer the call. For ISDN it is known as Connected Line Identification
+Presentation (COLP), Connected Line Identification Restriction (COLR), and
+Explicit Call Transfer (ECT). For SIP it is known either as
+P-Asserted-Identity or Remote-Party-Id.
+
+\item Redirecting information: When a call is forwarded, the call
+originator is informed that the call is redirecting-to a new destination.
+The new destination is also informed that the incoming call is
+redirecting-from the forwarding party. A call can be forwarded repeatedly
+until a new destination answers it or a forwarding limit is reached.
+
+\end{itemize}
+
+\section{Tools available}
+
+Asterisk contains several tools for manipulating the party ID information
+for a call. Additional information can be found by using the 'core show
+function' or 'core show application' console commands at the Asterisk CLI.
+The following list identifies some of the more common tools for
+manipulating the party ID information:
+
+\begin{itemize}
+\item CALLERID(datatype[,caller-id])
+
+\item CONNECTEDLINE(datatype[,i])
+
+\item REDIRECTING(datatype[,i])
+
+\item Dial() and Queue() dialplan application 'I' option
+
+\item Interception macros
+
+\item Channel driver specific configuration options.
+\end{itemize}
+
+\subsection{CALLERID dialplan function}
+
+The CALLERID function has been around for quite a while and its use is
+straightforward. It is used to examine and alter the caller information
+that came into the dialplan with the call. Then the call with it's caller
+information passes on to the destination using the Dial() or Queue()
+application.
+
+The CALLERID information is passed during the initial call setup.
+However, depending on the channel technology, the caller name may be
+delayed. Q.SIG is an example where the caller name may be delayed so your
+dialplan may need to wait for it.
+
+\subsection{CONNECTEDLINE dialplan function}
+
+The CONNECTEDLINE function does the opposite of the CALLERID function.
+CONNECTEDLINE can be used to setup connected line information to be sent when the
+call is answered. You can use it to send new connected line information
+to the remote party on the channel when a call is transferred. The
+CONNECTEDLINE information is passed when the call is answered and when the
+call is transferred.
+
+Since the connected line information can be sent while a call is
+connected, you may need to prevent the channel driver from acting on a
+partial update. The 'i' option is used to inhibit the channel driver from
+sending the changed information immediately.
+
+\subsection{REDIRECTING dialplan function}
+
+The REDIRECTING function allows you to report information about
+forwarded/deflected calls to the caller and to the new destination. The
+use of the REDIRECTING function is the most complicated of the party
+information functions.
+
+The REDIRECTING information is passed during the initial call setup and
+while the call is being routed through the network. Since the redirecting
+information is sent before a call is answered, you need to prevent the
+channel driver from acting on a partial update. The 'i' option is used to
+inhibit the channel driver from sending the changed information
+immediately.
+
+The incoming call may have already been redirected. An incoming call has
+already been redirected if the REDIRECTING(count) is not zero. (Alternate
+indications are if the REDIRECTING(from-num-valid) is non-zero or if the
+REDIRECTING(from-num) is not empty.)
+
+There are several things to do when a call is forwarded by the dialplan:
+
+\begin{itemize}
+
+\item Setup the REDIRECTING(to-xxx) values to be sent to the caller.
+
+\item Setup the REDIRECTING(from-xxx) values to be sent to the new
+destination.
+
+\item Increment the REDIRECTING(count).
+
+\item Set the REDIRECTING(reason).
+
+\item Dial() the new destination.
+
+\end{itemize}
+
+\subsection{Special REDIRECTING considerations for ISDN}
+
+Special considerations for Q.SIG and ISDN point-to-point links are needed
+to make the DivertingLegInformation1, DivertingLegInformation2, and
+DivertingLegInformation3 messages operate properly.
+
+You should manually send the COLR of the redirected-to party for an
+incoming redirected call if the incoming call could experience further
+redirects. For chan_misdn, just set the REDIRECTING(to-num,i) =
+\$\{EXTEN\} and set the REDIRECTING(to-num-pres) to the COLR. For
+chan_dahdi, just set the REDIRECTING(to-num,i) = CALLERID(dnid) and set
+the REDIRECTING(to-num-pres) to the COLR. (Setting the
+REDIRECTING(to-num,i) value may not be necessary since the channel driver
+has already attempted to preset that value for automatic generation of the
+needed DivertingLegInformation3 message.)
+
+For redirected calls out a trunk line, you need to use the 'i' option on
+all of the REDIRECTING statements before dialing the redirected-to party.
+The call will update the redirecting-to presentation (COLR) when it
+becomes available.
+
+\subsection{Dial() and Queue() dialplan application 'I' option}
+
+In the dialplan applications Dial() and Queue(), the 'I' option is a brute
+force option to block connected line and redirecting information updates
+while the application is running. Blocking the updates prevents the
+update from overwriting any CONNECTEDLINE or REDIRECTING values you may
+have setup before running the application.
+
+The option blocks all redirecting updates since they should only happen
+before a call is answered. The option only blocks the connected line
+update from the initial answer. Connected line updates resulting from
+call transfers happen after the application has completed. Better control
+of connected line and redirecting information is obtained using the
+interception macros.
+
+\subsection{Interception macros}
+
+The interception macros give the administrator an opportunity to alter
+connected line and redirecting information before the channel driver is
+given the information. If the macro does not change a value then that is
+what is going to be passed to the channel driver.
+
+The tag string available in CALLERID, CONNECTEDLINE, and REDIRECTING is
+useful for the interception macros to provide some information about where
+the information originally came from.
+
+\begin{verbatim}
+${REDIRECTING_SEND_CALLEE_MACRO}
+ Macro to call before sending a redirecting update to the callee.
+ This macro may never be needed since the redirecting updates
+ should only go from the callee to the caller direction. It is
+ available for completeness.
+${REDIRECTING_SEND_CALLEE_MACRO_ARGS}
+ Arguments to pass to ${REDIRECTING_SEND_CALLEE_MACRO}.
+
+${REDIRECTING_SEND_CALLER_MACRO}
+ Macro to call before sending a redirecting update to the caller.
+${REDIRECTING_SEND_CALLER_MACRO_ARGS}
+ Arguments to pass to ${REDIRECTING_SEND_CALLER_MACRO}.
+
+${CONNECTED_LINE_SEND_CALLEE_MACRO}
+ Macro to call before sending a connected line update to the callee.
+${CONNECTED_LINE_SEND_CALLEE_MACRO_ARGS}
+ Arguments to pass to ${CONNECTED_LINE_SEND_CALLEE_MACRO}.
+
+${CONNECTED_LINE_SEND_CALLER_MACRO}
+ Macro to call before sending a connected line update to the caller.
+${CONNECTED_LINE_SEND_CALLER_MACRO_ARGS}
+ Arguments to pass to ${CONNECTED_LINE_SEND_CALLER_MACRO}.
+\end{verbatim}
+
+\section{Manipulation examples}
+
+The following examples show several common scenarios in which you may need
+to manipulate party ID information from the dialplan.
+
+\subsection{Simple recording playback}
+
+\begin{verbatim}
+exten => 1000,1,NoOp
+; The CONNECTEDLINE information is sent when the call is answered.
+exten => 1000,n,Set(CONNECTEDLINE(name,i)="Company Name")
+exten => 1000,n,Set(CONNECTEDLINE(name-pres,i)=allowed)
+exten => 1000,n,Set(CONNECTEDLINE(num,i)=5551212)
+exten => 1000,n,Set(CONNECTEDLINE(num-pres)=allowed)
+exten => 1000,n,Answer
+exten => 1000,n,Playback(tt-weasels)
+exten => 1000,n,Hangup
+\end{verbatim}
+
+\subsection{Straightforward dial through}
+
+\begin{verbatim}
+exten => 1000,1,NoOp
+; The CONNECTEDLINE information is sent when the call is answered.
+exten => 1000,n,Set(CONNECTEDLINE(name,i)="Company Name")
+exten => 1000,n,Set(CONNECTEDLINE(name-pres,i)=allowed)
+exten => 1000,n,Set(CONNECTEDLINE(num,i)=5551212)
+exten => 1000,n,Set(CONNECTEDLINE(num-pres)=allowed)
+; The I option prevents overwriting the CONNECTEDLINE information
+; set above when the call is answered.
+exten => 1000,n,Dial(SIP/1000,20,I)
+exten => 1000,n,Hangup
+\end{verbatim}
+
+\subsection{Use of interception macro}
+
+\begin{verbatim}
+[macro-add_pfx]
+; ARG1 is the prefix to add.
+; ARG2 is the number of digits at the end to add the prefix to.
+; When the macro ends the CONNECTEDLINE data is passed to the
+; channel driver.
+exten => s,1,NoOp(Add prefix to connected line)
+exten => s,n,Set(NOPREFIX=${CONNECTEDLINE(number):-${ARG2}})
+exten => s,n,Set(CONNECTEDLINE(num,i)=${ARG1}${NOPREFIX})
+exten => s,n,MacroExit
+
+exten => 1000,1,NoOp
+exten => 1000,n,Set(__CONNECTED_LINE_CALLER_SEND_MACRO=add_pfx)
+exten => 1000,n,Set(__CONNECTED_LINE_CALLER_SEND_MACRO_ARGS=45,4)
+exten => 1000,n,Dial(SIP/1000,20)
+exten => 1000,n,Hangup
+\end{verbatim}
+
+\subsection{Simple redirection}
+\begin{verbatim}
+exten => 1000,1,NoOp
+; For Q.SIG or ISDN point-to-point we should determine the COLR for this
+; extension and send it if the call was redirected here.
+exten => 1000,n,GotoIf($[${REDIRECTING(count)}>0]?redirected:notredirected)
+exten => 1000,n(redirected),Set(REDIRECTING(to-num,i)=${CALLERID(dnid)})
+exten => 1000,n,Set(REDIRECTING(to-num-pres)=allowed)
+exten => 1000,n(notredirected),NoOp
+; Determine that the destination has forwarded the call.
+; ...
+exten => 1000,n,Set(REDIRECTING(from-num,i)=1000)
+exten => 1000,n,Set(REDIRECTING(from-num-pres,i)=allowed)
+exten => 1000,n,Set(REDIRECTING(to-num,i)=2000)
+; The DivertingLegInformation3 message is needed because at this point
+; we do not know the presentation (COLR) setting of the redirecting-to
+; party.
+exten => 1000,n,Set(REDIRECTING(count,i)=$[${REDIRECTING(count)} + 1])
+exten => 1000,n,Set(REDIRECTING(reason,i)=cfu)
+; The call will update the redirecting-to presentation (COLR) when it
+; becomes available with a redirecting update.
+exten => 1000,n,Dial(DAHDI/g1/2000,20)
+exten => 1000,n,Hangup
+\end{verbatim}
+
+\section{Ideas for usage}
+
+The following is a list of ideas in which the manipulation of party ID
+information would be beneficial.
+
+\begin{itemize}
+
+\item IVR that updates connected name on each selection made.
+
+\item Disguise the true number of an individual with a generic company
+number.
+
+\item Use interception macros to make outbound connected number E.164
+formatted.
+
+\item You can do a lot more in an interception macro than just manipulate
+party information...
+
+\end{itemize}
+
+\section{Troubleshooting tips}
+\begin{itemize}
+
+\item For CONNECTEDLINE and REDIRECTING, check the usage of the 'i'
+option.
+
+\item Check channel configuration settings. The default settings may not
+be what you want or expect.
+
+\item Check packet captures. Your equipment may not support what Asterisk
+sends.
+
+\end{itemize}
+
+\section{For further reading...}
+\begin{itemize}
+
+\item Relevant ETSI ISDN redirecting specification: EN 300 207-1
+
+\item Relevant ETSI ISDN COLP specification: EN 300 097-1
+
+\item Relevant ETSI ISDN ECT specification: EN 300 369-1
+
+\item Relevant Q.SIG ISDN redirecting specification: ECMA-174
+
+\item Relevant Q.SIG ISDN COLP specification: ECMA-148
+
+\item Relevant Q.SIG ISDN ECT specification: ECMA-178
+
+\item Relevant SIP RFC for P-Asserted-Id: RFC3325
+
+\item The expired draft (draft-ietf-sip-privacy-04.txt) defines
+Remote-Party-Id. Since Remote-Party-Id has not made it into an RFC at
+this time, its use is non-standard by definition.
+
+\end{itemize}
diff --git a/doc/tex/sounds.tex b/doc/tex/sounds.tex
new file mode 100644
index 000000000..59091983b
--- /dev/null
+++ b/doc/tex/sounds.tex
@@ -0,0 +1,80 @@
+\section{Introduction}
+Asterisk utilizes a variety of sound prompts that are available in several file
+formats and languages. Multiple languages and formats can be installed on the
+same system, and Asterisk will utilize prompts from languages installed, and
+will automatically pick the least CPU intensive format that is available on the
+system (based on codecs in use, in additional to the codec and format modules
+installed and available).
+
+In addition to the prompts available with Asterisk, you can create your own sets
+of prompts and utilize them as well. This document will tell you how the prompts
+available for Asterisk are created so that the prompts you create can be as close
+and consistent in the quality and volume levels as those shipped with Asterisk.
+
+\section{Getting The Sounds Tools}
+The sounds tools are available in the publicly accessible repotools repository.
+You can check these tools out with Subversion via the following command:
+
+\begin{astlisting}
+\begin{verbatim}
+# svn co http://svn.asterisk.org/svn/repotools
+\end{verbatim}
+\end{astlisting}
+
+The sound tools are available in the subdirectory sound_tools/ which contains the
+following directories:
+
+\begin{itemize}
+\item audiofilter
+\item makeg722
+\item scripts
+\end{itemize}
+
+\section{About The Sounds Tools}
+The following sections will describe the sound tools in more detail and explain what
+they are used for in the sounds package creation process.
+
+\subsection{audiofilter}
+The audiofilter application is used to "tune" the sound files in such a way that
+they sound good when being used while in a compressed format. The values in the
+scripts for creating the sound files supplied in repotools is essentially a
+high-pass filter that drops out audio below 100Hz (or so).
+
+(There is an ITU specification that states for 8KHz audio that is being compressed
+frequencies below a certain threshold should be removed because they make the
+resulting compressed audio sound worse than it should.)
+
+The audiofilter application is used by the 'converter' script located in the
+scripts subdirectory of repotools/sound_tools. The values being passed to the
+audiofilter application is as follows:
+
+\begin{astlisting}
+\begin{verbatim}
+audiofilter -n 0.86916 -1.73829 0.86916 -d 1.00000 -1.74152 0.77536
+\end{verbatim}
+\end{astlisting}
+
+
+The two options -n and -d are 'numerator' and 'denominator'. Per the author,
+Jean-Marc Valin, "These values are filter coefficients (-n means numerator, -d is
+denominator) expressed in the z-transform domain. There represent an elliptic filter
+that I designed with Octave such that 'the result sounds good'."
+
+\subsection{makeg722}
+The makeg722 application is used by the 'converters' script to generate the G.722
+sound files that are shipped with Asterisk. It starts with the RAW sound files and
+then converts them to G.722.
+
+\subsection{scripts}
+The scripts folder is where all the magic happens. These are the scripts that the
+Asterisk open source team use to build the packaged audio files for the various
+formats that are distributed with Asterisk.
+
+\begin{itemize}
+\item chkcore - used to check that the contents of core-sounds-$<$lang$>$.txt are in sync
+\item chkextra - same as above, but checks the extra sound files
+\item mkcore - script used to generate the core sounds packages
+\item mkextra - script used to generate the extra sounds packages
+\item mkmoh - script used to generate the music on hold packages
+\item converters - script used to convert the master files to various formats
+\end{itemize}
diff --git a/formats/format_wav.c b/formats/format_wav.c
index 37d81e58a..91a309ef4 100644
--- a/formats/format_wav.c
+++ b/formats/format_wav.c
@@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define WAV_BUF_SIZE 320
struct wav_desc { /* format-specific parameters */
+ int hz;
int bytes;
int lasttimeout;
int maxlen;
@@ -70,7 +71,7 @@ struct wav_desc { /* format-specific parameters */
#endif
-static int check_header(FILE *f)
+static int check_header(FILE *f, int hz)
{
int type, size, formtype;
int fmt, hsize;
@@ -135,8 +136,10 @@ static int check_header(FILE *f)
ast_log(LOG_WARNING, "Read failed (freq)\n");
return -1;
}
- if (ltohl(freq) != DEFAULT_SAMPLE_RATE) {
- ast_log(LOG_WARNING, "Unexpected frequency %d\n", ltohl(freq));
+ if (((ltohl(freq) != 8000) && (ltohl(freq) != 16000)) ||
+ ((ltohl(freq) == 8000) && (hz != 8000)) ||
+ ((ltohl(freq) == 16000) && (hz != 16000))) {
+ ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", ltohl(freq),hz);
return -1;
}
/* Ignore the byte frequency */
@@ -239,16 +242,24 @@ static int update_header(FILE *f)
return 0;
}
-static int write_header(FILE *f)
+static int write_header(FILE *f, int writehz)
{
- unsigned int hz=htoll(8000);
- unsigned int bhz = htoll(16000);
+ unsigned int hz;
+ unsigned int bhz;
unsigned int hs = htoll(16);
unsigned short fmt = htols(1);
unsigned short chans = htols(1);
unsigned short bysam = htols(2);
unsigned short bisam = htols(16);
unsigned int size = htoll(0);
+
+ if (writehz == 16000) {
+ hz = htoll(16000);
+ bhz = htoll(32000);
+ } else {
+ hz = htoll(8000);
+ bhz = htoll(16000);
+ }
/* Write a wav header, ignoring sizes which will be filled in later */
fseek(f,0,SEEK_SET);
if (fwrite("RIFF", 1, 4, f) != 4) {
@@ -308,7 +319,7 @@ static int wav_open(struct ast_filestream *s)
if we did, it would go here. We also might want to check
and be sure it's a valid file. */
struct wav_desc *tmp = (struct wav_desc *)s->_private;
- if ((tmp->maxlen = check_header(s->f)) < 0)
+ if ((tmp->maxlen = check_header(s->f, (s->fmt->format == AST_FORMAT_SLINEAR16 ? 16000 : 8000))) < 0)
return -1;
return 0;
}
@@ -319,7 +330,9 @@ static int wav_rewrite(struct ast_filestream *s, const char *comment)
if we did, it would go here. We also might want to check
and be sure it's a valid file. */
- if (write_header(s->f))
+ struct wav_desc *tmp = (struct wav_desc *)s->_private;
+ tmp->hz = (s->fmt->format == AST_FORMAT_SLINEAR16 ? 16000 : 8000);
+ if (write_header(s->f,tmp->hz))
return -1;
return 0;
}
@@ -349,11 +362,13 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
int x;
#endif
short *tmp;
- int bytes = WAV_BUF_SIZE; /* in bytes */
+ int bytes;
off_t here;
/* Send a frame from the file to the appropriate channel */
struct wav_desc *fs = (struct wav_desc *)s->_private;
+ bytes = (fs->hz == 16000 ? (WAV_BUF_SIZE * 2) : WAV_BUF_SIZE);
+
here = ftello(s->f);
if (fs->maxlen - here < bytes) /* truncate if necessary */
bytes = fs->maxlen - here;
@@ -361,7 +376,7 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
bytes = 0;
/* ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
s->fr.frametype = AST_FRAME_VOICE;
- s->fr.subclass.codec = AST_FORMAT_SLINEAR;
+ s->fr.subclass.codec = (fs->hz == 16000 ? AST_FORMAT_SLINEAR16 : AST_FORMAT_SLINEAR);
s->fr.mallocd = 0;
AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes);
@@ -388,7 +403,7 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
{
#if __BYTE_ORDER == __BIG_ENDIAN
int x;
- short tmp[8000], *tmpi;
+ short tmp[16000], *tmpi;
#endif
struct wav_desc *s = (struct wav_desc *)fs->_private;
int res;
@@ -397,8 +412,12 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1;
}
- if (f->subclass.codec != AST_FORMAT_SLINEAR) {
- ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%s)!\n", ast_getformatname(f->subclass.codec));
+ if ((f->subclass.codec != AST_FORMAT_SLINEAR) && (f->subclass.codec != AST_FORMAT_SLINEAR16)) {
+ ast_log(LOG_WARNING, "Asked to write non-SLINEAR%s frame (%s)!\n", s->hz == 16000 ? "16" : "", ast_getformatname(f->subclass.codec));
+ return -1;
+ }
+ if (f->subclass.codec != fs->fmt->format) {
+ ast_log(LOG_WARNING, "Can't change SLINEAR frequency during write\n");
return -1;
}
if (!f->datalen)
@@ -467,6 +486,22 @@ static off_t wav_tell(struct ast_filestream *fs)
return (offset - 44)/2;
}
+static const struct ast_format wav16_f = {
+ .name = "wav16",
+ .exts = "wav16",
+ .format = AST_FORMAT_SLINEAR16,
+ .open = wav_open,
+ .rewrite = wav_rewrite,
+ .write = wav_write,
+ .seek = wav_seek,
+ .trunc = wav_trunc,
+ .tell = wav_tell,
+ .read = wav_read,
+ .close = wav_close,
+ .buf_size = (WAV_BUF_SIZE * 2) + AST_FRIENDLY_OFFSET,
+ .desc_size = sizeof(struct wav_desc),
+};
+
static const struct ast_format wav_f = {
.name = "wav",
.exts = "wav",
@@ -485,17 +520,19 @@ static const struct ast_format wav_f = {
static int load_module(void)
{
- if (ast_format_register(&wav_f))
+ if (ast_format_register(&wav_f)
+ || ast_format_register(&wav16_f))
return AST_MODULE_LOAD_FAILURE;
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
- return ast_format_unregister(wav_f.name);
+ return ast_format_unregister(wav_f.name)
+ || ast_format_unregister(wav16_f.name);
}
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Microsoft WAV format (8000Hz Signed Linear)",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)",
.load = load_module,
.unload = unload_module,
.load_pri = AST_MODPRI_APP_DEPEND
diff --git a/funcs/func_aes.c b/funcs/func_aes.c
index 21ee244ab..7cc8f4d57 100644
--- a/funcs/func_aes.c
+++ b/funcs/func_aes.c
@@ -163,4 +163,8 @@ static int load_module(void)
return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "AES dialplan functions");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "AES dialplan functions",
+ .load = load_module,
+ .unload = unload_module,
+ .nonoptreq = "res_crypto",
+ );
diff --git a/funcs/func_channel.c b/funcs/func_channel.c
index 729bdf45b..69fb72fb3 100644
--- a/funcs/func_channel.c
+++ b/funcs/func_channel.c
@@ -88,6 +88,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="channeltype">
<para>R/O technology used for channel.</para>
</enum>
+ <enum name="checkhangup">
+ <para>R/O Whether the channel is hanging up (1/0)</para>
+ </enum>
<enum name="language">
<para>R/W language for sounds played.</para>
</enum>
@@ -298,7 +301,11 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
locked_copy_string(chan, buf, chan->tech->type, len);
else if (!strcasecmp(data, "accountcode"))
locked_copy_string(chan, buf, chan->accountcode, len);
- else if (!strcasecmp(data, "peeraccount"))
+ else if (!strcasecmp(data, "checkhangup")) {
+ ast_channel_lock(chan);
+ ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len);
+ ast_channel_unlock(chan);
+ } else if (!strcasecmp(data, "peeraccount"))
locked_copy_string(chan, buf, chan->peeraccount, len);
else if (!strcasecmp(data, "hangupsource"))
locked_copy_string(chan, buf, chan->hangupsource, len);
diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c
index 55c06f4f6..7f2de02fc 100644
--- a/funcs/func_odbc.c
+++ b/funcs/func_odbc.c
@@ -502,8 +502,10 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
if (stmt) {
break;
}
- ast_odbc_release_obj(obj);
- obj = NULL;
+ if (obj) {
+ ast_odbc_release_obj(obj);
+ obj = NULL;
+ }
}
if (!stmt) {
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index 172407b80..21dc60611 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -583,7 +583,7 @@ Operations on container include:
i = ao2_iterator_init(c, flags);
- while ( (o = ao2_iterator_next(&i)) ) {
+ while ((o = ao2_iterator_next(&i))) {
... do something on o ...
ao2_ref(o, -1);
}
@@ -1002,7 +1002,7 @@ void *__ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
*
* i = ao2_iterator_init(c, flags);
*
- * while ( (o = ao2_iterator_next(&i)) ) {
+ * while ((o = ao2_iterator_next(&i))) {
* ... do something on o ...
* ao2_ref(o, -1);
* }
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index acd3140c7..67ce9ee65 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -17,6 +17,10 @@
/* Define to 1 if the `closedir' function returns void instead of `int'. */
#undef CLOSEDIR_VOID
+/* Some configure tests will unexpectedly fail if configure is run by a
+ non-root user. These may be able to be tested at runtime. */
+#undef CONFIGURE_RAN_AS_ROOT
+
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
@@ -381,9 +385,6 @@
/* Define to 1 if your system defines the locale_t type in xlocale.h */
#undef HAVE_LOCALE_T_IN_XLOCALE_H
-/* Define to 1 if you have the `localtime_r' function. */
-#undef HAVE_LOCALTIME_R
-
/* Define to 1 if you have the `log' function. */
#undef HAVE_LOG
@@ -538,6 +539,9 @@
/* Define to 1 if you have the `powl' function. */
#undef HAVE_POWL
+/* Define to 1 if you have the `ppoll' function. */
+#undef HAVE_PPOLL
+
/* Define to 1 if you have the ISDN PRI library. */
#undef HAVE_PRI
@@ -956,6 +960,10 @@
/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
#undef HAVE_UTIME_NULL
+/* Define to 1 if your system can support larger than default select bitmasks.
+ */
+#undef HAVE_VARIABLE_FDSET
+
/* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF
@@ -1150,6 +1158,9 @@
#endif
+/* Define to 1 if running on Darwin. */
+#undef _DARWIN_UNLIMITED_SELECT
+
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
diff --git a/include/asterisk/calendar.h b/include/asterisk/calendar.h
index 09e5bcd5b..8b970ae69 100644
--- a/include/asterisk/calendar.h
+++ b/include/asterisk/calendar.h
@@ -95,7 +95,9 @@ struct ast_calendar_event {
AST_STRING_FIELD(organizer);
AST_STRING_FIELD(location);
AST_STRING_FIELD(uid);
+ AST_STRING_FIELD(categories);
);
+ int priority; /*!< Priority of event */
struct ast_calendar *owner; /*!< The calendar that owns this event */
time_t start; /*!< Start of event (UTC) */
time_t end; /*!< End of event (UTC) */
diff --git a/include/asterisk/ccss.h b/include/asterisk/ccss.h
index 4dc8e5922..31073a478 100644
--- a/include/asterisk/ccss.h
+++ b/include/asterisk/ccss.h
@@ -189,6 +189,21 @@ int ast_cc_is_config_param(const char * const name);
/*!
* \since 1.8
+ * \brief Set the specified CC config params to default values.
+ *
+ * \details
+ * This is just like ast_cc_copy_config_params() and could be used in place
+ * of it if you need to set the config params to defaults instead.
+ * You are simply "copying" defaults into the destination.
+ *
+ * \param params CC config params to set to default values.
+ *
+ * \return Nothing
+ */
+void ast_cc_default_config_params(struct ast_cc_config_params *params);
+
+/*!
+ * \since 1.8
* \brief copy CCSS configuration parameters from one structure to another
*
* \details
@@ -199,8 +214,8 @@ int ast_cc_is_config_param(const char * const name);
*
* \param src The structure from which data is copied
* \param dest The structure to which data is copied
- * \retval -1 Copy failed (no way for this to happen yet)
- * \retval 0 Copy succeeded
+ *
+ * \return Nothing
*/
void ast_cc_copy_config_params(struct ast_cc_config_params *dest, const struct ast_cc_config_params *src);
diff --git a/include/asterisk/cel.h b/include/asterisk/cel.h
index f221dd643..353c06110 100644
--- a/include/asterisk/cel.h
+++ b/include/asterisk/cel.h
@@ -28,8 +28,13 @@ extern "C" {
#include "asterisk/event.h"
-/*! \brief AMA Flags */
+/*!
+ * \brief AMA Flags
+ *
+ * \note This must much up with the AST_CDR_* defines for AMA flags.
+ */
enum ast_cel_ama_flag {
+ AST_CEL_AMA_FLAG_NONE,
AST_CEL_AMA_FLAG_OMIT,
AST_CEL_AMA_FLAG_BILLING,
AST_CEL_AMA_FLAG_DOCUMENTATION,
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index c54b02c1f..b0f589a9d 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -2232,44 +2232,6 @@ static inline void timersub(struct timeval *tvend, struct timeval *tvstart, stru
}
#endif
-/*!
- * \brief Waits for activity on a group of channels
- * \param nfds the maximum number of file descriptors in the sets
- * \param rfds file descriptors to check for read availability
- * \param wfds file descriptors to check for write availability
- * \param efds file descriptors to check for exceptions (OOB data)
- * \param tvp timeout while waiting for events
- * \details
- * This is the same as a standard select(), except it guarantees the
- * behaviour where the passed struct timeval is updated with how much
- * time was not slept while waiting for the specified events
- */
-static inline int ast_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tvp)
-{
-#ifdef __linux__
- return select(nfds, rfds, wfds, efds, tvp);
-#else
- if (tvp) {
- struct timeval tv, tvstart, tvend, tvlen;
- int res;
-
- tv = *tvp;
- gettimeofday(&tvstart, NULL);
- res = select(nfds, rfds, wfds, efds, tvp);
- gettimeofday(&tvend, NULL);
- timersub(&tvend, &tvstart, &tvlen);
- timersub(&tv, &tvlen, tvp);
- if (tvp->tv_sec < 0 || (tvp->tv_sec == 0 && tvp->tv_usec < 0)) {
- tvp->tv_sec = 0;
- tvp->tv_usec = 0;
- }
- return res;
- }
- else
- return select(nfds, rfds, wfds, efds, NULL);
-#endif
-}
-
/*! \brief Retrieves the current T38 state of a channel */
static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
{
diff --git a/include/asterisk/cli.h b/include/asterisk/cli.h
index 7258548b6..21a03834d 100644
--- a/include/asterisk/cli.h
+++ b/include/asterisk/cli.h
@@ -183,9 +183,13 @@ struct ast_cli_entry {
AST_LIST_ENTRY(ast_cli_entry) list;
};
+#if defined(__cplusplus) || defined(c_plusplus)
+#define AST_CLI_DEFINE(fn, txt) { { "" }, txt, NULL, 0, NULL, NULL, 0, 0, NULL, fn }
+#else
/* XXX the parser in gcc 2.95 gets confused if you don't put a space
* between the last arg before VA_ARGS and the comma */
#define AST_CLI_DEFINE(fn, txt , ... ) { .handler = fn, .summary = txt, ## __VA_ARGS__ }
+#endif
/*!
* Helper function to generate cli entries from a NULL-terminated array.
diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h
index b2db7ffdb..91112dbfe 100644
--- a/include/asterisk/compiler.h
+++ b/include/asterisk/compiler.h
@@ -41,6 +41,12 @@
#define attribute_const
#endif
+#ifdef HAVE_ATTRIBUTE_deprecated
+#define attribute_deprecated __attribute__((deprecated))
+#else
+#define attribute_deprecated
+#endif
+
#ifdef HAVE_ATTRIBUTE_unused
#define attribute_unused __attribute__((unused))
#else
diff --git a/include/asterisk/event_defs.h b/include/asterisk/event_defs.h
index 3779dac73..073d67bc6 100644
--- a/include/asterisk/event_defs.h
+++ b/include/asterisk/event_defs.h
@@ -52,8 +52,10 @@ enum ast_event_type {
AST_EVENT_CEL = 0x07,
/*! A report of a security related event (see security_events.h) */
AST_EVENT_SECURITY = 0x08,
+ /*! Used by res_stun_monitor to alert listeners to an exernal network address change. */
+ AST_EVENT_NETWORK_CHANGE = 0x09,
/*! Number of event types. This should be the last event type + 1 */
- AST_EVENT_TOTAL = 0x09,
+ AST_EVENT_TOTAL = 0x0a,
};
/*! \brief Event Information Element types */
diff --git a/include/asterisk/module.h b/include/asterisk/module.h
index 24f66fc36..aaa8cbef3 100644
--- a/include/asterisk/module.h
+++ b/include/asterisk/module.h
@@ -242,6 +242,11 @@ struct ast_module_info {
* this value will never be read and the module will be given the lowest possible priority
* on load. */
unsigned char load_pri;
+
+ /*! Modules which should be loaded first, in comma-separated string format.
+ * These are only required for loading, when the optional_api header file
+ * detects that the compiler does not support the optional API featureset. */
+ const char *nonoptreq;
};
void ast_module_register(const struct ast_module_info *);
diff --git a/include/asterisk/netsock2.h b/include/asterisk/netsock2.h
index 24330d236..73c57c5d2 100644
--- a/include/asterisk/netsock2.h
+++ b/include/asterisk/netsock2.h
@@ -233,6 +233,26 @@ static inline char *ast_sockaddr_stringify_port(const struct ast_sockaddr *addr)
* \since 1.8
*
* \brief
+ * Splits a string into its host and port components
+ *
+ * \param str[in] The string to parse. May be modified by writing a NUL at the end of
+ * the host part.
+ * \param host[out] Pointer to the host component within \a str.
+ * \param port[out] Pointer to the port component within \a str.
+ * \param flags If set to zero, a port MAY be present. If set to PARSE_PORT_IGNORE, a
+ * port MAY be present but will be ignored. If set to PARSE_PORT_REQUIRE,
+ * a port MUST be present. If set to PARSE_PORT_FORBID, a port MUST NOT
+ * be present.
+ *
+ * \retval 1 Success
+ * \retval 0 Failure
+ */
+int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags);
+
+/*!
+ * \since 1.8
+ *
+ * \brief
* Parse an IPv4 or IPv6 address string.
*
* \details
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index ac09f009b..a0ef3d476 100644
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -1220,14 +1220,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
const char *context, const char *exten, int priority,
const char *label, const char *callerid, enum ext_match_t action);
-
-/* every time a write lock is obtained for contexts,
- a counter is incremented. You can check this via the
- following func */
-
-int ast_wrlock_contexts_version(void);
-
-
/*! \brief hashtable functions for contexts */
/*! @{ */
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
diff --git a/include/asterisk/poll-compat.h b/include/asterisk/poll-compat.h
index 1156e694b..cbb610925 100644
--- a/include/asterisk/poll-compat.h
+++ b/include/asterisk/poll-compat.h
@@ -79,6 +79,8 @@
#ifndef __AST_POLL_COMPAT_H
#define __AST_POLL_COMPAT_H
+#include "asterisk/select.h"
+
#ifndef AST_POLL_COMPAT
#include <sys/poll.h>
@@ -114,4 +116,24 @@ int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout);
#endif /* AST_POLL_COMPAT */
+/*!
+ * \brief Same as poll(2), except the time is specified in microseconds and
+ * the tv argument is modified to indicate the time remaining.
+ */
+int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv);
+
+/*!
+ * \brief Shortcut for conversion of FD_ISSET to poll(2)-based
+ */
+static inline int ast_poll_fd_index(struct pollfd *haystack, int nfds, int needle)
+{
+ int i;
+ for (i = 0; i < nfds; i++) {
+ if (haystack[i].fd == needle) {
+ return i;
+ }
+ }
+ return -1;
+}
+
#endif /* __AST_POLL_COMPAT_H */
diff --git a/include/asterisk/res_srtp.h b/include/asterisk/res_srtp.h
index 7853ead6f..4aa830946 100644
--- a/include/asterisk/res_srtp.h
+++ b/include/asterisk/res_srtp.h
@@ -33,6 +33,7 @@ struct ast_srtp_res {
int (*create)(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy);
void (*destroy)(struct ast_srtp *srtp);
int (*add_stream)(struct ast_srtp *srtp, struct ast_srtp_policy *policy);
+ int (*change_source)(struct ast_srtp *srtp, unsigned int from_ssrc, unsigned int to_ssrc);
void (*set_cb)(struct ast_srtp *srtp, const struct ast_srtp_cb *cb, void *data);
int (*unprotect)(struct ast_srtp *srtp, void *buf, int *size, int rtcp);
int (*protect)(struct ast_srtp *srtp, void **buf, int *size, int rtcp);
diff --git a/include/asterisk/sched.h b/include/asterisk/sched.h
index 3904daf36..4f5fb4217 100644
--- a/include/asterisk/sched.h
+++ b/include/asterisk/sched.h
@@ -53,7 +53,7 @@ extern "C" {
int _count = 0; \
int _sched_res = -1; \
while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) \
- usleep(1000); \
+ usleep(1); \
if (_count == 10 && option_debug > 2) { \
ast_log(LOG_DEBUG, "Unable to cancel schedule ID %d.\n", id); \
} \
@@ -70,7 +70,7 @@ extern "C" {
do { \
int _count = 0; \
while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
- usleep(1000); \
+ usleep(1); \
} \
if (_count == 10) \
ast_log(LOG_WARNING, "Unable to cancel schedule ID %d. This is probably a bug (%s: %s, line %d).\n", id, __FILE__, __PRETTY_FUNCTION__, __LINE__); \
@@ -89,7 +89,7 @@ extern "C" {
int _sched_res = -1; \
while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) { \
ast_mutex_unlock(lock); \
- usleep(1000); \
+ usleep(1); \
ast_mutex_lock(lock); \
} \
if (_count == 10 && option_debug > 2) { \
@@ -103,7 +103,7 @@ extern "C" {
do { \
int _count = 0; \
while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
- usleep(1000); \
+ usleep(1); \
} \
if (_count == 10) \
ast_log(LOG_WARNING, "Unable to cancel schedule ID %d. This is probably a bug (%s: %s, line %d).\n", id, __FILE__, __PRETTY_FUNCTION__, __LINE__); \
@@ -122,7 +122,7 @@ extern "C" {
int _count = 0, _res=1; \
void *_data = (void *)ast_sched_find_data(sched, id); \
while (id > -1 && (_res = ast_sched_del(sched, id) && _count++ < 10)) { \
- usleep(1000); \
+ usleep(1); \
} \
if (!_res && _data) \
unrefcall; /* should ref _data! */ \
diff --git a/include/asterisk/select.h b/include/asterisk/select.h
new file mode 100644
index 000000000..fea8c7aff
--- /dev/null
+++ b/include/asterisk/select.h
@@ -0,0 +1,110 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Tilghman Lesher <tlesher AT digium DOT 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.
+ */
+
+/*!\file
+ * \brief Bitfield expansions for ast_select
+ */
+
+#ifndef __AST_SELECT_H
+#define __AST_SELECT_H
+
+#include <sys/select.h>
+#include <errno.h>
+#include "asterisk/utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned int ast_FD_SETSIZE;
+
+#if !defined(HAVE_VARIABLE_FDSET) && defined(CONFIGURE_RAN_AS_ROOT)
+#define ast_fdset fd_set
+#else
+typedef struct {
+ long fds_bits[4096 / sizeof(long)]; /* 32768 bits */
+} ast_fdset;
+
+#undef FD_ZERO
+#define FD_ZERO(a) \
+ do { \
+ long *bytes = (long *) a; \
+ int i; \
+ for (i = 0; i < sizeof(*(a)) / sizeof(long); i++) { \
+ bytes[i] = 0; \
+ } \
+ } while (0)
+#undef FD_SET
+#define FD_SET(fd, fds) \
+ do { \
+ long *bytes = (long *) fds; \
+ if (fd / sizeof(*bytes) + ((fd + 1) % sizeof(*bytes) ? 1 : 0) < sizeof(*(fds))) { \
+ bytes[fd / (sizeof(*bytes))] |= 1L << (fd % sizeof(*bytes)); \
+ } else { \
+ ast_log(LOG_ERROR, "FD %d exceeds the maximum size of ast_fdset!\n", fd); \
+ } \
+ } while (0)
+#endif /* HAVE_VARIABLE_FDSET */
+
+/*! \brief Waits for activity on a group of channels
+ * \param nfds the maximum number of file descriptors in the sets
+ * \param rfds file descriptors to check for read availability
+ * \param wfds file descriptors to check for write availability
+ * \param efds file descriptors to check for exceptions (OOB data)
+ * \param tvp timeout while waiting for events
+ * This is the same as a standard select(), except it guarantees the
+ * behaviour where the passed struct timeval is updated with how much
+ * time was not slept while waiting for the specified events
+ */
+static inline int ast_select(int nfds, ast_fdset *rfds, ast_fdset *wfds, ast_fdset *efds, struct timeval *tvp)
+{
+#ifdef __linux__
+ ast_assert((unsigned int) nfds <= ast_FD_SETSIZE);
+ return select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, tvp);
+#else
+ int save_errno = 0;
+
+ ast_assert((unsigned int) nfds <= ast_FD_SETSIZE);
+ if (tvp) {
+ struct timeval tv, tvstart, tvend, tvlen;
+ int res;
+
+ tv = *tvp;
+ gettimeofday(&tvstart, NULL);
+ res = select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, tvp);
+ save_errno = errno;
+ gettimeofday(&tvend, NULL);
+ timersub(&tvend, &tvstart, &tvlen);
+ timersub(&tv, &tvlen, tvp);
+ if (tvp->tv_sec < 0 || (tvp->tv_sec == 0 && tvp->tv_usec < 0)) {
+ tvp->tv_sec = 0;
+ tvp->tv_usec = 0;
+ }
+ errno = save_errno;
+ return res;
+ }
+ else
+ return select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, NULL);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AST_SELECT_H */
diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h
index 1d87adbf5..821463bf1 100644
--- a/include/asterisk/translate.h
+++ b/include/asterisk/translate.h
@@ -254,6 +254,14 @@ unsigned int ast_translate_path_steps(format_t dest, format_t src);
*/
format_t ast_translate_available_formats(format_t dest, format_t src);
+/*!
+ * \brief Puts a string representation of the translation path into outbuf
+ * \param translator structure containing the translation path
+ * \param ast_str output buffer
+ * \retval on success pointer to beginning of outbuf. on failure "".
+ */
+const char *ast_translate_path_to_str(struct ast_trans_pvt *t, struct ast_str **str);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/include/asterisk/unaligned.h b/include/asterisk/unaligned.h
index 63f430f89..9e6e743da 100644
--- a/include/asterisk/unaligned.h
+++ b/include/asterisk/unaligned.h
@@ -50,7 +50,7 @@ static inline unsigned short get_unaligned_uint16(const void *p)
static inline void put_unaligned_uint64(void *p, uint64_t datum)
{
- struct { unsigned int d; } __attribute__((packed,may_alias)) *pp = p;
+ struct { uint64_t d; } __attribute__((packed,may_alias)) *pp = p;
pp->d = datum;
}
diff --git a/keys/freeworlddialup.pub b/keys/freeworlddialup.pub
deleted file mode 100644
index 4ba3faf66..000000000
--- a/keys/freeworlddialup.pub
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcE53oHNoe3sBSkvW3JaO8v5Z1
-CC+Cm+JgocGwmUek0hlQST1NUsFWfYIMd5z/Iunnd1GziXLqDYzCQeZUtJ6Y9J4A
-cA9wNv1eYWrlH7ozKWOv592+Y5xF0kqQ1jFt+5zFTP5myL9N439Evu/BWALHw0B4
-aML+CsGHg0uIe5ZjNwIDAQAB
------END PUBLIC KEY-----
diff --git a/keys/iaxtel.pub b/keys/iaxtel.pub
deleted file mode 100644
index d7c8f6cc8..000000000
--- a/keys/iaxtel.pub
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3+joshldCUFgjj5DeYOgRLSPS
-0t7gxTHiy1BTfynadPzgn447dy9iIQfBykE0pEdIPgaPMEt+ZPqPtln1P4dX3Ynx
-I+RYKgtjsmYYnyJRMGHfHuLXwkbFkxyiEg0KDvbdBWbz7GUNZlp49BLXewWGY9DJ
-MauE7FXVyCVDchn0YQIDAQAB
------END PUBLIC KEY-----
diff --git a/main/asterisk.c b/main/asterisk.c
index d8d3aebdf..f8d619a79 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2008, Digium, Inc.
+ * Copyright (C) 1999 - 2010, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
@@ -272,6 +272,8 @@ static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
+extern unsigned int ast_FD_SETSIZE;
+
static char *_argv[256];
static int shuttingdown;
static int restartnow;
@@ -3167,7 +3169,8 @@ int main(int argc, char *argv[])
char *buf;
const char *runuser = NULL, *rungroup = NULL;
char *remotesock = NULL;
- int moduleresult; /*!< Result from the module load subsystem */
+ int moduleresult; /*!< Result from the module load subsystem */
+ struct rlimit l;
/* Remember original args for restart */
if (argc > ARRAY_LEN(_argv) - 1) {
@@ -3352,7 +3355,6 @@ int main(int argc, char *argv[])
}
if (ast_opt_dump_core) {
- struct rlimit l;
memset(&l, 0, sizeof(l));
l.rlim_cur = RLIM_INFINITY;
l.rlim_max = RLIM_INFINITY;
@@ -3361,6 +3363,44 @@ int main(int argc, char *argv[])
}
}
+ if (getrlimit(RLIMIT_NOFILE, &l)) {
+ ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
+ }
+
+#if !defined(CONFIGURE_RAN_AS_ROOT)
+ /* Check if select(2) will run with more file descriptors */
+ do {
+ int fd, fd2;
+ ast_fdset readers;
+ struct timeval tv = { 0, };
+
+ if (l.rlim_cur <= FD_SETSIZE) {
+ /* The limit of select()able FDs is irrelevant, because we'll never
+ * open one that high. */
+ break;
+ }
+
+ if (!(fd = open("/dev/null", O_RDONLY))) {
+ ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
+ break; /* XXX Should we exit() here? XXX */
+ }
+
+ fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
+ if (dup2(fd, fd2)) {
+ ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
+ break;
+ }
+
+ FD_ZERO(&readers);
+ FD_SET(fd2, &readers);
+ if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
+ ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
+ }
+ } while (0);
+#elif defined(HAVE_VARIABLE_FDSET)
+ ast_FD_SETSIZE = l.rlim_cur;
+#endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
+
if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
rungroup = ast_config_AST_RUN_GROUP;
if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
diff --git a/main/ccss.c b/main/ccss.c
index 2cf828470..4dcacd360 100644
--- a/main/ccss.c
+++ b/main/ccss.c
@@ -501,38 +501,45 @@ static int count_agents_cb(void *obj, void *arg, void *data, int flags)
return 0;
}
-static const unsigned int CC_OFFER_TIMER_DEFAULT = 20u;
-static const unsigned int CCNR_AVAILABLE_TIMER_DEFAULT = 7200u;
-static const unsigned int CCBS_AVAILABLE_TIMER_DEFAULT = 4800u;
-static const unsigned int CC_RECALL_TIMER_DEFAULT = 20u;
-static const unsigned int CC_MAX_AGENTS_DEFAULT = 5u;
-static const unsigned int CC_MAX_MONITORS_DEFAULT = 5u;
-static const unsigned int GLOBAL_CC_MAX_REQUESTS_DEFAULT = 20u;
+#define CC_OFFER_TIMER_DEFAULT 20 /* Seconds */
+#define CCNR_AVAILABLE_TIMER_DEFAULT 7200 /* Seconds */
+#define CCBS_AVAILABLE_TIMER_DEFAULT 4800 /* Seconds */
+#define CC_RECALL_TIMER_DEFAULT 20 /* Seconds */
+#define CC_MAX_AGENTS_DEFAULT 5
+#define CC_MAX_MONITORS_DEFAULT 5
+#define GLOBAL_CC_MAX_REQUESTS_DEFAULT 20
+
+static const struct ast_cc_config_params cc_default_params = {
+ .cc_agent_policy = AST_CC_AGENT_NEVER,
+ .cc_monitor_policy = AST_CC_MONITOR_NEVER,
+ .cc_offer_timer = CC_OFFER_TIMER_DEFAULT,
+ .ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT,
+ .ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT,
+ .cc_recall_timer = CC_RECALL_TIMER_DEFAULT,
+ .cc_max_agents = CC_MAX_AGENTS_DEFAULT,
+ .cc_max_monitors = CC_MAX_MONITORS_DEFAULT,
+ .cc_callback_macro = "",
+ .cc_agent_dialstring = "",
+};
+
+void ast_cc_default_config_params(struct ast_cc_config_params *params)
+{
+ *params = cc_default_params;
+}
struct ast_cc_config_params *__ast_cc_config_params_init(const char *file, int line, const char *function)
{
#if defined(__AST_DEBUG_MALLOC)
- struct ast_cc_config_params *params = __ast_calloc(1, sizeof(*params), file, line, function);
+ struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function);
#else
- struct ast_cc_config_params *params = ast_calloc(1, sizeof(*params));
+ struct ast_cc_config_params *params = ast_malloc(sizeof(*params));
#endif
if (!params) {
return NULL;
}
- /* Yeah, I could use the get/set functions, but what's the point since
- * I have direct access to the structure fields in this file.
- */
- params->cc_agent_policy = AST_CC_AGENT_NEVER;
- params->cc_monitor_policy = AST_CC_MONITOR_NEVER;
- params->cc_offer_timer = CC_OFFER_TIMER_DEFAULT;
- params->ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT;
- params->ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT;
- params->cc_recall_timer = CC_RECALL_TIMER_DEFAULT;
- params->cc_max_agents = CC_MAX_AGENTS_DEFAULT;
- params->cc_max_monitors = CC_MAX_MONITORS_DEFAULT;
- /* No need to set cc_callback_macro since calloc will 0 it out anyway */
+ ast_cc_default_config_params(params);
return params;
}
diff --git a/main/cdr.c b/main/cdr.c
index a6096976d..c9b58238b 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -84,18 +84,26 @@ static struct sched_context *sched;
static int cdr_sched = -1;
static pthread_t cdr_thread = AST_PTHREADT_NULL;
-#define BATCH_SIZE_DEFAULT 100
-#define BATCH_TIME_DEFAULT 300
-#define BATCH_SCHEDULER_ONLY_DEFAULT 0
-#define BATCH_SAFE_SHUTDOWN_DEFAULT 1
+static int enabled;
+static const int ENABLED_DEFAULT = 1;
-static int enabled; /*! Is the CDR subsystem enabled ? */
-static int unanswered;
static int batchmode;
+static const int BATCHMODE_DEFAULT = 0;
+
+static int unanswered;
+static const int UNANSWERED_DEFAULT = 0;
+
static int batchsize;
+static const int BATCH_SIZE_DEFAULT = 100;
+
static int batchtime;
+static const int BATCH_TIME_DEFAULT = 300;
+
static int batchscheduleronly;
+static const int BATCH_SCHEDULER_ONLY_DEFAULT = 0;
+
static int batchsafeshutdown;
+static const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1;
AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
@@ -1492,22 +1500,27 @@ static int do_reload(int reload)
int res=0;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
- return 0;
- if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
+ if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
}
ast_mutex_lock(&cdr_batch_lock);
+ was_enabled = enabled;
+ was_batchmode = batchmode;
+
batchsize = BATCH_SIZE_DEFAULT;
batchtime = BATCH_TIME_DEFAULT;
batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
- was_enabled = enabled;
- was_batchmode = batchmode;
- enabled = 1;
- batchmode = 0;
+ enabled = ENABLED_DEFAULT;
+ batchmode = BATCHMODE_DEFAULT;
+ unanswered = UNANSWERED_DEFAULT;
+
+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
+ ast_mutex_unlock(&cdr_batch_lock);
+ return 0;
+ }
/* don't run the next scheduled CDR posting while reloading */
AST_SCHED_DEL(sched, cdr_sched);
diff --git a/main/cel.c b/main/cel.c
index 0af890bde..7f5c24f40 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -122,6 +122,7 @@ static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
* \brief Map of ast_cel_ama_flags to strings
*/
static const char * const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] = {
+ [AST_CEL_AMA_FLAG_NONE] = "NONE",
[AST_CEL_AMA_FLAG_OMIT] = "OMIT",
[AST_CEL_AMA_FLAG_BILLING] = "BILLING",
[AST_CEL_AMA_FLAG_DOCUMENTATION] = "DOCUMENTATION",
@@ -349,6 +350,11 @@ const char *ast_cel_get_type_name(enum ast_cel_event_type type)
const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag)
{
+ if (flag < 0 || flag >= ARRAY_LEN(cel_ama_flags)) {
+ ast_log(LOG_WARNING, "Invalid AMA flag: %d\n", flag);
+ return "Unknown";
+ }
+
return S_OR(cel_ama_flags[flag], "Unknown");
}
diff --git a/main/channel.c b/main/channel.c
index 32d559d0f..c0a37aaa6 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -5863,6 +5863,7 @@ int ast_do_masquerade(struct ast_channel *original)
struct ast_party_redirecting redirecting;
} exchange;
struct ast_channel *clonechan, *chans[2];
+ struct ast_channel *bridged;
struct ast_cdr *cdr;
format_t rformat = original->readformat;
format_t wformat = original->writeformat;
@@ -6185,6 +6186,14 @@ int ast_do_masquerade(struct ast_channel *original)
pthread_kill(original->blocker, SIGURG);
ast_debug(1, "Done Masquerading %s (%d)\n", original->name, original->_state);
+ if ((bridged = ast_bridged_channel(original))) {
+ ast_channel_lock(bridged);
+ ast_indicate(bridged, AST_CONTROL_SRCCHANGE);
+ ast_channel_unlock(bridged);
+ }
+
+ ast_indicate(original, AST_CONTROL_SRCCHANGE);
+
done:
/* it is possible for the clone channel to disappear during this */
if (clonechan) {
@@ -6196,6 +6205,7 @@ done:
ast_channel_unlock(original);
ao2_link(channels, original);
}
+
return 0;
}
@@ -6716,8 +6726,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
manager_bridge_event(1, 1, c0, c1);
/* Before we enter in and bridge these two together tell them both the source of audio has changed */
- ast_indicate(c0, AST_CONTROL_SRCUPDATE);
- ast_indicate(c1, AST_CONTROL_SRCUPDATE);
+ ast_indicate(c0, AST_CONTROL_SRCCHANGE);
+ ast_indicate(c1, AST_CONTROL_SRCCHANGE);
for (/* ever */;;) {
struct timeval now = { 0, };
diff --git a/main/cli.c b/main/cli.c
index c9dbc6d02..77e52b863 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/lock.h"
#include "editline/readline/readline.h"
#include "asterisk/threadstorage.h"
+#include "asterisk/translate.h"
/*!
* \brief List of restrictions per user.
@@ -302,6 +303,28 @@ static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args
return CLI_SUCCESS;
}
+static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core reload";
+ e->usage =
+ "Usage: core reload\n"
+ " Execute a global reload.\n";
+ return NULL;
+
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != e->args) {
+ return CLI_SHOWUSAGE;
+ }
+
+ ast_module_reload(NULL);
+
+ return CLI_SUCCESS;
+}
/*!
* \brief Find the debug or verbose file setting
* \arg debug 1 for debug, 0 for verbose
@@ -1343,6 +1366,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
struct ast_str *out = ast_str_thread_get(&ast_str_thread_global_buf, 16);
char cdrtime[256];
char nf[256], wf[256], rf[256];
+ struct ast_str *write_transpath = ast_str_alloca(256);
+ struct ast_str *read_transpath = ast_str_alloca(256);
long elapsed_seconds=0;
int hour=0, min=0, sec=0;
#ifdef CHANNEL_TRACE
@@ -1398,8 +1423,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
" NativeFormats: %s\n"
" WriteFormat: %s\n"
" ReadFormat: %s\n"
- " WriteTranscode: %s\n"
- " ReadTranscode: %s\n"
+ " WriteTranscode: %s %s\n"
+ " ReadTranscode: %s %s\n"
"1st File Descriptor: %d\n"
" Frames in: %d%s\n"
" Frames out: %d%s\n"
@@ -1426,7 +1451,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
c->writetrans ? "Yes" : "No",
+ ast_translate_path_to_str(c->writetrans, &write_transpath),
c->readtrans ? "Yes" : "No",
+ ast_translate_path_to_str(c->readtrans, &read_transpath),
c->fds[0],
c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
@@ -1485,7 +1512,13 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta
return NULL;
}
- if (!(iter = ast_channel_iterator_by_name_new(word, strlen(word)))) {
+ if (ast_strlen_zero(word)) {
+ iter = ast_channel_iterator_all_new();
+ } else {
+ iter = ast_channel_iterator_by_name_new(word, strlen(word));
+ }
+
+ if (!iter) {
return NULL;
}
@@ -1609,7 +1642,9 @@ static struct ast_cli_entry cli_cli[] = {
AST_CLI_DEFINE(handle_load, "Load a module by name"),
- AST_CLI_DEFINE(handle_reload, "Reload configuration"),
+ AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"),
+
+ AST_CLI_DEFINE(handle_core_reload, "Global reload"),
AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
diff --git a/main/config.c b/main/config.c
index 34e4247a7..d763adac4 100644
--- a/main/config.c
+++ b/main/config.c
@@ -2361,7 +2361,7 @@ char *ast_realtime_decode_chunk(char *chunk)
char *orig = chunk;
for (; *chunk; chunk++) {
if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
- sscanf(chunk + 1, "%02hhd", chunk);
+ sscanf(chunk + 1, "%02hhX", chunk);
memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
}
}
diff --git a/main/features.c b/main/features.c
index ac0bc7cbf..99cde8bff 100644
--- a/main/features.c
+++ b/main/features.c
@@ -438,7 +438,7 @@ static const struct ast_datastore_info dial_features_info = {
static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
static void parkinglot_unref(struct ast_parkinglot *parkinglot);
static void parkinglot_destroy(void *obj);
-int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *fs, int *max);
+int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *fs);
struct ast_parkinglot *find_parkinglot(const char *name);
static struct ast_parkinglot *create_parkinglot(const char *name);
static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
@@ -2802,7 +2802,7 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
}
} else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
- ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ ast_indicate_data(caller, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
}
} else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
@@ -3603,9 +3603,10 @@ static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_
}
/*! \brief Run management on parkinglots, called once per parkinglot */
-int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
+int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *ms)
{
-
+ struct pollfd *new_fds = NULL;
+ int new_nfds = 0;
struct parkeduser *pu;
int res = 0;
char parkingslot[AST_MAX_EXTENSION];
@@ -3628,12 +3629,12 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
/* Get chan, exten from derived kludge */
if (pu->peername[0]) {
char *peername = ast_strdupa(pu->peername);
- char *cp = strrchr(peername, '-');
+ char *dash = strrchr(peername, '-');
char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
int i;
- if (cp) {
- *cp = 0;
+ if (dash) {
+ *dash = '\0';
}
peername_flat = ast_strdupa(peername);
@@ -3712,14 +3713,33 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
} else { /* still within parking time, process descriptors */
for (x = 0; x < AST_MAX_FDS; x++) {
struct ast_frame *f;
+ int y;
- if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds)))
+ if (chan->fds[x] == -1) {
+ continue; /* nothing on this descriptor */
+ }
+
+ for (y = 0; y < *nfds; y++) {
+ if ((*pfds[y]).fd == chan->fds[x]) {
+ /* Found poll record! */
+ break;
+ }
+ }
+ if (y == *nfds) {
+ /* Not found */
continue;
-
- if (FD_ISSET(chan->fds[x], efds))
+ }
+
+ if (!((*pfds[y]).revents & (POLLIN | POLLERR))) {
+ /* Next x */
+ continue;
+ }
+
+ if ((*pfds[y]).revents & POLLERR) {
ast_set_flag(chan, AST_FLAG_EXCEPTION);
- else
+ } else {
ast_clear_flag(chan, AST_FLAG_EXCEPTION);
+ }
chan->fdno = x;
/* See if they need servicing */
@@ -3760,22 +3780,32 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
}
} /* End for */
if (x >= AST_MAX_FDS) {
-std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
+std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
if (chan->fds[x] > -1) {
- FD_SET(chan->fds[x], nrfds);
- FD_SET(chan->fds[x], nefds);
- if (chan->fds[x] > *max)
- *max = chan->fds[x];
+ void *tmp = ast_realloc(new_fds, (new_nfds + 1) * sizeof(*new_fds));
+ if (!tmp) {
+ continue;
+ }
+ new_fds = tmp;
+ new_fds[new_nfds].fd = chan->fds[x];
+ new_fds[new_nfds].events = POLLIN | POLLERR;
+ new_fds[new_nfds].revents = 0;
+ new_nfds++;
}
}
/* Keep track of our shortest wait */
- if (tms < *ms || *ms < 0)
+ if (tms < *ms || *ms < 0) {
*ms = tms;
+ }
}
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&curlot->parkings);
+
+ ast_free(*pfds);
+ *pfds = new_fds;
+ *nfds = new_nfds;
return res;
}
@@ -3789,35 +3819,26 @@ std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
*/
static void *do_parking_thread(void *ignore)
{
- fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
- fd_set nrfds, nefds; /* args for the next select */
- FD_ZERO(&rfds);
- FD_ZERO(&efds);
+ struct pollfd *pfds = NULL;
+ int nfds = 0;
for (;;) {
- int res = 0;
- int ms = -1; /* select timeout, uninitialized */
- int max = -1; /* max fd, none there yet */
struct ao2_iterator iter;
struct ast_parkinglot *curlot;
- FD_ZERO(&nrfds);
- FD_ZERO(&nefds);
+ int ms = -1; /* poll2 timeout, uninitialized */
iter = ao2_iterator_init(parkinglots, 0);
while ((curlot = ao2_iterator_next(&iter))) {
- res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
+ manage_parkinglot(curlot, &pfds, &nfds, &ms);
ao2_ref(curlot, -1);
}
+ ao2_iterator_destroy(&iter);
- rfds = nrfds;
- efds = nefds;
- {
- struct timeval wait = ast_samp2tv(ms, 1000);
- /* Wait for something to happen */
- ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
- }
+ /* Wait for something to happen */
+ ast_poll(pfds, nfds, ms);
pthread_testcancel();
}
+ /* If this WERE reached, we'd need to free(pfds) */
return NULL; /* Never reached */
}
diff --git a/main/loader.c b/main/loader.c
index 17bb1f821..dea236b05 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -414,6 +414,26 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned
return NULL;
}
+ /* This section is a workaround for a gcc 4.1 bug that has already been
+ * fixed in later versions. Unfortunately, some distributions, such as
+ * RHEL/CentOS 5, distribute gcc 4.1, so we're stuck with having to deal
+ * with this issue. This basically ensures that optional_api modules are
+ * loaded before any module which requires their functionality. */
+#if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
+ if (!ast_strlen_zero(mod->info->nonoptreq)) {
+ /* Force any required dependencies to load */
+ char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
+ while ((each = strsep(&required_resource, ","))) {
+ each = ast_strip(each);
+
+ /* Is it already loaded? */
+ if (!find_resource(each, 0)) {
+ load_dynamic_module(each, global_symbols_only);
+ }
+ }
+ }
+#endif
+
while (!dlclose(lib));
resource_being_loaded = NULL;
diff --git a/main/manager.c b/main/manager.c
index e9007d804..97ab64c02 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -850,11 +850,19 @@ struct eventqent {
static AST_RWLIST_HEAD_STATIC(all_events, eventqent);
-static int displayconnects = 1;
+static const int DEFAULT_ENABLED = 0; /*!< Default setting for manager to be enabled */
+static const int DEFAULT_WEBENABLED = 0; /*!< Default setting for the web interface to be enabled */
+static const int DEFAULT_BLOCKSOCKETS = 0; /*!< Default setting for block-sockets */
+static const int DEFAULT_DISPLAYCONNECTS = 1; /*!< Default setting for displaying manager connections */
+static const int DEFAULT_TIMESTAMPEVENTS = 0; /*!< Default setting for timestampevents */
+static const int DEFAULT_HTTPTIMEOUT = 60; /*!< Default manager http timeout */
+static const int DEFAULT_BROKENEVENTSACTION = 0; /*!< Default setting for brokeneventsaction */
+
+static int displayconnects;
static int allowmultiplelogin = 1;
static int timestampevents;
-static int httptimeout = 60;
-static int broken_events_action = 0;
+static int httptimeout;
+static int broken_events_action;
static int manager_enabled = 0;
static int webmanager_enabled = 0;
static char *manager_channelvars;
@@ -1697,8 +1705,9 @@ static const char *__astman_get_header(const struct message *m, char *var, int m
for (x = 0; x < m->hdrcount; x++) {
const char *h = m->headers[x];
- if (!strncasecmp(var, h, l) && h[l] == ':' && h[l+1] == ' ') {
- const char *value = h + l + 2;
+ if (!strncasecmp(var, h, l) && h[l] == ':') {
+ const char *value = h + l + 1;
+ value = ast_skip_blanks(value); /* ignore leading spaces in the value */
/* found a potential candidate */
if (mode & GET_HEADER_SKIP_EMPTY && ast_strlen_zero(value))
continue; /* not interesting */
@@ -6130,7 +6139,7 @@ static int __init_manager(int reload)
struct ast_config *ucfg = NULL, *cfg = NULL;
const char *val;
char *cat = NULL;
- int newhttptimeout = 60;
+ int newhttptimeout = DEFAULT_HTTPTIMEOUT;
struct ast_manager_user *user = NULL;
struct ast_variable *var;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
@@ -6139,8 +6148,6 @@ static int __init_manager(int reload)
struct sockaddr_in ami_desc_local_address_tmp = { 0, };
struct sockaddr_in amis_desc_local_address_tmp = { 0, };
- manager_enabled = 0;
-
if (!registered) {
/* Register default actions */
ast_manager_register_xml("Ping", 0, action_ping);
@@ -6187,8 +6194,14 @@ static int __init_manager(int reload)
return 0;
}
- displayconnects = 1;
- broken_events_action = 0;
+ manager_enabled = DEFAULT_ENABLED;
+ webmanager_enabled = DEFAULT_WEBENABLED;
+ displayconnects = DEFAULT_DISPLAYCONNECTS;
+ broken_events_action = DEFAULT_BROKENEVENTSACTION;
+ block_sockets = DEFAULT_BLOCKSOCKETS;
+ timestampevents = DEFAULT_TIMESTAMPEVENTS;
+ httptimeout = DEFAULT_HTTPTIMEOUT;
+
if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n");
return 0;
diff --git a/main/netsock2.c b/main/netsock2.c
index 929f4b337..99f7eac89 100644
--- a/main/netsock2.c
+++ b/main/netsock2.c
@@ -118,7 +118,7 @@ char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format)
return ast_str_buffer(str);
}
-int static _ast_sockaddr_parse(char *str, char **host, char **port, int flags)
+int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
{
char *s = str;
@@ -187,7 +187,7 @@ int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
int e;
s = ast_strdupa(str);
- if (!_ast_sockaddr_parse(s, &host, &port, flags)) {
+ if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
return 0;
}
@@ -233,7 +233,7 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
int e, i, res_cnt;
s = ast_strdupa(str);
- if (!_ast_sockaddr_parse(s, &host, &port, flags)) {
+ if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
return 0;
}
@@ -343,7 +343,9 @@ uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, i
addr->len == sizeof(struct sockaddr_in6)) {
return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port);
}
- ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
+ if (option_debug >= 1) {
+ ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
+ }
return 0;
}
@@ -355,7 +357,7 @@ void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char
} else if (addr->ss.ss_family == AF_INET6 &&
addr->len == sizeof(struct sockaddr_in6)) {
((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
- } else {
+ } else if (option_debug >= 1) {
ast_log(__LOG_DEBUG, file, line, func,
"Not an IPv4 nor IPv6 address, cannot set port.\n");
}
@@ -485,7 +487,7 @@ int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
return 0;
}
- if (addr->ss.ss_family != AF_INET) {
+ if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
}
@@ -498,7 +500,7 @@ void _ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in
{
memcpy(&addr->ss, sin, sizeof(*sin));
- if (addr->ss.ss_family != AF_INET) {
+ if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
}
diff --git a/main/pbx.c b/main/pbx.c
index 4216b853a..8e20f8686 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -1164,7 +1164,11 @@ static struct pbx_builtin {
static struct ast_context *contexts;
static struct ast_hashtab *contexts_table = NULL;
-AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
+/*!\brief Lock for the ast_context list
+ * This lock MUST be recursive, or a deadlock on reload may result. See
+ * https://issues.asterisk.org/view.php?id=17643
+ */
+AST_MUTEX_DEFINE_STATIC(conlock);
static AST_RWLIST_HEAD_STATIC(apps, ast_app);
@@ -1904,15 +1908,15 @@ static struct match_char *add_pattern_node(struct ast_context *con, struct match
pattern matcher. */
m->is_pattern = is_pattern;
if (specificity == 1 && is_pattern && pattern[0] == 'N')
- m->specificity = 0x0802;
+ m->specificity = 0x0832;
else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
- m->specificity = 0x0901;
+ m->specificity = 0x0931;
else if (specificity == 1 && is_pattern && pattern[0] == 'X')
- m->specificity = 0x0a00;
+ m->specificity = 0x0a30;
else if (specificity == 1 && is_pattern && pattern[0] == '.')
- m->specificity = 0x10000;
+ m->specificity = 0x18000;
else if (specificity == 1 && is_pattern && pattern[0] == '!')
- m->specificity = 0x20000;
+ m->specificity = 0x28000;
else
m->specificity = specificity;
@@ -2189,10 +2193,10 @@ static int ext_cmp1(const char **p, unsigned char *bitwise)
return 0x0900 | '1';
case '.': /* wildcard */
- return 0x10000;
+ return 0x18000;
case '!': /* earlymatch */
- return 0x20000; /* less specific than NULL */
+ return 0x28000; /* less specific than NULL */
case '\0': /* empty string */
*p = NULL;
@@ -6850,7 +6854,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
ast_unlock_contexts();
ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
- ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
+ ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
} else {
tmp->next = *local_contexts;
if (exttable)
@@ -6858,7 +6862,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
*local_contexts = tmp;
ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
- ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
+ ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
}
return tmp;
}
@@ -7016,7 +7020,6 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
*/
struct timeval begintime, writelocktime, endlocktime, enddeltime;
- int wrlock_ver;
begintime = ast_tvnow();
ast_rdlock_contexts();
@@ -7025,15 +7028,6 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
context_merge(extcontexts, exttable, tmp, registrar);
}
ast_hashtab_end_traversal(iter);
- wrlock_ver = ast_wrlock_contexts_version();
-
- ast_unlock_contexts(); /* this feels real retarded, but you must do
- what you must do If this isn't done, the following
- wrlock is a guraranteed deadlock */
- ast_wrlock_contexts();
- if (ast_wrlock_contexts_version() > wrlock_ver+1) {
- ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
- }
AST_RWLIST_WRLOCK(&hints);
writelocktime = ast_tvnow();
@@ -8209,11 +8203,11 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
}
if (tmp->matchcid) {
- ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
- tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
+ ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
+ tmp->exten, tmp->priority, tmp->cidmatch, con->name);
} else {
- ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
- tmp->exten, tmp->priority, con->name, con);
+ ast_verb(3, "Added extension '%s' priority %d to %s\n",
+ tmp->exten, tmp->priority, con->name);
}
return 0;
@@ -9836,32 +9830,23 @@ int load_pbx(void)
return 0;
}
-static int conlock_wrlock_version = 0;
-
-int ast_wrlock_contexts_version(void)
-{
- return conlock_wrlock_version;
-}
/*
* Lock context list functions ...
*/
int ast_wrlock_contexts()
{
- int res = ast_rwlock_wrlock(&conlock);
- if (!res)
- ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
- return res;
+ return ast_mutex_lock(&conlock);
}
int ast_rdlock_contexts()
{
- return ast_rwlock_rdlock(&conlock);
+ return ast_mutex_lock(&conlock);
}
int ast_unlock_contexts()
{
- return ast_rwlock_unlock(&conlock);
+ return ast_mutex_unlock(&conlock);
}
/*
diff --git a/main/poll.c b/main/poll.c
index d10639077..e0f695504 100644
--- a/main/poll.c
+++ b/main/poll.c
@@ -10,9 +10,9 @@
struct pollfd
{
- int fd;
- short events;
- short revents;
+ int fd;
+ short events;
+ short revents;
}
int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
@@ -73,54 +73,44 @@
#include "asterisk.h"
-#include <unistd.h> /* standard Unix definitions */
-#include <sys/types.h> /* system types */
-#include <sys/time.h> /* time definitions */
-#include <assert.h> /* assertion macros */
-#include <string.h> /* string functions */
+#include <unistd.h> /* standard Unix definitions */
+#include <sys/types.h> /* system types */
+#include <sys/time.h> /* time definitions */
+#include <assert.h> /* assertion macros */
+#include <string.h> /* string functions */
+#include <errno.h>
#include "asterisk/utils.h" /* this package */
#include "asterisk/poll-compat.h" /* this package */
-#ifdef AST_POLL_COMPAT
+unsigned int ast_FD_SETSIZE = FD_SETSIZE;
#ifndef MAX
#define MAX(a,b) a > b ? a : b
#endif
/*---------------------------------------------------------------------------*\
- Private Functions
+ Private Functions
\*---------------------------------------------------------------------------*/
-static int map_poll_spec
-#if __STDC__ > 0
- (struct pollfd *pArray,
- unsigned long n_fds,
- fd_set *pReadSet,
- fd_set *pWriteSet,
- fd_set *pExceptSet)
-#else
- (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
- struct pollfd *pArray;
- unsigned long n_fds;
- fd_set *pReadSet;
- fd_set *pWriteSet;
- fd_set *pExceptSet;
-#endif
+#if defined(AST_POLL_COMPAT)
+static int map_poll_spec(struct pollfd *pArray, unsigned long n_fds,
+ ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
{
- register unsigned long i; /* loop control */
- register struct pollfd *pCur; /* current array element */
- register int max_fd = -1; /* return value */
+ register unsigned long i; /* loop control */
+ register struct pollfd *pCur; /* current array element */
+ register int max_fd = -1; /* return value */
- /*!\note
+ /*
* Map the poll() structures into the file descriptor sets required
* by select().
*/
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
/* Skip any bad FDs in the array. */
- if (pCur->fd < 0)
+ if (pCur->fd < 0) {
continue;
+ }
if (pCur->events & POLLIN) {
/* "Input Ready" notification desired. */
@@ -145,34 +135,28 @@ static int map_poll_spec
return max_fd;
}
-
-static struct timeval *map_timeout
-#if __STDC__ > 0
- (int poll_timeout, struct timeval *pSelTimeout)
-#else
- (poll_timeout, pSelTimeout)
- int poll_timeout;
- struct timeval *pSelTimeout;
-#endif
+
+#ifdef AST_POLL_COMPAT
+static struct timeval *map_timeout(int poll_timeout, struct timeval *pSelTimeout)
{
struct timeval *pResult;
- /*!\note
- * Map the poll() timeout value into a select() timeout. The possible
- * values of the poll() timeout value, and their meanings, are:
- *
- * VALUE MEANING
- *
- * -1 wait indefinitely (until signal occurs)
- * 0 return immediately, don't block
- * >0 wait specified number of milliseconds
- *
- * select() uses a "struct timeval", which specifies the timeout in
- * seconds and microseconds, so the milliseconds value has to be mapped
- * accordingly.
- */
+ /*
+ Map the poll() timeout value into a select() timeout. The possible
+ values of the poll() timeout value, and their meanings, are:
+
+ VALUE MEANING
- assert(pSelTimeout != (struct timeval *) NULL);
+ -1 wait indefinitely (until signal occurs)
+ 0 return immediately, don't block
+ >0 wait specified number of milliseconds
+
+ select() uses a "struct timeval", which specifies the timeout in
+ seconds and microseconds, so the milliseconds value has to be mapped
+ accordingly.
+ */
+
+ assert(pSelTimeout != NULL);
switch (poll_timeout) {
case -1:
@@ -203,25 +187,13 @@ static struct timeval *map_timeout
return pResult;
}
+#endif /* AST_POLL_COMPAT */
-static void map_select_results
-#if __STDC__ > 0
- (struct pollfd *pArray,
- unsigned long n_fds,
- fd_set *pReadSet,
- fd_set *pWriteSet,
- fd_set *pExceptSet)
-#else
- (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
- struct pollfd *pArray;
- unsigned long n_fds;
- fd_set *pReadSet;
- fd_set *pWriteSet;
- fd_set *pExceptSet;
-#endif
+static void map_select_results(struct pollfd *pArray, unsigned long n_fds,
+ ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
{
- register unsigned long i; /* loop control */
- register struct pollfd *pCur; /* current array element */
+ register unsigned long i; /* loop control */
+ register struct pollfd *pCur; /* current array element */
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
/* Skip any bad FDs in the array. */
@@ -231,59 +203,105 @@ static void map_select_results
}
/* Exception events take priority over input events. */
-
pCur->revents = 0;
- if (FD_ISSET (pCur->fd, pExceptSet)) {
+ if (FD_ISSET(pCur->fd, (fd_set *) pExceptSet)) {
pCur->revents |= POLLPRI;
- } else if (FD_ISSET (pCur->fd, pReadSet)) {
+ } else if (FD_ISSET(pCur->fd, (fd_set *) pReadSet)) {
pCur->revents |= POLLIN;
}
- if (FD_ISSET (pCur->fd, pWriteSet)) {
+ if (FD_ISSET(pCur->fd, (fd_set *) pWriteSet)) {
pCur->revents |= POLLOUT;
}
}
return;
}
+#endif /* defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL) */
/*---------------------------------------------------------------------------*\
- Public Functions
+ Public Functions
\*---------------------------------------------------------------------------*/
-
+#ifdef AST_POLL_COMPAT
int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout)
{
- fd_set read_descs; /* input file descs */
- fd_set write_descs; /* output file descs */
- fd_set except_descs; /* exception descs */
+ ast_fdset read_descs; /* input file descs */
+ ast_fdset write_descs; /* output file descs */
+ ast_fdset except_descs; /* exception descs */
struct timeval stime; /* select() timeout value */
- int ready_descriptors; /* function result */
- int max_fd = 0; /* maximum fd value */
+ int ready_descriptors; /* function result */
+ int max_fd = 0; /* maximum fd value */
struct timeval *pTimeout; /* actually passed */
+ int save_errno;
- FD_ZERO (&read_descs);
- FD_ZERO (&write_descs);
- FD_ZERO (&except_descs);
+ FD_ZERO(&read_descs);
+ FD_ZERO(&write_descs);
+ FD_ZERO(&except_descs);
/* Map the poll() file descriptor list in the select() data structures. */
if (pArray) {
- max_fd = map_poll_spec (pArray, n_fds,
+ max_fd = map_poll_spec (pArray, n_fds,
&read_descs, &write_descs, &except_descs);
}
/* Map the poll() timeout value in the select() timeout structure. */
- pTimeout = map_timeout(timeout, &stime);
+
+ pTimeout = map_timeout (timeout, &stime);
/* Make the select() call. */
- ready_descriptors = select(max_fd + 1, &read_descs, &write_descs,
+
+ ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs,
&except_descs, pTimeout);
+ save_errno = errno;
+
+ if (ready_descriptors >= 0) {
+ map_select_results (pArray, n_fds,
+ &read_descs, &write_descs, &except_descs);
+ }
+
+ errno = save_errno;
+ return ready_descriptors;
+}
+#endif /* AST_POLL_COMPAT */
+
+int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
+{
+#if !defined(AST_POLL_COMPAT)
+ struct timeval start = ast_tvnow();
+#if defined(HAVE_PPOLL)
+ struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 };
+ int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL);
+#else
+ int res = poll(pArray, n_fds, tv ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1);
+#endif
+ struct timeval after = ast_tvnow();
+ if (res > 0 && tv && ast_tvdiff_ms(ast_tvadd(*tv, start), after) > 0) {
+ *tv = ast_tvsub(*tv, ast_tvsub(after, start));
+ } else if (res > 0 && tv) {
+ *tv = ast_tv(0, 0);
+ }
+ return res;
+#else
+ ast_fdset read_descs, write_descs, except_descs;
+ int ready_descriptors, max_fd = 0;
+
+ FD_ZERO(&read_descs);
+ FD_ZERO(&write_descs);
+ FD_ZERO(&except_descs);
+
+ if (pArray) {
+ max_fd = map_poll_spec(pArray, n_fds, &read_descs, &write_descs, &except_descs);
+ }
+
+ ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, tv);
if (ready_descriptors >= 0) {
map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
}
return ready_descriptors;
+#endif
}
-#endif /* AST_POLL_COMPAT */
+
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 02c453ff9..9fe5c5a62 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -282,6 +282,10 @@ static void instance_destructor(void *obj)
return;
}
+ if (instance->srtp) {
+ res_srtp->destroy(instance->srtp);
+ }
+
/* Drop our engine reference */
ast_module_unref(instance->engine->mod);
diff --git a/main/sched.c b/main/sched.c
index 78de1a99e..8a3602a39 100644
--- a/main/sched.c
+++ b/main/sched.c
@@ -604,13 +604,13 @@ int ast_sched_runq(struct sched_context *con)
ast_mutex_lock(&con->lock);
+ when = ast_tvadd(ast_tvnow(), ast_tv(0, 1000));
for (numevents = 0; (current = ast_heap_peek(con->sched_heap, 1)); numevents++) {
/* schedule all events which are going to expire within 1ms.
* We only care about millisecond accuracy anyway, so this will
* help us get more than one event at one time if they are very
* close together.
*/
- when = ast_tvadd(ast_tvnow(), ast_tv(0, 1000));
if (ast_tvcmp(current->when, when) != -1) {
break;
}
diff --git a/main/stun.c b/main/stun.c
index 74652f90b..3ad326ee8 100644
--- a/main/stun.c
+++ b/main/stun.c
@@ -397,8 +397,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
/* send request, possibly wait for reply */
unsigned char reply_buf[1024];
- fd_set rfds;
- struct timeval to = { 3, 0 }; /* timeout, make it configurable */
+ struct pollfd pfds = { .fd = s, .events = POLLIN };
struct sockaddr_in src;
socklen_t srclen;
@@ -410,9 +409,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
}
if (answer == NULL)
break;
- FD_ZERO(&rfds);
- FD_SET(s, &rfds);
- res = ast_select(s + 1, &rfds, NULL, NULL, &to);
+ res = ast_poll(&pfds, 1, 3000);
if (res <= 0) /* timeout or error */
continue;
memset(&src, 0, sizeof(src));
diff --git a/main/translate.c b/main/translate.c
index 24d886473..61b4a4686 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -45,10 +45,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*! \brief the list of translators */
static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
+
+/*! \brief these values indicate how a translation path will affect the sample rate
+ *
+ * \note These must stay in this order. They are ordered by most optimal selection first.
+ */
+enum path_samp_change {
+ RATE_CHANGE_NONE = 0, /*!< path uses the same sample rate consistently */
+ RATE_CHANGE_UPSAMP = 1, /*!< path will up the sample rate during a translation */
+ RATE_CHANGE_DOWNSAMP = 2, /*!< path will have to down the sample rate during a translation. */
+ RATE_CHANGE_UPSAMP_DOWNSAMP = 3, /*!< path will both up and down the sample rate during translation */
+};
+
struct translator_path {
struct ast_translator *step; /*!< Next step translator */
unsigned int cost; /*!< Complete cost to destination */
unsigned int multistep; /*!< Multiple conversions required for this translation */
+ enum path_samp_change rate_change; /*!< does this path require a sample rate change, if so what kind. */
};
/*! \brief a matrix that, for any pair of supported formats,
@@ -402,6 +415,24 @@ static void calc_cost(struct ast_translator *t, int seconds)
t->cost = 1;
}
+static enum path_samp_change get_rate_change_result(format_t src, format_t dst)
+{
+ int src_rate = ast_format_rate(src);
+ int dst_rate = ast_format_rate(dst);
+
+ /* if src rate is less than dst rate, a sample upgrade is required */
+ if (src_rate < dst_rate) {
+ return RATE_CHANGE_UPSAMP;
+ }
+
+ /* if src rate is larger than dst rate, a downgrade is required */
+ if (src_rate > dst_rate) {
+ return RATE_CHANGE_DOWNSAMP;
+ }
+
+ return RATE_CHANGE_NONE;
+}
+
/*!
* \brief rebuild a translation matrix.
* \note This function expects the list of translators to be locked
@@ -409,6 +440,8 @@ static void calc_cost(struct ast_translator *t, int seconds)
static void rebuild_matrix(int samples)
{
struct ast_translator *t;
+ int new_rate_change;
+ int newcost;
int x; /* source format index */
int y; /* intermediate format index */
int z; /* destination format index */
@@ -427,10 +460,21 @@ static void rebuild_matrix(int samples)
if (samples)
calc_cost(t, samples);
-
- if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) {
+
+ new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt);
+
+ /* this translator is the best choice if any of the below are true.
+ * 1. no translation path is set between x and z yet.
+ * 2. the new translation costs less and sample rate is no worse than old one.
+ * 3. the new translation has a better sample rate conversion than the old one.
+ */
+ if (!tr_matrix[x][z].step ||
+ ((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) ||
+ (new_rate_change < tr_matrix[x][z].rate_change)) {
+
tr_matrix[x][z].step = t;
tr_matrix[x][z].cost = t->cost;
+ tr_matrix[x][z].rate_change = new_rate_change;
}
}
@@ -442,31 +486,73 @@ static void rebuild_matrix(int samples)
*/
for (;;) {
int changed = 0;
+ int better_choice = 0;
for (x = 0; x < MAX_FORMAT; x++) { /* source format */
for (y = 0; y < MAX_FORMAT; y++) { /* intermediate format */
if (x == y) /* skip ourselves */
continue;
-
- for (z = 0; z<MAX_FORMAT; z++) { /* dst format */
- int newcost;
-
+ for (z = 0; z < MAX_FORMAT; z++) { /* dst format */
if (z == x || z == y) /* skip null conversions */
continue;
if (!tr_matrix[x][y].step) /* no path from x to y */
continue;
if (!tr_matrix[y][z].step) /* no path from y to z */
continue;
+
+ /* Does x->y->z result in a less optimal sample rate change?
+ * Never downgrade the sample rate conversion quality regardless
+ * of any cost improvements */
+ if (tr_matrix[x][z].step &&
+ ((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) ||
+ (tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) {
+ continue;
+ }
+
+ /* is x->y->z a better sample rate confersion that the current x->z? */
+ new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change;
+
+ /* calculate cost from x->y->z */
newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
- if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost)
- continue; /* x->y->z is more expensive than
- * the existing path */
+
+ /* Is x->y->z a better choice than x->z?
+ * There are three conditions for x->y->z to be a better choice than x->z
+ * 1. if there is no step directly between x->z then x->y->z is the best and only current option.
+ * 2. if x->y->z costs less and the sample rate conversion is no less optimal.
+ * 3. if x->y->z results in a more optimal sample rate conversion. */
+ if (!tr_matrix[x][z].step) {
+ better_choice = 1;
+ } else if ((newcost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) {
+ better_choice = 1;
+ } else if (new_rate_change < tr_matrix[x][z].rate_change) {
+ better_choice = 1;
+ } else {
+ better_choice = 0;
+ }
+
+ if (!better_choice) {
+ continue;
+ }
/* ok, we can get from x to z via y with a cost that
- is the sum of the transition from x to y and
- from y to z */
-
+ is the sum of the transition from x to y and from y to z */
tr_matrix[x][z].step = tr_matrix[x][y].step;
tr_matrix[x][z].cost = newcost;
tr_matrix[x][z].multistep = 1;
+
+ /* now calculate what kind of sample rate change is required for this multi-step path
+ *
+ * if both paths require a change in rate, and they are not in the same direction
+ * then this is a up sample down sample conversion scenario. */
+ if ((tr_matrix[x][y].rate_change > RATE_CHANGE_NONE) &&
+ (tr_matrix[y][z].rate_change > RATE_CHANGE_NONE) &&
+ (tr_matrix[x][y].rate_change != tr_matrix[y][z].rate_change)) {
+
+ tr_matrix[x][z].rate_change = RATE_CHANGE_UPSAMP_DOWNSAMP;
+ } else {
+ /* else just set the rate change to whichever is worse */
+ tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change > tr_matrix[y][z].rate_change
+ ? tr_matrix[x][y].rate_change : tr_matrix[y][z].rate_change;
+ }
+
ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y));
changed++;
@@ -478,30 +564,134 @@ static void rebuild_matrix(int samples)
}
}
+const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
+{
+ struct ast_trans_pvt *pn = p;
+
+ if (!p || !p->t) {
+ return "";
+ }
+
+ ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt));
+
+ while ( (p = pn) ) {
+ pn = p->next;
+ ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt));
+ }
+
+ return ast_str_buffer(*str);
+}
+
+static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
+{
+ int which = 0;
+ int wordlen = strlen(word);
+ int i;
+ char *ret = NULL;
+ size_t len = 0;
+ const struct ast_format_list *format_list = ast_get_format_list(&len);
+
+ for (i = 0; i < len; i++) {
+ if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
+ continue;
+ }
+ if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
+ ret = ast_strdup(format_list[i].name);
+ break;
+ }
+ }
+ return ret;
+}
+
static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
-#define SHOW_TRANS 16
+#define SHOW_TRANS 64
+ static const char * const option1[] = { "recalc", "paths", NULL };
int x, y, z;
int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
switch (cmd) {
case CLI_INIT:
- e->command = "core show translation [recalc]";
+ e->command = "core show translation";
e->usage =
- "Usage: core show translation [recalc [<recalc seconds>]]\n"
- " Displays known codec translators and the cost associated\n"
- " with each conversion. If the argument 'recalc' is supplied along\n"
- " with optional number of seconds to test a new test will be performed\n"
- " as the chart is being displayed.\n";
+ "Usage: 'core show translation' can be used in two ways.\n"
+ " 1. 'core show translation [recalc [<recalc seconds>]]\n"
+ " Displays known codec translators and the cost associated\n"
+ " with each conversion. If the argument 'recalc' is supplied along\n"
+ " with optional number of seconds to test a new test will be performed\n"
+ " as the chart is being displayed.\n"
+ " 2. 'core show translation paths [codec]'\n"
+ " This will display all the translation paths associated with a codec\n";
return NULL;
case CLI_GENERATE:
+ if (a->pos == 3) {
+ return ast_cli_complete(a->word, option1, a->n);
+ }
+ if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) {
+ return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
+ }
return NULL;
}
if (a->argc > 5)
return CLI_SHOWUSAGE;
- if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
+ if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) {
+ format_t input_src = 0;
+ format_t src = 0;
+ size_t len = 0;
+ int dst;
+ int i;
+ const struct ast_format_list *format_list = ast_get_format_list(&len);
+ struct ast_str *str = ast_str_alloca(256);
+ struct ast_translator *step;
+
+ for (i = 0; i < len; i++) {
+ if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
+ continue;
+ }
+ if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
+ input_src = format_list[i].bits;
+ }
+ }
+
+ if (!input_src) {
+ ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
+ return CLI_FAILURE;
+ }
+
+ AST_RWLIST_RDLOCK(&translators);
+ ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src));
+ for (i = 0; i < len; i++) {
+ if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) {
+ continue;
+ }
+ dst = powerof(format_list[i].bits);
+ src = powerof(input_src);
+ ast_str_reset(str);
+ if (tr_matrix[src][dst].step) {
+ ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt));
+ while (src != dst) {
+ step = tr_matrix[src][dst].step;
+ if (!step) {
+ ast_str_reset(str);
+ break;
+ }
+ ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt));
+ src = step->dstfmt;
+ }
+ }
+
+ if (ast_strlen_zero(ast_str_buffer(str))) {
+ ast_str_set(&str, 0, "No Translation Path");
+ }
+
+ ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
+ }
+ AST_RWLIST_UNLOCK(&translators);
+
+ return CLI_SUCCESS;
+ } else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
z = a->argv[4] ? atoi(a->argv[4]) : 1;
if (z <= 0) {
@@ -526,22 +716,33 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n");
/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
for (x = 0; x < SHOW_TRANS; x++) {
+ /* translation only applies to audio right now. */
+ if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+ continue;
curlen = strlen(ast_getformatname(1LL << (x)));
if (curlen > longest)
longest = curlen;
for (y = 0; y < SHOW_TRANS; y++) {
+ if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
+ continue;
if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
magnitude[y] = floor(log10(tr_matrix[x][y].cost));
}
}
}
for (x = -1; x < SHOW_TRANS; x++) {
- struct ast_str *out = ast_str_alloca(125);
+ struct ast_str *out = ast_str_alloca(256);
+ /* translation only applies to audio right now. */
+ if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+ continue;
/*Go ahead and move to next iteration if dealing with an unknown codec*/
if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown"))
continue;
ast_str_set(&out, -1, " ");
for (y = -1; y < SHOW_TRANS; y++) {
+ /* translation only applies to audio right now. */
+ if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
+ continue;
/*Go ahead and move to next iteration if dealing with an unknown codec*/
if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown"))
continue;
@@ -715,37 +916,65 @@ void ast_translator_deactivate(struct ast_translator *t)
format_t ast_translator_best_choice(format_t *dst, format_t *srcs)
{
int x,y;
+ int better = 0;
+ int besttime = INT_MAX;
+ int beststeps = INT_MAX;
+ unsigned int best_rate_change = INT_MAX;
format_t best = -1;
format_t bestdst = 0;
format_t cur, cursrc;
- int besttime = INT_MAX;
- int beststeps = INT_MAX;
format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */
if (common) { /* yes, pick one and return */
for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
- if (cur & common) /* guaranteed to find one */
- break;
+ if (!(cur & common)) {
+ continue;
+ }
+
+ /* We are guaranteed to find one common format. */
+ if (best == -1) {
+ best = cur;
+ continue;
+ }
+ /* If there are multiple common formats, pick the one with the highest sample rate */
+ if (ast_format_rate(best) < ast_format_rate(cur)) {
+ best = cur;
+ continue;
+ }
}
/* We are done, this is a common format to both. */
- *srcs = *dst = cur;
+ *srcs = *dst = best;
return 0;
- } else { /* No, we will need to translate */
+ } else { /* No, we will need to translate */
AST_RWLIST_RDLOCK(&translators);
for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
- if (! (cur & *dst))
+ if (! (cur & *dst)) {
continue;
+ }
for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
- if (!(*srcs & cursrc) || !tr_matrix[x][y].step ||
- tr_matrix[x][y].cost > besttime)
- continue; /* not existing or no better */
- if (tr_matrix[x][y].cost < besttime ||
- tr_matrix[x][y].multistep < beststeps) {
+ if (!(*srcs & cursrc) || !tr_matrix[x][y].step) {
+ continue;
+ }
+
+ /* This is a better choice if any of the following are true.
+ * 1. The sample rate conversion is better than the current pick.
+ * 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better
+ */
+ better = 0;
+ if (tr_matrix[x][y].rate_change < best_rate_change) {
+ better = 1; /* this match has a better rate conversion */
+ }
+ if ((tr_matrix[x][y].rate_change <= best_rate_change) &&
+ (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) {
+ better = 1; /* this match has no worse rate conversion and the conversion cost is less */
+ }
+ if (better) {
/* better than what we have so far */
best = cursrc;
bestdst = cur;
besttime = tr_matrix[x][y].cost;
beststeps = tr_matrix[x][y].multistep;
+ best_rate_change = tr_matrix[x][y].rate_change;
}
}
}
diff --git a/main/utils.c b/main/utils.c
index 5961a7339..6f2c884d0 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1615,7 +1615,8 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
size_t space = (*pool_head)->size - (*pool_head)->used;
size_t to_alloc = needed + sizeof(ast_string_field_allocation);
- if (__builtin_expect(to_alloc > space, 0)) {
+ /* This +1 accounts for alignment on SPARC */
+ if (__builtin_expect(to_alloc + 1 > space, 0)) {
size_t new_size = (*pool_head)->size;
while (new_size < to_alloc) {
@@ -1632,6 +1633,13 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
}
result = (*pool_head)->base + (*pool_head)->used;
+#ifdef __sparc__
+ /* SPARC requires that the allocation field be aligned. */
+ if ((long) result % sizeof(ast_string_field_allocation)) {
+ result++;
+ (*pool_head)->used++;
+ }
+#endif
(*pool_head)->used += to_alloc;
(*pool_head)->active += needed;
result += sizeof(ast_string_field_allocation);
@@ -1706,6 +1714,12 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
}
} else {
target = (*pool_head)->base + (*pool_head)->used + sizeof(ast_string_field_allocation);
+#ifdef __sparc__
+ if ((long) target % sizeof(ast_string_field_allocation)) {
+ target++;
+ space--;
+ }
+#endif
available = space - sizeof(ast_string_field_allocation);
}
diff --git a/makeopts.in b/makeopts.in
index 750a41d7c..268096868 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -12,6 +12,7 @@ AWK=@AWK@
BISON=@BISON@
FLEX=@FLEX@
GREP=@GREP@
+MAKE=@GNU_MAKE@
AR=@AR@
RANLIB=@RANLIB@
FIND=@FIND@
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index ed1a2cd8c..0baa8e17c 100644
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -1456,15 +1456,15 @@ process_extension:
*cidmatch++ = '\0';
ast_shrink_phone_number(cidmatch);
}
- pri = S_OR(strsep(&stringp, ","), "");
- pri = ast_skip_blanks(pri);
- pri = ast_trim_blanks(pri);
+ pri = ast_strip(S_OR(strsep(&stringp, ","), ""));
if ((label = strchr(pri, '('))) {
*label++ = '\0';
if ((end = strchr(label, ')'))) {
*end = '\0';
} else {
ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
+ ast_free(tc);
+ continue;
}
}
if ((plus = strchr(pri, '+'))) {
@@ -1477,17 +1477,27 @@ process_extension:
ipri = lastpri + 1;
} else {
ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry at line %d!\n", v->lineno);
+ ast_free(tc);
+ continue;
}
} else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
if (lastpri > -2) {
ipri = lastpri;
} else {
ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry at line %d!\n", v->lineno);
+ ast_free(tc);
+ continue;
}
} else if (sscanf(pri, "%30d", &ipri) != 1 &&
(ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
ipri = 0;
+ ast_free(tc);
+ continue;
+ } else if (ipri < 1) {
+ ast_log(LOG_WARNING, "Invalid priority '%s' at line %d\n", pri, v->lineno);
+ ast_free(tc);
+ continue;
}
appl = S_OR(stringp, "");
/* Find the first occurrence of '(' */
@@ -1497,9 +1507,11 @@ process_extension:
} else {
char *orig_appl = ast_strdup(appl);
- if (!orig_appl)
- return -1;
-
+ if (!orig_appl) {
+ ast_free(tc);
+ continue;
+ }
+
appl = strsep(&stringp, "(");
/* check if there are variables or expressions without an application, like: exten => 100,hint,DAHDI/g0/${GLOBAL(var)} */
@@ -1526,8 +1538,8 @@ process_extension:
ipri += atoi(plus);
}
lastpri = ipri;
- if (!ast_opt_dont_warn && !strcmp(realext, "_.")) {
- ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno);
+ if (!ast_opt_dont_warn && (!strcmp(realext, "_.") || !strcmp(realext, "_!"))) {
+ ast_log(LOG_WARNING, "The use of '%s' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X%c' instead at line %d\n", realext, realext[1], v->lineno);
}
if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, registrar)) {
ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
@@ -1737,13 +1749,13 @@ static int pbx_load_module(void)
static int load_module(void)
{
- if (pbx_load_module())
- return AST_MODULE_LOAD_DECLINE;
-
if (static_config && !write_protect_config)
ast_cli_register(&cli_dialplan_save);
ast_cli_register_multiple(cli_pbx_config, ARRAY_LEN(cli_pbx_config));
+ if (pbx_load_module())
+ return AST_MODULE_LOAD_DECLINE;
+
return AST_MODULE_LOAD_SUCCESS;
}
diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c
index aaa30da0c..ef482df2c 100644
--- a/pbx/pbx_dundi.c
+++ b/pbx/pbx_dundi.c
@@ -4880,5 +4880,6 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Distributed Universal Nu
.load = load_module,
.unload = unload_module,
.reload = reload,
+ .nonoptreq = "res_crypto",
);
diff --git a/pbx/pbx_loopback.c b/pbx/pbx_loopback.c
index f51ec8204..9ab146398 100644
--- a/pbx/pbx_loopback.c
+++ b/pbx/pbx_loopback.c
@@ -41,7 +41,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/utils.h"
-#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c
index 833202af6..f183c867b 100644
--- a/pbx/pbx_realtime.c
+++ b/pbx/pbx_realtime.c
@@ -46,7 +46,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/utils.h"
-#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/app.h"
#include "asterisk/astobj2.h"
@@ -349,7 +348,8 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
appdata[0] = 0; /* just in case the substitute var func isn't called */
if(!ast_strlen_zero(tmp))
pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
- ast_verb(3, "Executing %s(\"%s\", \"%s\")\n",
+ ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
+ chan->exten, chan->context, chan->priority,
term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c
index 6c7b449a1..7a76aa84b 100644
--- a/pbx/pbx_spool.c
+++ b/pbx/pbx_spool.c
@@ -372,6 +372,7 @@ static void launch_service(struct outgoing *o)
}
}
+/* Called from scan_thread or queue_file */
static int scan_service(const char *fn, time_t now)
{
struct outgoing *o = NULL;
@@ -551,7 +552,7 @@ static void *scan_thread(void *unused)
}
#ifdef HAVE_INOTIFY
- inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_ATTRIB | IN_MOVED_TO);
+ inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_MOVED_TO);
#endif
/* First, run through the directory and clear existing entries */
@@ -590,8 +591,16 @@ static void *scan_thread(void *unused)
/* When a file arrives, add it to the queue, in mtime order. */
if ((res = poll(&pfd, 1, waittime)) > 0 && (stage = 1) &&
(res = read(inotify_fd, &buf, sizeof(buf))) >= sizeof(buf.iev)) {
- /* File added to directory, add it to my list */
- queue_file(buf.iev.name, 0);
+ /* File(s) added to directory, add them to my list */
+ do {
+ queue_file(buf.iev.name, 0);
+ res -= sizeof(buf.iev) + buf.iev.len;
+ if (res >= sizeof(buf.iev)) {
+ memmove(&buf.iev, &buf.iev.name[buf.iev.len], res);
+ continue;
+ }
+ break;
+ } while (1);
} else if (res < 0 && errno != EINTR && errno != EAGAIN) {
ast_debug(1, "Got an error back from %s(2): %s\n", stage ? "read" : "poll", strerror(errno));
}
diff --git a/res/res_ais.c b/res/res_ais.c
index adb3290e1..9bcceeade 100644
--- a/res/res_ais.c
+++ b/res/res_ais.c
@@ -113,9 +113,9 @@ const char *ais_err2str(SaAisErrorT error)
static void *dispatch_thread_handler(void *data)
{
- SaSelectionObjectT clm_fd, evt_fd, max_fd;
+ SaSelectionObjectT clm_fd, evt_fd;
int res;
- fd_set read_fds;
+ struct pollfd pfd[2] = { { .events = POLLIN, }, { .events = POLLIN, } };
SaAisErrorT ais_res;
ais_res = saClmSelectionObjectGet(clm_handle, &clm_fd);
@@ -132,24 +132,26 @@ static void *dispatch_thread_handler(void *data)
return NULL;
}
- max_fd = clm_fd > evt_fd ? clm_fd : evt_fd;
+ pfd[0].fd = clm_fd;
+ pfd[1].fd = evt_fd;
while (!dispatch_thread.stop) {
- FD_ZERO(&read_fds);
- FD_SET(clm_fd, &read_fds);
- FD_SET(evt_fd, &read_fds);
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
- res = ast_select(max_fd + 1, &read_fds, NULL, NULL, NULL);
+ res = ast_poll(pfd, 2, -1);
if (res == -1 && errno != EINTR && errno != EAGAIN) {
ast_log(LOG_ERROR, "Select error (%s) dispatch thread going away now, "
"and the module will no longer operate.\n", strerror(errno));
break;
}
- if (FD_ISSET(clm_fd, &read_fds))
+ if (pfd[0].revents & POLLIN) {
saClmDispatch(clm_handle, SA_DISPATCH_ALL);
- if (FD_ISSET(evt_fd, &read_fds))
+ }
+ if (pfd[1].revents & POLLIN) {
saEvtDispatch(evt_handle, SA_DISPATCH_ALL);
+ }
}
return NULL;
diff --git a/res/res_calendar.c b/res/res_calendar.c
index 2de995933..183b40845 100644
--- a/res/res_calendar.c
+++ b/res/res_calendar.c
@@ -65,6 +65,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="description"><para>The text description of the event</para></enum>
<enum name="organizer"><para>The organizer of the event</para></enum>
<enum name="location"><para>The location of the eventt</para></enum>
+ <enum name="categories"><para>The categories of the event</para></enum>
+ <enum name="priority"><para>The priority of the event</para></enum>
<enum name="calendar"><para>The name of the calendar associated with the event</para></enum>
<enum name="uid"><para>The unique identifier for this event</para></enum>
<enum name="start"><para>The start time of the event</para></enum>
@@ -112,6 +114,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="description"><para>The full event description</para></enum>
<enum name="organizer"><para>The event organizer</para></enum>
<enum name="location"><para>The event location</para></enum>
+ <enum name="categories"><para>The categories of the event</para></enum>
+ <enum name="priority"><para>The priority of the event</para></enum>
<enum name="calendar"><para>The name of the calendar associted with the event</para></enum>
<enum name="uid"><para>The unique identifier for the event</para></enum>
<enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
@@ -142,6 +146,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="description"><para>The full event description</para></enum>
<enum name="organizer"><para>The event organizer</para></enum>
<enum name="location"><para>The event location</para></enum>
+ <enum name="categories"><para>The categories of the event</para></enum>
+ <enum name="priority"><para>The priority of the event</para></enum>
<enum name="uid"><para>The unique identifier for the event</para></enum>
<enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
<enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
@@ -786,6 +792,8 @@ static void copy_event_data(struct ast_calendar_event *dst, struct ast_calendar_
ast_string_field_set(dst, organizer, src->organizer);
ast_string_field_set(dst, location, src->location);
ast_string_field_set(dst, uid, src->uid);
+ ast_string_field_set(dst, categories, src->categories);
+ dst->priority = src->priority;
dst->owner = src->owner;
dst->start = src->start;
dst->end = src->end;
@@ -1228,6 +1236,10 @@ static int calendar_query_result_exec(struct ast_channel *chan, const char *cmd,
ast_copy_string(buf, entry->event->organizer, len);
} else if (!strcasecmp(args.field, "location")) {
ast_copy_string(buf, entry->event->location, len);
+ } else if (!strcasecmp(args.field, "categories")) {
+ ast_copy_string(buf, entry->event->categories, len);
+ } else if (!strcasecmp(args.field, "priority")) {
+ snprintf(buf, len, "%d", entry->event->priority);
} else if (!strcasecmp(args.field, "calendar")) {
ast_copy_string(buf, entry->event->owner->name, len);
} else if (!strcasecmp(args.field, "uid")) {
@@ -1313,6 +1325,10 @@ static int calendar_write_exec(struct ast_channel *chan, const char *cmd, char *
ast_string_field_set(event, organizer, values.value[j]);
} else if (!strcasecmp(fields.field[i], "location")) {
ast_string_field_set(event, location, values.value[j]);
+ } else if (!strcasecmp(fields.field[i], "categories")) {
+ ast_string_field_set(event, categories, values.value[j]);
+ } else if (!strcasecmp(fields.field[i], "priority")) {
+ event->priority = atoi(values.value[j]);
} else if (!strcasecmp(fields.field[i], "uid")) {
ast_string_field_set(event, uid, values.value[j]);
} else if (!strcasecmp(fields.field[i], "start")) {
@@ -1468,6 +1484,8 @@ static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, FORMAT2, "Description", event->description);
ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
ast_cli(a->fd, FORMAT2, "Location", event->location);
+ ast_cli(a->fd, FORMAT2, "Cartegories", event->categories);
+ ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
ast_cli(a->fd, FORMAT2, "UID", event->uid);
ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
@@ -1539,6 +1557,10 @@ static int calendar_event_read(struct ast_channel *chan, const char *cmd, char *
ast_copy_string(buf, event->organizer, len);
} else if (!strcasecmp(data, "location")) {
ast_copy_string(buf, event->location, len);
+ } else if (!strcasecmp(data, "categories")) {
+ ast_copy_string(buf, event->categories, len);
+ } else if (!strcasecmp(data, "priority")) {
+ snprintf(buf, len, "%d", event->priority);
} else if (!strcasecmp(data, "calendar")) {
ast_copy_string(buf, event->owner->name, len);
} else if (!strcasecmp(data, "uid")) {
diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c
index 664f25b87..e0d8c483e 100644
--- a/res/res_calendar_caldav.c
+++ b/res/res_calendar_caldav.c
@@ -216,6 +216,12 @@ static int caldav_write_event(struct ast_calendar_event *event)
if (!ast_strlen_zero(event->location)) {
icalcomponent_add_property(icalevent, icalproperty_new_location(event->location));
}
+ if (!ast_strlen_zero(event->categories)) {
+ icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories));
+ }
+ if (event->priority > 0) {
+ icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority));
+ }
switch (event->busy_state) {
case AST_CALENDAR_BS_BUSY:
@@ -365,6 +371,14 @@ static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, vo
ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
}
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
+ ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
+ }
+
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
+ event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
+ }
+
if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
} else {
diff --git a/res/res_calendar_ews.c b/res/res_calendar_ews.c
index 931e36854..840ca104e 100644
--- a/res/res_calendar_ews.c
+++ b/res/res_calendar_ews.c
@@ -87,6 +87,9 @@ enum {
XML_EVENT_ATTENDEE,
XML_EVENT_MAILBOX,
XML_EVENT_EMAIL_ADDRESS,
+ XML_EVENT_CATEGORIES,
+ XML_EVENT_CATEGORY,
+ XML_EVENT_IMPORTANCE,
};
struct ewscal_pvt {
@@ -271,6 +274,23 @@ static int startelm(void *userdata, int parent, const char *nspace, const char *
}
ast_str_reset(ctx->cdata);
return XML_EVENT_LOCATION;
+ } else if (!strcmp(name, "Categories")) {
+ /* Event categories */
+ if (!ctx->cdata) {
+ return NE_XML_ABORT;
+ }
+ ast_str_reset(ctx->cdata);
+ return XML_EVENT_CATEGORIES;
+ } else if (parent == XML_EVENT_CATEGORIES && !strcmp(name, "String")) {
+ /* Event category */
+ return XML_EVENT_CATEGORY;
+ } else if (!strcmp(name, "Importance")) {
+ /* Event importance (priority) */
+ if (!ctx->cdata) {
+ return NE_XML_ABORT;
+ }
+ ast_str_reset(ctx->cdata);
+ return XML_EVENT_IMPORTANCE;
} else if (!strcmp(name, "RequiredAttendees") || !strcmp(name, "OptionalAttendees")) {
return XML_EVENT_ATTENDEE_LIST;
} else if (!strcmp(name, "Attendee") && parent == XML_EVENT_ATTENDEE_LIST) {
@@ -331,6 +351,13 @@ static int cdata(void *userdata, int state, const char *cdata, size_t len)
ctx->event->busy_state = AST_CALENDAR_BS_FREE;
}
break;
+ case XML_EVENT_CATEGORY:
+ if (ast_str_strlen(ctx->cdata) == 0) {
+ ast_str_set(&ctx->cdata, 0, "%s", data);
+ } else {
+ ast_str_append(&ctx->cdata, 0, ",%s", data);
+ }
+ break;
default:
ast_str_append(&ctx->cdata, 0, "%s", data);
}
@@ -364,6 +391,22 @@ static int endelm(void *userdata, int state, const char *nspace, const char *nam
ast_string_field_set(ctx->event, location, ast_str_buffer(ctx->cdata));
ast_debug(3, "EWS: XML: Location: %s\n", ctx->event->location);
ast_str_reset(ctx->cdata);
+ } else if (!strcmp(name, "Categories")) {
+ /* Event categories end */
+ ast_string_field_set(ctx->event, categories, ast_str_buffer(ctx->cdata));
+ ast_debug(3, "EWS: XML: Categories: %s\n", ctx->event->categories);
+ ast_str_reset(ctx->cdata);
+ } else if (!strcmp(name, "Importance")) {
+ /* Event importance end */
+ if (!strcmp(ast_str_buffer(ctx->cdata), "Low")) {
+ ctx->event->priority = 9;
+ } else if (!strcmp(ast_str_buffer(ctx->cdata), "Normal")) {
+ ctx->event->priority = 5;
+ } else if (!strcmp(ast_str_buffer(ctx->cdata), "High")) {
+ ctx->event->priority = 1;
+ }
+ ast_debug(3, "EWS: XML: Importance: %s (%d)\n", ast_str_buffer(ctx->cdata), ctx->event->priority);
+ ast_str_reset(ctx->cdata);
} else if (state == XML_EVENT_EMAIL_ADDRESS) {
struct ast_calendar_attendee *attendee;
@@ -501,6 +544,7 @@ static int ewscal_write_event(struct ast_calendar_event *event)
.pvt = pvt,
};
int ret;
+ char *category, *categories;
if (!pvt) {
return -1;
@@ -531,12 +575,7 @@ static int ewscal_write_event(struct ast_calendar_event *event)
"<End>%s</End>"
"<IsAllDayEvent>false</IsAllDayEvent>"
"<LegacyFreeBusyStatus>%s</LegacyFreeBusyStatus>"
- "<Location>%s</Location>"
- "</t:CalendarItem>"
- "</Items>"
- "</CreateItem>"
- "</soap:Body>"
- "</soap:Envelope>",
+ "<Location>%s</Location>",
event->summary,
event->description,
mstime(event->start, start, sizeof(start)),
@@ -544,6 +583,37 @@ static int ewscal_write_event(struct ast_calendar_event *event)
msstatus(event->busy_state),
event->location
);
+ /* Event priority */
+ switch (event->priority) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ ast_str_append(&request, 0, "<Importance>High</Importance>");
+ break;
+ case 5:
+ ast_str_append(&request, 0, "<Importance>Normal</Importance>");
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ ast_str_append(&request, 0, "<Importance>Low</Importance>");
+ break;
+ }
+ /* Event categories*/
+ if (strlen(event->categories) > 0) {
+ ast_str_append(&request, 0, "<Categories>");
+ categories = ast_strdupa(event->categories); /* Duplicate string, since strsep() is destructive */
+ category = strsep(&categories, ",");
+ while (category != NULL) {
+ ast_str_append(&request, 0, "<String>%s</String>", category);
+ category = strsep(&categories, ",");
+ }
+ ast_str_append(&request, 0, "</Categories>");
+ }
+ /* Finish request */
+ ast_str_append(&request, 0, "</t:CalendarItem></Items></CreateItem></soap:Body></soap:Envelope>");
ret = send_ews_request_and_parse(request, &ctx);
diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c
index 2eda35245..300da2ac9 100644
--- a/res/res_calendar_icalendar.c
+++ b/res/res_calendar_icalendar.c
@@ -224,6 +224,14 @@ static void icalendar_add_event(icalcomponent *comp, struct icaltime_span *span,
ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
}
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
+ ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
+ }
+
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
+ event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
+ }
+
if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
} else {
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index 15534c7fa..64628c286 100644
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -62,7 +62,7 @@ static void decode_chunk(char *chunk)
{
for (; *chunk; chunk++) {
if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
- sscanf(chunk + 1, "%02hhd", chunk);
+ sscanf(chunk + 1, "%02hhX", chunk);
memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
}
}
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index e356e8f83..b4398e8c9 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -1179,12 +1179,16 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap
size, column->type);
res = -1;
}
- } else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
- ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
- res = -1;
- } else if (strncmp(column->type, "timestamp", 9) == 0 && type != RQ_DATETIME) {
- ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
- res = -1;
+ } else if (strncmp(column->type, "float", 5) == 0) {
+ if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
+ ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
+ res = -1;
+ }
+ } else if (strncmp(column->type, "timestamp", 9) == 0) {
+ if (type != RQ_DATETIME && type != RQ_DATE) {
+ ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
+ res = -1;
+ }
} else { /* There are other types that no module implements yet */
ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
res = -1;
diff --git a/res/res_fax.c b/res/res_fax.c
index 03fd128a7..3da2d02f8 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -387,9 +387,6 @@ static struct ast_fax_session_details *session_details_new(void)
d->modems = general_options.modems;
d->minrate = general_options.minrate;
d->maxrate = general_options.maxrate;
- ast_string_field_set(d, result, "FAILED");
- ast_string_field_set(d, resultstr, "error starting fax session");
- ast_string_field_set(d, error, "INIT_ERROR");
return d;
}
@@ -500,6 +497,45 @@ static int ast_fax_modem_to_str(enum ast_fax_modems bits, char *tbuf, size_t buf
return 0;
}
+static int check_modem_rate(enum ast_fax_modems modems, unsigned int rate)
+{
+ switch (rate) {
+ case 2400:
+ if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 4800:
+ if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 7200:
+ case 9600:
+ if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 12000:
+ case 14400:
+ if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 28800:
+ case 33600:
+ if (!(modems & AST_FAX_MODEM_V34)) {
+ return 1;
+ }
+ break;
+ default:
+ /* this should never happen */
+ return 1;
+ }
+
+ return 0;
+}
+
/*! \brief register a FAX technology module */
int ast_fax_tech_register(struct ast_fax_tech *tech)
{
@@ -1363,7 +1399,7 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
/*! \brief initiate a receive FAX session */
static int receivefax_exec(struct ast_channel *chan, const char *data)
{
- char *parse;
+ char *parse, modems[128] = "";
int channel_alive;
struct ast_fax_session_details *details;
struct ast_fax_document *doc;
@@ -1390,8 +1426,40 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
return -1;
}
+ ast_string_field_set(details, result, "FAILED");
+ ast_string_field_set(details, resultstr, "error starting fax session");
+ ast_string_field_set(details, error, "INIT_ERROR");
set_channel_variables(chan, details);
+ if (details->maxrate < details->minrate) {
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "maxrate is less than minrate");
+ set_channel_variables(chan, details);
+ ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->minrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->maxrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
if (ast_strlen_zero(data)) {
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "invalid arguments");
@@ -1768,7 +1836,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
/*! \brief initiate a send FAX session */
static int sendfax_exec(struct ast_channel *chan, const char *data)
{
- char *parse, *filenames, *c;
+ char *parse, *filenames, *c, modems[128] = "";
int channel_alive, file_count;
struct ast_fax_session_details *details;
struct ast_fax_document *doc;
@@ -1795,8 +1863,40 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
return -1;
}
+ ast_string_field_set(details, result, "FAILED");
+ ast_string_field_set(details, resultstr, "error starting fax session");
+ ast_string_field_set(details, error, "INIT_ERROR");
set_channel_variables(chan, details);
+ if (details->maxrate < details->minrate) {
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "maxrate is less than minrate");
+ set_channel_variables(chan, details);
+ ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->minrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->maxrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
if (ast_strlen_zero(data)) {
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "invalid arguments");
@@ -2292,6 +2392,7 @@ static int set_config(const char *config_file)
struct ast_config *cfg;
struct ast_variable *v;
struct ast_flags config_flags = { 0 };
+ char modems[128] = "";
/* set defaults */
general_options.minrate = RES_FAX_MINRATE;
@@ -2342,6 +2443,23 @@ static int set_config(const char *config_file)
ast_config_destroy(cfg);
+ if (general_options.maxrate < general_options.minrate) {
+ ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", general_options.maxrate, general_options.minrate);
+ return -1;
+ }
+
+ if (check_modem_rate(general_options.modems, general_options.minrate)) {
+ ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, general_options.minrate);
+ return -1;
+ }
+
+ if (check_modem_rate(general_options.modems, general_options.maxrate)) {
+ ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, general_options.maxrate);
+ return -1;
+ }
+
return 0;
}
diff --git a/res/res_jabber.c b/res/res_jabber.c
index 5238441f1..13c7bf2cd 100644
--- a/res/res_jabber.c
+++ b/res/res_jabber.c
@@ -1283,38 +1283,27 @@ static int aji_tls_handshake(struct aji_client *client)
*/
static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
{
- int sock;
- fd_set fds;
- struct timeval tv, *tvptr = NULL;
+ struct pollfd pfd = { .events = POLLIN };
int len, res;
#ifdef HAVE_OPENSSL
if (aji_is_secure(client)) {
- sock = SSL_get_fd(client->ssl_session);
- if (sock < 0) {
+ pfd.fd = SSL_get_fd(client->ssl_session);
+ if (pfd.fd < 0) {
return -1;
}
} else
#endif /* HAVE_OPENSSL */
- sock = iks_fd(client->p);
-
- memset(&tv, 0, sizeof(struct timeval));
- FD_ZERO(&fds);
- FD_SET(sock, &fds);
- tv.tv_sec = timeout;
-
- /* NULL value for tvptr makes ast_select wait indefinitely */
- tvptr = (timeout != -1) ? &tv : NULL;
+ pfd.fd = iks_fd(client->p);
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
+ res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
if (res > 0) {
#ifdef HAVE_OPENSSL
if (aji_is_secure(client)) {
len = SSL_read(client->ssl_session, buffer, buf_len);
} else
#endif /* HAVE_OPENSSL */
- len = recv(sock, buffer, buf_len, 0);
+ len = recv(pfd.fd, buffer, buf_len, 0);
if (len > 0) {
return len;
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 2361b2280..6024e9da8 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -41,16 +41,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <netinet/in.h>
#include <sys/stat.h>
#include <dirent.h>
-#include <sys/ioctl.h>
#ifdef SOLARIS
#include <thread.h>
#endif
-#ifdef HAVE_DAHDI
-#include <dahdi/user.h>
-#endif
-
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
@@ -68,6 +63,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/manager.h"
#include "asterisk/paths.h"
#include "asterisk/astobj2.h"
+#include "asterisk/timing.h"
+#include "asterisk/time.h"
+#include "asterisk/poll-compat.h"
#define INITIAL_NUM_FILES 8
#define HANDLE_REF 1
@@ -198,10 +196,10 @@ struct mohclass {
pthread_t thread;
/*! Source of audio */
int srcfd;
- /*! FD for timing source */
- int pseudofd;
+ /*! Generic timer */
+ struct ast_timer *timer;
/*! Created on the fly, from RT engine */
- int realtime;
+ unsigned int realtime:1;
unsigned int delete:1;
AST_LIST_HEAD_NOLOCK(, mohdata) members;
AST_LIST_ENTRY(mohclass) list;
@@ -320,10 +318,17 @@ static int ast_moh_files_next(struct ast_channel *chan)
state->samples = 0;
}
- if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
+ for (tries = 0; tries < state->class->total_files; ++tries) {
+ if (ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
+ break;
+ }
+
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
state->pos++;
state->pos %= state->class->total_files;
+ }
+
+ if (tries == state->class->total_files) {
return -1;
}
@@ -607,9 +612,8 @@ static void *monmp3thread(void *data)
struct mohclass *class = data;
struct mohdata *moh;
- char buf[8192];
short sbuf[8192];
- int res, res2;
+ int res = 0, res2;
int len;
struct timeval deadline, tv_tmp;
@@ -626,12 +630,22 @@ static void *monmp3thread(void *data)
pthread_testcancel();
}
}
- if (class->pseudofd > -1) {
+ if (class->timer) {
+ struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN, };
+ struct timeval tv;
+
#ifdef SOLARIS
thr_yield();
#endif
/* Pause some amount of time */
- res = read(class->pseudofd, buf, sizeof(buf));
+ tv = ast_tvnow();
+ if (ast_poll(&pfd, 1, -1) > 0) {
+ ast_timer_ack(class->timer, 1);
+ res = 320;
+ } else {
+ ast_log(LOG_ERROR, "poll() failed: %s\n", strerror(errno));
+ res = 0;
+ }
pthread_testcancel();
} else {
long delta;
@@ -1107,6 +1121,19 @@ static int init_files_class(struct mohclass *class)
return 0;
}
+static void moh_rescan_files(void) {
+ struct ao2_iterator i;
+ struct mohclass *c;
+
+ i = ao2_iterator_init(mohclasses, 0);
+
+ while ((c = ao2_iterator_next(&i))) {
+ moh_scan_files(c);
+ ao2_ref(c, -1);
+ }
+
+ ao2_iterator_destroy(&i);
+}
static int moh_diff(struct mohclass *old, struct mohclass *new)
{
@@ -1129,10 +1156,6 @@ static int moh_diff(struct mohclass *old, struct mohclass *new)
static int init_app_class(struct mohclass *class)
{
-#ifdef HAVE_DAHDI
- int x;
-#endif
-
if (!strcasecmp(class->mode, "custom")) {
ast_set_flag(class, MOH_CUSTOM);
} else if (!strcasecmp(class->mode, "mp3nb")) {
@@ -1142,27 +1165,23 @@ static int init_app_class(struct mohclass *class)
} else if (!strcasecmp(class->mode, "quietmp3")) {
ast_set_flag(class, MOH_QUIET);
}
-
+
class->srcfd = -1;
- class->pseudofd = -1;
-
-#ifdef HAVE_DAHDI
- /* Open /dev/zap/pseudo for timing... Is
- there a better, yet reliable way to do this? */
- class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
- if (class->pseudofd < 0) {
- ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n");
- } else {
- x = 320;
- ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
+
+ if (!(class->timer = ast_timer_open())) {
+ ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
+ }
+ if (class->timer && ast_timer_set_rate(class->timer, 25)) {
+ ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
+ ast_timer_close(class->timer);
+ class->timer = NULL;
}
-#endif
if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
ast_log(LOG_WARNING, "Unable to create moh thread...\n");
- if (class->pseudofd > -1) {
- close(class->pseudofd);
- class->pseudofd = -1;
+ if (class->timer) {
+ ast_timer_close(class->timer);
+ class->timer = NULL;
}
return -1;
}
@@ -1192,7 +1211,7 @@ static int _moh_register(struct mohclass *moh, int reload, int unref, const char
time(&moh->start);
moh->start -= respawn_time;
-
+
if (!strcasecmp(moh->mode, "files")) {
if (init_files_class(moh)) {
if (unref) {
@@ -1222,7 +1241,7 @@ static int _moh_register(struct mohclass *moh, int reload, int unref, const char
if (unref) {
moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
}
-
+
return 0;
}
@@ -1390,7 +1409,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
time(&mohclass->start);
mohclass->start -= respawn_time;
-
+
if (!strcasecmp(mohclass->mode, "files")) {
if (!moh_scan_files(mohclass)) {
mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
@@ -1408,21 +1427,17 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
else if (!strcasecmp(mohclass->mode, "quietmp3"))
ast_set_flag(mohclass, MOH_QUIET);
-
+
mohclass->srcfd = -1;
-#ifdef HAVE_DAHDI
- /* Open /dev/dahdi/pseudo for timing... Is
- there a better, yet reliable way to do this? */
- mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
- if (mohclass->pseudofd < 0) {
- ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n");
- } else {
- int x = 320;
- ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
+ if (!(mohclass->timer = ast_timer_open())) {
+ ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
}
-#else
- mohclass->pseudofd = -1;
-#endif
+ if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
+ ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
+ ast_timer_close(mohclass->timer);
+ mohclass->timer = NULL;
+ }
+
/* Let's check if this channel already had a moh class before */
if (state && state->class) {
/* Class already exist for this channel */
@@ -1435,9 +1450,9 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
} else {
if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
ast_log(LOG_WARNING, "Unable to create moh...\n");
- if (mohclass->pseudofd > -1) {
- close(mohclass->pseudofd);
- mohclass->pseudofd = -1;
+ if (mohclass->timer) {
+ ast_timer_close(mohclass->timer);
+ mohclass->timer = NULL;
}
mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
return -1;
@@ -1612,13 +1627,16 @@ static int load_moh_classes(int reload)
ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes");
}
+ if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+ moh_rescan_files();
+ }
return 0;
}
if (reload) {
ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
}
-
+
ast_clear_flag(global_flags, AST_FLAGS_ALL);
cat = ast_category_browse(cfg, NULL);
diff --git a/res/res_odbc.c b/res/res_odbc.c
index d2ee97948..6e179efff 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -780,6 +780,7 @@ static int load_odbc_config(void)
pooling = 0;
limit = 0;
bse = 1;
+ conntimeout = 10;
forcecommit = 0;
isolation = SQL_TXN_READ_COMMITTED;
for (v = ast_variable_browse(config, cat); v; v = v->next) {
@@ -1203,7 +1204,7 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
unsigned char state[10], diagnostic[256];
if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
- ast_debug(1, "Class not found!\n");
+ ast_debug(1, "Class '%s' not found!\n", name);
return NULL;
}
diff --git a/res/res_pktccops.c b/res/res_pktccops.c
index 8069e723d..33ecc3817 100644
--- a/res/res_pktccops.c
+++ b/res/res_pktccops.c
@@ -703,9 +703,8 @@ static void *do_pktccops(void *data)
int res, nfds, len;
struct copsmsg *recmsg, *sendmsg;
struct copsmsg recmsgb, sendmsgb;
- fd_set rfds;
- struct timeval tv;
- struct pktcobj *pobject;
+ struct pollfd *pfds = NULL, *tmp;
+ struct pktcobj *pobject;
struct cops_cmts *cmts;
struct cops_gate *gate;
char *sobjp;
@@ -719,9 +718,8 @@ static void *do_pktccops(void *data)
ast_debug(3, "COPS: thread started\n");
for (;;) {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- FD_ZERO(&rfds);
+ ast_free(pfds);
+ pfds = NULL;
nfds = 0;
AST_LIST_LOCK(&cmts_list);
AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
@@ -735,15 +733,27 @@ static void *do_pktccops(void *data)
}
}
if (cmts->sfd > 0) {
- FD_SET(cmts->sfd, &rfds);
- if (cmts->sfd > nfds) nfds = cmts->sfd;
+ if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
+ continue;
+ }
+ pfds = tmp;
+ pfds[nfds].fd = cmts->sfd;
+ pfds[nfds].events = POLLIN;
+ pfds[nfds].revents = 0;
+ nfds++;
} else {
cmts->sfd = cops_connect(cmts->host, cmts->port);
if (cmts->sfd > 0) {
cmts->state = 1;
if (cmts->sfd > 0) {
- FD_SET(cmts->sfd, &rfds);
- if (cmts->sfd > nfds) nfds = cmts->sfd;
+ if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
+ continue;
+ }
+ pfds = tmp;
+ pfds[nfds].fd = cmts->sfd;
+ pfds[nfds].events = POLLIN;
+ pfds[nfds].revents = 0;
+ nfds++;
}
}
}
@@ -781,10 +791,11 @@ static void *do_pktccops(void *data)
if (pktcreload == 2) {
pktcreload = 0;
}
- if ((res = select(nfds + 1, &rfds, NULL, NULL, &tv))) {
+ if ((res = ast_poll(pfds, nfds, 1000))) {
AST_LIST_LOCK(&cmts_list);
AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
- if (FD_ISSET(cmts->sfd, &rfds)) {
+ int idx;
+ if ((idx = ast_poll_fd_index(pfds, nfds, cmts->sfd)) > -1 && (pfds[idx].revents & POLLIN)) {
len = cops_getmsg(cmts->sfd, recmsg);
if (len > 0) {
ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%.2x opcode=%i clienttype=0x%.4x msglength=%i\n",
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 396aed533..6ddd33902 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -270,6 +270,7 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in
static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1);
static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username);
static void ast_rtp_stop(struct ast_rtp_instance *instance);
+static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, const char* desc);
/* RTP Engine Declaration */
static struct ast_rtp_engine asterisk_rtp_engine = {
@@ -293,6 +294,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
.dtmf_compatible = ast_rtp_dtmf_compatible,
.stun_request = ast_rtp_stun_request,
.stop = ast_rtp_stop,
+ .qos = ast_rtp_qos_set,
};
static inline int rtp_debug_test_addr(struct ast_sockaddr *addr)
@@ -715,12 +717,24 @@ static void ast_rtp_update_source(struct ast_rtp_instance *instance)
static void ast_rtp_change_source(struct ast_rtp_instance *instance)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+ struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
unsigned int ssrc = ast_random();
+ if (!rtp->lastts) {
+ ast_debug(3, "Not changing SSRC since we haven't sent any RTP yet\n");
+ return;
+ }
+
/* We simply set this bit so that the next packet sent will have the marker bit turned on */
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
+
+ if (srtp) {
+ ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc);
+ res_srtp->change_source(srtp, rtp->ssrc, ssrc);
+ }
+
rtp->ssrc = ssrc;
return;
@@ -2549,6 +2563,13 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance)
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
}
+static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
+{
+ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+
+ return ast_set_qos(rtp->s, tos, cos, desc);
+}
+
static char *rtp_do_debug_ip(struct ast_cli_args *a)
{
char *arg = ast_strdupa(a->argv[4]);
diff --git a/res/res_srtp.c b/res/res_srtp.c
index 546f0733d..f92154f90 100644
--- a/res/res_srtp.c
+++ b/res/res_srtp.c
@@ -53,14 +53,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/rtp_engine.h"
+#include "asterisk/astobj2.h"
struct ast_srtp {
struct ast_rtp_instance *rtp;
+ struct ao2_container *policies;
srtp_t session;
const struct ast_srtp_cb *cb;
void *data;
unsigned char buf[8192 + AST_FRIENDLY_OFFSET];
- unsigned int has_stream:1;
};
struct ast_srtp_policy {
@@ -73,6 +74,7 @@ static int g_initialized = 0;
static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy);
static void ast_srtp_destroy(struct ast_srtp *srtp);
static int ast_srtp_add_stream(struct ast_srtp *srtp, struct ast_srtp_policy *policy);
+static int ast_srtp_change_source(struct ast_srtp *srtp, unsigned int from_ssrc, unsigned int to_ssrc);
static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rtcp);
static int ast_srtp_protect(struct ast_srtp *srtp, void **buf, int *len, int rtcp);
@@ -90,6 +92,7 @@ static struct ast_srtp_res srtp_res = {
.create = ast_srtp_create,
.destroy = ast_srtp_destroy,
.add_stream = ast_srtp_add_stream,
+ .change_source = ast_srtp_change_source,
.set_cb = ast_srtp_set_cb,
.unprotect = ast_srtp_unprotect,
.protect = ast_srtp_protect,
@@ -144,6 +147,32 @@ static const char *srtp_errstr(int err)
}
}
+static int policy_hash_fn(const void *obj, const int flags)
+{
+ const struct ast_srtp_policy *policy = obj;
+
+ return policy->sp.ssrc.type == ssrc_specific ? policy->sp.ssrc.value : policy->sp.ssrc.type;
+}
+
+static int policy_cmp_fn(void *obj, void *arg, int flags)
+{
+ const struct ast_srtp_policy *one = obj, *two = arg;
+
+ return one->sp.ssrc.type == two->sp.ssrc.type && one->sp.ssrc.value == two->sp.ssrc.value;
+}
+
+static struct ast_srtp_policy *find_policy(struct ast_srtp *srtp, const srtp_policy_t *policy, int flags)
+{
+ struct ast_srtp_policy tmp = {
+ .sp = {
+ .ssrc.type = policy->ssrc.type,
+ .ssrc.value = policy->ssrc.value,
+ },
+ };
+
+ return ao2_t_find(srtp->policies, &tmp, flags, "Looking for policy");
+}
+
static struct ast_srtp *res_srtp_new(void)
{
struct ast_srtp *srtp;
@@ -153,6 +182,11 @@ static struct ast_srtp *res_srtp_new(void)
return NULL;
}
+ if (!(srtp->policies = ao2_t_container_alloc(5, policy_hash_fn, policy_cmp_fn, "SRTP policy container"))) {
+ ast_free(srtp);
+ return NULL;
+ }
+
return srtp;
}
@@ -188,11 +222,21 @@ static void ast_srtp_policy_set_ssrc(struct ast_srtp_policy *policy,
}
}
+static void policy_destructor(void *obj)
+{
+ struct ast_srtp_policy *policy = obj;
+
+ if (policy->sp.key) {
+ ast_free(policy->sp.key);
+ policy->sp.key = NULL;
+ }
+}
+
static struct ast_srtp_policy *ast_srtp_policy_alloc()
{
struct ast_srtp_policy *tmp;
- if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
+ if (!(tmp = ao2_t_alloc(sizeof(*tmp), policy_destructor, "Allocating policy"))) {
ast_log(LOG_ERROR, "Unable to allocate memory for srtp_policy\n");
}
@@ -201,11 +245,7 @@ static struct ast_srtp_policy *ast_srtp_policy_alloc()
static void ast_srtp_policy_destroy(struct ast_srtp_policy *policy)
{
- if (policy->sp.key) {
- ast_free(policy->sp.key);
- policy->sp.key = NULL;
- }
- ast_free(policy);
+ ao2_t_ref(policy, -1, "Destroying policy");
}
static int policy_set_suite(crypto_policy_t *p, enum ast_srtp_suite suite)
@@ -344,6 +384,8 @@ static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp,
temp->rtp = rtp;
*srtp = temp;
+ ao2_t_link((*srtp)->policies, policy, "Created initial policy");
+
return 0;
}
@@ -353,16 +395,52 @@ static void ast_srtp_destroy(struct ast_srtp *srtp)
srtp_dealloc(srtp->session);
}
+ ao2_t_callback(srtp->policies, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Unallocate policy");
+ ao2_t_ref(srtp->policies, -1, "Destroying container");
+
ast_free(srtp);
}
static int ast_srtp_add_stream(struct ast_srtp *srtp, struct ast_srtp_policy *policy)
{
- if (!srtp->has_stream && srtp_add_stream(srtp->session, &policy->sp) != err_status_ok) {
+ struct ast_srtp_policy *match;
+
+ if ((match = find_policy(srtp, &policy->sp, OBJ_POINTER))) {
+ ast_debug(3, "Policy already exists, not re-adding\n");
+ ao2_t_ref(match, -1, "Unreffing already existing policy");
return -1;
}
- srtp->has_stream = 1;
+ if (srtp_add_stream(srtp->session, &policy->sp) != err_status_ok) {
+ return -1;
+ }
+
+ ao2_t_link(srtp->policies, policy, "Added additional stream");
+
+ return 0;
+}
+
+static int ast_srtp_change_source(struct ast_srtp *srtp, unsigned int from_ssrc, unsigned int to_ssrc)
+{
+ struct ast_srtp_policy *match;
+ struct srtp_policy_t sp = {
+ .ssrc.type = ssrc_specific,
+ .ssrc.value = from_ssrc,
+ };
+ err_status_t status;
+
+ /* If we find a mach, return and unlink it from the container so we
+ * can change the SSRC (which is part of the hash) and then have
+ * ast_srtp_add_stream link it back in if all is well */
+ if ((match = find_policy(srtp, &sp, OBJ_POINTER | OBJ_UNLINK))) {
+ match->sp.ssrc.value = to_ssrc;
+ if (ast_srtp_add_stream(srtp, match)) {
+ ast_log(LOG_WARNING, "Couldn't add stream\n");
+ } else if ((status = srtp_remove_stream(srtp->session, from_ssrc))) {
+ ast_debug(3, "Couldn't remove stream (%d)\n", status);
+ }
+ ao2_t_ref(match, -1, "Unreffing found policy in change_source");
+ }
return 0;
}
diff --git a/res/res_stun_monitor.c b/res/res_stun_monitor.c
new file mode 100644
index 000000000..54be1e44c
--- /dev/null
+++ b/res/res_stun_monitor.c
@@ -0,0 +1,311 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.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.
+ */
+
+/*!
+ * \file
+ * \brief STUN Network Monitor
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/event.h"
+#include "asterisk/sched.h"
+#include "asterisk/config.h"
+#include "asterisk/stun.h"
+#include "asterisk/netsock2.h"
+#include "asterisk/lock.h"
+#include <fcntl.h>
+
+static const int STANDARD_STUN_PORT = 3478;
+static const int DEFAULT_MONITOR_REFRESH = 30;
+
+static const char stun_conf_file[] = "res_stun_monitor.conf";
+static struct ast_sched_thread *sched;
+
+static struct {
+ struct sockaddr_in stunaddr; /*!< The stun address we send requests to*/
+ struct sockaddr_in externaladdr; /*!< current perceived external address. */
+ ast_mutex_t lock;
+ unsigned int refresh;
+ int stunsock;
+ unsigned int monitor_enabled:1;
+ unsigned int externaladdr_known:1;
+} args;
+
+static inline void stun_close_sock(void)
+{
+ if (args.stunsock != -1) {
+ close(args.stunsock);
+ args.stunsock = -1;
+ memset(&args.externaladdr, 0, sizeof(args.externaladdr));
+ args.externaladdr_known = 0;
+ }
+}
+
+/* \brief purge the stun socket's receive buffer before issuing a new request
+ *
+ * XXX Note that this is somewhat of a hack. This function is essentially doing
+ * a cleanup on the socket rec buffer to handle removing any STUN responses we have not
+ * handled. This is called before sending out a new STUN request so we don't read
+ * a latent previous response thinking it is new.
+ */
+static void stun_purge_socket(void)
+{
+ int flags = fcntl(args.stunsock, F_GETFL);
+ int res = 0;
+ unsigned char reply_buf[1024];
+
+ fcntl(args.stunsock, F_SETFL, flags | O_NONBLOCK);
+ while (res != -1) {
+ /* throw away everything in the buffer until we reach the end. */
+ res = recv(args.stunsock, reply_buf, sizeof(reply_buf), 0);
+ }
+ fcntl(args.stunsock, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+/* \brief called by scheduler to send STUN request */
+static int stun_monitor_request(const void *blarg)
+{
+ int res;
+ int generate_event = 0;
+ struct sockaddr_in answer = { 0, };
+
+
+ /* once the stun socket goes away, this scheduler item will go away as well */
+ ast_mutex_lock(&args.lock);
+ if (args.stunsock == -1) {
+ ast_log(LOG_ERROR, "STUN monitor: can not send STUN request, socket is not open\n");
+ goto monitor_request_cleanup;
+ }
+
+ stun_purge_socket();
+
+ if (!(ast_stun_request(args.stunsock, &args.stunaddr, NULL, &answer)) &&
+ (memcmp(&args.externaladdr, &answer, sizeof(args.externaladdr)))) {
+ const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
+ int newport = ntohs(answer.sin_port);
+
+ ast_log(LOG_NOTICE, "STUN MONITOR: Old external address/port %s:%d now seen as %s:%d \n",
+ ast_inet_ntoa(args.externaladdr.sin_addr), ntohs(args.externaladdr.sin_port),
+ newaddr, newport);
+
+ memcpy(&args.externaladdr, &answer, sizeof(args.externaladdr));
+
+ if (args.externaladdr_known) {
+ /* the external address was already known, and has changed... generate event. */
+ generate_event = 1;
+
+ } else {
+ /* this was the first external address we found, do not alert listeners
+ * until this address changes to something else. */
+ args.externaladdr_known = 1;
+ }
+ }
+
+ if (generate_event) {
+ struct ast_event *event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
+ if (!event) {
+ ast_log(LOG_ERROR, "STUN monitor: could not create AST_EVENT_NETWORK_CHANGE event.\n");
+ goto monitor_request_cleanup;
+ }
+ if (ast_event_queue(event)) {
+ ast_event_destroy(event);
+ event = NULL;
+ ast_log(LOG_ERROR, "STUN monitor: could not queue AST_EVENT_NETWORK_CHANGE event.\n");
+ goto monitor_request_cleanup;
+ }
+ }
+
+monitor_request_cleanup:
+ /* always refresh this scheduler item. It will be removed elsewhere when
+ * it is supposed to go away */
+ res = args.refresh * 1000;
+ ast_mutex_unlock(&args.lock);
+
+ return res;
+}
+
+/* \brief stops the stun monitor thread
+ * \note do not hold the args->lock while calling this
+ */
+static void stun_stop_monitor(void)
+{
+ if (sched) {
+ sched = ast_sched_thread_destroy(sched);
+ ast_log(LOG_NOTICE, "STUN monitor stopped\n");
+ }
+ /* it is only safe to destroy the socket without holding arg->lock
+ * after the sched thread is destroyed */
+ stun_close_sock();
+}
+
+/* \brief starts the stun monitor thread
+ * \note The args->lock MUST be held when calling this function
+ */
+static int stun_start_monitor(void)
+{
+ struct ast_sockaddr dst;
+ /* clean up any previous open socket */
+ stun_close_sock();
+
+ /* create destination ast_sockaddr */
+ ast_sockaddr_from_sin(&dst, &args.stunaddr);
+
+ /* open new socket binding */
+ args.stunsock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (args.stunsock < 0) {
+ ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (ast_connect(args.stunsock, &dst) != 0) {
+ ast_log(LOG_WARNING, "SIP STUN Failed to connect to %s\n", ast_sockaddr_stringify(&dst));
+ stun_close_sock();
+ return -1;
+ }
+
+ /* if scheduler thread is not started, make sure to start it now */
+ if (sched) {
+ return 0; /* already started */
+ }
+
+ if (!(sched = ast_sched_thread_create())) {
+ ast_log(LOG_ERROR, "Failed to create stun monitor scheduler thread\n");
+ stun_close_sock();
+ return -1;
+ }
+
+ if (ast_sched_thread_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
+ ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
+ sched = ast_sched_thread_destroy(sched);
+ stun_close_sock();
+ return -1;
+ }
+
+ ast_log(LOG_NOTICE, "STUN monitor started\n");
+ return 0;
+}
+
+static int load_config(int startup)
+{
+ struct ast_flags config_flags = { 0, };
+ struct ast_config *cfg;
+ struct ast_variable *v;
+
+ if (!startup) {
+ ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
+ }
+
+ if (!(cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags)) ||
+ cfg == CONFIG_STATUS_FILEINVALID) {
+ ast_log(LOG_ERROR, "Unable to load config %s\n", stun_conf_file);
+ return -1;
+ }
+
+ if (cfg == CONFIG_STATUS_FILEUNCHANGED && !startup) {
+ return 0;
+ }
+
+ /* set defaults */
+ args.monitor_enabled = 0;
+ memset(&args.stunaddr, 0, sizeof(args.stunaddr));
+ args.refresh = DEFAULT_MONITOR_REFRESH;
+
+ for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+ if (!strcasecmp(v->name, "stunaddr")) {
+ args.stunaddr.sin_port = htons(STANDARD_STUN_PORT);
+ if (ast_parse_arg(v->value, PARSE_INADDR, &args.stunaddr)) {
+ ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value);
+ } else {
+ ast_log(LOG_NOTICE, "STUN monitor enabled: %s\n", v->value);
+ args.monitor_enabled = 1;
+ }
+ } else if (!strcasecmp(v->name, "stunrefresh")) {
+ if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
+ ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
+ args.refresh = DEFAULT_MONITOR_REFRESH;
+ } else {
+ ast_log(LOG_NOTICE, "STUN Monitor set to refresh every %d seconds\n", args.refresh);
+ }
+ } else {
+ ast_log(LOG_WARNING, "SIP STUN: invalid config option %s at line %d\n", v->value, v->lineno);
+ }
+ }
+
+ ast_config_destroy(cfg);
+
+ return 0;
+}
+
+static int __reload(int startup)
+{
+ int res;
+
+ ast_mutex_lock(&args.lock);
+ if (!(res = load_config(startup)) && args.monitor_enabled) {
+ res = stun_start_monitor();
+ }
+ ast_mutex_unlock(&args.lock);
+
+ if ((res == -1) || !args.monitor_enabled) {
+ args.monitor_enabled = 0;
+ stun_stop_monitor();
+ }
+
+ return res;
+}
+
+static int reload(void)
+{
+ return __reload(0);
+}
+
+static int unload_module(void)
+{
+ stun_stop_monitor();
+ ast_mutex_destroy(&args.lock);
+ return 0;
+}
+
+static int load_module(void)
+{
+ ast_mutex_init(&args.lock);
+ args.stunsock = -1;
+ memset(&args.externaladdr, 0, sizeof(args.externaladdr));
+ args.externaladdr_known = 0;
+ sched = NULL;
+ if (__reload(1)) {
+ stun_stop_monitor();
+ ast_mutex_destroy(&args.lock);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND
+ );
diff --git a/tests/test_poll.c b/tests/test_poll.c
new file mode 100644
index 000000000..7fbf8cc51
--- /dev/null
+++ b/tests/test_poll.c
@@ -0,0 +1,253 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Tilghman Lesher <tlesher AT digium DOT 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.
+ */
+
+/*!
+ * \file
+ * \brief Poll Tests
+ *
+ * \author\verbatim Tilghman Lesher <tlesher AT digium DOT com> \endverbatim
+ *
+ * Verify that the various poll implementations work as desired (ast_poll, ast_poll2)
+ * \ingroup tests
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ ***/
+
+#include "asterisk.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/poll-compat.h"
+
+#ifndef HAVE_SBIN_LAUNCHD
+static void *failsafe_cancel(void *vparent)
+{
+ pthread_t parent = (pthread_t) (long) vparent;
+
+ sleep(1);
+ pthread_testcancel();
+ pthread_kill(parent, SIGURG);
+ sleep(1);
+ pthread_testcancel();
+ pthread_kill(parent, SIGURG);
+ sleep(1);
+ pthread_testcancel();
+ pthread_kill(parent, SIGURG);
+ pthread_exit(NULL);
+}
+
+#define RESET for (i = 0; i < 4; i++) { pfd[i].revents = 0; }
+AST_TEST_DEFINE(poll_test)
+{
+#define FDNO 3
+ int fd[2], res = AST_TEST_PASS, i, res2;
+ int rdblocker[2];
+#if FDNO > 3
+ int wrblocker[2], consec_interrupt = 0;
+#endif
+ struct pollfd pfd[4] = { { .events = POLLOUT, }, { .events = POLLIN, }, { .events = POLLIN }, { .events = POLLOUT } };
+ pthread_t failsafe_tid;
+ struct timeval tv = { 0, 0 };
+#if FDNO > 3
+ char garbage[256] =
+ "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
+ "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
+ "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
+ "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/";
+#endif
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "poll_test";
+ info->category = "main/poll/";
+ info->summary = "unit test for the ast_poll() API";
+ info->description =
+ "Verifies behavior for the ast_poll() API call\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_test_status_update(test, "Creating handle that should NEVER block on write\n");
+ if ((fd[0] = open("/dev/null", O_WRONLY)) < 0) {
+ ast_test_status_update(test, "Unable to open a writable handle to /dev/null: %s\n", strerror(errno));
+ return AST_TEST_FAIL;
+ }
+
+ ast_test_status_update(test, "Creating handle that should NEVER block on read\n");
+ if ((fd[1] = open("/dev/zero", O_RDONLY)) < 0) {
+ ast_test_status_update(test, "Unable to open a readable handle to /dev/zero: %s\n", strerror(errno));
+ close(fd[0]);
+ return AST_TEST_FAIL;
+ }
+
+ ast_test_status_update(test, "Creating handle that should block on read\n");
+ if (pipe(rdblocker) < 0) {
+ ast_test_status_update(test, "Unable to open a pipe: %s\n", strerror(errno));
+ close(fd[0]);
+ close(fd[1]);
+ return AST_TEST_FAIL;
+ }
+
+#if FDNO > 3
+ ast_test_status_update(test, "Creating handle that should block on write\n");
+ if (pipe(wrblocker) < 0) {
+ ast_test_status_update(test, "Unable to open a pipe: %s\n", strerror(errno));
+ close(fd[0]);
+ close(fd[1]);
+ close(rdblocker[0]);
+ close(rdblocker[1]);
+ return AST_TEST_FAIL;
+ }
+
+ ast_test_status_update(test, "Starting thread to ensure we don't block forever\n");
+ if (ast_pthread_create_background(&failsafe_tid, NULL, failsafe_cancel, (void *) (long) pthread_self())) {
+ ast_test_status_update(test, "Unable to start failsafe thread\n");
+ close(fd[0]);
+ close(fd[1]);
+ close(fd[2]);
+ close(rdblocker[0]);
+ close(rdblocker[1]);
+ close(wrblocker[0]);
+ close(wrblocker[1]);
+ return AST_TEST_FAIL;
+ }
+
+ /* Fill the pipe full of data */
+ ast_test_status_update(test, "Making pipe block on write\n");
+ for (i = 0; i < 4096; i++) { /* 1MB of data should be more than enough for any pipe */
+ errno = 0;
+ if (write(wrblocker[1], garbage, sizeof(garbage)) < sizeof(garbage)) {
+ ast_test_status_update(test, "Got %d\n", errno);
+ if (errno == EINTR && ++consec_interrupt > 1) {
+ break;
+ }
+ } else {
+ consec_interrupt = 0;
+ }
+ }
+
+ ast_test_status_update(test, "Cancelling failsafe thread.\n");
+ pthread_cancel(failsafe_tid);
+ pthread_kill(failsafe_tid, SIGURG);
+ pthread_join(failsafe_tid, NULL);
+#endif
+
+ pfd[0].fd = fd[0];
+ pfd[1].fd = fd[1];
+ pfd[2].fd = rdblocker[0];
+#if FDNO > 3
+ pfd[3].fd = wrblocker[1];
+#endif
+
+ /* Need to ensure the infinite timeout doesn't stall the process */
+ ast_test_status_update(test, "Starting thread to ensure we don't block forever\n");
+ if (ast_pthread_create_background(&failsafe_tid, NULL, failsafe_cancel, (void *) (long) pthread_self())) {
+ ast_test_status_update(test, "Unable to start failsafe thread\n");
+ close(fd[0]);
+ close(fd[1]);
+ close(rdblocker[0]);
+ close(rdblocker[1]);
+#if FDNO > 3
+ close(wrblocker[0]);
+ close(wrblocker[1]);
+#endif
+ return AST_TEST_FAIL;
+ }
+
+ RESET;
+ if ((res2 = ast_poll(pfd, FDNO, -1)) != 2) {
+ ast_test_status_update(test, "ast_poll does not return that only two handles are available (inf timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
+ res = AST_TEST_FAIL;
+ }
+
+ RESET;
+ if ((res2 = ast_poll2(pfd, FDNO, NULL)) != 2) {
+ ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (inf timeout): %d %s\n", res2, res2 == -1 ? strerror(errno) : "");
+ res = AST_TEST_FAIL;
+ }
+
+ ast_test_status_update(test, "Cancelling failsafe thread.\n");
+ pthread_cancel(failsafe_tid);
+ pthread_kill(failsafe_tid, SIGURG);
+ pthread_join(failsafe_tid, NULL);
+
+ RESET;
+ if (ast_poll(pfd, FDNO, 0) != 2) {
+ ast_test_status_update(test, "ast_poll does not return that only two handles are available (0 timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
+ res = AST_TEST_FAIL;
+ }
+
+ RESET;
+ if (ast_poll2(pfd, FDNO, &tv) != 2) {
+ ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (0 timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
+ res = AST_TEST_FAIL;
+ }
+
+ RESET;
+ if (ast_poll(pfd, FDNO, 1) != 2) {
+ ast_test_status_update(test, "ast_poll does not return that only two handles are available (1ms timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
+ res = AST_TEST_FAIL;
+ }
+
+ tv.tv_usec = 1000;
+ if (ast_poll2(pfd, FDNO, &tv) != 2) {
+ ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (1ms timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
+ res = AST_TEST_FAIL;
+ }
+
+ close(fd[0]);
+ close(fd[1]);
+ close(rdblocker[0]);
+ close(rdblocker[1]);
+#if FDNO > 3
+ close(wrblocker[0]);
+ close(wrblocker[1]);
+#endif
+ return res;
+}
+#endif
+
+static int unload_module(void)
+{
+#ifndef HAVE_SBIN_LAUNCHD
+ AST_TEST_UNREGISTER(poll_test);
+#endif
+ return 0;
+}
+
+static int load_module(void)
+{
+#ifndef HAVE_SBIN_LAUNCHD
+ AST_TEST_REGISTER(poll_test);
+#endif
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Poll test");