Improve TLS WebSocket and network failure diagnostics

This commit is contained in:
chenjintao
2026-10-29 15:36:00 +08:00
parent 407051d420
commit b3e0b5bbb4
7 changed files with 147 additions and 24 deletions
@@ -340,8 +340,13 @@ rws_bool rws_socket_recv(_rws_socket *s)
break;
}
if (len <= 0) {
LOG_E("WSS TLS peer closed or read failed: %d\n", len);
s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, "TLS peer closed or read failed");
const char *reason = len == 0 ? "tls_eof" :
(len == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ? "peer_close_notify" :
(len == MBEDTLS_ERR_SSL_TIMEOUT ? "tls_read_timeout" : "tls_read_error"));
printf("[WSS-DIAG] stage=tls_read reason=%s ret=%d hex=-0x%04x command=%d rx_bytes=%u buffered=%u\n",
reason, len, (unsigned int)-len, s->command,
s->diag_rx_bytes, (unsigned int)s->received_len);
s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, reason);
s->command = COMMAND_INFORM_DISCONNECTED;
result = rws_false;
goto _exit;
@@ -1032,10 +1037,14 @@ void rws_socket_idle_send(_rws_socket *s)
void rws_socket_wait_handshake_responce(_rws_socket *s)
{
unsigned int started = ql_rtos_get_systicks();
unsigned int started = ql_rtos_get_systicks(), polls = 0;
unsigned int rx_before = s->diag_rx_bytes;
size_t header_length = 0;
int status = 0, result = 0;
const char *reason;
printf("[WSS-DIAG] stage=ws_upgrade event=begin timeout_ms=10000\n");
while (result == 0) {
++polls;
rws_socket_recv(s);
if (s->error) break;
result = rws_check_handshake((const char *)s->received, s->received_len,
@@ -1045,6 +1054,9 @@ void rws_socket_wait_handshake_responce(_rws_socket *s)
rws_thread_sleep(10);
}
if (result == 1 && !s->error) {
printf("[WSS-DIAG] stage=ws_upgrade result=ok http=101 elapsed_ms=%u rx_bytes=%u header_bytes=%u polls=%u\n",
(unsigned int)(ql_rtos_get_systicks() - started) * 5,
s->diag_rx_bytes - rx_before, (unsigned int)header_length, polls);
s->received_len -= header_length;
if (s->received_len)
memmove(s->received, (char *)s->received + header_length, s->received_len);
@@ -1052,10 +1064,15 @@ void rws_socket_wait_handshake_responce(_rws_socket *s)
s->command = COMMAND_INFORM_CONNECTED;
LOG_I("WebSocket upgrade verified: HTTP 101\n");
} else {
LOG_E("WebSocket upgrade failed: HTTP %d (0 means incomplete/invalid headers)\n", status);
reason = s->error ? "transport_error" :
(result == 0 ? (s->received_len ? "incomplete_headers_timeout" : "no_response_timeout") :
(status && status != 101 ? "http_rejected" : "invalid_upgrade_response"));
printf("[WSS-DIAG] stage=ws_upgrade result=failed reason=%s http=%d elapsed_ms=%u timeout_ms=10000 rx_bytes=%u buffered=%u header_bytes=%u parser=%d polls=%u\n",
reason, status, (unsigned int)(ql_rtos_get_systicks() - started) * 5,
s->diag_rx_bytes - rx_before, (unsigned int)s->received_len,
(unsigned int)header_length, result, polls);
if (!s->error)
s->error = rws_error_new_code_descr(rws_error_code_parse_handshake,
"Invalid or timed out WebSocket upgrade");
s->error = rws_error_new_code_descr(rws_error_code_parse_handshake, reason);
rws_socket_close(s);
s->command = COMMAND_INFORM_DISCONNECTED;
}
@@ -1905,6 +1922,19 @@ static const char *rws_tls_phase_name(int state)
case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: return "server key exchange";
case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: return "client key exchange";
case MBEDTLS_SSL_SERVER_FINISHED: return "server finished";
case MBEDTLS_SSL_HELLO_REQUEST: return "hello request";
case MBEDTLS_SSL_CERTIFICATE_REQUEST: return "certificate request";
case MBEDTLS_SSL_SERVER_HELLO_DONE: return "server hello done";
case MBEDTLS_SSL_CLIENT_CERTIFICATE: return "client certificate";
case MBEDTLS_SSL_CERTIFICATE_VERIFY: return "certificate verify";
case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: return "client change cipher spec";
case MBEDTLS_SSL_CLIENT_FINISHED: return "client finished";
case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: return "server change cipher spec";
case MBEDTLS_SSL_FLUSH_BUFFERS: return "flush buffers";
case MBEDTLS_SSL_HANDSHAKE_WRAPUP: return "handshake wrapup";
case MBEDTLS_SSL_HANDSHAKE_OVER: return "handshake over";
case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: return "server new session ticket";
case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT: return "server hello verify request sent";
default: return "other";
}
}
@@ -1913,10 +1943,14 @@ static int rws_tls_handshake_timed(mbedtls_ssl_context *ctx)
{
unsigned int started = ql_rtos_get_systicks();
unsigned int phase_started = started, call_ticks = 0, retries = 0;
int state = ctx->state, ret = 0;
int state = ctx->state, ret = 0, last_step_ret = 0;
unsigned int want_read = 0, want_write = 0;
while (ctx->state != MBEDTLS_SSL_HANDSHAKE_OVER) {
unsigned int before = ql_rtos_get_systicks();
ret = mbedtls_ssl_handshake_step(ctx);
last_step_ret = ret;
if (ret == MBEDTLS_ERR_SSL_WANT_READ) ++want_read;
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ++want_write;
call_ticks += (unsigned int)(ql_rtos_get_systicks() - before);
if (ret != 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
break;
@@ -1946,6 +1980,12 @@ static int rws_tls_handshake_timed(mbedtls_ssl_context *ctx)
}
LOG_I("WSS TLS handshake total=%u ms, state=%d, ret=%d\n",
(unsigned int)(ql_rtos_get_systicks() - started) * 5, ctx->state, ret);
LOG_I("[WSS-DIAG] stage=tls_handshake result=%s phase=%s state=%d elapsed_ms=%u timeout_ms=20000 ret=%d hex=-0x%04x last_step=%d want_read=%u want_write=%u phase_ms=%u calls_ms=%u\n",
ret == 0 ? "ok" : (ret == MBEDTLS_ERR_SSL_TIMEOUT ? "timeout" : "failed"),
rws_tls_phase_name(ctx->state), ctx->state,
(unsigned int)(ql_rtos_get_systicks() - started) * 5, ret, (unsigned int)-ret,
last_step_ret, want_read, want_write,
(unsigned int)(ql_rtos_get_systicks() - phase_started) * 5, call_ticks * 5);
return ret;
}
@@ -2037,7 +2077,13 @@ int rws_ssl_conn(_rws_socket *s)
exit:
LOG_E("WSS TLS connection failed at %s: %d (-0x%04x)\n", stage, ret, (unsigned int)-ret);
rws_error_delete_clean(&s->error);
s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "TLS connection or certificate verification failed");
if (s->ssl)
LOG_E("[WSS-DIAG] stage=tls_connect failed_at=%s ret=%d verify_flags=0x%08lx\n",
stage, ret, (unsigned long)mbedtls_ssl_get_verify_result(&s->ssl->ssl_ctx));
s->error = rws_error_new_code_descr(rws_error_code_connect_to_host,
ret == MBEDTLS_ERR_SSL_TIMEOUT ? "TLS handshake timeout" :
(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ? "TLS certificate verification failed" :
"TLS connection setup or handshake failed"));
if (s->ssl) {
/* Do not send close_notify for an incomplete handshake. */
mbedtls_net_free(&s->ssl->net_ctx);