是否可以在没有基于文件描述符的套接字的情况下使用libcurl?

问题描述

我使用自定义的读写套接函数编写了以下libcurl代码

//...
CURL *curl;
FILE *fp;
CURLcode res;
char outfilename[FILENAME_MAX] = "file";
curl = curl_easy_init();

/* no progress meter please */
//curl_easy_setopt(curl,CURLOPT_nopROGRESS,1L);

curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,write_data);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,&sharedValue);

curl_easy_setopt(curl,CURLOPT_READFUNCTION,read_data);
curl_easy_setopt(curl,CURLOPT_READDATA,CURLOPT_OPENSOCKETFUNCTION,opensocket);
curl_easy_setopt(curl,CURLOPT_OPENSOCKETDATA,CURLOPT_CLOSESOCKETFUNCTION,closecb);
curl_easy_setopt(curl,CURLOPT_CLOSESOCKETDATA,CURLOPT_URL,hostname.c_str());

curl_easy_setopt(curl,CURLOPT_SOCKOPTFUNCTION,sockopt_callback);

curl_easy_setopt(curl,CURLOPT_VERBOSE,1);

res = curl_easy_perform(curl);

curl_easy_cleanup(curl);

我不知道该怎么处理CURLOPT_SOCKOPTFUNCTION,所以我做了sockopt_callback

static curl_socket_t opensocket(void *clientp,curlsocktype purpose,struct curl_sockaddr *address)
{
    return 0;
}

但是我明白了

*   Trying 212.183.159.230:80...
* Could not set TCP_NODELAY: Socket operation on non-socket
* connect to 212.183.159.230 port 80 Failed: Socket operation on non-socket
libcurl wants to close 0 Now

因为可能正在尝试写入套接0。显然,我不能阻止它调用套接字上的选项,例如设置TCP_NODELAY和最重要的connect

是否可以使libcurl永远不调用套接文件描述符?

我的一个想法是传递一个现有的套接字作为libcurl的虚拟对象,然后仍然使用我的写入和读取功能。但是,libcurl只是通过套接字发送内容,而不是通过write和read函数发送

解决方法

我以为write_data是重定向套接字调用的一种方法,但它与它无关,它实际上是一个写客户端收到的内容的函数。

但是,通过传递一个socketpair(如@domen表示的那样),我使它起作用了!

素描:


    //...

    static curl_socket_t opensocket(void *clientp,curlsocktype purpose,struct curl_sockaddr *address)
    {
        auto *sharedValue = static_cast<SharedValue *>(clientp);
        return sharedValue->curl_socket;
    }

    int socket_vector[2];
    if (0 != socketpair(AF_UNIX,SOCK_STREAM,socket_vector))
    {
        std::cout << "problem creating socketpair" << std::endl;
        std::exit(2);
    }

    sharedValue.curl_socket = socket_vector[0];
    sharedValue.vpn_socket = socket_vector[1];

    //writes the result to a file
    curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,write_data_file);
    curl_easy_setopt(curl,CURLOPT_WRITEDATA,destFile);

    curl_easy_setopt(curl,CURLOPT_OPENSOCKETFUNCTION,opensocket);
    curl_easy_setopt(curl,CURLOPT_OPENSOCKETDATA,&sharedValue);

    curl_easy_setopt(curl,CURLOPT_CLOSESOCKETFUNCTION,closecb);
    curl_easy_setopt(curl,CURLOPT_CLOSESOCKETDATA,CURLOPT_SOCKOPTFUNCTION,sockopt_callback);

    curl_easy_setopt(curl,CURLOPT_URL,hostname.c_str());

    //curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
    
    //Start a thread here that will read/write to the socket pair on the other endpoint (in my case vpn_socket)

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);

    if (res)
    {
        std::cout << "libcurl error code: " << res << ",libcurl error: " << curl_easy_strerror(res) << std::endl;
        return 1;
    }