return NULL;
}
-/* this func is used with ao2_callback to unlink/delete all marked
- peers */
-static int peer_is_marked(void *peerobj, void *arg, int flags)
-{
- struct sip_peer *peer = peerobj;
- if (peer->the_mark && peer->pokeexpire != -1) {
- AST_SCHED_DEL(sched, peer->pokeexpire);
- }
- return peer->the_mark ? CMP_MATCH : 0;
-}
-
-
-/* \brief Unlink all marked peers from ao2 containers */
-static void unlink_marked_peers_from_tables(void)
+#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)
{
- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
- "initiating callback to remove marked peers");
- ao2_t_callback(peers_by_ip, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL,
- "initiating callback to remove marked peers");
+ 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;
}
-/* \brief Unlink single peer from all ao2 containers */
-static void unlink_peer_from_tables(struct sip_peer *peer)
+static struct sip_peer *_unref_peer(struct sip_peer *peer, char *tag, char *file, int line, const char *func)
{
- ao2_t_unlink(peers, peer, "ao2_unlink of peer from peers table");
- if (peer->addr.sin_addr.s_addr) {
- ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table");
- }
+ 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
ao2_t_ref(peer, 1, tag);
return peer;
}
+#endif /* REF_DEBUG */
+
+static void peer_sched_cleanup(struct sip_peer *peer)
+{
+ if (peer->pokeexpire != -1) {
+ AST_SCHED_DEL_UNREF(sched, peer->pokeexpire,
+ unref_peer(peer, "removing poke peer ref"));
+ }
+ if (peer->expire != -1) {
+ AST_SCHED_DEL_UNREF(sched, peer->expire,
+ unref_peer(peer, "remove register expire ref"));
+ }
+}
+
+typedef enum {
+ SIP_PEERS_MARKED,
+ SIP_PEERS_ALL,
+} peer_unlink_flag_t;
+
+/* this func is used with ao2_callback to unlink/delete all marked or linked
+ peers, depending on arg */
+static int match_and_cleanup_peer_sched(void *peerobj, void *arg, int flags)
+{
+ struct sip_peer *peer = peerobj;
+ peer_unlink_flag_t which = *(peer_unlink_flag_t *)arg;
+
+ if (which == SIP_PEERS_ALL || peer->the_mark) {
+ peer_sched_cleanup(peer);
+ return CMP_MATCH;
+ }
+ return 0;
+}
+
+static void unlink_peers_from_tables(peer_unlink_flag_t flag)
+{
+ ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
+ match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers");
+ ao2_t_callback(peers_by_ip, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
+ match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers");
+}
+
+/* \brief Unlink all marked peers from ao2 containers */
+static void unlink_marked_peers_from_tables(void)
+{
+ unlink_peers_from_tables(SIP_PEERS_MARKED);
+}
+
+static void unlink_all_peers_from_tables(void)
+{
+ unlink_peers_from_tables(SIP_PEERS_ALL);
+}
+
+/* \brief Unlink single peer from all ao2 containers */
+static void unlink_peer_from_tables(struct sip_peer *peer)
+{
+ ao2_t_unlink(peers, peer, "ao2_unlink of peer from peers table");
+ if (peer->addr.sin_addr.s_addr) {
+ ao2_t_unlink(peers_by_ip, peer, "ao2_unlink of peer from peers_by_ip table");
+ }
+}
/*! \brief maintain proper refcounts for a sip_pvt's outboundproxy
*
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"));
}
+ if (dialog->stimer) {
+ 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;
}
*/
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
{
struct sip_request *req;
- if (p->stimer) {
+ /* Destroy Session-Timers if allocated */
+ if (p->stimer) {
+ p->stimer->quit_flag = 1;
+ stop_session_timer(p);
ast_free(p->stimer);
p->stimer = NULL;
}
}
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;
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, ¶meters, sizeof(parameters));
/*! \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)
{
if (sip_pvt_trylock(p)) {
ao2_unlock(dialogs);
usleep(1);
+ p = dialog_unref(p, "pedantic linear search for dialog unref to restart search");
goto restartsearch;
}
ao2_unlock(dialogs);
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);
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);
ao2_lock(peer);
if (havepattern && regexec(®exbuf, peer->name, 0, NULL, 0)) {
ao2_unlock(peer);
- unref_peer(peer, "toss iterator peer ptr before continue");
+ peer = peerarray[k] = unref_peer(peer, "toss iterator peer ptr before continue");
continue;
}
realtimepeers ? (peer->is_realtime ? "yes":"no") : "no");
}
ao2_unlock(peer);
- unref_peer(peer, "toss iterator peer ptr");
+ peer = peerarray[k] = unref_peer(peer, "toss iterator peer ptr");
}
if (!s)
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);
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);
if (pkt->seqno == p->lastinvite && pkt->response_code == 487) {
AST_SCHED_DEL(sched, pkt->retransid);
UNLINK(pkt, p->packets, prev_pkt);
+ dialog_unref(pkt->owner, "unref packet->owner from dialog");
+ if (pkt->data) {
+ ast_free(pkt->data);
+ }
ast_free(pkt);
break;
}
return 0;
}
+ /* At this point, if we have an authpeer (which we have to have to get here) we should unref
+ * it since if we have actually used it, we have reffed it when p->relatedpeer was set. */
+ authpeer = unref_peer(authpeer, "unref pointer into (*authpeer)");
+
/* Add subscription for extension state from the PBX core */
if (p->subscribed != MWI_NOTIFICATION && !resubscribe) {
if (p->stateid > -1) {
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);
}
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);
}
}
if (p->stimer->st_active == TRUE) {
p->stimer->st_active = FALSE;
+ 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);
}
}
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);
}
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);
}
#endif
peer->ps = ast_tvnow();
if (xmitres == XMIT_ERROR) {
- sip_poke_noanswer(peer); /* Immediately unreachable, network problems */
+ /* Immediately unreachable, network problems */
+ sip_poke_noanswer(ref_peer(peer, "add ref for peerexpire (fake, for sip_poke_noanswer to remove)"));
} else if (!force) {
AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, peer->maxms * 2, sip_poke_noanswer, peer,
unref_peer(_data, "removing poke peer ref"),
}
ao2_iterator_destroy(&i);
+ unlink_all_peers_from_tables();
+
ast_mutex_lock(&monlock);
if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
pthread_cancel(monitor_thread);