将SSL集成到使用BSD套接字的程序中

时间:2012-04-24 08:03:14

标签: c sockets ssl openssl

我有一个TCP网络库,它实现了一堆协议(redis,http等),它们是使用BSD套接字实现的。

许多代码使用select()和其他适用于BSD套接字的函数。我是否正确地认为这不适用于SSL套接字?或者他们会按原样工作吗?

我只是想知道SSL和BSD套接字是否如此不同,以至于它们需要一种完全不同的实现方法。

3 个答案:

答案 0 :(得分:6)

假设您指的是OpenSSL,它位于套接字的顶部,它不会替换它。所以所有直接套接字操作,如select(),仍然有效。但是,不同之处在于OpenSSL会为您处理读写操作,因此您可以将recv()替换为ssl_read(),将send()替换为ssl_write(),但您可以(在某些情况下)需要)仍然直接使用select()。但是,您不能随时调用它,您必须等到OpenSSL告诉您调用它。因此,例如,如果您有一个首先调用select()然后仅在recv()报告可读性时调用select()的阅读循环,则必须交换该逻辑。首先致电ssl_read(),然后仅在select返回ssl_read()SSL_ERROR_WANT_READ时调用SSL_ERROR_WANT_WRITE()(请注意ssl_read()可执行写入操作在内部,ssl_write()可以在内部执行读取操作。

答案 1 :(得分:2)

有一件事是你不应该对运行ssl连接的fd做一个选择。那是因为它可能会说你可以在ssl_read阻塞时读取它。然后由例如SSL执行密钥重新协商而不是应用程序数据变得可用。那是陷阱之一。

答案 2 :(得分:0)

这可能会迟到,但可能会为未来的用户提供很好的参考。在url http://developerweb.net/viewtopic.php?id=6824上使用select()函数有一个很好的主题。引用的一个例子如下

int sslsock_handle_nbio (ssl, ret, totv)
    void            *ssl;           /* -> the SSL info                      */
    int             ret;            /* the SSL I/O function return value    */
    struct timeval  *totv;          /* -> timeout info, or NULL             */
{
    int     sfd, i;
    fd_set  rset, wset;

    sfd = SSL_get_fd (ssl);
    i = SSL_get_error (ssl, ret);

    if (i == SSL_ERROR_WANT_READ) {
    do {
        FD_ZERO (&rset);
        FD_SET (sfd, &rset);
        i = select (sfd + 1, &rset, NULL, NULL, totv);
    } while ((i < 0) && (errno == EINTR));
    if (i == 0) {
        /* the select() timed out */
        ret = -2;
        errno = ETIMEDOUT;
    } else {
        /* either an error, or it's readable */
        ret = i;
    }
    } else if (i == SSL_ERROR_WANT_WRITE) {
    do {
        FD_ZERO (&wset);
        FD_SET (sfd, &wset);
        i = select (sfd + 1, NULL, &wset, NULL, totv);
    } while ((i < 0) && (errno == EINTR));
    if (i == 0) {
        /* the select() timed out */
        ret = -2;
        errno = ETIMEDOUT;
    } else {
        /* either an error, or it's writable */
        ret = i;
    }
    }
    /* else, leave "ret" alone, and return it as-is */

    return (ret);
}

仅在执行SSL_read()SSL_write()之后才会这样做。