Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 307181)
+++ channels/chan_sip.c	(working copy)
@@ -2381,6 +2381,7 @@
 static void ast_quiet_chan(struct ast_channel *chan);
 static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
 static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
+static int scheduler_process_request_queue(const void *data);
 
 /*!
  * \brief generic function for determining if a correct transport is being 
@@ -2625,6 +2626,7 @@
 static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
 static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
 static void change_t38_state(struct sip_pvt *p, int state);
+static int sip_t38_abort(const void *data);
 
 /*------ Session-Timers functions --------- */
 static void proc_422_rsp(struct sip_pvt *p, struct sip_request *rsp);
@@ -3127,6 +3129,25 @@
 	}
 }
 
+#ifdef REF_DEBUG
+#define ref_peer(arg1,arg2) _ref_peer((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define unref_peer(arg1,arg2) _unref_peer((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+static struct sip_peer *_ref_peer(struct sip_peer *peer, char *tag, char *file, int line, const char *func)
+{
+	if (peer)
+		_ao2_ref_debug(peer, 1, tag, file, line, func);
+	else
+		ast_log(LOG_ERROR, "Attempt to Ref a null peer pointer\n");
+	return peer;
+}
+
+static struct sip_peer *_unref_peer(struct sip_peer *peer, char *tag, char *file, int line, const char *func)
+{
+	if (peer)
+		_ao2_ref_debug(peer, -1, tag, file, line, func);
+	return NULL;
+}
+#else
 /*!
  * helper functions to unreference various types of objects.
  * By handling them this way, we don't have to declare the
@@ -3134,15 +3155,16 @@
  */
 static void *unref_peer(struct sip_peer *peer, char *tag)
 {
-	ao2_t_ref(peer, -1, tag);
+	ao2_ref(peer, -1);
 	return NULL;
 }
 
 static struct sip_peer *ref_peer(struct sip_peer *peer, char *tag)
 {
-	ao2_t_ref(peer, 1, tag);
+	ao2_ref(peer, 1);
 	return peer;
 }
+#endif
 
 /*! \brief maintain proper refcounts for a sip_pvt's outboundproxy
  *
@@ -3181,6 +3203,11 @@
 {
 	struct sip_pkt *cp;
 
+	if (!dialog) {
+		ast_log(LOG_ERROR, "Attempt unlink a null dialog\n");
+		return NULL;
+	}
+
 	dialog_ref(dialog, "Let's bump the count in the unlink so it doesn't accidentally become dead before we are done");
 
 	ao2_t_unlink(dialogs, dialog, "unlinking dialog via ao2_unlink");
@@ -3196,8 +3223,8 @@
 	}
 	if (dialog->registry) {
 		if (dialog->registry->call == dialog)
-			dialog->registry->call = dialog_unref(dialog->registry->call, "nulling out the registry's call dialog field in unlink_all");
-		dialog->registry = registry_unref(dialog->registry, "delete dialog->registry");
+			dialog->registry->call = dialog_unref(dialog->registry->call, "unref registry->call from dialog");
+		dialog->registry = registry_unref(dialog->registry, "unref dialog->registry from registry");
 	}
 	if (dialog->stateid > -1) {
 		ast_extension_state_del(dialog->stateid, NULL);
@@ -3238,6 +3265,8 @@
 		AST_SCHED_DEL_UNREF(sched, dialog->t38id, dialog_unref(dialog, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
 	}
 
+	stop_session_timer(dialog);
+
 	dialog_unref(dialog, "Let's unbump the count in the unlink so the poor pvt can disappear if it is time");
 	return NULL;
 }
@@ -4034,15 +4063,13 @@
 	} else {
 		append_history(p, "AutoDestroy", "%s", p->callid);
 		ast_debug(3, "Auto destroying SIP dialog '%s'\n", p->callid);
-		dialog_unlink_all(p, TRUE, TRUE); /* once it's unlinked and unrefd everywhere, it'll be freed automagically */
-		/* dialog_unref(p, "unref dialog-- no other matching conditions"); -- unlink all now should finish off the dialog's references and free it. */
-		/* sip_destroy(p); */		/* Go ahead and destroy dialog. All attempts to recover is done */
-		/* sip_destroy also absorbs the reference */
+		dialog_unlink_all(p, TRUE, TRUE);
+		dialog_unref(p, "destroy dialog when ref removed for autokillid");
 	}
 
 	sip_pvt_unlock(p);
 
-	dialog_unref(p, "The ref to a dialog passed to this sched callback is going out of scope; unref it.");
+	dialog_unref(p, "remove ref for autokillid");
 
 	return 0;
 }
@@ -4076,17 +4103,11 @@
  */
 static int sip_cancel_destroy(struct sip_pvt *p)
 {
-	int res = 0;
 	if (p->autokillid > -1) {
-		int res3;
-
-		if (!(res3 = ast_sched_del(sched, p->autokillid))) {
-			append_history(p, "CancelDestroy", "");
-			p->autokillid = -1;
-			dialog_unref(p, "dialog unrefd because autokillid is de-sched'd");
-		}
+		append_history(p, "CancelDestroy", "");
+		AST_SCHED_DEL_UNREF(sched, p->autokillid, dialog_unref(p, "remove ref for autokillid"));
 	}
-	return res;
+	return 0;
 }
 
 /*! \brief Acknowledges receipt of a packet and stops retransmission 
@@ -4719,8 +4740,8 @@
 
 	/* Delete it, it needs to disappear */
 	if (peer->call) {
-		dialog_unlink_all(peer->call, TRUE, TRUE);
-		peer->call = dialog_unref(peer->call, "peer->call is being unset");
+		dialog_unref(peer->call, "peer->call is being unset");
+		peer->call = dialog_unlink_all(peer->call, TRUE, TRUE);
 	}
 	
 
@@ -5543,8 +5564,7 @@
 		reg->call->registry = registry_unref(reg->call->registry, "destroy reg->call->registry");
 		ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", reg->username, reg->hostname);
 		dialog_unlink_all(reg->call, TRUE, TRUE);
-		reg->call = dialog_unref(reg->call, "unref reg->call");
-		/* reg->call = sip_destroy(reg->call); */
+		reg->call = dialog_unref(reg->call, "destroy dialog");
 	}
 	AST_SCHED_DEL(sched, reg->expire);	
 	AST_SCHED_DEL(sched, reg->timeout);
@@ -5574,7 +5594,10 @@
 {
 	struct sip_request *req;
 
+	/* Destroy Session-Timers if allocated */
 	if (p->stimer) {
+		p->stimer->quit_flag = 1;
+		stop_session_timer(p);
 		ast_free(p->stimer);
 		p->stimer = NULL;
 	}
@@ -5652,17 +5675,6 @@
 	}
 	deinit_req(&p->initreq);
 
-	/* Destroy Session-Timers if allocated */
-	if (p->stimer) {
-		p->stimer->quit_flag = 1;
-		if (p->stimer->st_active == TRUE && p->stimer->st_schedid > -1) {
-			AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid,
-					dialog_unref(p, "removing session timer ref"));
-		}
-		ast_free(p->stimer);
-		p->stimer = NULL;
-	}
-
 	/* Clear history */
 	if (p->history) {
 		struct sip_history *hist;
@@ -6558,7 +6570,7 @@
 		struct ast_control_t38_parameters parameters = p->t38.their_parms;
 
 		if (p->t38.state == T38_PEER_REINVITE) {
-			AST_SCHED_DEL(sched, p->t38id);
+			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
 			parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
 			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
 			ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
@@ -7261,8 +7273,7 @@
 		return NULL;
 
 	if (ast_string_field_init(p, 512)) {
-		ao2_t_ref(p, -1, "failed to string_field_init, drop p");
-		return NULL;
+		return dialog_unref(p, "failed to string_field_init, drop p");
 	}
 
 	if (req) {
@@ -7316,13 +7327,6 @@
 			p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
  		if (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT))
  			p->trtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
-		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
-			if (!(p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) {
-				/* udptl creation failed, T38 can not be supported on this dialog */
-				ast_log(LOG_ERROR, "UDPTL creation failed\n");
-				ast_clear_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT);
-			}
-		}
  		if (!p->rtp|| (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp) 
 				|| (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) && !p->trtp)) {
  			ast_log(LOG_WARNING, "Unable to create RTP audio %s%ssession: %s\n",
@@ -7332,8 +7336,8 @@
 				ast_variables_destroy(p->chanvars);
 				p->chanvars = NULL;
 			}
-			ao2_t_ref(p, -1, "failed to create RTP audio session, drop p");
-			return NULL;
+			return dialog_unref(p, "failed to create RTP audio session, drop p");
+			/* Why is this next line still here? */
 			p->t38_maxdatagram = global_t38_maxdatagram;
 		}
 		ast_rtp_setqos(p->rtp, global_tos_audio, global_cos_audio, "SIP RTP");
@@ -7453,7 +7457,7 @@
 /*! \brief find or create a dialog structure for an incoming SIP message.
  * Connect incoming SIP message to current dialog or create new dialog structure
  * Returns a reference to the sip_pvt object, remember to give it back once done.
- *     Called by handle_incoming(), sipsock_read
+ *     Called by handle_request_do()
  */
 static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
 {
@@ -7547,6 +7551,7 @@
 			if ((p = sip_alloc(callid, sin, 1, intended_method, req)))  {
 				/* Ok, we've created a dialog, let's go and process it */
 				sip_pvt_lock(p);
+				dialog_ref(p, "add ref in find_call()");
 			} else {
 				/* We have a memory or file/socket error (can't allocate RTP sockets or something) so we're not
 					getting a dialog from sip_alloc. 
@@ -9734,7 +9739,6 @@
 		char se_hdr[256];
 		snprintf(se_hdr, sizeof(se_hdr), "%d;refresher=%s", p->stimer->st_interval, 
 			strefresher2str(p->stimer->st_ref));
-		add_header(req, "Require", "timer");
 		add_header(req, "Session-Expires", se_hdr);
 		snprintf(se_hdr, sizeof(se_hdr), "%d", st_get_se(p, FALSE));
 		add_header(req, "Min-SE", se_hdr);
@@ -11562,8 +11566,7 @@
 	if (create_addr(p, channame, NULL, 0)) {
 		/* Maybe they're not registered, etc. */
 		dialog_unlink_all(p, TRUE, TRUE);
-		dialog_unref(p, "unref dialog inside for loop" );
-		/* sip_destroy(p); */
+		dialog_unref(p, "destroy dialog");
 		astman_send_error(s, m, "Could not create address");
 		return 0;
 	}
@@ -11754,7 +11757,7 @@
 			ast_log(LOG_WARNING, "Already have a REGISTER going on to %s@%s?? \n", r->username, r->hostname);
 			return 0;
 		} else {
-			p = dialog_ref(r->call, "getting a copy of the r->call dialog in transmit_register");
+			p = dialog_ref(r->call, "add ref for transmit_register()");
 			make_our_tag(p->tag, sizeof(p->tag));	/* create a new local tag for every register attempt */
 			ast_string_field_set(p, theirtag, NULL);	/* forget their old tag, so we don't match tags when getting response */
 		}
@@ -11782,7 +11785,7 @@
 			/* we have what we hope is a temporary network error,
 			 * probably DNS.  We need to reschedule a registration try */
 			dialog_unlink_all(p, TRUE, TRUE);
-			p = dialog_unref(p, "unref dialog after unlink_all");
+			p = dialog_unref(p, "destroy dialog");
 			if (r->timeout > -1) {
 				AST_SCHED_REPLACE_UNREF(r->timeout, sched, global_reg_timeout * 1000, sip_reg_timeout, r,
 										registry_unref(_data, "del for REPLACE of registry ptr"), 
@@ -11797,6 +11800,8 @@
 			return 0;
 		}
 
+		dialog_ref(p, "add ref for transmit_register()");
+
 		/* Copy back Call-ID in case create_addr changed it */
 		ast_string_field_set(r, callid, p->callid);
 		if (!r->dnsmgr && r->portno) {
@@ -11806,8 +11811,8 @@
 			r->portno = ntohs(p->sa.sin_port);
 		}
 		ast_set_flag(&p->flags[0], SIP_OUTGOING);	/* Registration is outgoing call */
-		r->call = dialog_ref(p, "copying dialog into registry r->call");		/* Save pointer to SIP dialog */
-		p->registry = registry_addref(r, "transmit_register: addref to p->registry in transmit_register");	/* Add pointer to registry in packet */
+		r->call = dialog_ref(p, "point registry->call to dialog");		/* Save pointer to SIP dialog */
+		p->registry = registry_addref(r, "point dialog->registry to registry");	/* Add pointer to registry in packet */
 		if (!ast_strlen_zero(r->secret)) {	/* Secret (password) */
 			ast_string_field_set(p, peersecret, r->secret);
 		}
@@ -11964,7 +11969,7 @@
 	r->regattempts++;	/* Another attempt */
 	ast_debug(4, "REGISTER attempt %d to %s@%s\n", r->regattempts, r->username, r->hostname);
 	res = send_request(p, &req, XMIT_CRITICAL, p->ocseq);
-	dialog_unref(p, "p is finished here at the end of transmit_register");
+	dialog_unref(p, "remove ref for transmit_register()");
 	return res;
 }
 
@@ -14265,7 +14270,7 @@
 		}
 
 		if (authpeer) {
-			ao2_t_ref(peer, 1, "copy pointer into (*authpeer)");
+			ref_peer(peer, "copy pointer into (*authpeer)");
 			(*authpeer) = peer;	/* Add a ref to the object here, to keep it in memory a bit longer if it is realtime */
 		}
 
@@ -14765,7 +14770,7 @@
 	ast_cli(a->fd, FORMAT, "Username", "Secret", "Accountcode", "Def.Context", "ACL", "NAT");
 
 	user_iter = ao2_iterator_init(peers, 0);
-	while ((user = ao2_iterator_next(&user_iter))) {
+	while ((user = ao2_t_iterator_next(&user_iter, "iterate thru peers table"))) {
 		ao2_lock(user);
 		if (!(user->type & SIP_TYPE_USER)) {
 			ao2_unlock(user);
@@ -14976,6 +14981,7 @@
 
 		peerarray[total_peers++] = peer;
 		ao2_unlock(peer);
+		unref_peer(peer, "toss iterator peer ptr");
 	}
 	ao2_iterator_destroy(&i);
 	
@@ -14990,7 +14996,6 @@
 		ao2_lock(peer);
 		if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0)) {
 			ao2_unlock(peer);
-			unref_peer(peer, "toss iterator peer ptr before continue");
 			continue;
 		}
 
@@ -15057,7 +15062,6 @@
 			realtimepeers ? (peer->is_realtime ? "yes":"no") : "no");
 		}
 		ao2_unlock(peer);
-		unref_peer(peer, "toss iterator peer ptr");
 	}
 	
 	if (!s)
@@ -15239,10 +15243,9 @@
 		}
 
 		sip_pvt_unlock(dialog);
-		/* no, the unlink should handle this: dialog_unref(dialog, "needdestroy: one more refcount decrement to allow dialog to be destroyed"); */
-		/* the CMP_MATCH will unlink this dialog from the dialog hash table */
-		dialog_unlink_all(dialog, TRUE, FALSE);
-		return 0; /* the unlink_all should unlink this from the table, so.... no need to return a match */
+		dialog_unlink_all(dialog, TRUE, TRUE);
+		dialog = dialog_unref(dialog, "destroy dialog");
+		return 0; 
 	}
 
 	sip_pvt_unlock(dialog);
@@ -15834,7 +15837,7 @@
 	struct sip_peer *user;
 
 	user_iter = ao2_iterator_init(peers, 0);
-	while ((user = ao2_iterator_next(&user_iter))) {
+	while ((user = ao2_t_iterator_next(&user_iter, "iterate thru peers table"))) {
 		ao2_lock(user);
 		if (!(user->type & SIP_TYPE_USER)) {
 			ao2_unlock(user);
@@ -15939,24 +15942,45 @@
 static char *sip_show_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ast_str *cbuf;
-	struct ast_cb_names cbnames = {9, { "retrans_pkt",
-                                        "__sip_autodestruct",
-                                        "expire_register",
-                                        "auto_congest",
-                                        "sip_reg_timeout",
-                                        "sip_poke_peer_s",
-                                        "sip_poke_noanswer",
-                                        "sip_reregister",
-                                        "sip_reinvite_retry"},
-								   { retrans_pkt,
-                                     __sip_autodestruct,
-                                     expire_register,
-                                     auto_congest,
-                                     sip_reg_timeout,
-                                     sip_poke_peer_s,
-                                     sip_poke_noanswer,
-                                     sip_reregister,
-                                     sip_reinvite_retry}};
+	struct ast_cb_names cbnames = {17,
+		{
+		"__sip_autodestruct",
+		"ast_rtcp_write",
+		"ast_rtp_red_write",
+		"auto_congest",
+		"expire_register",
+		"proc_session_timer",
+		"retrans_pkt",
+		"scheduler_process_request_queue",
+		"send_provisional_keepalive_with_sdp",
+		"send_provisional_keepalive",
+		"sip_poke_noanswer",
+		"sip_poke_peer_s",
+		"sip_reg_timeout",
+		"sip_reinvite_retry",
+		"sip_reregister",
+		"sip_subscribe_mwi_do",
+		"sip_t38_abort"
+		},
+		{
+		__sip_autodestruct,
+		ast_rtcp_write,
+		ast_rtp_red_write,
+		auto_congest,
+		expire_register,
+		proc_session_timer,
+		retrans_pkt,
+		scheduler_process_request_queue,
+		send_provisional_keepalive_with_sdp,
+		send_provisional_keepalive,
+		sip_poke_noanswer,
+		sip_poke_peer_s,
+		sip_reg_timeout,
+		sip_reinvite_retry,
+		sip_reregister,
+		sip_subscribe_mwi_do,
+		sip_t38_abort
+		}};
 	
 	switch (cmd) {
 	case CLI_INIT:
@@ -16745,7 +16769,7 @@
 
 		sip_pvt_unlock(cur);
 
-		ao2_t_ref(cur, -1, "toss dialog ptr set by iterator_next");
+		dialog_unref(cur, "toss dialog ptr set by iterator_next");
 	}
 	ao2_iterator_destroy(&i);
 
@@ -16802,7 +16826,7 @@
 			found++;
 		}
 		sip_pvt_unlock(cur);
-		ao2_t_ref(cur, -1, "toss dialog ptr from iterator_next");
+		dialog_unref(cur, "toss dialog ptr from iterator_next");
 	}
 	ao2_iterator_destroy(&i);
 
@@ -17164,8 +17188,7 @@
 		if (create_addr(p, a->argv[i], NULL, 1)) {
 			/* Maybe they're not registered, etc. */
 			dialog_unlink_all(p, TRUE, TRUE);
-			dialog_unref(p, "unref dialog inside for loop" );
-			/* sip_destroy(p); */
+			p = dialog_unref(p, "destroy dialog");
 			ast_cli(a->fd, "Could not create address for '%s'\n", a->argv[i]);
 			continue;
 		}
@@ -20525,7 +20548,7 @@
 	if (c) {	/* We have a call  -either a new call or an old one (RE-INVITE) */
 		enum ast_channel_state c_state = c->_state;
 
-		if (c_state != AST_STATE_UP && reinvite &&
+		if (c_state != AST_STATE_UP && (c_state != AST_STATE_DOWN) && reinvite &&
 			(p->invitestate == INV_TERMINATED || p->invitestate == INV_CONFIRMED)) {
 			/* If these conditions are true, and the channel is still in the 'ringing'
 			 * state, then this likely means that we have a situation where the initial
@@ -20610,6 +20633,10 @@
 			transmit_response(p, "100 Trying", req);
 
 			if (p->t38.state == T38_PEER_REINVITE) {
+				if (p->t38id > -1) {
+					/* reset t38 abort timer */
+					AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "remove ref for t38id"));
+				}
 				p->t38id = ast_sched_add(sched, 5000, sip_t38_abort, dialog_ref(p, "passing dialog ptr into sched structure based on t38id for sip_t38_abort."));
 			} else if (p->t38.state == T38_ENABLED) {
 				ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
@@ -20695,7 +20722,7 @@
 		transferer->refer->status = REFER_FAILED;
 		sip_pvt_unlock(targetcall_pvt);
 		if (targetcall_pvt)
-			ao2_t_ref(targetcall_pvt, -1, "Drop targetcall_pvt pointer");
+			dialog_unref(targetcall_pvt, "Drop targetcall_pvt pointer");
 		return -1;
 	}
 
@@ -20756,7 +20783,7 @@
 		}
 	}
 	if (targetcall_pvt)
-		ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt");
+		dialog_unref(targetcall_pvt, "drop targetcall_pvt");
 	return 1;
 }
 
@@ -21158,6 +21185,10 @@
 			if (pkt->seqno == p->lastinvite && pkt->response_code == 487) {
 				AST_SCHED_DEL(sched, pkt->retransid);
 				UNLINK(pkt, p->packets, prev_pkt);
+				dialog_unref(p, "unref packet->owner from dialog");
+				if (pkt->data) {
+					ast_free(pkt->data);
+				}
 				ast_free(pkt);
 				break;
 			}
@@ -22252,7 +22283,7 @@
 		ast_mutex_lock(&netlock);
 
 		/* Find the active SIP dialog or create a new one */
-		p = find_call(req, sin, req->method);	/* returns p locked */
+		p = find_call(req, sin, req->method);	/* returns p locked, and ref'd */
 		if (p == NULL) {
 			ast_debug(1, "Invalid SIP message - rejected , no callid, len %d\n", req->len);
 			ast_mutex_unlock(&netlock);
@@ -22268,7 +22299,7 @@
 
 		if (lockretry != 1) {
 			sip_pvt_unlock(p);
-			ao2_t_ref(p, -1, "release p (from find_call) inside lockretry loop"); /* we'll look for it again, but p is dead now */
+			dialog_unref(p, "release p (from find_call) inside lockretry loop"); /* we'll look for it again, but p is dead now */
 			ast_mutex_unlock(&netlock);
 			/* Sleep for a very short amount of time */
 			usleep(1);
@@ -22283,7 +22314,7 @@
 		if (!queue_request(p, req)) {
 			/* the request has been queued for later handling */
 			sip_pvt_unlock(p);
-			ao2_t_ref(p, -1, "release p (from find_call) after queueing request");
+			dialog_unref(p, "release p (from find_call) after queueing request");
 			ast_mutex_unlock(&netlock);
 			return 1;
 		}
@@ -22296,7 +22327,7 @@
 		/* XXX We could add retry-after to make sure they come back */
 		append_history(p, "LockFail", "Owner lock failed, transaction failed.");
 		sip_pvt_unlock(p);
-		ao2_t_ref(p, -1, "release p (from find_call) at end of lockretry"); /* p is gone after the return */
+		dialog_unref(p, "release p (from find_call) at end of lockretry"); /* p is gone after the return */
 		ast_mutex_unlock(&netlock);
 		return 1;
 	}
@@ -22320,7 +22351,7 @@
 	if (p->owner && !nounlock)
 		ast_channel_unlock(p->owner);
 	sip_pvt_unlock(p);
-	ao2_t_ref(p, -1, "throw away dialog ptr from find_call at end of routine"); /* p is gone after the return */
+	dialog_unref(p, "throw away dialog ptr from find_call at end of routine"); /* p is gone after the return */
 	ast_mutex_unlock(&netlock);
 	return 1;
 }
@@ -22613,8 +22644,7 @@
 		if (create_addr_from_peer(p, peer)) {
 			/* Maybe they're not registered, etc. */
 			dialog_unlink_all(p, TRUE, TRUE);
-			dialog_unref(p, "unref dialog p just created via sip_alloc");
-			/* sip_destroy(p); */
+			dialog_unref(p, "destroy dialog");
 			return 0;
 		}
 		/* Recalculate our side, and recalculate Call ID */
@@ -22819,9 +22849,9 @@
 	}
 
 	if (p->stimer->st_active == TRUE) {
+		ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid);
 		AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid,
 				dialog_unref(p, "Removing session timer ref"));
-		ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid);
 		start_session_timer(p);
 	}
 }
@@ -22831,15 +22861,16 @@
 static void stop_session_timer(struct sip_pvt *p)
 {
 	if (!p->stimer) {
-		ast_log(LOG_WARNING, "Null stimer in stop_session_timer - %s\n", p->callid);
 		return;
 	}
 
 	if (p->stimer->st_active == TRUE) {
 		p->stimer->st_active = FALSE;
-		AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid,
+		if (p->stimer->st_schedid > -1) {
+			ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid);
+			AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid,
 				dialog_unref(p, "removing session timer ref"));
-		ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid);
+		}
 	}
 }
 
@@ -22852,13 +22883,22 @@
 		return;
 	}
 
-	p->stimer->st_schedid  = ast_sched_add(sched, p->stimer->st_interval * 1000 / 2, proc_session_timer, 
-			dialog_ref(p, "adding session timer ref"));
+	if (p->stimer->st_schedid > -1) {
+		/* in the event a timer is already going, stop it */
+		ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid);
+		AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid,
+			dialog_unref(p, "unref stimer->st_schedid from dialog"));
+	}
+
+	p->stimer->st_schedid = ast_sched_add(sched, p->stimer->st_interval * 1000 / 2, proc_session_timer,
+		dialog_ref(p, "adding session timer ref"));
 	if (p->stimer->st_schedid < 0) {
 		dialog_unref(p, "removing session timer ref");
-		ast_log(LOG_ERROR, "ast_sched_add failed.\n");
+		ast_log(LOG_ERROR, "ast_sched_add failed - %s\n", p->callid);
+	} else {
+		p->stimer->st_active = TRUE;
+		ast_debug(2, "Session timer started: %d - %s in %d ms\n", p->stimer->st_schedid, p->callid, p->stimer->st_interval * 500);
 	}
-	ast_debug(2, "Session timer started: %d - %s\n", p->stimer->st_schedid, p->callid);
 }
 
 
@@ -22930,8 +22970,9 @@
 	if (!res) {
 		/* An error occurred.  Stop session timer processing */
 		if (p->stimer) {
+			ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid);
 			p->stimer->st_schedid = -1;
-			stop_session_timer(p);
+			p->stimer->st_active = FALSE;
 		}
 
 		/* If we are not asking to be rescheduled, then we need to release our
@@ -23146,9 +23187,8 @@
 	}
 
 	if (peer->call) {
-		dialog_unlink_all(peer->call, TRUE, TRUE);
-		peer->call = dialog_unref(peer->call, "unref dialog peer->call");
-		/* peer->call = sip_destroy(peer->call);*/
+		dialog_unref(peer->call, "unref dialog peer->call");
+		peer->call = dialog_unlink_all(peer->call, TRUE, TRUE);
 	}
 
 	/* Don't send a devstate change if nothing changed. */
@@ -23196,9 +23236,8 @@
 		if (sipdebug) {
 			ast_log(LOG_NOTICE, "Still have a QUALIFY dialog active, deleting\n");
 		}
-		dialog_unlink_all(peer->call, TRUE, TRUE);
-		peer->call = dialog_unref(peer->call, "unref dialog peer->call");
-		/* peer->call = sip_destroy(peer->call); */
+		dialog_unref(peer->call, "unref dialog peer->call");
+		peer->call = dialog_unlink_all(peer->call, TRUE, TRUE);
 	}
 	if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS, NULL))) {
 		return -1;
@@ -23242,6 +23281,7 @@
 #endif
 	peer->ps = ast_tvnow();
 	if (xmitres == XMIT_ERROR) {
+		ref_peer(peer, "add ref for peerexpire (fake, for sip_poke_noanswer to remove");
 		sip_poke_noanswer(peer);	/* Immediately unreachable, network problems */
 	} else if (!force) {
 		AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, peer->maxms * 2, sip_poke_noanswer, peer,
@@ -23249,7 +23289,6 @@
 				unref_peer(peer, "removing poke peer ref"),
 				ref_peer(peer, "adding poke peer ref"));
 	}
-	dialog_unref(p, "unref dialog at end of sip_poke_peer, obtained from sip_alloc, just before it goes out of scope");
 	return 0;
 }
 
@@ -23405,8 +23444,7 @@
 
 	if (!(p->options = ast_calloc(1, sizeof(*p->options)))) {
 		dialog_unlink_all(p, TRUE, TRUE);
-		dialog_unref(p, "unref dialog p from mem fail");
-		/* sip_destroy(p); */
+		dialog_unref(p, "destroy dialog");
 		ast_log(LOG_ERROR, "Unable to build option SIP data structure - Out of memory\n");
 		*cause = AST_CAUSE_SWITCH_CONGESTION;
 		return NULL;
@@ -23475,8 +23513,7 @@
 		*cause = AST_CAUSE_UNREGISTERED;
 		ast_debug(3, "Cant create SIP call - target device not registered\n");
 		dialog_unlink_all(p, TRUE, TRUE);
-		dialog_unref(p, "unref dialog p UNREGISTERED");
-		/* sip_destroy(p); */
+		dialog_unref(p, "destroy dialog");
 		return NULL;
 	}
 	if (ast_strlen_zero(p->peername) && ext)
@@ -23519,9 +23556,8 @@
 	sip_pvt_unlock(p);
 	if (!tmpc) {
 		dialog_unlink_all(p, TRUE, TRUE);
-		/* sip_destroy(p); */
+		dialog_unref(p, "destroy dialog");
 	}
-	dialog_unref(p, "toss pvt ptr at end of sip_request_call");
 	ast_update_use_count();
 	restart_monitor();
 	return tmpc;
@@ -23965,7 +24001,7 @@
 		return NULL;
 
 	if (ast_string_field_init(peer, 512)) {
-		ao2_t_ref(peer, -1, "failed to string_field_init, drop peer");
+		unref_peer(peer, "failed to string_field_init, drop peer");
 		return NULL;
 	}
 
@@ -24061,7 +24097,7 @@
 			return NULL;
 
 		if (ast_string_field_init(peer, 512)) {
-			ao2_t_ref(peer, -1, "failed to string_field_init, drop peer");
+			unref_peer(peer, "failed to string_field_init, drop peer");
 			return NULL;
 		}
 
@@ -26175,6 +26211,7 @@
 static int unload_module(void)
 {
 	struct sip_pvt *p;
+	struct sip_peer *peer;
 	struct sip_threadinfo *th;
 	struct ast_context *con;
 	struct ao2_iterator i;
@@ -26233,7 +26270,7 @@
 	while ((p = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
 		if (p->owner)
 			ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
-		ao2_t_ref(p, -1, "toss dialog ptr from iterator_next");
+		dialog_unref(p, "toss dialog ptr from iterator_next");
 	}
 	ao2_iterator_destroy(&i);
 
@@ -26250,10 +26287,25 @@
 	i = ao2_iterator_init(dialogs, 0);
 	while ((p = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
 		dialog_unlink_all(p, TRUE, TRUE);
-		ao2_t_ref(p, -1, "throw away iterator result"); 
+		dialog_unref(p, "throw away iterator result"); 
+		p = dialog_unref(p, "destroy dialog");
 	}
 	ao2_iterator_destroy(&i);
 
+	/* Destroy all the peers and free their memory */
+	i = ao2_iterator_init(peers, 0);
+	while ((peer = ao2_t_iterator_next(&i, "iterate thru peers"))) {
+		if (peer->pokeexpire > -1) {
+			AST_SCHED_DEL_UNREF(sched, peer->pokeexpire, unref_peer(peer, "remove poke peer ref"));
+		}
+		if (peer->expire > -1) {
+			AST_SCHED_DEL_UNREF(sched, peer->expire, unref_peer(peer, "remove registration ref"));
+		}
+		unlink_peer_from_tables(peer);
+		unref_peer(peer, "throw away iterator result");
+	}
+	ao2_iterator_destroy(&i);
+
 	/* Free memory for local network address mask */
 	ast_free_ha(localaddr);
 
Index: include/asterisk/rtp.h
===================================================================
--- include/asterisk/rtp.h	(revision 307181)
+++ include/asterisk/rtp.h	(working copy)
@@ -202,6 +202,10 @@
 
 struct ast_frame *ast_rtp_read(struct ast_rtp *rtp);
 
+int ast_rtcp_write(const void *data);
+
+int ast_rtp_red_write(const void *data);
+
 struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp);
 
 int ast_rtp_fd(struct ast_rtp *rtp);
Index: include/asterisk/sched.h
===================================================================
--- include/asterisk/sched.h	(revision 307181)
+++ include/asterisk/sched.h	(working copy)
@@ -162,8 +162,8 @@
 
 struct ast_cb_names {
 	int numassocs;
-	char *list[10];
-	ast_sched_cb cblist[10];
+	char *list[18];
+	ast_sched_cb cblist[18];
 };
 
 /*!
Index: main/rtp.c
===================================================================
--- main/rtp.c	(revision 307181)
+++ main/rtp.c	(working copy)
@@ -179,7 +179,6 @@
 };
 
 static struct ast_frame *red_t140_to_red(struct rtp_red *red);
-static int red_write(const void *data);
  
 struct rtp_red {
 	struct ast_frame t140;  /*!< Primary data  */
@@ -199,7 +198,6 @@
 AST_LIST_HEAD_NOLOCK(frame_list, ast_frame);
 
 /* Forward declarations */
-static int ast_rtcp_write(const void *data);
 static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw);
 static int ast_rtcp_write_sr(const void *data);
 static int ast_rtcp_write_rr(const void *data);
@@ -3612,7 +3610,7 @@
 /*! \brief Write and RTCP packet to the far end
  * \note Decide if we are going to send an SR (with Reception Block) or RR 
  * RR is sent if we have not sent any rtp packets in the previous interval */
-static int ast_rtcp_write(const void *data)
+int ast_rtcp_write(const void *data)
 {
 	struct ast_rtp *rtp = (struct ast_rtp *)data;
 	int res;
@@ -4883,7 +4881,7 @@
 /*! \brief Write t140 redundacy frame 
  * \param data primary data to be buffered
  */
-static int red_write(const void *data)
+int ast_rtp_red_write(const void *data)
 {
 	struct ast_rtp *rtp = (struct ast_rtp*) data;
 	
@@ -4966,7 +4964,7 @@
 		r->t140red_data[x*4] = r->pt[x];
 	}
 	r->t140red_data[x*4] = r->pt[x] = red_data_pt[x]; /* primary pt */
-	r->schedid = ast_sched_add(rtp->sched, ti, red_write, rtp);
+	r->schedid = ast_sched_add(rtp->sched, ti, ast_rtp_red_write, rtp);
 	rtp->red = r;
 
 	r->t140.datalen = 0;
Index: main/sched.c
===================================================================
--- main/sched.c	(revision 307181)
+++ main/sched.c	(working copy)
@@ -539,7 +539,7 @@
 		ast_str_append(buf, 0, "    %s : %d\n", cbnames->list[i], countlist[i]);
 	}
 
-	ast_str_append(buf, 0, "   <unknown> : %d\n", countlist[cbnames->numassocs]);
+	ast_str_append(buf, 0, "    <unknown> : %d\n", countlist[cbnames->numassocs]);
 }
 	
 /*! \brief Dump the contents of the scheduler to LOG_DEBUG */
