Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 318229)
+++ channels/chan_sip.c	(working copy)
@@ -1540,6 +1540,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);
@@ -2806,15 +2807,23 @@
  * By handling them this way, we don't have to declare the
  * destructor on each call, which removes the chance of errors.
  */
-static void *unref_peer(struct sip_peer *peer, char *tag)
+static void *unref_peer_debug(struct sip_peer *peer, char *tag, char *file, int line, const char *func)
 {
+#ifdef REF_DEBUG
+	__ao2_ref_debug(peer, -1, tag, file, line, func);
+#else
 	ao2_t_ref(peer, -1, tag);
+#endif
 	return NULL;
 }
 
-static struct sip_peer *ref_peer(struct sip_peer *peer, char *tag)
+static struct sip_peer *ref_peer_debug(struct sip_peer *peer, char *tag, char *file, int line, const char *func)
 {
+#ifdef REF_DEBUG
+	__ao2_ref_debug(peer, 1, tag, file, line, func);
+#else
 	ao2_t_ref(peer, 1, tag);
+#endif
 	return peer;
 }
 
@@ -2855,6 +2864,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");
@@ -2871,9 +2885,9 @@
 	}
 	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->call = dialog_unref(dialog->registry->call, "unref registry->call from dialog");
 		}
-		dialog->registry = registry_unref(dialog->registry, "delete dialog->registry");
+		dialog->registry = registry_unref(dialog->registry, "unref dialog->registry from registry");
 	}
 	if (dialog->stateid > -1) {
 		ast_extension_state_del(dialog->stateid, NULL);
@@ -2917,6 +2931,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;
 }
@@ -3779,15 +3795,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;
 }
@@ -3846,22 +3860,15 @@
  */
 int sip_cancel_destroy(struct sip_pvt *p)
 {
-	int res = 0;
-
 	if (p->final_destruction_scheduled) {
-		return res;
+		return 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
@@ -4461,14 +4468,14 @@
 
 	/* 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);
 	}
 	
 
 	if (peer->mwipvt) {	/* We have an active subscription, delete it */
 		dialog_unlink_all(peer->mwipvt, TRUE, TRUE);
-		peer->mwipvt = dialog_unref(peer->mwipvt, "unreffing peer->mwipvt");
+		peer->mwipvt = dialog_unref(peer->mwipvt, "destroy dialog");
 	}
 	
 	if (peer->chanvars) {
@@ -5431,8 +5438,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);
@@ -5462,7 +5468,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;
 	}
@@ -5538,17 +5547,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;
@@ -6494,7 +6492,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));
@@ -7257,12 +7255,11 @@
 		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 (!(p->cc_params = ast_cc_config_params_init())) {
-		ao2_t_ref(p, -1, "Yuck, couldn't allocate cc_params struct. Get rid o' p");
+		dialog_unref(p, "Yuck, couldn't allocate cc_params struct. Get rid o' p");
 		return NULL;
 	}
 
@@ -7337,16 +7334,6 @@
 	p->allowed_methods = UINT_MAX;
 
 	if (sip_methods[intended_method].need_rtp) {
-		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
-			if ((p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &bindaddr))) {
-				ast_udptl_setqos(p->udptl, global_tos_audio, global_cos_audio);
-				p->t38_maxdatagram = global_t38_maxdatagram;
-			} else {
-				/* 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);
-			}
-		}
 		p->maxcallbitrate = default_maxcallbitrate;
 		p->autoframing = global_autoframing;
 	}
@@ -7673,7 +7660,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 ast_sockaddr *addr, const int intended_method)
 {
@@ -7802,19 +7789,23 @@
 		if (intended_method == SIP_REFER) {
 			/* We do support REFER, but not outside of a dialog yet */
 			transmit_response_using_temp(callid, addr, 1, intended_method, req, "603 Declined (no dialog)");
-	
-		/* Ok, time to create a new SIP dialog object, a pvt */
-		} else if (!(p = sip_alloc(callid, addr, 1, intended_method, req)))  {
-			/* 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.
+		} else {
+			/* Ok, time to create a new SIP dialog object, a pvt */
+			if ((p = sip_alloc(callid, addr, 1, intended_method, req)))  {
+				/* Ok, we've created a dialog, let's go and process it */
+				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.
 
-				Without a dialog we can't retransmit and handle ACKs and all that, but at least
-				send an error message.
+					Without a dialog we can't retransmit and handle ACKs and all that, but at least
+					send an error message.
 
-				Sorry, we apologize for the inconvienience
-			*/
-			transmit_response_using_temp(callid, addr, 1, intended_method, req, "500 Server internal error");
-			ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
+					Sorry, we apologize for the inconvienience
+				*/
+				transmit_response_using_temp(callid, addr, 1, intended_method, req, "500 Server internal error");
+				ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
+			}
 		}
 		return p; /* can be NULL */
 	} else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
@@ -11617,7 +11608,7 @@
 	if (create_addr(pvt, epa_entry->destination, NULL, TRUE, NULL)) {
 		sip_pvt_unlock(pvt);
 		dialog_unlink_all(pvt, TRUE, TRUE);
-		dialog_unref(pvt, "create_addr failed in transmit_publish. Unref dialog");
+		dialog_unref(pvt, "destroy dialog");
 		return -1;
 	}
 	ast_sip_ouraddrfor(&pvt->sa, &pvt->ourip, pvt);
@@ -11855,23 +11846,23 @@
 	if (!ast_sockaddr_port(&mwi->us) && mwi->portno) {
 		ast_sockaddr_set_port(&mwi->us, mwi->portno);
 	}
-	
+
 	/* Setup the destination of our subscription */
 	if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0, NULL)) {
 		dialog_unlink_all(mwi->call, TRUE, TRUE);
-		mwi->call = dialog_unref(mwi->call, "unref dialog after unlink_all");
+		mwi->call = dialog_unref(mwi->call, "destroy dialog");
 		return 0;
 	}
 
 	mwi->call->expiry = mwi_expiry;
-	
+
 	if (!mwi->dnsmgr && mwi->portno) {
 		ast_sockaddr_set_port(&mwi->call->sa, mwi->portno);
 		ast_sockaddr_set_port(&mwi->call->recv, mwi->portno);
 	} else {
 		mwi->portno = ast_sockaddr_port(&mwi->call->sa);
 	}
-	
+
 	/* Set various other information */
 	if (!ast_strlen_zero(mwi->authuser)) {
 		ast_string_field_set(mwi->call, peername, mwi->authuser);
@@ -11893,7 +11884,7 @@
 	build_via(mwi->call);
 	build_callid_pvt(mwi->call);
 	ast_set_flag(&mwi->call->flags[0], SIP_OUTGOING);
-	
+
 	/* Associate the call with us */
 	mwi->call->mwi = ASTOBJ_REF(mwi);
 
@@ -12314,8 +12305,7 @@
 	if (create_addr(p, channame, NULL, 0, NULL)) {
 		/* 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;
 	}
@@ -12591,7 +12581,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 */
 		}
@@ -12621,7 +12611,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"),
@@ -12636,6 +12626,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);
 
@@ -12652,8 +12644,8 @@
 		}
 
 		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);
 		}
@@ -12780,7 +12772,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;
 }
 
@@ -15330,7 +15322,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 */
 		}
 
@@ -15801,7 +15793,7 @@
 	ast_cli(a->fd, FORMAT, "Username", "Secret", "Accountcode", "Def.Context", "ACL", "ForcerPort");
 
 	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);
@@ -16007,9 +15999,10 @@
 
 		peerarray[total_peers++] = peer;
 		ao2_unlock(peer);
+		unref_peer(peer, "toss iterator peer ptr");
 	}
 	ao2_iterator_destroy(&i);
-	
+
 	qsort(peerarray, total_peers, sizeof(struct sip_peer *), peercomparefunc);
 
 	for(k=0; k < total_peers; k++) {
@@ -16017,11 +16010,10 @@
 		char srch[2000];
 		char pstatus;
 		peer = peerarray[k];
-		
+
 		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;
 		}
 
@@ -16089,9 +16081,8 @@
 			realtimepeers ? (peer->is_realtime ? "yes":"no") : "no");
 		}
 		ao2_unlock(peer);
-		unref_peer(peer, "toss iterator peer ptr");
 	}
-	
+
 	if (!s)
 		ast_cli(fd, "%d sip peers [Monitored: %d online, %d offline Unmonitored: %d online, %d offline]\n",
 		        total_peers, peers_mon_online, peers_mon_offline, peers_unmon_online, peers_unmon_offline);
@@ -16286,10 +16277,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);
@@ -16894,7 +16884,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);
@@ -17003,25 +16993,48 @@
 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 = {18,
+		{
+		"__sip_autodestruct",
+		"ast_cc_available_timer_expire",
+		"auto_congest",
+		"expire_register",
+		"network_change_event_sched_cb",
+		"proc_session_timer",
+		"publish_expire",
+		"retrans_pkt",
+		"send_provisional_keepalive_with_sdp",
+		"send_provisional_keepalive",
+		"sip_poke_noanswer",
+		"sip_poke_peer_s",
+		"sip_reinvite_retry",
+		"sip_reg_timeout",
+		"sip_reregister",
+		"sip_subscribe_mwi_do",
+		"sip_t38_abort",
+		"sip_offer_timer_expire"
+		},
+		{
+		__sip_autodestruct,
+		ast_cc_available_timer_expire,
+		auto_congest,
+		expire_register,
+		network_change_event_sched_cb,
+		proc_session_timer,
+		publish_expire,
+		retrans_pkt,
+		send_provisional_keepalive_with_sdp,
+		send_provisional_keepalive,
+		sip_poke_noanswer,
+		sip_poke_peer_s,
+		sip_reinvite_retry,
+		sip_reg_timeout,
+		sip_reregister,
+		sip_subscribe_mwi_do,
+		sip_t38_abort,
+		sip_offer_timer_expire
+		}};
+
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "sip show sched";
@@ -17831,7 +17844,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);
 
@@ -17888,7 +17901,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);
 
@@ -18233,8 +18246,7 @@
 		if (create_addr(p, a->argv[i], NULL, 1, NULL)) {
 			/* 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;
 		}
@@ -21953,7 +21965,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
@@ -22037,6 +22049,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);
@@ -22142,8 +22158,9 @@
 		ast_clear_flag(&transferer->flags[0], SIP_GOTREFER);
 		transferer->refer->status = REFER_FAILED;
 		sip_pvt_unlock(targetcall_pvt);
-		if (targetcall_pvt)
-			ao2_t_ref(targetcall_pvt, -1, "Drop targetcall_pvt pointer");
+		if (targetcall_pvt) {
+			dialog_unref(targetcall_pvt, "Drop targetcall_pvt pointer");
+		}
 		return -1;
 	}
 
@@ -22285,7 +22302,7 @@
 	ast_party_connected_line_free(&connected_to_target);
 	ast_party_connected_line_free(&connected_to_transferee);
 	if (targetcall_pvt)
-		ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt");
+		dialog_unref(targetcall_pvt, "drop targetcall_pvt");
 	return 1;
 }
 
@@ -22735,6 +22752,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;
 			}
@@ -23727,8 +23748,7 @@
 		if (authpeer->mwipvt && authpeer->mwipvt != p) {	/* Destroy old PVT if this is a new one */
 			/* We only allow one subscription per peer */
 			dialog_unlink_all(authpeer->mwipvt, TRUE, TRUE);
-			authpeer->mwipvt = dialog_unref(authpeer->mwipvt, "unref dialog authpeer->mwipvt");
-			/* sip_destroy(authpeer->mwipvt); */
+			authpeer->mwipvt = dialog_unref(authpeer->mwipvt, "destroy dialog");
 		}
 		if (authpeer->mwipvt)
 			dialog_unref(authpeer->mwipvt, "Unref previously stored mwipvt dialog pointer");
@@ -24288,7 +24308,7 @@
 		ast_channel_unref(owner_chan_ref);
 	}
 	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;
@@ -24546,8 +24566,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 */
@@ -24743,9 +24762,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);
 	}
 }
@@ -24755,15 +24774,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);
+		}
 	}
 }
 
@@ -24776,13 +24796,22 @@
 		return;
 	}
 
+	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\n", p->stimer->st_schedid, p->callid);
 	}
-	ast_debug(2, "Session timer started: %d - %s\n", p->stimer->st_schedid, p->callid);
 }
 
 
@@ -24854,8 +24883,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
@@ -25059,9 +25089,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. */
@@ -25109,9 +25138,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;
@@ -25156,6 +25184,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,
@@ -25163,7 +25192,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;
 }
 
@@ -25336,8 +25364,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;
@@ -25425,8 +25452,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)
@@ -25469,9 +25495,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;
@@ -25931,12 +25956,12 @@
 		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;
 	}
-	
+
 	if (!(peer->cc_params = ast_cc_config_params_init())) {
-		ao2_t_ref(peer, -1, "failed to allocate cc_params for peer");
+		unref_peer(peer, "failed to allocate cc_params for peer");
 		return NULL;
 	}
 
@@ -26036,12 +26061,12 @@
 			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;
 		}
 
 		if (!(peer->cc_params = ast_cc_config_params_init())) {
-			ao2_t_ref(peer, -1, "failed to allocate cc_params for peer");
+			unref_peer(peer, "failed to allocate cc_params for peer");
 			return NULL;
 		}
 
@@ -26745,7 +26770,7 @@
 					ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", iterator->username, iterator->hostname);
 					/* This will also remove references to the registry */
 					dialog_unlink_all(iterator->call, TRUE, TRUE);
-					iterator->call = dialog_unref(iterator->call, "remove iterator->call from registry traversal");
+					iterator->call = dialog_unref(iterator->call, "destroy dialog");
 				}
 				if (iterator->expire > -1) {
 					AST_SCHED_DEL_UNREF(sched, iterator->expire, registry_unref(iterator, "reg ptr unref from reload config"));
@@ -29091,7 +29116,7 @@
 	if (ast_cc_monitor_register(&sip_cc_monitor_callbacks)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	if (!(sip_monitor_instances = ao2_container_alloc(37, sip_monitor_instance_hash_fn, sip_monitor_instance_cmp_fn))) {
+	if (!(sip_monitor_instances = ao2_t_container_alloc(37, sip_monitor_instance_hash_fn, sip_monitor_instance_cmp_fn, "allocate sip_monitor_instances"))) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
@@ -29121,6 +29146,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;
@@ -29190,7 +29216,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);
 
@@ -29207,10 +29233,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);
 
@@ -29243,6 +29284,7 @@
 	ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table");
 	ao2_t_ref(dialogs, -1, "unref the dialogs table");
 	ao2_t_ref(threadt, -1, "unref the thread table");
+	ao2_t_ref(sip_monitor_instances, -1, "unref the sip_monitor_instances table");
 
 	clear_sip_domains();
 	ast_free_ha(sip_cfg.contact_ha);
Index: channels/sip/include/sip.h
===================================================================
--- channels/sip/include/sip.h	(revision 318229)
+++ channels/sip/include/sip.h	(working copy)
@@ -1779,4 +1779,7 @@
 	{ SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED,	"tdialog" },
 };
 
+#define ref_peer(arg1,arg2) ref_peer_debug((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define unref_peer(arg1,arg2) unref_peer_debug((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
 #endif
Index: include/asterisk/sched.h
===================================================================
--- include/asterisk/sched.h	(revision 318229)
+++ 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[20];
+	ast_sched_cb cblist[20];
 };
 
 /*!
Index: main/sched.c
===================================================================
--- main/sched.c	(revision 318229)
+++ main/sched.c	(working copy)
@@ -554,7 +554,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 */
