From 64b7c7ec33fb5eb12477a62b3fbc19683aaf3573 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 3 Feb 2026 14:16:00 -0400 Subject: [PATCH] Fix SSL_pending busy-wait causing 100% CPU usage The tls_recv() function was skipping the select() call when SSL_pending() returned non-zero, causing a tight busy-wait loop. This fix ensures select() is always called, using a zero timeout when SSL has buffered data to return immediately, or the full timeout to properly block when waiting for new data. This prevents the relay client from consuming 100% CPU while maintaining the WebSocket connection. --- nostr_websocket/nostr_websocket_openssl.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/nostr_websocket/nostr_websocket_openssl.c b/nostr_websocket/nostr_websocket_openssl.c index 2f955ead..38714c9b 100644 --- a/nostr_websocket/nostr_websocket_openssl.c +++ b/nostr_websocket/nostr_websocket_openssl.c @@ -580,23 +580,30 @@ static int tls_recv(void* ctx, void* data, size_t len, int timeout_ms) { return -1; } - // Check if SSL has pending data first - if (SSL_pending(tls->ssl) == 0 && timeout_ms > 0) { - // Only use select() if no data is pending in SSL buffers + // Always use select() to ensure proper blocking behavior + // If SSL has pending data, use zero timeout to return immediately + // Otherwise use the full timeout to block until data arrives + if (timeout_ms > 0) { fd_set readfds; struct timeval tv; FD_ZERO(&readfds); FD_SET(tls->socket_fd, &readfds); - tv.tv_sec = timeout_ms / 1000; - tv.tv_usec = (timeout_ms % 1000) * 1000; + // If SSL has buffered data, use zero timeout; otherwise use full timeout + if (SSL_pending(tls->ssl) > 0) { + tv.tv_sec = 0; + tv.tv_usec = 0; + } else { + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + } int result = select(tls->socket_fd + 1, &readfds, NULL, NULL, &tv); if (result < 0) { return -1; - } else if (result == 0) { - return -1; // Timeout + } else if (result == 0 && SSL_pending(tls->ssl) == 0) { + return -1; // Timeout with no pending data } }