Windows 使用libcurl连接到IMAP服务器

Windows 使用libcurl连接到IMAP服务器,windows,imap,libcurl,winsock2,gmail-imap,Windows,Imap,Libcurl,Winsock2,Gmail Imap,我维护一个用VC 2017编写的IMAP应用程序(Windows),它使用Winsock2作为底层连接。我正在研究使用libcurl而不是Winsock,以解决代理和SSL/TLS等各种问题 我知道libcurl中的高级IMAP函数,但我不想去那里,我需要对IMAP进行更直接的控制,并且需要重用现有代码。所以我想用curl\u easy\u send()和curl\u easy\u recv()进行实验 到目前为止运气不太好。我基本上是在运行libcurl附带的演示程序sendrecv.c(我稍

我维护一个用VC 2017编写的IMAP应用程序(Windows),它使用Winsock2作为底层连接。我正在研究使用libcurl而不是Winsock,以解决代理和SSL/TLS等各种问题

我知道libcurl中的高级IMAP函数,但我不想去那里,我需要对IMAP进行更直接的控制,并且需要重用现有代码。所以我想用curl\u easy\u send()和curl\u easy\u recv()进行实验

到目前为止运气不太好。我基本上是在运行libcurl附带的演示程序sendrecv.c(我稍微修改过的版本,如下所示)

当您连接到IMAP服务器时,它会立即发回一个列出其功能的响应。客户端不需要请求它。在我的程序中,我可以连接到我的测试服务器(outlook.office365.com),如果我使用端口143(不安全的IMAP端口),我可以接收响应。但是如果我使用安全端口993,程序将挂起select()命令,60秒后超时

因此,我可能对SSL有问题。我尝试过使用CURLOPT_USE_SSL启用SSL,但没有任何区别。我错过了什么

另外,可能是一个无关的问题,但当我尝试连接到imap.gmail.com时,连接失败,出现错误56(CURLE_RECV_error)


您忽略了
curl\u easy\u perform()
的返回值,它实际返回的是什么?您也根本没有解析
buf
的内容,因此您不知道何时到达IMAP响应的末尾,需要停止读取以避免尝试等待永远不会到达的更多数据的错误超时。谢谢您的评论。curl\u easy\u perform的返回值为0。我没有在我的代码中显示它,但是我有调试函数显示结果,它显示libcurl成功连接到服务器。在这一点上,我调用curl\u easy\u recv()并立即得到81的返回码(再次调用CURLE\u)。根据示例,我调用wait_on_socket(),超时时间为60秒。然后,该例程将挂起select()调用,直到超时。是的,我确实需要更好地解析buf,以防我得到数据,但我没有。正如我提到的,此代码适用于端口143,但不适用于端口993。我猜curl实际上并没有发送SSL/TLS握手,但服务器正在等待您的客户端发送一个。这可以解释超时问题。你只需要嗅探网络流量就可以知道到底发生了什么。我通过在服务器名称前粘贴“imaps://”就可以让它正常工作。还必须禁用CURLOPT_SSL_VERIFYPEER。IMAP连接消息出现在debug_函数中,这与我使用端口143时不同,但它似乎工作得足够好,我可以继续测试。
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
    struct timeval tv;
    fd_set infd, outfd, errfd;
    int res;

    tv.tv_sec = timeout_ms / 1000;
    tv.tv_usec = (timeout_ms % 1000) * 1000;

    FD_ZERO(&infd);
    FD_ZERO(&outfd);
    FD_ZERO(&errfd);

    FD_SET(sockfd, &errfd); /* always check for error */

    if (for_recv) {
        FD_SET(sockfd, &infd);
    }
    else {
        FD_SET(sockfd, &outfd);
    }

    /* select() returns the number of signalled sockets or -1 */
    printf("starting select\n");
    res = select((int)sockfd + 1, &infd, &outfd, &errfd, &tv);
    printf("finished select, res=%d\n", res);
    return res;
}


int main()
{
    CURL *curl;
    CURLcode res;
    int port = 993;
    curl_socket_t sockfd;
    char imap_host[256] = "";
    char buf[1024];
    size_t nread;

    printf("Starting sendrecv demo\n");

    curl = curl_easy_init();
    if (!curl) {
        printf("Unable to initialize curl\n");
        return(0);
    }

    curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_function);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, true);

    //strcpy_s(imap_host, "imap.gmail.com");
    strcpy_s(imap_host, "outlook.office365.com");
    curl_easy_setopt(curl, CURLOPT_URL, imap_host);
    curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
    curl_easy_setopt(curl, CURLOPT_PORT, port);
    curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
    res = curl_easy_perform(curl);

    printf("Return from connect: %d\n", res);

    /* Extract the socket from the curl handle - we'll need it for waiting. */
    res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd);
    if (res != CURLE_OK) {
        printf("Error getting socket\n");
        return(0);
    }

    printf("Reading IMAP response\n");

    while (1) {
        /* Warning: This example program may loop indefinitely (see above). */
        
        do {
            nread = 0;
            res = curl_easy_recv(curl, buf, sizeof(buf), &nread);

            if (res == CURLE_AGAIN && !wait_on_socket(sockfd, 1, 60000L)) {
                printf("Error: timeout.\n");
                return(0);
            }
        } while (res == CURLE_AGAIN);

        if (res != CURLE_OK) {
            printf("Error: %s\n", curl_easy_strerror(res));
            break;
        }

        if (nread == 0) {
            /* end of the response */
            break;
        }

        printf("Received %d bytes\n", nread);
        buf[nread] = 0;
        break;

    }

    printf("response: %s\n", buf);

    /* always cleanup */
    curl_easy_cleanup(curl);

    return(0);


}