#5891: Fix crash on session shutdown (evdns_getaddrinfo_cancel)

This commit is contained in:
Mike Gelfand
2015-12-31 14:17:37 +00:00
parent 7ea2b71ec8
commit d3f5b5d5ab
3 changed files with 53 additions and 18 deletions

View File

@@ -451,10 +451,10 @@ static void tau_tracker_upkeep (struct tau_tracker *);
static void static void
tau_tracker_free (struct tau_tracker * t) tau_tracker_free (struct tau_tracker * t)
{ {
assert (t->dns_request == NULL);
if (t->addr) if (t->addr)
evutil_freeaddrinfo (t->addr); evutil_freeaddrinfo (t->addr);
if (t->dns_request != NULL)
evdns_getaddrinfo_cancel (t->dns_request);
tr_ptrArrayDestruct (&t->announces, (PtrArrayForeachFunc)tau_announce_request_free); tr_ptrArrayDestruct (&t->announces, (PtrArrayForeachFunc)tau_announce_request_free);
tr_ptrArrayDestruct (&t->scrapes, (PtrArrayForeachFunc)tau_scrape_request_free); tr_ptrArrayDestruct (&t->scrapes, (PtrArrayForeachFunc)tau_scrape_request_free);
tr_free (t->host); tr_free (t->host);
@@ -500,7 +500,7 @@ tau_tracker_on_dns (int errcode, struct evutil_addrinfo *addr, void * vtracker)
if (errcode) if (errcode)
{ {
char * errmsg = tr_strdup_printf (_("DNS Lookup failed: %s"), char * errmsg = tr_strdup_printf (_("DNS Lookup failed: %s"),
evdns_err_to_string (errcode)); evutil_gai_strerror (errcode));
dbgmsg (tracker->key, "%s", errmsg); dbgmsg (tracker->key, "%s", errmsg);
tau_tracker_fail_all (tracker, false, false, errmsg); tau_tracker_fail_all (tracker, false, false, errmsg);
tr_free (errmsg); tr_free (errmsg);
@@ -654,16 +654,18 @@ static bool
tau_tracker_is_idle (const struct tau_tracker * tracker) tau_tracker_is_idle (const struct tau_tracker * tracker)
{ {
return tr_ptrArrayEmpty (&tracker->announces) return tr_ptrArrayEmpty (&tracker->announces)
&& tr_ptrArrayEmpty (&tracker->scrapes); && tr_ptrArrayEmpty (&tracker->scrapes)
&& tracker->dns_request == NULL;
} }
static void static void
tau_tracker_upkeep (struct tau_tracker * tracker) tau_tracker_upkeep (struct tau_tracker * tracker)
{ {
const time_t now = tr_time (); const time_t now = tr_time ();
const bool closing = tracker->close_at != 0;
/* if the address info is too old, expire it */ /* if the address info is too old, expire it */
if (tracker->addr && (tracker->addr_expiration_time <= now)) { if (tracker->addr != NULL && (closing || tracker->addr_expiration_time <= now)) {
dbgmsg (tracker->host, "Expiring old DNS result"); dbgmsg (tracker->host, "Expiring old DNS result");
evutil_freeaddrinfo (tracker->addr); evutil_freeaddrinfo (tracker->addr);
tracker->addr = NULL; tracker->addr = NULL;
@@ -674,7 +676,7 @@ tau_tracker_upkeep (struct tau_tracker * tracker)
return; return;
/* if we don't have an address yet, try & get one now. */ /* if we don't have an address yet, try & get one now. */
if (!tracker->addr && (tracker->dns_request == NULL)) if (!closing && tracker->addr == NULL && tracker->dns_request == NULL)
{ {
struct evutil_addrinfo hints; struct evutil_addrinfo hints;
memset (&hints, 0, sizeof (hints)); memset (&hints, 0, sizeof (hints));
@@ -853,6 +855,8 @@ tr_tracker_udp_start_shutdown (tr_session * session)
for (i=0, n=tr_ptrArraySize (&tau->trackers); i<n; ++i) for (i=0, n=tr_ptrArraySize (&tau->trackers); i<n; ++i)
{ {
struct tau_tracker * tracker = tr_ptrArrayNth (&tau->trackers, i); struct tau_tracker * tracker = tr_ptrArrayNth (&tau->trackers, i);
if (tracker->dns_request != NULL)
evdns_getaddrinfo_cancel (tracker->dns_request);
tracker->close_at = now + 3; tracker->close_at = now + 3;
tau_tracker_upkeep (tracker); tau_tracker_upkeep (tracker);
} }

View File

@@ -1781,13 +1781,10 @@ compareTorrentByCur (const void * va, const void * vb)
static void closeBlocklists (tr_session *); static void closeBlocklists (tr_session *);
static void static void
sessionCloseImpl (void * vsession) sessionCloseImplStart (tr_session * session)
{ {
int i, n; int i, n;
tr_torrent ** torrents; tr_torrent ** torrents;
tr_session * session = vsession;
assert (tr_isSession (session));
session->isClosing = true; session->isClosing = true;
@@ -1829,15 +1826,11 @@ sessionCloseImpl (void * vsession)
tr_cacheFree (session->cache); tr_cacheFree (session->cache);
session->cache = NULL; session->cache = NULL;
/* gotta keep udp running long enough to send out all
the &event=stopped UDP tracker messages */
while (!tr_tracker_udp_is_idle (session))
{
tr_tracker_udp_upkeep (session);
tr_wait_msec (100);
} }
static void
sessionCloseImplFinish (tr_session * session)
{
/* we had to wait until UDP trackers were closed before closing these: */ /* we had to wait until UDP trackers were closed before closing these: */
evdns_base_free (session->evdns_base, 0); evdns_base_free (session->evdns_base, 0);
session->evdns_base = NULL; session->evdns_base = NULL;
@@ -1854,6 +1847,42 @@ sessionCloseImpl (void * vsession)
session->isClosed = true; session->isClosed = true;
} }
static void
sessionCloseImplWaitForIdleUdp (evutil_socket_t foo UNUSED,
short bar UNUSED,
void * vsession)
{
tr_session * session = vsession;
assert (tr_isSession (session));
/* gotta keep udp running long enough to send out all
the &event=stopped UDP tracker messages */
if (!tr_tracker_udp_is_idle (session))
{
tr_tracker_udp_upkeep (session);
tr_timerAdd (session->saveTimer, 0, 100000);
return;
}
sessionCloseImplFinish (session);
}
static void
sessionCloseImpl (void * vsession)
{
tr_session * session = vsession;
assert (tr_isSession (session));
sessionCloseImplStart (session);
/* saveTimer is not used at this point, reusing for UDP shutdown wait */
assert (session->saveTimer == NULL);
session->saveTimer = evtimer_new (session->event_base, sessionCloseImplWaitForIdleUdp, session);
tr_timerAdd (session->saveTimer, 0, 0);
}
static int static int
deadlineReached (const time_t deadline) deadlineReached (const time_t deadline)
{ {

View File

@@ -203,6 +203,8 @@ readFromPipe (evutil_socket_t fd,
{ {
dbgmsg ("pipe eof reached... removing event listener"); dbgmsg ("pipe eof reached... removing event listener");
event_free (eh->pipeEvent); event_free (eh->pipeEvent);
tr_netCloseSocket (eh->fds[0]);
event_base_loopexit (eh->base, NULL);
break; break;
} }