[asterisk-commits] oej: branch oej/teapot-1.8 r411782 - in /team/oej/teapot-1.8: ./ apps/ channe...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 7 05:07:36 CDT 2014


Author: oej
Date: Mon Apr  7 05:07:25 2014
New Revision: 411782

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=411782
Log:
Reset, resolve and have a nice cup of tea.

Modified:
    team/oej/teapot-1.8/   (props changed)
    team/oej/teapot-1.8/UPGRADE.txt
    team/oej/teapot-1.8/apps/app_queue.c
    team/oej/teapot-1.8/channels/chan_sip.c
    team/oej/teapot-1.8/channels/sip/include/sip.h
    team/oej/teapot-1.8/configs/asterisk.conf.sample
    team/oej/teapot-1.8/configs/res_odbc.conf.sample
    team/oej/teapot-1.8/include/asterisk/options.h
    team/oej/teapot-1.8/include/asterisk/res_odbc.h
    team/oej/teapot-1.8/main/asterisk.c
    team/oej/teapot-1.8/main/channel.c
    team/oej/teapot-1.8/main/http.c
    team/oej/teapot-1.8/main/manager.c
    team/oej/teapot-1.8/main/tcptls.c
    team/oej/teapot-1.8/res/res_config_odbc.c
    team/oej/teapot-1.8/res/res_odbc.c
    team/oej/teapot-1.8/res/res_odbc.exports.in

Propchange: team/oej/teapot-1.8/
------------------------------------------------------------------------------
    automerge = Is-there-life-off-net?

Propchange: team/oej/teapot-1.8/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Apr  7 05:07:25 2014
@@ -1,1 +1,1 @@
-/branches/1.8:1-411359
+/branches/1.8:1-411779

Modified: team/oej/teapot-1.8/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/UPGRADE.txt?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/UPGRADE.txt (original)
+++ team/oej/teapot-1.8/UPGRADE.txt Mon Apr  7 05:07:25 2014
@@ -17,11 +17,32 @@
 === UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
 ===
 ===========================================================
+
+from 1.8.27.0 to 1.8.28.0:
+* The asterisk command line -I option and the asterisk.conf internal_timing
+  option are removed and always enabled if any timing module is loaded.
+
 from 1.8.26.0 to 1.8.27.0:
 * res_fax now returns the correct rates for V.27ter (4800 or 9600 bit/s).
   Because of this the default settings would not load, so the minrate (minimum
   transmission rate) option was changed to default to 4800 since that is the
   minimum rate for v.27 which is included in the default modem options.
+
+* When communicating with a peer on an Asterisk 1.4 or earlier system, the
+  chan_iax2 parameter 'connectedline' must be set to "no" in iax.conf. This
+  prevents an incompatible connected line frame from an Astersik 1.8 or later
+  system from causing a hangup in an Asterisk 1.4 or earlier system. Note that
+  this particular incompatibility has always existed between 1.4 and 1.8 and
+  later versions; this upgrade note is simply informing users of its existance.
+
+* A compatibility setting, allow_empty_string_in_nontext, has been added to
+  res_odbc.conf. When enabled (default behavior), empty column values are
+  stored as empty strings during realtime updates. Disabling this option
+  causes empty column values to be stored as NULLs for non-text columns.
+
+  Disable it for PostgreSQL backends in order to avoid errors caused by
+  updating integer columns with an empty string instead of NULL
+  (sipppeers,sipregs)
 
 from 1.8.23.0 to 1.8.24.0:
 * res_agi will now properly indicate if there was an error in streaming an

Modified: team/oej/teapot-1.8/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/apps/app_queue.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/apps/app_queue.c (original)
+++ team/oej/teapot-1.8/apps/app_queue.c Mon Apr  7 05:07:25 2014
@@ -6952,7 +6952,7 @@
 static int mark_member_dead(void *obj, void *arg, int flags)
 {
 	struct member *member = obj;
-	if (!member->dynamic) {
+	if (!member->dynamic && !member->realtime) {
 		member->delme = 1;
 	}
 	return 0;

Modified: team/oej/teapot-1.8/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/channels/chan_sip.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/channels/chan_sip.c (original)
+++ team/oej/teapot-1.8/channels/chan_sip.c Mon Apr  7 05:07:25 2014
@@ -12029,8 +12029,9 @@
 
 		ast_debug(3, "-- Done with adding codecs to SDP\n");
 
-		if (!p->owner || !ast_internal_timing_enabled(p->owner))
+		if (!p->owner || p->owner->timingfd == -1) {
 			ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
+		}
 
 		if (min_audio_packet_size)
 			ast_str_append(&a_audio, 0, "a=ptime:%d\r\n", min_audio_packet_size);

Modified: team/oej/teapot-1.8/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/channels/sip/include/sip.h?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/channels/sip/include/sip.h (original)
+++ team/oej/teapot-1.8/channels/sip/include/sip.h Mon Apr  7 05:07:25 2014
@@ -157,7 +157,7 @@
  *  \todo This string should be set dynamically. We only support REFER and SUBSCRIBE if we have
  *  allowsubscribe and allowrefer on in sip.conf.
  */
-#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, PRACK"
+#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, PRACK, MESSAGE"
 
 /*! \brief Standard SIP unsecure port for UDP and TCP from RFC 3261. DO NOT CHANGE THIS */
 #define STANDARD_SIP_PORT	5060

Modified: team/oej/teapot-1.8/configs/asterisk.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/configs/asterisk.conf.sample?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/configs/asterisk.conf.sample (original)
+++ team/oej/teapot-1.8/configs/asterisk.conf.sample Mon Apr  7 05:07:25 2014
@@ -27,7 +27,6 @@
 ;dontwarn = yes			; Disable some warnings.
 ;dumpcore = yes			; Dump core on crash (same as -g at startup).
 ;languageprefix = yes		; Use the new sound prefix path syntax.
-;internal_timing = yes
 ;systemname = my_system_name	; Prefix uniqueid with a system name for
 				; Global uniqueness issues.
 ;autosystemname = yes		; Automatically set systemname to hostname,

Modified: team/oej/teapot-1.8/configs/res_odbc.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/configs/res_odbc.conf.sample?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/configs/res_odbc.conf.sample (original)
+++ team/oej/teapot-1.8/configs/res_odbc.conf.sample Mon Apr  7 05:07:25 2014
@@ -64,6 +64,14 @@
 ; MS SQL Server, the answer is no.
 ;backslash_is_escape => yes
 ;
+; When enabled (default behavior), empty column values are stored as empty strings
+; during realtime updates. Disabling this option causes empty column values to be
+; stored as NULLs for non-text columns.
+; Disable it for PostgreSQL backend in order to avoid errors caused by updating
+; integer columns with an empty string instead of NULL (sipppeers,sipregs)
+; NOTE: This option will be removed in asterisk 13. At that point, it will always behave as if it was set to 'no'.
+;allow_empty_string_in_nontext => yes
+;
 ; How long (in seconds) should we attempt to connect before considering the
 ; connection dead?  The default is 10 seconds, but you may wish to reduce it,
 ; to increase responsiveness.

Modified: team/oej/teapot-1.8/include/asterisk/options.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/include/asterisk/options.h?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/include/asterisk/options.h (original)
+++ team/oej/teapot-1.8/include/asterisk/options.h Mon Apr  7 05:07:25 2014
@@ -74,7 +74,7 @@
 	AST_OPT_FLAG_DONT_WARN = (1 << 18),
 	/*! End CDRs before the 'h' extension */
 	AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
-	/*! Use DAHDI Timing for generators if available */
+	/*! Use DAHDI Timing for generators if available (No longer used) */
 	AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
 	/*! Always fork, even if verbose or debug settings are non-zero */
 	AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
@@ -99,11 +99,7 @@
 };
 
 /*! These are the options that set by default when Asterisk starts */
-#if (defined(HAVE_DAHDI_VERSION) && HAVE_DAHDI_VERSION >= 230)
-#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN | AST_OPT_FLAG_INTERNAL_TIMING
-#else
 #define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
-#endif
 
 #define ast_opt_exec_includes		ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
 #define ast_opt_no_fork			ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)

Modified: team/oej/teapot-1.8/include/asterisk/res_odbc.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/include/asterisk/res_odbc.h?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/include/asterisk/res_odbc.h (original)
+++ team/oej/teapot-1.8/include/asterisk/res_odbc.h Mon Apr  7 05:07:25 2014
@@ -222,4 +222,10 @@
  */
 SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind);
 
+/*! \brief Checks if the database natively supports implicit conversion from an empty string to a number (0).
+ * \param obj The ODBC object
+ * \return Returns 1 if the implicit conversion is valid and non-text columns can take empty strings, 0 if the conversion is not valid and NULLs should be used instead '\'
+ */
+int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj);
+
 #endif /* _ASTERISK_RES_ODBC_H */

Modified: team/oej/teapot-1.8/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/asterisk.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/main/asterisk.c (original)
+++ team/oej/teapot-1.8/main/asterisk.c Mon Apr  7 05:07:25 2014
@@ -484,7 +484,6 @@
 	ast_cli(a->fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
 	ast_cli(a->fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Transcode via SLIN:          %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
-	ast_cli(a->fd, "  Internal timing:             %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Generic PLC:                 %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
 
@@ -3003,7 +3002,6 @@
 	printf("   -g              Dump core in case of a crash\n");
 	printf("   -h              This help screen\n");
 	printf("   -i              Initialize crypto keys at startup\n");
-	printf("   -I              Enable internal timing if DAHDI timer is available\n");
 	printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
 	printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
 	printf("   -m              Mute debugging and console output on the console\n");
@@ -3171,9 +3169,6 @@
 		/* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
 		} else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
 			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
-		/* Enable internal timing */
-		} else if (!strcasecmp(v->name, "internal_timing")) {
-			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
 		} else if (!strcasecmp(v->name, "maxcalls")) {
 			if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
 				option_maxcalls = 0;
@@ -3482,9 +3477,6 @@
 		case 'h':
 			show_cli_help();
 			exit(0);
-		case 'I':
-			ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
-			break;
 		case 'i':
 			ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
 			break;

Modified: team/oej/teapot-1.8/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/channel.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/main/channel.c (original)
+++ team/oej/teapot-1.8/main/channel.c Mon Apr  7 05:07:25 2014
@@ -3093,18 +3093,26 @@
 	return __ast_answer(chan, 0, 1);
 }
 
-void ast_deactivate_generator(struct ast_channel *chan)
-{
-	ast_channel_lock(chan);
+static void deactivate_generator_nolock(struct ast_channel *chan)
+{
 	if (chan->generatordata) {
-		if (chan->generator && chan->generator->release)
-			chan->generator->release(chan, chan->generatordata);
+		struct ast_generator *generator = chan->generator;
+
+		if (generator && generator->release) {
+			generator->release(chan, chan->generatordata);
+		}
 		chan->generatordata = NULL;
 		chan->generator = NULL;
 		ast_channel_set_fd(chan, AST_GENERATOR_FD, -1);
 		ast_clear_flag(chan, AST_FLAG_WRITE_INT);
 		ast_settimeout(chan, 0, NULL, NULL);
 	}
+}
+
+void ast_deactivate_generator(struct ast_channel *chan)
+{
+	ast_channel_lock(chan);
+	deactivate_generator_nolock(chan);
 	ast_channel_unlock(chan);
 }
 
@@ -3148,8 +3156,11 @@
 
 	ast_channel_lock(chan);
 	if (chan->generatordata) {
-		if (chan->generator && chan->generator->release)
-			chan->generator->release(chan, chan->generatordata);
+		struct ast_generator *generator_old = chan->generator;
+
+		if (generator_old && generator_old->release) {
+			generator_old->release(chan, chan->generatordata);
+		}
 		chan->generatordata = NULL;
 	}
 	if (gen->alloc && !(chan->generatordata = gen->alloc(chan, params))) {
@@ -3715,48 +3726,56 @@
 
 static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f)
 {
-	if (chan->generator && chan->generator->generate && chan->generatordata &&  !ast_internal_timing_enabled(chan)) {
-		void *tmp = chan->generatordata;
-		int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples) = chan->generator->generate;
-		int res;
-		int samples;
-
-		if (chan->timingfunc) {
-			ast_debug(1, "Generator got voice, switching to phase locked mode\n");
-			ast_settimeout(chan, 0, NULL, NULL);
-		}
-
-		chan->generatordata = NULL;     /* reset, to let writes go through */
-
-		if (f->subclass.codec != chan->writeformat) {
-			float factor;
-			factor = ((float) ast_format_rate(chan->writeformat)) / ((float) ast_format_rate(f->subclass.codec));
-			samples = (int) ( ((float) f->samples) * factor );
-		} else {
-			samples = f->samples;
-		}
-		
-		/* This unlock is here based on two assumptions that hold true at this point in the
-		 * code. 1) this function is only called from within __ast_read() and 2) all generators
-		 * call ast_write() in their generate callback.
-		 *
-		 * The reason this is added is so that when ast_write is called, the lock that occurs 
-		 * there will not recursively lock the channel. Doing this will cause intended deadlock 
-		 * avoidance not to work in deeper functions
-		 */
-		ast_channel_unlock(chan);
-		res = generate(chan, tmp, f->datalen, samples);
-		ast_channel_lock(chan);
-		chan->generatordata = tmp;
+	struct ast_generator *generator;
+	void *gendata;
+	int res;
+	int samples;
+
+	generator = chan->generator;
+	if (!generator
+		|| !generator->generate
+		|| f->frametype != AST_FRAME_VOICE
+		|| !chan->generatordata
+		|| chan->timingfunc) {
+		return;
+	}
+
+	/*
+	 * We must generate frames in phase locked mode since
+	 * we have no internal timer available.
+	 */
+
+	if (f->subclass.codec != chan->writeformat) {
+		float factor;
+
+		factor = ((float) ast_format_rate(chan->writeformat)) / ((float) ast_format_rate(f->subclass.codec));
+		samples = (int) (((float) f->samples) * factor);
+	} else {
+		samples = f->samples;
+	}
+
+	gendata = chan->generatordata;
+	chan->generatordata = NULL;     /* reset, to let writes go through */
+
+	/*
+	 * This unlock is here based on two assumptions that hold true at
+	 * this point in the code. 1) this function is only called from
+	 * within __ast_read() and 2) all generators call ast_write() in
+	 * their generate callback.
+	 *
+	 * The reason this is added is so that when ast_write is called,
+	 * the lock that occurs there will not recursively lock the
+	 * channel.  Doing this will allow deadlock avoidance to work in
+	 * deeper functions.
+	 */
+	ast_channel_unlock(chan);
+	res = generator->generate(chan, gendata, f->datalen, samples);
+	ast_channel_lock(chan);
+	if (generator == chan->generator) {
+		chan->generatordata = gendata;
 		if (res) {
 			ast_debug(1, "Auto-deactivating generator\n");
 			ast_deactivate_generator(chan);
-		}
-
-	} else if (f->frametype == AST_FRAME_CNG) {
-		if (chan->generator && !chan->timingfunc && (chan->timingfd > -1)) {
-			ast_debug(1, "Generator got CNG, switching to timed mode\n");
-			ast_settimeout(chan, 50, generator_force, chan);
 		}
 	}
 }
@@ -4363,7 +4382,7 @@
 
 int ast_internal_timing_enabled(struct ast_channel *chan)
 {
-	return (ast_opt_internal_timing && chan->timingfd > -1);
+	return chan->timingfd > -1;
 }
 
 struct ast_frame *ast_read(struct ast_channel *chan)
@@ -8333,30 +8352,24 @@
 	return state;
 }
 
-static int internal_deactivate_generator(struct ast_channel *chan, void* generator)
+static int deactivate_silence_generator(struct ast_channel *chan)
 {
 	ast_channel_lock(chan);
 
 	if (!chan->generatordata) {
-		ast_debug(1, "Trying to stop silence generator when there is no "
-		    "generator on '%s'\n", chan->name);
+		ast_debug(1, "Trying to stop silence generator when there is no generator on '%s'\n",
+			chan->name);
 		ast_channel_unlock(chan);
 		return 0;
 	}
-	if (chan->generator != generator) {
-		ast_debug(1, "Trying to stop silence generator when it is not the current "
-		    "generator on '%s'\n", chan->name);
+	if (chan->generator != &silence_generator) {
+		ast_debug(1, "Trying to stop silence generator when it is not the current generator on '%s'\n",
+			chan->name);
 		ast_channel_unlock(chan);
 		return 0;
 	}
-	if (chan->generator && chan->generator->release) {
-		chan->generator->release(chan, chan->generatordata);
-	}
-	chan->generatordata = NULL;
-	chan->generator = NULL;
-	ast_channel_set_fd(chan, AST_GENERATOR_FD, -1);
-	ast_clear_flag(chan, AST_FLAG_WRITE_INT);
-	ast_settimeout(chan, 0, NULL, NULL);
+	deactivate_generator_nolock(chan);
+
 	ast_channel_unlock(chan);
 
 	return 1;
@@ -8364,10 +8377,11 @@
 
 void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
 {
-	if (!state)
+	if (!state) {
 		return;
-
-	if (internal_deactivate_generator(chan, &silence_generator)) {
+	}
+
+	if (deactivate_silence_generator(chan)) {
 		ast_debug(1, "Stopped silence generator on '%s'\n", chan->name);
 
 		if (ast_set_write_format(chan, state->old_write_format) < 0)

Modified: team/oej/teapot-1.8/main/http.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/http.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/main/http.c (original)
+++ team/oej/teapot-1.8/main/http.c Mon Apr  7 05:07:25 2014
@@ -434,7 +434,9 @@
 	/* send content */
 	if (method != AST_HTTP_HEAD || status_code >= 400) {
 		if (out) {
-			fprintf(ser->f, "%s", ast_str_buffer(out));
+			if (fwrite(ast_str_buffer(out), content_length, 1, ser->f) != 1) {
+				ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
+			}
 		}
 
 		if (fd) {
@@ -456,8 +458,7 @@
 		ast_free(out);
 	}
 
-	fclose(ser->f);
-	ser->f = 0;
+	ast_tcptls_close_session_file(ser);
 	return;
 }
 

Modified: team/oej/teapot-1.8/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/manager.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/main/manager.c (original)
+++ team/oej/teapot-1.8/main/manager.c Mon Apr  7 05:07:25 2014
@@ -1353,6 +1353,15 @@
 	}
 
 	if (session->f != NULL) {
+		/*
+		 * Issuing shutdown() is necessary here to avoid a race
+		 * condition where the last data written may not appear
+		 * in the the TCP stream.  See ASTERISK-23548
+		*/
+		fflush(session->f);
+		if (session->fd != -1) {
+			shutdown(session->fd, SHUT_RDWR);
+		}
 		fclose(session->f);
 	}
 	if (eqe) {
@@ -5913,12 +5922,21 @@
 	}
 
 	if (s->f) {
+		/*
+		 * Issuing shutdown() is necessary here to avoid a race
+		 * condition where the last data written may not appear
+		 * in the the TCP stream.  See ASTERISK-23548
+		*/
+		if (s->fd != -1) {
+			shutdown(s->fd, SHUT_RDWR);
+		}
 		if (fclose(s->f)) {
 			ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
 		}
 		s->f = NULL;
 		s->fd = -1;
 	} else if (s->fd != -1) {
+		shutdown(s->fd, SHUT_RDWR);
 		if (close(s->fd)) {
 			ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
 		}

Modified: team/oej/teapot-1.8/main/tcptls.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/tcptls.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/main/tcptls.c (original)
+++ team/oej/teapot-1.8/main/tcptls.c Mon Apr  7 05:07:25 2014
@@ -612,12 +612,22 @@
 void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session)
 {
 	if (tcptls_session->f) {
+		/*
+		 * Issuing shutdown() is necessary here to avoid a race
+		 * condition where the last data written may not appear
+		 * in the TCP stream.  See ASTERISK-23548
+		*/
+		fflush(tcptls_session->f);
+		if (tcptls_session->fd != -1) {
+			shutdown(tcptls_session->fd, SHUT_RDWR);
+		}
 		if (fclose(tcptls_session->f)) {
 			ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
 		}
 		tcptls_session->f = NULL;
 		tcptls_session->fd = -1;
 	} else if (tcptls_session->fd != -1) {
+		shutdown(tcptls_session->fd, SHUT_RDWR);
 		if (close(tcptls_session->fd)) {
 			ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
 		}

Modified: team/oej/teapot-1.8/res/res_config_odbc.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/res/res_config_odbc.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/res/res_config_odbc.c (original)
+++ team/oej/teapot-1.8/res/res_config_odbc.c Mon Apr  7 05:07:25 2014
@@ -67,6 +67,12 @@
 			memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
 		}
 	}
+}
+
+static inline int is_text(const struct odbc_cache_columns *column)
+{
+	return column->type == SQL_CHAR || column->type == SQL_VARCHAR || column->type == SQL_LONGVARCHAR
+		|| column->type == SQL_WCHAR || column->type == SQL_WVARCHAR || column->type == SQL_WLONGVARCHAR;
 }
 
 static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
@@ -484,15 +490,15 @@
 	SQLHSTMT stmt;
 	char sql[256];
 	SQLLEN rowcount=0;
-	const char *newparam;
-	int res, count = 1;
+	const char *newparam, *newval;
+	int res, count = 0, paramcount = 0;
 	va_list aq;
 	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
 	struct odbc_cache_tables *tableptr;
 	struct odbc_cache_columns *column = NULL;
 	struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-	if (!table) {
+	if (!table || !keyfield) {
 		return -1;
 	}
 
@@ -507,39 +513,31 @@
 		return -1;
 	}
 
+	if (tableptr && !ast_odbc_find_column(tableptr, keyfield)) {
+		ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", keyfield, table, database);
+	}
+
 	va_copy(aq, ap);
-	newparam = va_arg(aq, const char *);
-	if (!newparam)  {
-		va_end(aq);
-		ast_odbc_release_obj(obj);
-		ast_odbc_release_table(tableptr);
-		ast_string_field_free_memory(&cps);
-		return -1;
-	}
-	va_arg(aq, const char *);
-
-	if (tableptr && !ast_odbc_find_column(tableptr, newparam)) {
-		ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", newparam, table, database);
-	}
-
-	snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
+
+	snprintf(sql, sizeof(sql), "UPDATE %s SET ", table);
 	while((newparam = va_arg(aq, const char *))) {
-		va_arg(aq, const char *);
-		if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count > 63) {
-			/* NULL test for integer-based columns */
-			if (ast_strlen_zero(newparam) && tableptr && column && column->nullable && count < 64 &&
-				(column->type == SQL_INTEGER || column->type == SQL_BIGINT ||
-				 column->type == SQL_SMALLINT || column->type == SQL_TINYINT ||
-				 column->type == SQL_NUMERIC || column->type == SQL_DECIMAL)) {
-				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=NULL", newparam);
+		newval = va_arg(aq, const char *);
+		if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count >= 64) {
+			if (paramcount++) {
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", ");
+			}
+			/* NULL test for non-text columns */
+			if (count < 64 && ast_strlen_zero(newval) && column->nullable && !is_text(column) && !ast_odbc_allow_empty_string_in_nontext(obj)) {
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", newparam);
 				cps.skip |= (1LL << count);
 			} else {
-				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
+				/* Value is not an empty string, or column accepts empty strings, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", newparam);
 			}
 		} else { /* the column does not exist in the table */
 			cps.skip |= (1LL << count);
 		}
-		count++;
+		++count;
 	}
 	va_end(aq);
 	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);

Modified: team/oej/teapot-1.8/res/res_odbc.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/res/res_odbc.c?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/res/res_odbc.c (original)
+++ team/oej/teapot-1.8/res/res_odbc.c Mon Apr  7 05:07:25 2014
@@ -128,6 +128,7 @@
 	unsigned int delme:1;                /*!< Purge the class */
 	unsigned int backslash_is_escape:1;  /*!< On this database, the backslash is a native escape sequence */
 	unsigned int forcecommit:1;          /*!< Should uncommitted transactions be auto-committed on handle release? */
+	unsigned int allow_empty_strings:1;  /*!< Implicit conversion from an empty string to a number is valid for this database */
 	unsigned int isolation;              /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
 	unsigned int limit;                  /*!< Maximum number of database handles we will allow */
 	int count;                           /*!< Running count of pooled connections */
@@ -773,7 +774,7 @@
 	struct ast_variable *v;
 	char *cat;
 	const char *dsn, *username, *password, *sanitysql;
-	int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation;
+	int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation, allow_empty_strings;
 	struct timeval ncache = { 0, 0 };
 	unsigned int idlecheck;
 	int preconnect = 0, res = 0;
@@ -802,6 +803,7 @@
 			bse = 1;
 			conntimeout = 10;
 			forcecommit = 0;
+			allow_empty_strings = 1;
 			isolation = SQL_TXN_READ_COMMITTED;
 			for (v = ast_variable_browse(config, cat); v; v = v->next) {
 				if (!strcasecmp(v->name, "pooling")) {
@@ -837,6 +839,8 @@
 					sanitysql = v->value;
 				} else if (!strcasecmp(v->name, "backslash_is_escape")) {
 					bse = ast_true(v->value);
+				} else if (!strcasecmp(v->name, "allow_empty_string_in_nontext")) {
+					allow_empty_strings = ast_true(v->value);
 				} else if (!strcasecmp(v->name, "connect_timeout")) {
 					if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
 						ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
@@ -898,6 +902,7 @@
 				new->idlecheck = idlecheck;
 				new->conntimeout = conntimeout;
 				new->negative_connection_cache = ncache;
+				new->allow_empty_strings = allow_empty_strings ? 1 : 0;
 
 				if (cat)
 					ast_copy_string(new->name, cat, sizeof(new->name));
@@ -1113,6 +1118,11 @@
 int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
 {
 	return obj->parent->backslash_is_escape;
+}
+
+int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj)
+{
+	return obj->parent->allow_empty_strings;
 }
 
 static int commit_exec(struct ast_channel *chan, const char *data)

Modified: team/oej/teapot-1.8/res/res_odbc.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/res/res_odbc.exports.in?view=diff&rev=411782&r1=411781&r2=411782
==============================================================================
--- team/oej/teapot-1.8/res/res_odbc.exports.in (original)
+++ team/oej/teapot-1.8/res/res_odbc.exports.in Mon Apr  7 05:07:25 2014
@@ -2,6 +2,7 @@
 	global:
 		LINKER_SYMBOL_PREFIXast_odbc_ast_str_SQLGetData;
 		LINKER_SYMBOL_PREFIXast_odbc_backslash_is_escape;
+		LINKER_SYMBOL_PREFIXast_odbc_allow_empty_string_in_nontext;
 		LINKER_SYMBOL_PREFIXast_odbc_clear_cache;
 		LINKER_SYMBOL_PREFIXast_odbc_direct_execute;
 		LINKER_SYMBOL_PREFIXast_odbc_find_column;




More information about the asterisk-commits mailing list