gpt4 book ai didi

c - 边缘触发的非阻塞 epoll 的 SSL_accept 总是返回 SSL_ERROR_WANT_READ

转载 作者:太空宇宙 更新时间:2023-11-04 10:33:20 29 4
gpt4 key购买 nike

我们有 3 个人致力于将 SSL 添加到基于 epoll 的服务器,但在 3 天的沮丧之后,我们决定向全世界寻求帮助。

问题是 SSL_accept() 总是返回 SSL_ERROR_WANT_READ,我们确实有关联套接字的 EPOLLIN 和 EPOLLOUT 的 epoll 事件,但即使我们得到一个事件并召回SSL_accept 它只是返回想要阅读的内容....如此令人沮丧。

似乎没有我们能找到的将 openssl 与 epoll 一起使用的良好工作示例,如果有的话,请将代码示例发送给我们,我们花了几天时间解决这个问题并阅读了每条 SE/SO 消息并花费了openssl 邮件列表上的小时数。

我们有一个基本的应用程序结构,看起来像这样用于接受:

            if (http_sock == source_fd || https_sock == source_fd) {
// new connection
req_type_t req_type = (http_sock == source_fd) ? HTTP : HTTPS;
int infd;

while (1) {
struct sockaddr_in in_addr;
socklen_t in_addr_len;
ZLOG_DBG(zlog_cat, "New %s request on source_fd: %d http_sock: %d https_sock: %d", req_type == HTTP ? "HTTP" : "HTTPS", source_fd, http_sock, https_sock);
in_addr_len = sizeof in_addr;
infd = accept4(source_fd, &in_addr, &in_addr_len, SOCK_NONBLOCK);
if (infd <= 0)
{
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
/* We have processed all incoming
connections. */
break;
} else {
ZLOG_ERR(zlog_cat, "ERROR: accept");
break;
}
}

req = new_req_data(kds, req_type, &g_data, infd, &in_addr, in_addr_len, cert_q);


event.events = EPOLLIN | EPOLLRDHUP | EPOLLET;

if (req->type == HTTPS) {
req->c_tls.want_ssl_accept = 1;
event.events = EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLET;
ssl_establish(req);
}
if ( (s = set_socket_blocking(req->client.fd, 1)) < 0)
err(EXIT_FAILURE, "[%s:%d] set_socket_blocking()", __FUNCTION__, __LINE__);

epoll_event_t *epoll_event = new_epoll_event_t(infd, req);

event.data.ptr = epoll_event;
// add new infd to our epoll listener
if ( (s = epoll_ctl(efd, EPOLL_CTL_ADD, req->client.fd, &event)) == -1 )
err(EXIT_FAILURE, "epoll_ctl(http) %s", strerror(errno));
}
ZLOG_DBG(zlog_cat, "New %s connection from %s:%d on FD %d mac_address: %s", req->type ? "HTTPS" : "HTTP",
inet_ntoa(req->client.sock.sin_addr), ntohs(req->client.sock.sin_port), req->client.fd, req->device->mac_address);
g_data.conn_counter++;
continue; // continue to next accept event

} // end new connection

ssl_establish() 方法如下所示:

int ssl_establish(req_data_t *req) {
unsigned long e;
int ssl_err, rc;

// create openssl server context and ssl object
if ((req->s_tls.ctx = create_context(0)) == NULL) {
ZLOG_ERR(zlog_cat, "create_context() %s", strerror(errno));
return -1;
}

if ((req->s_tls.ssl = SSL_new(req->s_tls.ctx)) == NULL) {
ZLOG_ERR(zlog_cat, "SSL_new() %s", strerror(errno));
return -1;
}

// Establishing SSL/TLS connections with client
if (req->https_def_rsa != NULL && req->https_def_cert != NULL) {
req->c_tls.servername = req->https_def_domain;
req->c_tls.cert = req->https_def_cert;
req->c_tls.rsa_key = req->https_def_rsa;
req->c_tls.dest_ip = req->orig.sock.sin_addr.s_addr;
req->c_tls.dc_cache = req->dc_cache;
req->c_tls.q_entry = NULL;

if (req->c_tls.ctx == NULL ) {
if ((req->c_tls.ctx = create_context(1)) == NULL)
ZLOG_ERR(zlog_cat, "ERROR create_context");
if (configure_context(&req->c_tls))
ZLOG_ERR(zlog_cat, "ERROR configure_context");
if ((req->c_tls.ssl = SSL_new(req->c_tls.ctx)) == NULL)
ZLOG_ERR(zlog_cat, "ERROR ssl_new");

// SSL_set_mode(req->c_tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); // This doesn't seem to do anything

if (SSL_set_fd(req->c_tls.ssl, req->client.fd) == 0)
ZLOG_ERR(zlog_cat, "ERROR ssl_set_fd");
}
req->client.ssl = req->c_tls.ssl;
}
if ((rc = SSL_accept(req->c_tls.ssl)) < 0) {
ssl_err = SSL_get_error(req->c_tls.ssl, rc);

switch (ssl_err) {
case SSL_ERROR_WANT_READ:
ZLOG_DBG(zlog_cat, "SSL_accept SSL_ERROR_WANT_READ");
req->c_tls.want_ssl_accept = 1;
return 0;
break;
case SSL_ERROR_WANT_WRITE:
ZLOG_DBG(zlog_cat, "SSL_accept SSL_ERROR_WANT_WRITE");
req->c_tls.want_ssl_accept = 1;
return 0;
break;
case SSL_ERROR_ZERO_RETURN:
ZLOG_ERR(zlog_cat, "SSL_accept SSL_ERROR_ZERO_RETURN");
req->c_tls.want_ssl_accept = 0;
return -1;
break;
case SSL_ERROR_WANT_X509_LOOKUP:
ZLOG_ERR(zlog_cat, "SSL_accept SSL_ERROR_WANT_X509_LOOKUP");
req->c_tls.want_ssl_accept = 0;
return -1;
break;
case SSL_ERROR_SYSCALL:
ZLOG_ERR(zlog_cat, "SSL_accept SSL_ERROR_SYSCALL");
req->c_tls.want_ssl_accept = 0;
return -1;
break;
case SSL_ERROR_SSL:
ZLOG_ERR(zlog_cat, "SSL_accept SSL_ERROR_SSL");
req->c_tls.want_ssl_accept = 0;
return -1;
break;
}
}
ZLOG_DBG(zlog_cat, "SSL_accept success");
req->c_tls.want_ssl_accept = 0;
return 1;
}

在 pollin/pollout 处理程序中,我们这样做:

                if (req->type == HTTPS && req->c_tls.want_ssl_accept) {
ZLOG_DBG(zlog_cat, "ssl_establish EPOLLIN");
if ((rc = ssl_establish(req)) <= 0) {
ZLOG_DBG(zlog_cat, "ssl_establish EPOLLIN retry...");
continue;
}
}

我们的日志是这样的:

2016-08-03 23:26:32.224  New HTTPS connection from 192.168.1.195:52659 on FD 15 mac_address: e4:f8:9c:85:63:99
2016-08-03 23:26:32.224 epoll_wait returned 1
2016-08-03 23:26:32.224 epoll event number: 0 on fd: 15
2016-08-03 23:26:32.224 Reading data from Client, source_fd: 15 source_sock->fd: 15 dest_sock->fd: -1 mac_address: e4:f8:9c:85:63:99
2016-08-03 23:26:32.224 ssl_establish EPOLLIN
2016-08-03 23:26:32.484 SSL_accept SSL_ERROR_WANT_READ
2016-08-03 23:26:32.484 ssl_establish EPOLLIN retry...
2016-08-03 23:26:32.954 New HTTPS connection from 192.168.1.195:52660 on FD 16 mac_address: e4:f8:9c:85:63:99
2016-08-03 23:26:32.954 epoll_wait returned 1
2016-08-03 23:26:32.954 epoll event number: 0 on fd: 16
2016-08-03 23:26:32.954 Establishing SSL (EPOLLOUT)
2016-08-03 23:26:32.974 SSL_accept SSL_ERROR_WANT_READ
2016-08-03 23:26:32.974 ssl_establish EPOLLOUT retry...

最佳答案

好的 - 我终于让它工作了。如果有人偶然发现这一点,请不要使用 SSL_accept()。

我在主结构中添加了一些状态跟踪,并将 ssl_establish() 方法更新为如下所示:

int ssl_establish(req_data_t *req, epoll_event_t *epoll_event ) {
unsigned long e;
int ssl_err, rc;
struct epoll_event event;
memset(&event, 0, sizeof(struct epoll_event));
event.events = req->client.events;
event.data.ptr = epoll_event;

if (!req->client.tcp_connected) {
struct pollfd pfd;
pfd.fd = req->client.fd;
pfd.events = POLLOUT | POLLERR;
int r = poll(&pfd, 1, 0);
if (r == 1 && pfd.revents == POLLOUT) {
ZLOG_DBG(zlog_cat, "tcp connected fd %d", req->client.fd);
req->client.tcp_connected = 1;
req->client.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET;
event.events = req->client.events;
if(epoll_ctl(req->efd, EPOLL_CTL_MOD, req->client.fd, &event) != 0)
ZLOG_ERR(zlog_cat, "ERROR: unable to modify epoll_ctl");
} else {
ZLOG_ERR(zlog_cat, "[%d | %d] ERROR poll fd return %d revents %d", req->client.fd, req->state, r, pfd.revents);
return -1;
}
}


// create openssl server context and ssl object
if (!req->s_tls.ctx)
if ((req->s_tls.ctx = create_context(0)) == NULL) {
ZLOG_ERR(zlog_cat, "create_context() %s", strerror(errno));
return -1;
}

if (!req->s_tls.ssl)
if ((req->s_tls.ssl = SSL_new(req->s_tls.ctx)) == NULL) {
ZLOG_ERR(zlog_cat, "SSL_new() %s", strerror(errno));
return -1;
}

req->orig.ssl = req->s_tls.ssl;
req->proxy.ssl = req->s_tls.ssl;

// Establishing SSL/TLS connections with client
if (req->https_def_rsa != NULL && req->https_def_cert != NULL) {
req->c_tls.servername = req->https_def_domain;
req->c_tls.cert = req->https_def_cert;
req->c_tls.rsa_key = req->https_def_rsa;
req->c_tls.dest_ip = req->orig.sock.sin_addr.s_addr;
req->c_tls.kudoso = req->kudoso;
req->c_tls.dc_cache = req->dc_cache;
req->c_tls.q_entry = NULL;

if (!req->errBio)
req->errBio = BIO_new_fd(2, BIO_NOCLOSE);


if (!req->c_tls.ctx) {
if ((req->c_tls.ctx = create_context(1)) == NULL)
ZLOG_ERR(zlog_cat, "ERROR create_context");
if (configure_context(&req->c_tls))
ZLOG_ERR(zlog_cat, "ERROR configure_context");
}
if (!req->c_tls.ssl) {
if ((req->c_tls.ssl = SSL_new(req->c_tls.ctx)) == NULL)
ZLOG_ERR(zlog_cat, "ERROR ssl_new");

// SSL_set_mode(req->c_tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

if (SSL_set_fd(req->c_tls.ssl, req->client.fd) == 0)
ZLOG_ERR(zlog_cat, "ERROR ssl_set_fd");

SSL_set_accept_state(req->c_tls.ssl);
req->client.ssl = req->c_tls.ssl;
}
}
int r = SSL_do_handshake(req->c_tls.ssl);
if (r == 1) {
req->client.ssl_connected = 1;
ZLOG_DBG(zlog_cat, "[%d | %d] ssl connected", req->client.fd, req->state);
req->client.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
event.events = req->client.events;
if(epoll_ctl(req->efd, EPOLL_CTL_MOD, req->client.fd, &event) != 0)
ZLOG_ERR(zlog_cat, "ERROR: unable to modify epoll_ctl");
return 1;
}
int err = SSL_get_error(req->c_tls.ssl, r);
int oldev = req->client.events;
if (err == SSL_ERROR_WANT_WRITE) {
req->client.events |= EPOLLOUT;
req->client.events &= ~EPOLLIN;
ZLOG_DBG(zlog_cat, "do_handshake return want write set events %d", req->client.events);
if (oldev == req->client.events) return 0;
} else if (err == SSL_ERROR_WANT_READ) {
req->client.events |= EPOLLIN;
req->client.events &= ~EPOLLOUT;
ZLOG_DBG(zlog_cat, "do_handshake return want read set events %d", req->client.events);
if (oldev == req->client.events) return 0;
} else {
ZLOG_ERR(zlog_cat, "ERROR SSL_do_handshake return %d error %d errno %d msg %s", r, err, errno, strerror(errno));
ERR_print_errors(req->errBio);
return -1;
}
event.events = req->client.events;
if(epoll_ctl(req->efd, EPOLL_CTL_MOD, req->client.fd, &event) != 0)
ZLOG_ERR(zlog_cat, "[%d | %d] ERROR: unable to modify epoll_ctl", req->client.fd, req->state);
return 0;
}

关于c - 边缘触发的非阻塞 epoll 的 SSL_accept 总是返回 SSL_ERROR_WANT_READ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38755515/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com