[asterisk-commits] branch bweschke/bug_6047 r14656 - in /team/bweschke/bug_6047: ./ channels/ in...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu Mar 23 18:12:32 MST 2006


Author: bweschke
Date: Thu Mar 23 19:12:31 2006
New Revision: 14656

URL: http://svn.digium.com/view/asterisk?rev=14656&view=rev
Log:
 Updating code/functionality to bring it in line with /trunk and fix a possible memory leak problem in rare situations


Modified:
    team/bweschke/bug_6047/channels/chan_sip.c
    team/bweschke/bug_6047/include/asterisk/sched.h
    team/bweschke/bug_6047/sched.c

Modified: team/bweschke/bug_6047/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/bweschke/bug_6047/channels/chan_sip.c?rev=14656&r1=14655&r2=14656&view=diff
==============================================================================
--- team/bweschke/bug_6047/channels/chan_sip.c (original)
+++ team/bweschke/bug_6047/channels/chan_sip.c Thu Mar 23 19:12:31 2006
@@ -534,6 +534,15 @@
 	char md5secret[256];		/*!< MD5Secret */
 	struct sip_auth *next;		/*!< Next auth structure in list */
 };
+
+/*! \brief hintmgrparam: A structure to hold on to pointers for cb_hintmanager */
+struct hintmgrparam {
+	int state;			/*!< The original state causing the cb */
+	char *context;			/*!< Context the hint is for */
+	char *exten;			/*!< Extension the hint is for */
+	struct sip_pvt *p;		/*!< SIP Session Structure Ptr */
+};
+
 
 /*--- Various flags for the flags field in the pvt structure 
  Peer only flags should be set in PAGE2 below
@@ -961,6 +970,7 @@
 static int determine_firstline_parts(struct sip_request *req);
 static void sip_dump_history(struct sip_pvt *dialog);	/* Dump history to LOG_DEBUG at end of dialog, before destroying data */
 static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
+static int cb_extensionstate(char *context, char* exten, int state, void *data);
 static int transmit_state_notify(struct sip_pvt *p, int state, int full);
 static char *gettag(struct sip_request *req, char *header, char *tagbuf, int tagbufsize);
 static int find_sip_method(char *msg);
@@ -6447,29 +6457,70 @@
 	}
 }
 
+/*! \brief  cb_hintmanager: Callback to check on the status of an AST_EXTENSION_DEACTIVATED/REMOVED call already received ---*/
+/*    When you do a 'reload' in Asterisk the ast_merge_contexts_and_delete() function call that gets
+      called during the reload will rebuild hints sending AST_EXTENSION_DEACTIVATED state msgs. Now, instead of 
+      acting immediately on those msgs, we schedule this callback for 5 secs later and if the hint is 
+      still not there, then we tear down the subscription, otherwise, we re-establish our connection with 
+      the core and re-sync and re-transmit current state. */
+static int cb_hintmanager(void *data)
+{
+	struct hintmgrparam *hmgrp = data;
+	struct sip_pvt *p = NULL;
+	int firststate = hmgrp->state;
+
+	/* Verify first that the SIP session is still around after having waited 5 secs */
+	if (hmgrp->p) {
+		p = hmgrp->p;
+		p->stateid = ast_extension_state_add(p->context, p->exten, cb_extensionstate, p);
+		ast_log(LOG_DEBUG, "ast_extension_state on %s@%s is %d\n", p->exten, p->context, ast_extension_state(NULL, p->context, p->exten));
+		if ((firststate = ast_extension_state(NULL, p->context, p->exten)) < 0) {
+			ast_log(LOG_DEBUG, "Still cannot retrieve state on %s@%s. Time to throw in the towel.\n", p->exten, p->context);
+			if (p->autokillid > -1)
+				sip_cancel_destroy(p);		/* Remove subscription expiry for renewals */
+			sip_scheddestroy(p, 10000);		/* Delete subscription in 10 more secs since we've already waited 5 */
+			ast_verbose(VERBOSE_PREFIX_2 "Extension state: Watcher for hint %s %s. Notify User %s\n", hmgrp->exten, hmgrp->state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
+			p->stateid = -1;
+			p->subscribed = NONE;
+			append_history(p, "Subscribestatus", "%s", hmgrp->state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
+			transmit_state_notify(p, hmgrp->state, 1);
+		} else {
+			if (option_debug > 1)
+				ast_verbose(VERBOSE_PREFIX_1 "Extension State Resync %s new state %s for Notify User %s\n", hmgrp->exten, ast_extension_state2str(firststate), p->username);
+				transmit_state_notify(p, firststate, 1);	/* Send current notification */
+		}	
+	} else
+		ast_log(LOG_DEBUG, "The SIP Session has gone away while we were waiting to be called back. Cleaning up and done.\n");
+
+	return 0;
+}
+
 /*! \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 */
 static int cb_extensionstate(char *context, char* exten, int state, void *data)
 {
 	struct sip_pvt *p = data;
+	struct hintmgrparam *hmgrp = NULL;
 
 	switch(state) {
 	case AST_EXTENSION_DEACTIVATED:	/* Retry after a while */
 	case AST_EXTENSION_REMOVED:	/* Extension is gone */
-		if (p->autokillid > -1)
-			sip_cancel_destroy(p);	/* Remove subscription expiry for renewals */
-		sip_scheddestroy(p, 15000);	/* Delete subscription in 15 secs */
-		ast_verbose(VERBOSE_PREFIX_2 "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
-		p->stateid = -1;
-		p->subscribed = NONE;
-		append_history(p, "Subscribestatus", "%s", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
+		hmgrp = ast_calloc(1, sizeof(*hmgrp));
+		hmgrp->state = state;
+		hmgrp->context = context;
+		hmgrp->exten = exten;
+		hmgrp->p = p;
+		ast_sched_add_variable_and_cleanup(sched, 5000, cb_hintmanager, hmgrp, 0, hmgrp);
 		break;
 	default:	/* Tell user */
 		p->laststate = state;
 		break;
 	}
-	transmit_state_notify(p, state, 1);
+
+	if (state != AST_EXTENSION_DEACTIVATED && state != AST_EXTENSION_REMOVED)
+		transmit_state_notify(p, state, 1);
+
 
 	if (option_debug > 1)
 		ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %s for Notify User %s\n", exten, ast_extension_state2str(state), p->username);

Modified: team/bweschke/bug_6047/include/asterisk/sched.h
URL: http://svn.digium.com/view/asterisk/team/bweschke/bug_6047/include/asterisk/sched.h?rev=14656&r1=14655&r2=14656&view=diff
==============================================================================
--- team/bweschke/bug_6047/include/asterisk/sched.h (original)
+++ team/bweschke/bug_6047/include/asterisk/sched.h Thu Mar 23 19:12:31 2006
@@ -70,6 +70,23 @@
  * \return Returns a schedule item ID on success, -1 on failure
  */
 extern int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, void *data);
+
+/*!Adds a scheduled event with rescheduling support and cleanup/free of memory upon completion
+ * \param con Scheduler context to add
+ * \param when how many milliseconds to wait for event to occur
+ * \param callback function to call when the amount of time expires
+ * \param data data to pass to the callback
+ * \param variable If true, the result value of callback function will be 
+ *       used for rescheduling
+ * \param memptrcleanup Free the memory at this pointer when callback is
+ *       complete
+ * Schedule an event to take place at some point in the future.  Callback 
+ * will be called with data as the argument, when milliseconds into the
+ * future (approximately)
+ * If callback returns 0, no further events will be re-scheduled
+ * \return Returns a schedule item ID on success, -1 on failure
+ */
+extern int ast_sched_add_variable_and_cleanup(struct sched_context *con, int when, ast_sched_cb callback, void *data, int variable, void *memptrcleanup);
 
 /*!Adds a scheduled event with rescheduling support
  * \param con Scheduler context to add

Modified: team/bweschke/bug_6047/sched.c
URL: http://svn.digium.com/view/asterisk/team/bweschke/bug_6047/sched.c?rev=14656&r1=14655&r2=14656&view=diff
==============================================================================
--- team/bweschke/bug_6047/sched.c (original)
+++ team/bweschke/bug_6047/sched.c Thu Mar 23 19:12:31 2006
@@ -56,6 +56,7 @@
 	int resched;			/*!< When to reschedule */
 	int variable;			/*!< Use return value from callback to reschedule */
 	void *data; 			/*!< Data */
+	void *memptrcleanup;		/*!< Cleanup/free the memory at this pointer when the callback is complete */
 	ast_sched_cb callback;		/*!< Callback */
 };
 
@@ -102,6 +103,8 @@
 	while(s) {
 		sl = s;
 		s = s->next;
+		if (sl->memptrcleanup)
+			free(sl->memptrcleanup);
 		free(sl);
 	}
 	/* And the context */
@@ -211,20 +214,13 @@
 	return 0;
 }
 
-
-/*! \brief
- * Schedule callback(data) to happen when ms into the future
- */
-int ast_sched_add_variable(struct sched_context *con, int when, ast_sched_cb callback, void *data, int variable)
+/*! \brief
+ * Populate the scheduler struct with data from params called from the add_variable and add_variable_and_cleanup functions
+ */
+static struct sched *ast_sched_populate(struct sched_context *con, int when, ast_sched_cb callback, void *data, int variable, void *memptrcleanup)
 {
 	struct sched *tmp;
-	int res = -1;
-	DEBUG(ast_log(LOG_DEBUG, "ast_sched_add()\n"));
-	if (!when) {
-		ast_log(LOG_NOTICE, "Scheduled event in 0 ms?\n");
-		return -1;
-	}
-	ast_mutex_lock(&con->lock);
+
 	if ((tmp = sched_alloc(con))) {
 		tmp->id = con->eventcnt++;
 		tmp->callback = callback;
@@ -232,6 +228,57 @@
 		tmp->resched = when;
 		tmp->variable = variable;
 		tmp->when = ast_tv(0, 0);
+		tmp->memptrcleanup = memptrcleanup;
+	}
+	
+	return tmp;
+}
+
+/*! \brief
+ * Schedule callback(data) to happen when ms into the future and cleanup/free the memory at memptrcleanup after execution
+ */
+int ast_sched_add_variable_and_cleanup(struct sched_context *con, int when, ast_sched_cb callback, void *data, int variable, void *memptrcleanup)
+{
+	struct sched *tmp;
+	int res = -1;
+	DEBUG(ast_log(LOG_DEBUG, "ast_sched_add()\n"));
+	if (!when) {
+		ast_log(LOG_NOTICE, "Scheduled event in 0 ms?\n");
+		return -1;
+	}
+	ast_mutex_lock(&con->lock);
+	tmp = ast_sched_populate(con, when, callback, data, variable, memptrcleanup);
+	if (tmp) {
+		if (sched_settime(&tmp->when, when)) {
+			sched_release(con, tmp);
+		} else {
+			schedule(con, tmp);
+			res = tmp->id;
+		}
+	}
+#ifdef DUMP_SCHEDULER
+	/* Dump contents of the context while we have the lock so nothing gets screwed up by accident. */
+	ast_sched_dump(con);
+#endif
+	ast_mutex_unlock(&con->lock);
+	return res;
+}
+
+/*! \brief
+ * Schedule callback(data) to happen when ms into the future
+ */
+int ast_sched_add_variable(struct sched_context *con, int when, ast_sched_cb callback, void *data, int variable)
+{
+	struct sched *tmp;
+	int res = -1;
+	DEBUG(ast_log(LOG_DEBUG, "ast_sched_add()\n"));
+	if (!when) {
+		ast_log(LOG_NOTICE, "Scheduled event in 0 ms?\n");
+		return -1;
+	}
+	ast_mutex_lock(&con->lock);
+	tmp = ast_sched_populate(con, when, callback, data, variable, NULL);
+	if (tmp) {
 		if (sched_settime(&tmp->when, when)) {
 			sched_release(con, tmp);
 		} else {
@@ -271,6 +318,8 @@
 			else
 				con->schedq = s->next;
 			con->schedcnt--;
+			if (s->memptrcleanup)
+				free(s->memptrcleanup);
 			sched_release(con, s);
 			break;
 		}
@@ -374,6 +423,8 @@
 					schedule(con, current);
 			} else {
 				/* No longer needed, so release it */
+				if (current->memptrcleanup)
+					free(current->memptrcleanup);
 			 	sched_release(con, current);
 			}
 			x++;



More information about the asterisk-commits mailing list