Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 307669)
+++ channels/chan_sip.c	(working copy)
@@ -1324,6 +1324,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);
 
 /*--- Device monitoring and Device/extension state/event handling */
 static int cb_extensionstate(char *context, char* exten, int state, void *data);
@@ -1535,6 +1536,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);
@@ -2657,15 +2659,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;
 }
 
@@ -2706,6 +2716,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");
@@ -2722,9 +2737,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);
@@ -2768,6 +2783,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;
 }
@@ -3630,15 +3647,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;
 }
@@ -3697,22 +3712,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
@@ -4312,14 +4320,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) {
@@ -5258,8 +5266,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);
@@ -5289,7 +5296,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;
 	}
@@ -5365,17 +5375,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;
@@ -6321,7 +6320,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));
@@ -7083,12 +7082,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;
 	}
 
@@ -7163,16 +7161,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;
 	}
@@ -7422,7 +7410,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)
 {
@@ -7558,6 +7546,7 @@
 			if ((p = sip_alloc(callid, addr, 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.
@@ -9729,7 +9718,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);
@@ -11370,7 +11358,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);
@@ -11612,7 +11600,7 @@
 	/* 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;
 	}
 
@@ -12067,8 +12055,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;
 	}
@@ -12344,7 +12331,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 */
 		}
@@ -12374,7 +12361,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"),
@@ -12389,6 +12376,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);
 
@@ -12405,8 +12394,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);
 		}
@@ -12533,7 +12522,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;
 }
 
@@ -15089,7 +15078,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 */
 		}
 
@@ -15560,7 +15549,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);
@@ -15766,6 +15755,7 @@
 
 		peerarray[total_peers++] = peer;
 		ao2_unlock(peer);
+		unref_peer(peer, "toss iterator peer ptr");
 	}
 	ao2_iterator_destroy(&i);
 	
@@ -15780,7 +15770,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;
 		}
 
@@ -15848,7 +15837,6 @@
 			realtimepeers ? (peer->is_realtime ? "yes":"no") : "no");
 		}
 		ao2_unlock(peer);
-		unref_peer(peer, "toss iterator peer ptr");
 	}
 	
 	if (!s)
@@ -16043,10 +16031,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);
@@ -16644,7 +16631,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);
@@ -16753,24 +16740,49 @@
 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 = {19,
+		{
+		"__sip_autodestruct",
+		"ast_cc_available_timer_expire",
+		"auto_congest",
+		"expire_register",
+		"network_change_event_sched_cb",
+		"proc_session_timer",
+		"publish_expire",
+		"retrans_pkt",
+		"scheduler_process_request_queue",
+		"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,
+		scheduler_process_request_queue,
+		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:
@@ -17576,7 +17588,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);
 
@@ -17633,7 +17645,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);
 
@@ -17978,8 +17990,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;
 		}
@@ -21673,7 +21684,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
@@ -21757,6 +21768,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);
@@ -21863,7 +21878,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;
 	}
 
@@ -22005,7 +22020,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;
 }
 
@@ -22455,6 +22470,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;
 			}
@@ -23447,8 +23466,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");
@@ -24056,7 +24074,7 @@
 		ast_mutex_lock(&netlock);
 
 		/* Find the active SIP dialog or create a new one */
-		p = find_call(req, addr, req->method);	/* returns p locked */
+		p = find_call(req, addr, 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);
@@ -24072,7 +24090,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);
@@ -24087,7 +24105,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;
 		}
@@ -24100,7 +24118,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;
 	}
@@ -24124,7 +24142,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;
 }
@@ -24381,8 +24399,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 */
@@ -24579,9 +24596,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);
 	}
 }
@@ -24591,15 +24608,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);
+		}
 	}
 }
 
@@ -24612,13 +24630,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_debug(2, "Session timer started: %d - %s\n", p->stimer->st_schedid, p->callid);
+		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);
+	}	
 }
 
 
@@ -24690,8 +24717,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
@@ -24892,9 +24920,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. */
@@ -24942,9 +24969,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;
@@ -24989,6 +25015,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,
@@ -24996,7 +25023,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;
 }
 
@@ -25169,8 +25195,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;
@@ -25258,8 +25283,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)
@@ -25302,9 +25326,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;
@@ -25764,12 +25787,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;
 	}
 
@@ -25870,12 +25893,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;
 		}
 
@@ -26579,7 +26602,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"));
@@ -28884,7 +28907,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;
 	}
 
@@ -28914,6 +28937,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;
@@ -28983,7 +29007,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);
 
@@ -29000,10 +29024,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);
 
@@ -29036,6 +29075,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 307669)
+++ channels/sip/include/sip.h	(working copy)
@@ -1775,4 +1775,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 307669)
+++ 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 307669)
+++ 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 */
