簡體   English   中英

非阻塞BIO並在BIO_do_connect之后掛起

[英]Non-blocking BIO and hang after BIO_do_connect

我正在使用openssl在C中編寫一個小小的IRC bot來啟動安全套接字。 它不是編寫得最精美的機器人,但它主要是為了了解openssl API的工作原理。 目前我有以下代碼:

#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

int main() {
    SSL_load_error_strings();
    ERR_load_BIO_strings();
    OpenSSL_add_all_algorithms();

    BIO *bio;
    SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());
    SSL * ssl;

    SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs/");
    bio = BIO_new_ssl_connect(ctx);
    BIO_get_ssl(bio, & ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    BIO_set_nbio(bio, 1);
    BIO_set_conn_hostname(bio, "irc.freenode.net:6697");
    BIO_do_connect(bio);

    if(SSL_get_verify_result(ssl) != X509_V_OK) {
        printf("error\n");
    }

    char irc1[] = "NICK bartender\r\n";
    char irc2[] = "USER bartender * * :serve(&drinks);\r\n";

    BIO_write(bio, irc1, strlen(irc1));
    BIO_write(bio, irc2, strlen(irc2));

    fd_set read_set;
    int sock = BIO_get_fd(bio, NULL);

    while(1) {
        FD_ZERO(&read_set);
        FD_SET(sock, &read_set);

        struct timeval timeout = { 0, 0 };
        select(sock+1, &read_set, NULL, NULL, &timeout);

        if(FD_ISSET(sock, &read_set)) {
            char buf[21];
            size_t x = BIO_read(bio, buf, 20);

            if(x == 0) {
                continue;
            } else if(x == -1){
                int code = ERR_get_error();

                if(code == 0) {
                    continue;
                }

                printf("(%d)%s\n", code, ERR_error_string(code, NULL));
            } else {
                buf[x] = '\0';
                printf("%s", buf);
            }
        }
    }
}

每當我編譯並運行此代碼時,它只會掛起並打印任何內容。 但是,如果我刪除第20行(當前將套接字置於非阻塞模式),它可以正常工作。 為什么將套接字置於非阻塞模式會導致此行為? 謝謝你,祝你有個美好的一天!

每當我運行此代碼時,它只會掛起並打印任何內容。 但是,如果我刪除第20行(當前將套接字置於非阻塞模式),它可以正常工作。

BIO_do_connect立即以非阻塞模式返回。 你應該循環BIO_should_retry 以下是手冊頁有關BIO_do_connect

BIO_do_connect()嘗試連接提供的BIO。 如果連接成功建立,則返回1。 如果無法建立連接,則返回零值或負值,應將呼叫BIO_should_retry()用於非阻塞連接BIO以確定是否應重試該呼叫。


為什么將套接字置於非阻塞模式會導致此行為?

BIO_do_connect的調用立即返回; socket / bio可能尚未准備好數據(尚未)。


循環BIO_do_connect / BIO_should_retry的替代方法是等待底層文件描述符。 它是OpenSSL在ocsp子命令中使用的技術(源代碼可以在<openssl src>/apps/ocsp.c ):

if (req_timeout != -1)
    BIO_set_nbio(cbio, 1);

rv = BIO_do_connect(cbio);

if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
    BIO_puts(err, "Error connecting BIO\n");
    return NULL;
}

if (BIO_get_fd(cbio, &fd) < 0) {
    BIO_puts(bio_err, "Can't get connection fd\n");
    goto err;
}

if (req_timeout != -1 && rv <= 0) {
    FD_ZERO(&confds);
    openssl_fdset(fd, &confds);
    tv.tv_usec = 0;
    tv.tv_sec = req_timeout;
    rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
    if (rv == 0) {
        BIO_puts(err, "Timeout on connect\n");
        return NULL;
    }
}

另請參閱OpenSSL Users郵件列表中的非阻塞BIO和BIO_do_connect問題 Stack Overflow上也有一些點擊 ,但我不確定哪個最適合這個問題:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM