Improve TLS WebSocket and network failure diagnostics
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""Test the actual timed handshake loop with scripted SDK steps and 5 ms ticks."""
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
source = (root / 'ql-application/threadx/interface/custom_app/lib/librws/src/rws_socketpriv.c').read_bytes().decode('latin1')
|
||||
@@ -15,7 +16,12 @@ typedef struct { int ret, next_state; unsigned int duration; } step;
|
||||
static step steps[16];
|
||||
static int count, calls, sleeps;
|
||||
static unsigned int ticks;
|
||||
static void test_log(const char *fmt, ...) { (void)fmt; }
|
||||
static char diagnostic[1024];
|
||||
static void test_log(const char *fmt, ...) {
|
||||
va_list args;
|
||||
if (!strstr(fmt, "[WSS-DIAG]")) return;
|
||||
va_start(args, fmt); vsnprintf(diagnostic, sizeof(diagnostic), fmt, args); va_end(args);
|
||||
}
|
||||
#define LOG_I test_log
|
||||
static unsigned int ql_rtos_get_systicks(void) { return ticks; }
|
||||
static void rws_thread_sleep(unsigned int ms) { ticks += ms / 5; ++sleeps; }
|
||||
@@ -52,8 +58,11 @@ int main(void) {
|
||||
assert(rws_tls_handshake_timed(&ctx) == 0 && calls == 2 && sleeps == 0);
|
||||
reset(&ctx); steps[0] = (step){-99, MBEDTLS_SSL_SERVER_CERTIFICATE, 1}; count = 1;
|
||||
assert(rws_tls_handshake_timed(&ctx) == -99 && calls == 1 && sleeps == 0);
|
||||
reset(&ctx);
|
||||
assert(strstr(diagnostic, "result=failed phase=server certificate") && strstr(diagnostic, "ret=-99"));
|
||||
reset(&ctx); ctx.state = MBEDTLS_SSL_SERVER_HELLO;
|
||||
assert(rws_tls_handshake_timed(&ctx) == MBEDTLS_ERR_SSL_TIMEOUT && ticks == 4000 && calls < 2100);
|
||||
assert(strstr(diagnostic, "result=timeout phase=server hello") && strstr(diagnostic, "elapsed_ms=20000"));
|
||||
assert(strstr(diagnostic, "last_step=-26880") && strstr(diagnostic, "want_write=0"));
|
||||
reset(&ctx); ticks = (unsigned int)-1000;
|
||||
assert(rws_tls_handshake_timed(&ctx) == MBEDTLS_ERR_SSL_TIMEOUT && calls < 2100);
|
||||
reset(&ctx); steps[0] = (step){0, MBEDTLS_SSL_SERVER_CERTIFICATE, 4001}; count = 1;
|
||||
@@ -69,7 +78,12 @@ output.mkdir(parents=True, exist_ok=True)
|
||||
cfile = output / 'test_wss_handshake.c'
|
||||
cfile.write_text(harness, encoding='utf-8')
|
||||
exe = output / 'test_wss_handshake.exe'
|
||||
subprocess.run(['cl', '/nologo', '/W4', '/WX', '/TC', str(cfile),
|
||||
'/I' + str(root / 'ql-application/threadx/common/include'),
|
||||
'/Fo' + str(output / 'test_wss_handshake.obj'), '/Fe' + str(exe)], check=True)
|
||||
if os.name == "nt":
|
||||
subprocess.run(['cl', '/nologo', '/W4', '/WX', '/TC', str(cfile),
|
||||
'/I' + str(root / 'ql-application/threadx/common/include'),
|
||||
'/Fo' + str(output / 'test_wss_handshake.obj'), '/Fe' + str(exe)], check=True)
|
||||
else:
|
||||
subprocess.run(['cc', '-std=c99', '-Wall', '-Wextra', '-Werror',
|
||||
'-I' + str(root / 'ql-application/threadx/common/include'),
|
||||
str(cfile), '-o', str(exe)], check=True)
|
||||
subprocess.run([str(exe)], check=True)
|
||||
|
||||
@@ -18,6 +18,8 @@ harness = r'''
|
||||
#define MBEDTLS_ERR_SSL_WANT_READ -2
|
||||
#define MBEDTLS_ERR_SSL_WANT_WRITE -3
|
||||
#define MBEDTLS_ERR_NET_RECV_FAILED -4
|
||||
#define MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -30848
|
||||
#define MBEDTLS_ERR_SSL_TIMEOUT -26624
|
||||
#define WSAEWOULDBLOCK 11
|
||||
#define WSAEINPROGRESS 115
|
||||
#define RWS_RECEIVE_BUFF_SIZE 1024
|
||||
@@ -44,9 +46,10 @@ typedef struct {
|
||||
static int replies[16], reply_count, calls, closes;
|
||||
static size_t offset;
|
||||
static unsigned int ticks;
|
||||
static const char response[] =
|
||||
static const char good_response[] =
|
||||
"HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\nDATA";
|
||||
static const char *response = good_response;
|
||||
static unsigned int ql_rtos_get_systicks(void) { return ticks; }
|
||||
static void rws_thread_sleep(int ms) { ticks += (unsigned int)ms; }
|
||||
static void rws_error_delete_clean(const char **e) { *e = NULL; }
|
||||
@@ -64,7 +67,7 @@ static int mbedtls_ssl_read(int *ctx, unsigned char *buf, size_t size) {
|
||||
int ret = calls < reply_count ? replies[calls] : MBEDTLS_ERR_SSL_WANT_READ;
|
||||
(void)ctx; ++calls;
|
||||
if (ret > 0) {
|
||||
assert((size_t)ret <= size && offset + (size_t)ret <= sizeof(response) - 1);
|
||||
assert((size_t)ret <= size && offset + (size_t)ret <= strlen(response));
|
||||
memcpy(buf, response + offset, (size_t)ret); offset += (size_t)ret;
|
||||
}
|
||||
return ret;
|
||||
@@ -78,7 +81,7 @@ static void reset(_rws_socket *s, tls *ctx) {
|
||||
s->expected_accept = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=";
|
||||
s->payload_buff = (char *)malloc(RWS_RECEIVE_BUFF_SIZE); assert(s->payload_buff);
|
||||
s->command = COMMAND_WAIT_HANDSHAKE_RESPONCE;
|
||||
calls = closes = reply_count = 0; offset = 0; ticks = 0;
|
||||
calls = closes = reply_count = 0; offset = 0; ticks = 0; response = good_response;
|
||||
}
|
||||
int main(void) {
|
||||
tls ctx = {0}; _rws_socket s = {0}; int want;
|
||||
@@ -86,7 +89,7 @@ int main(void) {
|
||||
reset(&s, &ctx); replies[0] = want; reply_count = 1;
|
||||
assert(!rws_socket_recv(&s));
|
||||
assert(!s.error && s.command == COMMAND_WAIT_HANDSHAKE_RESPONCE && closes == 0);
|
||||
replies[1] = 17; replies[2] = want; replies[3] = (int)sizeof(response) - 1 - 17;
|
||||
replies[1] = 17; replies[2] = want; replies[3] = (int)strlen(response) - 17;
|
||||
reply_count = 4;
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
assert(s.is_connected && !s.error && s.command == COMMAND_INFORM_CONNECTED);
|
||||
@@ -96,6 +99,7 @@ int main(void) {
|
||||
reset(&s, &ctx);
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
assert(!s.is_connected && s.error && closes == 1 && ticks >= 2000 && calls < 300);
|
||||
assert(!strcmp(s.error, "no_response_timeout"));
|
||||
free(s.payload_buff);
|
||||
reset(&s, &ctx); ticks = (unsigned int)-1000;
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
@@ -109,11 +113,25 @@ int main(void) {
|
||||
reset(&s, NULL); rws_socket_wait_handshake_responce(&s);
|
||||
assert(s.error && closes == 1 && calls == 0); free(s.payload_buff);
|
||||
reset(&s, &ctx); s.expected_accept = "wrong";
|
||||
replies[0] = (int)sizeof(response) - 1; reply_count = 1;
|
||||
replies[0] = (int)strlen(response); reply_count = 1;
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
assert(!s.is_connected && s.error && closes == 1); free(s.payload_buff);
|
||||
assert(!strcmp(s.error, "invalid_upgrade_response"));
|
||||
reset(&s, &ctx); response = "HTTP/1.1 503 Service Unavailable\r\nContent-Length: 0\r\n\r\n";
|
||||
replies[0] = (int)strlen(response); reply_count = 1;
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
assert(!s.is_connected && closes == 1 && !strcmp(s.error, "http_rejected")); free(s.payload_buff);
|
||||
reset(&s, &ctx); replies[0] = 17; reply_count = 1;
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
assert(!s.is_connected && closes == 1 && !strcmp(s.error, "incomplete_headers_timeout")); free(s.payload_buff);
|
||||
reset(&s, &ctx); replies[0] = MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY; reply_count = 1;
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
assert(closes == 1 && !strcmp(s.error, "peer_close_notify")); free(s.payload_buff);
|
||||
reset(&s, &ctx); replies[0] = MBEDTLS_ERR_SSL_TIMEOUT; reply_count = 1;
|
||||
rws_socket_wait_handshake_responce(&s);
|
||||
assert(closes == 1 && !strcmp(s.error, "tls_read_timeout")); free(s.payload_buff);
|
||||
free(s.received);
|
||||
puts("PASS: actual TLS receive/upgrade loop: WANT_READ/WRITE, split HTTP 101, trailing frame bytes, timeout/wrap, EOF/fatal, null TLS, invalid Accept");
|
||||
puts("PASS: actual TLS receive/upgrade loop: WANT_READ/WRITE, split HTTP 101, trailing frame bytes, timeout/wrap, EOF/fatal, null TLS, invalid Accept, HTTP rejection, partial-header timeout, close_notify, TLS timeout");
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user