Commit ca319f63 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Ingmar Runge provided a source snippet that caused a crash. The reason for

the crash was that libcurl internally was a bit confused about who owned the
DNS cache at all times so if you created an easy handle that uses a shared
DNS cache and added that to a multi handle it would crash. Now we keep more
careful internal track of exactly what kind of DNS cache each easy handle
uses: None, Private (allocated for and used only by this single handle),
Shared (points to a cache held by a shared object), Global (points to the
global cache) or Multi (points to the cache within the multi handle that is
automatically shared between all easy handles that are added with private
caches).
parent a09a8164
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -6,6 +6,18 @@


                                  Changelog
                                  Changelog


Daniel (8 July 2006)
- Ingmar Runge provided a source snippet that caused a crash. The reason for
  the crash was that libcurl internally was a bit confused about who owned the
  DNS cache at all times so if you created an easy handle that uses a shared
  DNS cache and added that to a multi handle it would crash. Now we keep more
  careful internal track of exactly what kind of DNS cache each easy handle
  uses: None, Private (allocated for and used only by this single handle),
  Shared (points to a cache held by a shared object), Global (points to the
  global cache) or Multi (points to the cache within the multi handle that is
  automatically shared between all easy handles that are added with private
  caches).

Daniel (4 July 2006)
Daniel (4 July 2006)
- Toshiyuki Maezawa fixed a problem where you couldn't override the
- Toshiyuki Maezawa fixed a problem where you couldn't override the
  Proxy-Connection: header when using a proxy and not doing CONNECT.
  Proxy-Connection: header when using a proxy and not doing CONNECT.
+3 −1
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ This release includes the following changes:


This release includes the following bugfixes:
This release includes the following bugfixes:


 o an easy handle with shared DNS cache added to a multi handle caused a crash
 o couldn't override the Proxy-Connection: header for non-CONNECT requests
 o couldn't override the Proxy-Connection: header for non-CONNECT requests
 o curl_multi_fdset() could wrongly return -1 as max_fd value
 o curl_multi_fdset() could wrongly return -1 as max_fd value


@@ -35,6 +36,7 @@ New curl mirrors:
This release would not have looked like this without help, code, reports and
This release would not have looked like this without help, code, reports and
advice from friends like these:
advice from friends like these:


 Dan Fandrich, Peter Silva, Arve Knudsen, Michael Wallner, Toshiyuki Maezawa
 Dan Fandrich, Peter Silva, Arve Knudsen, Michael Wallner, Toshiyuki Maezawa,
 Ingmar Runge


        Thanks! (and sorry if I forgot to mention someone)
        Thanks! (and sorry if I forgot to mention someone)
+10 −8
Original line number Original line Diff line number Diff line
@@ -5,7 +5,7 @@
 *                            | (__| |_| |  _ <| |___
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *                             \___|\___/|_| \_\_____|
 *
 *
 * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
 * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 *
 * This software is licensed as described in the file COPYING, which
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * you should have received as part of this distribution. The terms
@@ -436,16 +436,18 @@ CURLcode curl_easy_perform(CURL *curl)
  if ( ! (data->share && data->share->hostcache) ) {
  if ( ! (data->share && data->share->hostcache) ) {


    if (Curl_global_host_cache_use(data) &&
    if (Curl_global_host_cache_use(data) &&
        data->hostcache != Curl_global_host_cache_get()) {
        (data->dns.hostcachetype != HCACHE_GLOBAL)) {
      if (data->hostcache)
      if (data->dns.hostcachetype == HCACHE_PRIVATE)
        Curl_hash_destroy(data->hostcache);
        Curl_hash_destroy(data->dns.hostcache);
      data->hostcache = Curl_global_host_cache_get();
      data->dns.hostcache = Curl_global_host_cache_get();
      data->dns.hostcachetype = HCACHE_GLOBAL;
    }
    }


    if (!data->hostcache) {
    if (!data->dns.hostcache) {
      data->hostcache = Curl_mk_dnscache();
      data->dns.hostcachetype = HCACHE_PRIVATE;
      data->dns.hostcache = Curl_mk_dnscache();


      if(!data->hostcache)
      if(!data->dns.hostcache)
        /* While we possibly could survive and do good without a host cache,
        /* While we possibly could survive and do good without a host cache,
           the fact that creating it failed indicates that things are truly
           the fact that creating it failed indicates that things are truly
           screwed up and we should bail out! */
           screwed up and we should bail out! */
+7 −6
Original line number Original line Diff line number Diff line
@@ -255,7 +255,7 @@ void Curl_hostcache_prune(struct SessionHandle *data)
{
{
  time_t now;
  time_t now;


  if((data->set.dns_cache_timeout == -1) || !data->hostcache)
  if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
    /* cache forever means never prune, and NULL hostcache means
    /* cache forever means never prune, and NULL hostcache means
       we can't do it */
       we can't do it */
    return;
    return;
@@ -266,7 +266,7 @@ void Curl_hostcache_prune(struct SessionHandle *data)
  time(&now);
  time(&now);


  /* Remove outdated and unused entries from the hostcache */
  /* Remove outdated and unused entries from the hostcache */
  hostcache_prune(data->hostcache,
  hostcache_prune(data->dns.hostcache,
                  data->set.dns_cache_timeout,
                  data->set.dns_cache_timeout,
                  now);
                  now);


@@ -279,7 +279,7 @@ remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
{
{
  struct hostcache_prune_data user;
  struct hostcache_prune_data user;


  if( !dns || (data->set.dns_cache_timeout == -1) || !data->hostcache)
  if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
    /* cache forever means never prune, and NULL hostcache means
    /* cache forever means never prune, and NULL hostcache means
       we can't do it */
       we can't do it */
    return 0;
    return 0;
@@ -296,7 +296,7 @@ remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
  if(data->share)
  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);


  Curl_hash_clean_with_criterium(data->hostcache,
  Curl_hash_clean_with_criterium(data->dns.hostcache,
                                 (void *) &user,
                                 (void *) &user,
                                 hostcache_timestamp_remove);
                                 hostcache_timestamp_remove);


@@ -356,7 +356,8 @@ Curl_cache_addr(struct SessionHandle *data,
  /* Store the resolved data in our DNS cache. This function may return a
  /* Store the resolved data in our DNS cache. This function may return a
     pointer to an existing struct already present in the hash, and it may
     pointer to an existing struct already present in the hash, and it may
     return the same argument we pass in. Make no assumptions. */
     return the same argument we pass in. Make no assumptions. */
  dns2 = Curl_hash_add(data->hostcache, entry_id, entry_len+1, (void *)dns);
  dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
                       (void *)dns);
  if(!dns2) {
  if(!dns2) {
    /* Major badness, run away. */
    /* Major badness, run away. */
    free(dns);
    free(dns);
@@ -428,7 +429,7 @@ int Curl_resolv(struct connectdata *conn,
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);


  /* See if its already in our dns cache */
  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);


  if(data->share)
  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+24 −13
Original line number Original line Diff line number Diff line
@@ -317,13 +317,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
  easy->easy_handle = easy_handle;
  easy->easy_handle = easy_handle;
  multistate(easy, CURLM_STATE_INIT);
  multistate(easy, CURLM_STATE_INIT);


  /* for multi interface connections, we share DNS cache automaticly.
  /* for multi interface connections, we share DNS cache automaticly if the
     First kill the existing one if there is any. */
     easy handle's one is currently private. */
  if (easy->easy_handle->hostcache &&
  if (easy->easy_handle->dns.hostcache &&
      easy->easy_handle->hostcache != multi->hostcache)
      (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
    Curl_hash_destroy(easy->easy_handle->hostcache);
    Curl_hash_destroy(easy->easy_handle->dns.hostcache);

    easy->easy_handle->dns.hostcache = multi->hostcache;
  easy->easy_handle->hostcache = multi->hostcache;
    easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
  }


  /* We add this new entry first in the list. We make our 'next' point to the
  /* We add this new entry first in the list. We make our 'next' point to the
     previous next and our 'prev' point back to the 'first' struct */
     previous next and our 'prev' point back to the 'first' struct */
@@ -374,8 +375,12 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
    /* If the 'state' is not INIT or COMPLETED, we might need to do something
    /* If the 'state' is not INIT or COMPLETED, we might need to do something
       nice to put the easy_handle in a good known state when this returns. */
       nice to put the easy_handle in a good known state when this returns. */


    if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
      /* clear out the usage of the shared DNS cache */
      /* clear out the usage of the shared DNS cache */
    easy->easy_handle->hostcache = NULL;
      easy->easy_handle->dns.hostcache = NULL;
      easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
    }

    Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association
    Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association
                                                    to this multi handle */
                                                    to this multi handle */


@@ -893,8 +898,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
  } while (easy->easy_handle->change.url_changed);
  } while (easy->easy_handle->change.url_changed);


  if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
  if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
    if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
      /* clear out the usage of the shared DNS cache */
      /* clear out the usage of the shared DNS cache */
    easy->easy_handle->hostcache = NULL;
      easy->easy_handle->dns.hostcache = NULL;
      easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
    }


    /* now add a node to the Curl_message linked list with this info */
    /* now add a node to the Curl_message linked list with this info */
    msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
    msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
@@ -975,8 +983,11 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
    easy = multi->easy.next;
    easy = multi->easy.next;
    while(easy) {
    while(easy) {
      nexteasy=easy->next;
      nexteasy=easy->next;
      if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
        /* clear out the usage of the shared DNS cache */
        /* clear out the usage of the shared DNS cache */
      easy->easy_handle->hostcache = NULL;
        easy->easy_handle->dns.hostcache = NULL;
        easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
      }
      Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */
      Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */


      if (easy->msg)
      if (easy->msg)
Loading