Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 61305) +++ channels/chan_sip.c (working copy) @@ -861,6 +861,11 @@ ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer); } peerl; +/*! \brief List of peers to be destroyed ---*/ +static struct ast_peer_destroy_list { + ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer); +} peerdestroyl; + /*! \brief The register list: Other SIP proxys we register with and call ---*/ static struct ast_register_list { ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry); @@ -1646,7 +1651,9 @@ } } -/*! \brief sip_destroy_peer: Destroy peer object from memory */ +/*! \brief sip_destroy_peer: Immediately destroy peer object from memory + should only be used from monitor thread or when monitor thread is not running + in other cases, sip_queue_destroy_peer should be used */ static void sip_destroy_peer(struct sip_peer *peer) { /* Delete it, it needs to disappear */ @@ -1676,6 +1683,16 @@ free(peer); } +/*! \brief sip_queue_destroy_peer: Queue peer for destruction */ +static void sip_queue_destroy_peer(struct sip_peer *peer) +{ + ASTOBJ_INIT(peer); + ASTOBJ_RDLOCK(&peerdestroyl); + ASTOBJ_CONTAINER_LINK(&peerdestroyl, peer); + ASTOBJ_UNREF(peer, sip_destroy_peer); + ASTOBJ_UNLOCK(&peerdestroyl); +} + /*! \brief update_peer: Update peer data in database (if used) ---*/ static void update_peer(struct sip_peer *p, int expiry) { @@ -1962,7 +1979,7 @@ if (p) { found++; if (create_addr_from_peer(dialog, p)) - ASTOBJ_UNREF(p, sip_destroy_peer); + ASTOBJ_UNREF(p, sip_queue_destroy_peer); } if (!p) { if (found) @@ -1996,7 +2013,7 @@ return -1; } } else { - ASTOBJ_UNREF(p, sip_destroy_peer); + ASTOBJ_UNREF(p, sip_queue_destroy_peer); return 0; } } @@ -2274,7 +2291,7 @@ if (u) ASTOBJ_UNREF(u,sip_destroy_user); else - ASTOBJ_UNREF(p,sip_destroy_peer); + ASTOBJ_UNREF(p,sip_queue_destroy_peer); return -1; } } @@ -2290,7 +2307,7 @@ if (u) ASTOBJ_UNREF(u,sip_destroy_user); else - ASTOBJ_UNREF(p,sip_destroy_peer); + ASTOBJ_UNREF(p,sip_queue_destroy_peer); return 0; } @@ -5866,7 +5883,8 @@ */ if (ast_test_flag(peer, SIP_SELFDESTRUCT) || ast_test_flag((&peer->flags_page2), SIP_PAGE2_RTAUTOCLEAR)) { peer = ASTOBJ_CONTAINER_UNLINK(&peerl, peer); /* Remove from peer list */ - ASTOBJ_UNREF(peer, sip_destroy_peer); + if(peer) /* Somebody might have gotten to it before us */ + ASTOBJ_UNREF(peer, sip_queue_destroy_peer); } return 0; @@ -6630,7 +6648,7 @@ if (!(peer && ast_apply_ha(peer->ha, sin))) { /* Peer fails ACL check */ if (peer) - ASTOBJ_UNREF(peer,sip_destroy_peer); + ASTOBJ_UNREF(peer,sip_queue_destroy_peer); peer = NULL; } if (peer) { @@ -6727,7 +6745,7 @@ } } if (peer) - ASTOBJ_UNREF(peer,sip_destroy_peer); + ASTOBJ_UNREF(peer,sip_queue_destroy_peer); return res; } @@ -7444,7 +7462,7 @@ else p->noncodeccapability &= ~AST_RTP_DTMF; } - ASTOBJ_UNREF(peer,sip_destroy_peer); + ASTOBJ_UNREF(peer,sip_queue_destroy_peer); } else { if (debug) ast_verbose("Found no matching peer or user for '%s:%d'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port)); @@ -7987,7 +8005,7 @@ ASTOBJ_UNLOCK(iterator); } while (0) ); if (pruned) { - ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, sip_destroy_peer); + ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, sip_queue_destroy_peer); ast_cli(fd, "%d peers pruned.\n", pruned); } else ast_cli(fd, "No peers found to prune.\n"); @@ -8024,7 +8042,7 @@ ASTOBJ_CONTAINER_LINK(&peerl, peer); } else ast_cli(fd, "Peer '%s' pruned.\n", name); - ASTOBJ_UNREF(peer, sip_destroy_peer); + ASTOBJ_UNREF(peer, sip_queue_destroy_peer); } else ast_cli(fd, "Peer '%s' not found.\n", name); } @@ -8242,7 +8260,7 @@ ast_cli(fd, " %s = %s\n", v->name, v->value); } ast_cli(fd,"\n"); - ASTOBJ_UNREF(peer,sip_destroy_peer); + ASTOBJ_UNREF(peer,sip_queue_destroy_peer); } else if (peer && type == 1) { /* manager listing */ ast_cli(fd, "Channeltype: SIP\r\n"); ast_cli(fd, "ObjectName: %s\r\n", peer->name); @@ -8310,7 +8328,7 @@ } } - ASTOBJ_UNREF(peer,sip_destroy_peer); + ASTOBJ_UNREF(peer,sip_queue_destroy_peer); } else { ast_cli(fd,"Peer %s not found.\n", argv[3]); @@ -8998,7 +9016,7 @@ sipdebug |= SIP_DEBUG_CONSOLE; } else ast_cli(fd, "Unable to get IP address of peer '%s'\n", argv[3]); - ASTOBJ_UNREF(peer,sip_destroy_peer); + ASTOBJ_UNREF(peer,sip_queue_destroy_peer); } else ast_cli(fd, "No such peer '%s'\n", argv[3]); return RESULT_SUCCESS; @@ -9554,7 +9572,7 @@ } ret = buf; - ASTOBJ_UNREF(peer, sip_destroy_peer); + ASTOBJ_UNREF(peer, sip_queue_destroy_peer); return ret; } @@ -11694,6 +11712,8 @@ ast_log(LOG_DEBUG, "chan_sip: ast_sched_runq ran %d all at once\n", res); } + ASTOBJ_CONTAINER_DESTROYALL(&peerdestroyl, sip_destroy_peer); + /* needs work to send mwi to realtime peers */ time(&t); fastrestart = 0; @@ -11891,7 +11911,7 @@ /* there is no address, it's unavailable */ res = AST_DEVICE_UNAVAILABLE; } - ASTOBJ_UNREF(p,sip_destroy_peer); + ASTOBJ_UNREF(p,sip_queue_destroy_peer); } else { hp = ast_gethostbyname(host, &ahp); if (hp) @@ -12534,7 +12554,7 @@ ast_clear_flag(&peer->flags_page2, SIP_PAGE2_DYNAMIC); if (!obproxyfound || !strcasecmp(v->name, "outboundproxy")) { if (ast_get_ip_or_srv(&peer->addr, v->value, srvlookup ? "_sip._udp" : NULL)) { - ASTOBJ_UNREF(peer, sip_destroy_peer); + ASTOBJ_UNREF(peer, sip_queue_destroy_peer); return NULL; } } @@ -12548,7 +12568,7 @@ } } else if (!strcasecmp(v->name, "defaultip")) { if (ast_get_ip(&peer->defaddr, v->value)) { - ASTOBJ_UNREF(peer, sip_destroy_peer); + ASTOBJ_UNREF(peer, sip_queue_destroy_peer); return NULL; } } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) { @@ -12965,7 +12985,7 @@ peer = build_peer(cat, ast_variable_browse(cfg, cat), 0); if (peer) { ASTOBJ_CONTAINER_LINK(&peerl,peer); - ASTOBJ_UNREF(peer, sip_destroy_peer); + ASTOBJ_UNREF(peer, sip_queue_destroy_peer); } } else if (strcasecmp(utype, "user")) { ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, "sip.conf"); @@ -13523,6 +13543,7 @@ { ASTOBJ_CONTAINER_INIT(&userl); /* User object list */ ASTOBJ_CONTAINER_INIT(&peerl); /* Peer object list */ + ASTOBJ_CONTAINER_INIT(&peerdestroyl); ASTOBJ_CONTAINER_INIT(®l); /* Registry object list */ sched = sched_context_create(); @@ -13649,6 +13670,8 @@ ASTOBJ_CONTAINER_DESTROY(&userl); ASTOBJ_CONTAINER_DESTROYALL(&peerl, sip_destroy_peer); ASTOBJ_CONTAINER_DESTROY(&peerl); + ASTOBJ_CONTAINER_DESTROYALL(&peerdestroyl, sip_destroy_peer); + ASTOBJ_CONTAINER_DESTROY(&peerdestroyl); ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy); ASTOBJ_CONTAINER_DESTROY(®l);