Hi,

Continuing the work for the custom resolver, I've made some simple test for the situation which nervous me: what the library does if the cancel and destroy happens for the request which is in the WAITRESOLVE state? It may happen in case of slow or temporary unavailable network when the result of the request is not necessary for the application at the moment, just because of user interaction (canceling of the request, or entering a new download URL, or something else). It may be called early-stage-request-cancellation.

This test is not deterministic enough to include it into the test suite, just because of different network timeouts and bandwidth, but has predictable behavior looking to output generated by valgrind tool starting the test. The test code itself is applied. The test has meaning only for asynchronous resolver of different natures, either threading, or c-ares.

When the library was compiled with threaded resolver ( ./configure --enable-debug --enable-curldebug --disable-shared --enable-threaded-resolver ), the test has been passed fine. Test was compiled using the following line: cc -o test -I ~/curl/include -I ~/curl/lib `curl-config --cflags` `curl-config --libs` -g test.c /usr/local/lib/libcurl.a

(I've included additional #include paths to have a possibility to use "memdebug.h" in the test, and added a static curl library manually)

For the c-ares resolver the library was configured as the following:
./configure --enable-debug --enable-curldebug --disable-shared --enable-ares

Test was compiled using the following line:
cc -o test -I /home/seva/curl/include -I /home/seva/curl/lib `curl-config --cflags` `curl-config --libs` -g test.c /usr/local/lib/libcurl.a /usr/local/lib/libcares.a (I've included additional #include paths to have a possibility to use "memdebug.h" in the test, and added static curl and c-ares libraries manually)

The test compiled against c-ares and started by valgring, fails - see the following test/valgrind output:

seva@SEVA (2):~/testcurl$ valgrind --leak-check=full --show-reachable=yes ./test http://www.nnov.ru
==2449== Memcheck, a memory error detector
==2449== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==2449== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==2449== Command: ./test http://www.nnov.ru
==2449==
Starting ...
Initializing ...
Start at URL http://www.nnov.ru, steps = 1
Step for URL http://www.nnov.ru:0 started ...
* 0x468fccc is at send pipe head!
* STATE: CONNECT => WAITRESOLVE handle 0x46b4f84; (connection #0)
Progress 0.000000 0.000000 0.000000 0.000000 ...
Step for URL http://www.nnov.ru:0 finished, res = 0
Canceling URL http://www.nnov.ru
problem we 0x468fccc are still in send pipe for 0x46b51cc done 0
* Expire cleared
Progress 0.000000 0.000000 0.000000 0.000000 ...
* Closing connection #0
==2449== Invalid write of size 4
==2449==    at 0x8055650: Curl_addrinfo_callback (hostasyn.c:110)
==2449==    by 0x8055335: ares_query_completed_cb (hostares.c:339)
==2449==    by 0x8099DCD: end_hquery (ares_gethostbyname.c:230)
==2449==    by 0x8099D87: host_callback (ares_gethostbyname.c:222)
==2449==    by 0x80A0B69: qcallback (ares_query.c:151)
==2449==    by 0x809967C: ares_destroy (ares_destroy.c:53)
==2449==    by 0x80641C5: Curl_close (url.c:559)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==  Address 0x46b5540 is 888 bytes inside a block of size 1,056 free'd
==2449==    at 0x4024B3A: free (vg_replace_malloc.c:366)
==2449==    by 0x804DF22: curl_dofree (memdebug.c:271)
==2449==    by 0x8067434: conn_free (url.c:2610)
==2449==    by 0x80676C1: Curl_disconnect (url.c:2713)
==2449==    by 0x806B97F: Curl_done (url.c:5282)
==2449==    by 0x8050F44: curl_multi_remove_handle (multi.c:684)
==2449==    by 0x8063FB7: Curl_close (url.c:489)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==
==2449== Invalid read of size 4
==2449==    at 0x80557BF: Curl_addrinfo_callback (hostasyn.c:161)
==2449==    by 0x8055335: ares_query_completed_cb (hostares.c:339)
==2449==    by 0x8099DCD: end_hquery (ares_gethostbyname.c:230)
==2449==    by 0x8099D87: host_callback (ares_gethostbyname.c:222)
==2449==    by 0x80A0B69: qcallback (ares_query.c:151)
==2449==    by 0x809967C: ares_destroy (ares_destroy.c:53)
==2449==    by 0x80641C5: Curl_close (url.c:559)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==  Address 0x46b5548 is 896 bytes inside a block of size 1,056 free'd
==2449==    at 0x4024B3A: free (vg_replace_malloc.c:366)
==2449==    by 0x804DF22: curl_dofree (memdebug.c:271)
==2449==    by 0x8067434: conn_free (url.c:2610)
==2449==    by 0x80676C1: Curl_disconnect (url.c:2713)
==2449==    by 0x806B97F: Curl_done (url.c:5282)
==2449==    by 0x8050F44: curl_multi_remove_handle (multi.c:684)
==2449==    by 0x8063FB7: Curl_close (url.c:489)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==
==2449== Invalid write of size 4
==2449==    at 0x80557CB: Curl_addrinfo_callback (hostasyn.c:161)
==2449==    by 0x8055335: ares_query_completed_cb (hostares.c:339)
==2449==    by 0x8099DCD: end_hquery (ares_gethostbyname.c:230)
==2449==    by 0x8099D87: host_callback (ares_gethostbyname.c:222)
==2449==    by 0x80A0B69: qcallback (ares_query.c:151)
==2449==    by 0x809967C: ares_destroy (ares_destroy.c:53)
==2449==    by 0x80641C5: Curl_close (url.c:559)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==  Address 0x46b5548 is 896 bytes inside a block of size 1,056 free'd
==2449==    at 0x4024B3A: free (vg_replace_malloc.c:366)
==2449==    by 0x804DF22: curl_dofree (memdebug.c:271)
==2449==    by 0x8067434: conn_free (url.c:2610)
==2449==    by 0x80676C1: Curl_disconnect (url.c:2713)
==2449==    by 0x806B97F: Curl_done (url.c:5282)
==2449==    by 0x8050F44: curl_multi_remove_handle (multi.c:684)
==2449==    by 0x8063FB7: Curl_close (url.c:489)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==
==2449== Invalid read of size 4
==2449==    at 0x80557D4: Curl_addrinfo_callback (hostasyn.c:161)
==2449==    by 0x8055335: ares_query_completed_cb (hostares.c:339)
==2449==    by 0x8099DCD: end_hquery (ares_gethostbyname.c:230)
==2449==    by 0x8099D87: host_callback (ares_gethostbyname.c:222)
==2449==    by 0x80A0B69: qcallback (ares_query.c:151)
==2449==    by 0x809967C: ares_destroy (ares_destroy.c:53)
==2449==    by 0x80641C5: Curl_close (url.c:559)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==  Address 0x46b5548 is 896 bytes inside a block of size 1,056 free'd
==2449==    at 0x4024B3A: free (vg_replace_malloc.c:366)
==2449==    by 0x804DF22: curl_dofree (memdebug.c:271)
==2449==    by 0x8067434: conn_free (url.c:2610)
==2449==    by 0x80676C1: Curl_disconnect (url.c:2713)
==2449==    by 0x806B97F: Curl_done (url.c:5282)
==2449==    by 0x8050F44: curl_multi_remove_handle (multi.c:684)
==2449==    by 0x8063FB7: Curl_close (url.c:489)
==2449==    by 0x804D0A5: curl_easy_cleanup (easy.c:582)
==2449==    by 0x804CBAE: start_and_cancel (test.c:74)
==2449==    by 0x804CBF9: test (test.c:87)
==2449==    by 0x804CC24: main (test.c:94)
==2449==
...
the following lines have no sense

The test has been executed on main development  branch, using c-ares v.1.7.4

That's what I meant when told about complexity ...

Regards,
Vsevolod

#include <curl/curl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "memdebug.h"

#define MAIN_LOOP_HANG_TIMEOUT     90 * 1000
#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000

static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
  (void)clientp;
  fprintf(stderr, "Progress %f %f %f %f ...\n", dltotal, dlnow, ultotal, ulnow);
  return 0;
}

static int start_and_cancel(char *URL,int steps)
{
  int res = 0;
  int counter = 0;
  CURL *curl;
  int running;
  CURLM *m = NULL;

  fprintf(stderr, "Starting ...\n");
  if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
    fprintf(stderr, "curl_global_init() failed\n");
    return 2;
  }

  if ((curl = curl_easy_init()) == NULL) {
    fprintf(stderr, "curl_easy_init() failed\n");
    curl_global_cleanup();
    return 2;
  }

  curl_easy_setopt(curl, CURLOPT_URL, URL);
  curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);

  /* we want to use our own progress function */
  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
  curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);

  fprintf(stderr, "Initializing ...\n");
  if ((m = curl_multi_init()) == NULL) {
    fprintf(stderr, "curl_multi_init() failed\n");
    curl_easy_cleanup(curl);
    curl_global_cleanup();
    return 2;
  }

  if ((res = (int)curl_multi_add_handle(m, curl)) != CURLM_OK) {
    fprintf(stderr, "curl_multi_add_handle() failed, "
            "with code %d\n", res);
    curl_multi_cleanup(m);
    curl_easy_cleanup(curl);
    curl_global_cleanup();
    return 2;
  }

  fprintf(stderr, "Start at URL %s, steps = %d\n",URL,steps);

  for(counter=0; counter < steps; counter++) {
      usleep(1000);
      fprintf(stderr, "Step for URL %s:%d started ...\n",URL,counter);
      res = (int)curl_multi_perform(m, &running);
      fprintf(stderr, "Step for URL %s:%d finished, res = %d\n",URL,counter,res);
  }

  fprintf(stderr, "Canceling URL %s\n",URL);

  curl_easy_cleanup(curl);
  curl_multi_cleanup(m);
  curl_global_cleanup();

  sleep(2);

  return CURLE_OK;
}

int test(char *URL)
{
  int steps=0;
  for(steps=1; steps < 10; steps++) {
    start_and_cancel(URL,steps);
  }
}

int main(int ac, char **av)
{
    if( ac > 1 )
        test(av[1]);
    else {
        fprintf(stderr, "Usage: %s URL\n",av[0]);
        return 1;
    }
    return 0;
}
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to