Improve TLS WebSocket and network failure diagnostics
This commit is contained in:
@@ -33,3 +33,32 @@
|
||||
`inc/app_gnss_log.h` 中的 `APP_GNSS_LOG_ENABLED` 默认是 `0`,关闭应用侧全部 GNSS/NMEA 原始输出、解析失败、模式切换、卫星搜索、坐标打印和 GPS 查询提示。需要恢复时可在编译参数中设置 `-DAPP_GNSS_LOG_ENABLED=1`。语音与 NITZ 时间校准诊断继续输出。
|
||||
|
||||
GNSS 数据解析、定位上报和硬件开关流程继续运行。原先放在打印参数内的四处 `ql_gnss_close()` 已分离为独立操作,避免禁用日志时跳过关闭定位。`python3 tools/test_gnss_logging.py` 在日志开启和关闭两种配置下验证真实解析代码、无卫星退出、卫星不足退出、搜索超时退出及 FAST 切换 SLOW 的关闭路径。
|
||||
|
||||
## 连接失败与提示音诊断
|
||||
|
||||
`WSS-DIAG` 使用 `stage` 区分 TLS 握手、TLS 读取、WebSocket 升级。日志记录阶段、实际耗时、超时配置、错误码和收包情况,不输出原始响应头、Cookie 或音频内容。TLS 握手仍是 20 秒总窗口,WebSocket 升级仍是 10 秒窗口,HTTP select 等待仍是 2 秒。
|
||||
|
||||
| 日志字段 | 含义和排查方向 |
|
||||
| --- | --- |
|
||||
| `stage=tls_handshake result=timeout phase=server hello` | TLS 等待服务器 Hello 超时,不能据此判断证书错误。结合 `last_step`、`want_read`/`want_write`、`phase_ms`、`calls_ms` 判断等待和本地计算耗时 |
|
||||
| `stage=tls_connect failed_at=… verify_flags=…` | 记录 TLS 初始化/建连的失败步骤和证书校验标志;校验标志仅在已进行证书校验时有解释意义 |
|
||||
| `stage=tls_read reason=peer_close_notify` | 对端发送 TLS 关闭通知;仅证明关闭由对端通知,不证明为何关闭 |
|
||||
| `stage=tls_read reason=tls_eof/tls_read_timeout/tls_read_error` | 分别表示读取返回 0、TLS 读取超时、其他读取错误;保留原始十进制和十六进制返回值 |
|
||||
| `stage=ws_upgrade reason=no_response_timeout` | 升级等待超时,缓冲中没有响应数据;对照 `rx_bytes=0`,服务端需核查请求是否到达及是否返回 101 |
|
||||
| `stage=ws_upgrade reason=incomplete_headers_timeout` | 收到部分数据,但在窗口内未收到完整 HTTP 响应头 |
|
||||
| `stage=ws_upgrade reason=http_rejected http=…` | 收到了完整响应头及非 101 状态;按实际 HTTP 状态检查代理或后端 |
|
||||
| `stage=ws_upgrade reason=invalid_upgrade_response` | 收到非法或不符合 WebSocket 校验的响应;例如 101 响应的 Accept/Upgrade/Connection 不符合要求,或响应格式错误;当前不进一步细分具体头字段 |
|
||||
| `stage=ws_upgrade reason=transport_error` | 等待升级期间底层连接出错,结合紧邻的 `tls_read` 日志及断开回调的具体错误描述 |
|
||||
| `HTTP-DIAG stage=tcp_connect/response_header/response_body` | HTTP 在建连、响应头或响应体等待期间失败;`timeout` 表示 select 返回 0,`select_error` 表示负值,并记录立即保存的 errno;超时的 errno 字段为 0,不能用历史 errno 推断原因 |
|
||||
| `NET-GATE leave recording=… pending=… mqtt=… action=…` | 记录留言键为什么被拦截,区分正在录音、等待留言请求回复和 MQTT 离线。忙碌分支当前仍播放原有网络提示并清除 pending,此次仅增加诊断 |
|
||||
| `NET-GATE tip=network_ok reason=mqtt_connected voice_service=not_checked` | “已连上网络”仅由 MQTT 连通触发,不表示 TLS/WebSocket/语音业务已验证 |
|
||||
|
||||
例如此次无响应升级会输出类似以下摘要(示例,并非当前固件已有的历史日志):
|
||||
|
||||
```text
|
||||
[WSS-DIAG] stage=ws_upgrade result=failed reason=no_response_timeout http=0 elapsed_ms=10000 timeout_ms=10000 rx_bytes=0 buffered=0 header_bytes=0 parser=0 polls=...
|
||||
```
|
||||
|
||||
`http=0` 表示尚未解析到有效状态码,不是服务器返回的 HTTP 状态码。成功 TLS 写入只证明本地传输层接受了数据,设备端仍不能独自证明请求到达服务器或定位中间链路丢包。诊断不会改变现有提示音、重试或业务状态机。
|
||||
|
||||
验证:`python3 tools/test_wss_receive.py` 覆盖完整/分段 101、零响应超时、部分响应头超时、503 拒绝、非法 Accept、对端关闭、TLS 读取超时等分支;`python3 tools/test_wss_handshake.py` 验证真实握手函数的超时/失败摘要及原有时限、重试和 tick 回绕。以上为主机侧函数测试,需重新构建并烧录目标固件后采集新日志。
|
||||
|
||||
@@ -168,6 +168,7 @@ static void key_thread_entry(void *parameter)
|
||||
!mic_pdp ? "blocked_no_pdp" : (mic_mqtt != 1 ? "blocked_mqtt_offline" : "start_voice"));
|
||||
if(mic_pdp && mic_mqtt == 1){
|
||||
if(tts_play_interrupt_func()==-2){
|
||||
printf("[NET-GATE] mic tip=network_check reason=voice_connect_failed pdp=%d mqtt=%d\r\n", mic_pdp, mic_mqtt);
|
||||
app_play_tips_file(2);
|
||||
}
|
||||
}else{
|
||||
@@ -213,7 +214,14 @@ static void key_thread_entry(void *parameter)
|
||||
build_alarm();
|
||||
}
|
||||
else if(ql_rtos_get_systicks() - key_press_alarm_time > KEY_WAIT_TIME){
|
||||
if(!vad_audio_is_recording()&&key_start_leave==0&&get_mqtt_connect_status()==1){
|
||||
int leave_recording = vad_audio_is_recording();
|
||||
int leave_mqtt = get_mqtt_connect_status();
|
||||
printf("[NET-GATE] leave recording=%d pending=%d mqtt=%d action=%s\r\n",
|
||||
leave_recording, key_start_leave, leave_mqtt,
|
||||
leave_recording ? "blocked_recording" :
|
||||
(key_start_leave ? "blocked_pending" :
|
||||
(leave_mqtt != 1 ? "blocked_mqtt_offline" : "request_leave")));
|
||||
if(!leave_recording&&key_start_leave==0&&leave_mqtt==1){
|
||||
key_start_leave = 1;
|
||||
build_leave_to_parent();
|
||||
}else{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <webclient.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -131,12 +132,14 @@ static int webclient_read_line(struct webclient_session *session, char *buffer,
|
||||
FD_SET(session->socket, &read_fds);
|
||||
|
||||
ret = select(session->socket + 1, &read_fds, NULL, NULL, &t);
|
||||
int select_errno = ret < 0 ? errno : 0;
|
||||
|
||||
// printf("select ret: %d\r\n", ret);
|
||||
|
||||
if(ret <= 0)
|
||||
{
|
||||
printf("*** select timeout or error ***\r\n");
|
||||
printf("[HTTP-DIAG] stage=response_header reason=%s select_ret=%d errno_snapshot=%d timeout_ms=2000\r\n",
|
||||
ret == 0 ? "timeout" : "select_error", ret, select_errno);
|
||||
return -WEBCLIENT_ERROR;
|
||||
}
|
||||
|
||||
@@ -561,12 +564,14 @@ static int webclient_connect(struct webclient_session *session, const char *URI)
|
||||
FD_SET(socket_handle, &write_fds);
|
||||
|
||||
rc= select(socket_handle + 1, &read_fds, &write_fds, NULL, &t);
|
||||
int select_errno = rc < 0 ? errno : 0;
|
||||
|
||||
printf("select ret: %d\r\n", rc);
|
||||
|
||||
if(rc <= 0)
|
||||
{
|
||||
printf("*** select timeout or error ***\r\n");
|
||||
printf("[HTTP-DIAG] stage=tcp_connect reason=%s select_ret=%d errno_snapshot=%d timeout_ms=2000\r\n",
|
||||
rc == 0 ? "timeout" : "select_error", rc, select_errno);
|
||||
rc = -WEBCLIENT_CONNECT_FAILED;
|
||||
goto __exit;
|
||||
}
|
||||
@@ -1376,12 +1381,14 @@ int webclient_read(struct webclient_session *session, void *buffer, size_t lengt
|
||||
FD_SET(session->socket, &read_fds);
|
||||
|
||||
ret = select(session->socket + 1, &read_fds, NULL, NULL, &t);
|
||||
int select_errno = ret < 0 ? errno : 0;
|
||||
|
||||
// printf("select ret: %d\r\n", ret);
|
||||
|
||||
if(ret <= 0)
|
||||
{
|
||||
printf("*** select timeout or error ***\r\n");
|
||||
printf("[HTTP-DIAG] stage=response_body reason=%s select_ret=%d errno_snapshot=%d timeout_ms=2000\r\n",
|
||||
ret == 0 ? "timeout" : "select_error", ret, select_errno);
|
||||
return -WEBCLIENT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -821,6 +821,7 @@ int app_mqtt_connect()
|
||||
MQTT_CONN_UNLOCK();
|
||||
|
||||
// [ADD] 连接成功提示音
|
||||
printf("[NET-GATE] tip=network_ok reason=mqtt_connected voice_service=not_checked\r\n");
|
||||
app_play_tips_file(11);
|
||||
|
||||
if(ret!=0){
|
||||
|
||||
@@ -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