5

I'm developing a FUSE driver and when I run it as a daemon (without the -f or -d flags) all https request made through libcurl fail. I was able to reproduce the error by making an https request, forking and returning the parent process, and then making a second request from the new process. If I remove the fork call or make an http request there are no errors.

I'm making an official bug report right now, but does anyone know how I can make it work?

Here's my code and the (logfile) output:

Note: if you run my program, pipe to /dev/null because libcurl sends the received buffer to stdout by default.

#include <curl/curl.h>
#include <string>
#include <unistd.h>
#include <iostream>

using namespace std;

void log(string str)
{   //TODO: remove
    static const char logfile[] = "/home/austin/megalog";
    FILE *f = fopen(logfile, "a");
    fwrite(str.data(), str.size(), 1, f);
    fclose(f);
    cout << str;
}

int main(int argc, char *argv[])
{
    string url = "https://www.google.com/";
    char errBuf[1024];
    CURLcode err;

    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL *handle = curl_easy_init();
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
    curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errBuf);

    if ((err = curl_easy_perform(handle)))
    {
        log("first request failed\n");
        return 1;
    }
    curl_easy_cleanup(handle);

    if(fork())
        return 0;

    handle = curl_easy_init();
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
    curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errBuf);

    if ((err = curl_easy_perform(handle)))
    {
        log(string("curl error while sending: (") + to_string(err) + ") " + curl_easy_strerror(err) + "\n");
        log(errBuf);
    }
    else
        log("no error\n");

    return 0;
}

...and the output:

$ g++ -std=c++11 main.cpp -lcurl
$ rm -f log
$ ./a.out > /dev/null
$ cat log
curl error while sending: (35) SSL connect error
A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.

I'm using (the latest) libcurl version 7.29.0, (the latest) openssl version 1.0.1e, and I'm running Fedora 18 with kernel version 3.7.4.

br1ckd
  • 556
  • 3
  • 15

1 Answers1

4

To make this work, you need to call curl_global_cleanup before fork and curl_global_init again after fork. Someone in the libcurl mailing list mentioned that this is a common problem when calling fork after initializing libraries that need to be initialized.

br1ckd
  • 556
  • 3
  • 15
  • For those with the same issue in other languages (perl in my case), note that it seems the problem only occurs when curl is linked in nss instead of openssl. So you might as well recompile your curl to use openssl only. – FlorianB Feb 15 '17 at 00:26
  • This solution is OK but makes curl not to be available for the parent after the fork. Is there a solution enabling the parent to continue working and using curl after the fork? (e.g. a process that needs to log some data using curl but that forks childs that also user culr for logging) – lulop Jun 15 '17 at 11:20
  • This saved my bacon. Thanks! – Jason Miesionczek Aug 01 '17 at 13:39