]> granicus.if.org Git - transmission/commitdiff
#5891: Fix crash on session shutdown (evdns_getaddrinfo_cancel)
authorMike Gelfand <mikedld@mikedld.com>
Thu, 31 Dec 2015 14:17:37 +0000 (14:17 +0000)
committerMike Gelfand <mikedld@mikedld.com>
Thu, 31 Dec 2015 14:17:37 +0000 (14:17 +0000)
libtransmission/announcer-udp.c
libtransmission/session.c
libtransmission/trevent.c

index a09e8c392a3075334ace361dce917e260b4e3d3d..3b7c41341c61823b6140231725b36d18050e9ed3 100644 (file)
@@ -451,10 +451,10 @@ static void tau_tracker_upkeep (struct tau_tracker *);
 static void
 tau_tracker_free (struct tau_tracker * t)
 {
+    assert (t->dns_request == NULL);
+
     if (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->scrapes, (PtrArrayForeachFunc)tau_scrape_request_free);
     tr_free (t->host);
@@ -500,7 +500,7 @@ tau_tracker_on_dns (int errcode, struct evutil_addrinfo *addr, void * vtracker)
     if (errcode)
     {
         char * errmsg = tr_strdup_printf (_("DNS Lookup failed: %s"),
-                                          evdns_err_to_string (errcode));
+                                          evutil_gai_strerror (errcode));
         dbgmsg (tracker->key, "%s", errmsg);
         tau_tracker_fail_all (tracker, false, false, errmsg);
         tr_free (errmsg);
@@ -654,16 +654,18 @@ static bool
 tau_tracker_is_idle (const struct tau_tracker * tracker)
 {
     return tr_ptrArrayEmpty (&tracker->announces)
-        && tr_ptrArrayEmpty (&tracker->scrapes);
+        && tr_ptrArrayEmpty (&tracker->scrapes)
+        && tracker->dns_request == NULL;
 }
 
 static void
 tau_tracker_upkeep (struct tau_tracker * tracker)
 {
     const time_t now = tr_time ();
+    const bool closing = tracker->close_at != 0;
 
     /* 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");
         evutil_freeaddrinfo (tracker->addr);
         tracker->addr = NULL;
@@ -674,7 +676,7 @@ tau_tracker_upkeep (struct tau_tracker * tracker)
         return;
 
     /* 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;
         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)
         {
             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;
             tau_tracker_upkeep (tracker);
         }
index 2fe45a2be7285787cfef24059fab842455ec9bee..146c0fd02af29fff0143cc9dec36780c3fa8cd72 100644 (file)
@@ -1781,13 +1781,10 @@ compareTorrentByCur (const void * va, const void * vb)
 static void closeBlocklists (tr_session *);
 
 static void
-sessionCloseImpl (void * vsession)
+sessionCloseImplStart (tr_session * session)
 {
   int i, n;
   tr_torrent ** torrents;
-  tr_session * session = vsession;
-
-  assert (tr_isSession (session));
 
   session->isClosing = true;
 
@@ -1829,15 +1826,11 @@ sessionCloseImpl (void * vsession)
 
   tr_cacheFree (session->cache);
   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: */
   evdns_base_free (session->evdns_base, 0);
   session->evdns_base = NULL;
@@ -1854,6 +1847,42 @@ sessionCloseImpl (void * vsession)
   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
 deadlineReached (const time_t deadline)
 {
index d3cfbe44618f41b692a4ecf2688023776a43b97a..8fc0d06c8a9bd97b682e8a0450c7783db8485997 100644 (file)
@@ -203,6 +203,8 @@ readFromPipe (evutil_socket_t   fd,
         {
             dbgmsg ("pipe eof reached... removing event listener");
             event_free (eh->pipeEvent);
+            tr_netCloseSocket (eh->fds[0]);
+            event_base_loopexit (eh->base, NULL);
             break;
         }