void acceptcb(evconnlistener *listener, int fd,
sockaddr *addr, int addrlen, void *arg) {
info_log("new conn accepted");
auto *server_dt = (server_data *)arg;
SSL *ssl = initializeSSL(server_dt->app_ctx->ssl_ctx, fd);
if (doHandshake(ssl) < 0) {
error_log("handshake error, returning");
return;
}
printf("handshake succesfull");
const unsigned char *alpn = nullptr;
unsigned int alpn_len = 0;
SSL_get0_alpn_selected(ssl, &alpn, &alpn_len);
info_log("alpn: %s\n", alpn);
}
SSL *initializeSSL(SSL_CTX *SSL_ctx, int fd) {
SSL *ssl = SSL_new(SSL_ctx);
BIO *bio = BIO_new_socket(fd, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);
// 2 lines above can be changed to SSL_set_fd(ssl, fd) with no effect
return ssl;
}
int doHandshake(SSL *ssl) {
ERR_clear_error();
while (true) {
int ret = SSL_do_handshake(ssl);
if (ret > 0) {
break; // Handshake successful
}
else {
int err = SSL_get_error(ssl, ret);
info_log("handshake in progress, %d, %s, %d, %d", ret, ERR_error_string(err, NULL), SSL_ERROR_SSL, SSL_ERROR_ZERO_RETURN);
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
// temporarely just continue.
continue;
}
else {
error_log("handshake error, returning");
// Handle handshake error
SSL_free(ssl);
return -1;
}
}
}
return 0;
}
The curl command I used for testing and the verbose output
curl https://broken-bonds.com -v
* Trying 94.241.168.130:443...
* Connected to broken-bonds.com (94.241.168.130) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
Just for a little context, why I don't just use bufferevent ssl init. I am currently rewriting our little project to depend less on libevent and SSL_do_handshake fails on the first attempt and I don't know why. res is 1, err is 1 which is SSL_ERROR_ZERO_RETURN if I'm not mistaken. https://www.openssl.org/docs/manmaster/man3/SSL_get_error.html
The code below works just fine and works nicely, so i don't think it's a problem with context, certs or network and honesty I'm stuck, I'm doing this alike to the libevent impl.
void acceptcb(evconnlistener listener, int fd,sockaddr addr, int addrlen, void arg) {
auto server_dt = (server_data)arg;
http_session_data session_data = new http_session_data(server_dt->app_ctx, server_dt->endpoint_handler, addr, addrlen);
int val = 1;
SSL *ssl = create_ssl(server_dt->app_ctx->ssl_ctx);
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
bufferevent *bev = bufferevent_openssl_socket_new(
server_dt->app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
bufferevent_enable(bev, EV_READ | EV_WRITE);
ssl = bufferevent_openssl_get_ssl(bev);
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
#if DEBUG_EXTENDED_INFO
printf("acceptcb \tSSL_in_init: %d, SSL_in_before: %d, SSL_is_init_finished: %d, SSL_in_connect_init: %d, SSL_in_accept_init: %d, SSL_get_state: %d\n",
SSL_in_init(ssl), SSL_in_before(ssl), SSL_is_init_finished(ssl), SSL_in_connect_init(ssl), SSL_in_accept_init(ssl), SSL_get_state(ssl));
char client_ip[INET6_ADDRSTRLEN];
int client_port;
if (addr->sa_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)addr;
inet_ntop(AF_INET, &s->sin_addr, client_ip, sizeof client_ip);
client_port = ntohs(s->sin_port);
}
else { // AF_INET6
struct sockaddr_in6 *s = (struct sockaddr_in6 *)addr;
inet_ntop(AF_INET6, &s->sin6_addr, client_ip, sizeof client_ip);
client_port = ntohs(s->sin6_port);
}
// Log the connection details
printf("New connection accepted: FD=%d, IP=%s, Port=%d\n", fd, client_ip, client_port);
#endif
}