On Tue, 2 Feb 2010, Michael Schuster wrote:

I'm seeking assistance with a rather problematic issue I've been working on for a while, and would welcome all/any thoughts, pointers, RTFMs ... you're willing to share.

Thanks for the very detailed report.

Unfortunately (I think?) I can't repeat this in my end on my Debian Linux. I tried this with libcurl 7.19.7 (my stock Debian version).

I edited away the glib-related details from the curltest.c example and when running as instructed I can see the curltest process use the same amount of memory all the time...

I then fired up the curltest program with valgrind --leak-check=full, had it run for a while before I control-c'ed it, and it showed no leaks either!

I'm attaching my edited version of curltest.c to show you what I used.

--

 / daniel.haxx.se
/*
 * curltest.c
 *
 * repeatedly sends the XML string "heartbeat" (included from curltest.h
 * because of its size) to http_url or https_url (if using SSL)
 */
#include <stdio.h>
#include <sys/types.h>
#include <curl/curl.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "curltest.h" /* defines static strings, too long for this file */

#define FALSE 0
#define TRUE 1

typedef char boolean_t;
typedef char gchar;

/*static char url[] = "https://agent:ag...@127.0.0.1:18443/heartbeat";; */
static char https_url[] = "https://agent:ag...@localhost:18443/heartbeat";;
static char http_url[] = "http://agent:ag...@localhost:18080/heartbeat";;

static int                      curl_glob_arg = CURL_GLOBAL_ALL;
static boolean_t        no_ssl = FALSE;
static boolean_t        do_cleanup = TRUE;
static boolean_t        isUrlDefault = TRUE;
static char                     *url = https_url;

static char                     *post_data = heartbeat;
static int                      post_size = sizeof (heartbeat);

static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
        return nmemb * size;
}

static void
timestamp(char *loc, int loc_sz, boolean_t for_xml)
{
        time_t  now;
        struct tm *now_tm;

        now = time(NULL);
        if (!for_xml) {
                now_tm = localtime(&now);

                sprintf(loc, "%d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d", now_tm->tm_year + 1900,
                                now_tm->tm_mon+1, now_tm->tm_mday,
                                now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
        } else {
                now_tm = localtime(&now);

                /*
                 * this needs to be in sync with <agentUtc>..</agentUtc> string
                 * in curltest.h
                 */
                sprintf(loc, "%d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d", now_tm->tm_year + 1900,
                                now_tm->tm_mon+1, now_tm->tm_mday,
                                now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
                loc[19] = '.'; /* hack: sprintf overwrites this with \0, which we need to get rid of */
        }
}

static void
do_curl_thing(CURL **cu)
{
        CURL                            *curl = *cu;
        struct curl_slist       *httpheaders = NULL;
        CURLcode                        res;
        gchar                           *tmp_char;
        char                            errbuf[CURL_ERROR_SIZE];
        long                            http_code = 0;
        boolean_t                       success = TRUE;
        char                            time_str[30];
        static time_t           last_cleanup = 0;
        static int                      consecutive_successes = 0;

        errbuf[0] = '\0';

        if (post_data != NULL) {
                httpheaders = curl_slist_append(httpheaders,
                        "User-Agent: MySQL Enterprise Agent/");

                assert(httpheaders != NULL);
                tmp_char = "Content-Type: application/xml";
                httpheaders = curl_slist_append(httpheaders, tmp_char);

                /* get current timestamp into xml ... this is a hack */
                /* make sure offset is in sync with curltest.h */
                timestamp(&post_data[51], 30, TRUE);
                curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
                curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_size);
        }

        curl_easy_setopt(curl, CURLOPT_URL, url);

        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
        curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);

        curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);

        if (no_ssl) {
                curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_NONE);
        } else {
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
                curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
        }

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 4);
        curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1);

        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
        curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120);

        curl_easy_setopt(curl, CURLOPT_POST, 1);

        /* for test, not in MySQL agent */
        if (post_data == NULL)
                curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);

        res = curl_easy_perform(curl);
        timestamp(time_str, sizeof (time_str), FALSE);
        if (CURLE_OK != res) {
                long curl_errno = 0;
#if LIBCURL_VERSION_NUM > 0x070c02
                curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &curl_errno);
#endif
                if (res == CURLE_UNSUPPORTED_PROTOCOL) {
                        fprintf(stderr, "%s you requested a unsupported protocol: %s\n",
                                        time_str, errbuf);
                        exit(1);
                } else if (curl_errno != 0) {
                        fprintf(stderr, "%s curl_easy_perform() failed: %s (curl-error = "
                            "'%s' (%u), os-error = '%s' (%ld))\n",
                                        time_str, errbuf,
                                        curl_easy_strerror(res), res,
                                        strerror(curl_errno), curl_errno);
                } else {
                        fprintf(stderr, "%s curl_easy_perform() failed: %s "
                            "(curl-error = '%s' (%u))\n",
                                        time_str, errbuf,
                                        curl_easy_strerror(res), res);
                }
                success = FALSE;
        } else if (CURLE_OK != curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &http_code)) {
                 fprintf(stderr, "%s curl_easy_getinfo(CURLINFO_HTTP_CODE) failed "
                     "(code = %u)\n", time_str, res);
                success = FALSE;
        } else if (200 != http_code) {
                if (http_code == 401) {
                        fprintf(stderr, "%s -- received HTTP-status: %ld (failed):"
                            " authentication credentials incorrect\n", time_str, http_code);
                } else {
                        fprintf(stderr, "%s -- received HTTP-status: %ld (failed)\n",
                            time_str, http_code);
                }

                success = FALSE;
        }

        curl_slist_free_all(httpheaders);

        /*
         * whenever we fail, reset curl connection in the hope of
         * keeping mem footprint low.
         * every 5 minutes or more, reset whole curl state
         */
        if (FALSE == success) {
                consecutive_successes = 0;
                if (do_cleanup == FALSE)
                  return;
                time_t  now;
                curl_easy_cleanup(curl);
                now = time(NULL);
                if (last_cleanup == 0) {
                        last_cleanup = now;
                } else if (now - last_cleanup > (5 * 60)) {
                        curl_global_cleanup();
                        if (curl_global_init(curl_glob_arg) != 0) {
                                fprintf(stderr, "periodic re-global-init failed\n");
                                exit(2);
                        }
                }
                *cu = curl_easy_init();
        }

        if (success && (consecutive_successes++ % 10 == 0))
          printf("%s successfully reconnected to %s\n",
                 time_str, url);
}

CURL *curl;
static void
cleanup(int sig)
{
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        exit(0);
}

static void
Usage(char *name)
{
        fprintf(stderr, "Usage: %s [-scr] [-u url]\n"
                        "\t-s ... no ssl (default: use ssl)\n"
                        "\t-c ... no curl cleanup after error\n"
                        "\t-p ... no post data (get only)\n"
                        "\t-r ... use \"resync\" xml message instead of longer heartbeat\n"
                        "\t-u url ... use url instead of default\n", name);
        exit(1);
}

int
main(int argc, char **argv)
{
        int     c;

        while ((c = getopt(argc, argv, "spcru:")) != -1) {
                switch (c) {
                case 'u': url = optarg;
                                isUrlDefault = FALSE;
                                break;
                case 's': no_ssl = TRUE;
                                curl_glob_arg = CURL_GLOBAL_NOTHING;
                                /* only change url if it's not in argv (see -u) */
                                if (url == https_url)
                                        url = http_url;
                                break;
                case 'p': post_data = NULL;
                                break;
                case 'r': post_data = xml_resync;
                                post_size = sizeof (xml_resync);
                                break;
                case 'c': do_cleanup = FALSE;
                                break;
                default: Usage(argv[0]);
                                /* notreached */
                                break;
                }
        }

        if (curl_global_init(curl_glob_arg) != 0) {
                fprintf(stderr, "cannot curl_global_init()\n");
                exit(1);
        }

        curl = curl_easy_init();
        assert(curl != NULL);

        for (;;) {
                do_curl_thing(&curl);
                sleep(5);
        }

}

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to