Adapt WSS to new boards and use MQTT domain for eSIM connectivity
Preserve main GNSS and volume behavior while porting verified TLS, receive fixes and full-handshake optimizations. Add MQTT connection diagnostics and route MQTT through banban.api.talkingq.com:1883. Include migration documentation and regression tools. Firmware builds and package checks passed; user confirmed new-board connectivity after switching the MQTT host to the domain.
This commit is contained in:
@@ -13,6 +13,7 @@ MAKEFILE_PATH :=$(subst $(strip \),/,$(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
SRC_FILES+= \
|
||||
custom_app.c \
|
||||
lib/cJSON/cJSON.c\
|
||||
lib/librws/src/rws_handshake.c\
|
||||
lib/librws/src/rws_error.c\
|
||||
lib/librws/src/rws_frame.c\
|
||||
lib/librws/src/rws_list.c\
|
||||
@@ -67,6 +68,8 @@ SRC_FILES+= \
|
||||
http_aofei.c \
|
||||
net_mgt.c \
|
||||
ws_talkingq.c \
|
||||
talkingq_wss.c \
|
||||
talkingq_root_ca.c \
|
||||
hal_key.c \
|
||||
audio.c \
|
||||
hal_led.c \
|
||||
@@ -78,6 +81,7 @@ SRC_FILES+= \
|
||||
nfc.c \
|
||||
DP1312EA.c \
|
||||
mqtt.c \
|
||||
mqtt_connect_diag.c \
|
||||
vad_det.c \
|
||||
sleep_wake.c \
|
||||
battery.c \
|
||||
|
||||
@@ -126,7 +126,12 @@ static void key_thread_entry(void *parameter)
|
||||
app_set_app_operation(1);
|
||||
}
|
||||
|
||||
if(app_get_data_call_net_status()&&get_mqtt_connect_status()==1){
|
||||
int mic_pdp = app_get_data_call_net_status();
|
||||
int mic_mqtt = get_mqtt_connect_status();
|
||||
printf("[NET-GATE] mic pdp=%d mqtt=%d action=%s\r\n",
|
||||
mic_pdp, mic_mqtt,
|
||||
!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){
|
||||
app_play_tips_file(2);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef TALKINGQ_MQTT_CONNECT_DIAG_H
|
||||
#define TALKINGQ_MQTT_CONNECT_DIAG_H
|
||||
|
||||
#include "MQTTClient.h"
|
||||
|
||||
/* Called by the single MQTT connection worker, before MQTTStartTask(). */
|
||||
int talkingq_mqtt_connect_diagnosed(MQTTClient *client, MQTTPacket_connectData *options);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef TALKINGQ_WSS_H
|
||||
#define TALKINGQ_WSS_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define TALKINGQ_WSS_URL "wss://banban.api.talkingq.com:443/ws"
|
||||
#define TALKINGQ_URL_CAPACITY 64
|
||||
#define TALKINGQ_HOST_CAPACITY 64
|
||||
#define TALKINGQ_PATH_CAPACITY 128
|
||||
|
||||
extern const char talkingq_root_ca[];
|
||||
extern const size_t talkingq_root_ca_size;
|
||||
|
||||
/* Reject cleartext, malformed authorities, invalid ports and oversized URLs. */
|
||||
int talkingq_parse_wss_url(const char *url, char *host, size_t host_size,
|
||||
int *port, char *path, size_t path_size);
|
||||
/* Only the former built-in endpoints migrate; custom WSS endpoints are kept. */
|
||||
int talkingq_is_legacy_ws_url(const char *url);
|
||||
|
||||
#endif
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "hal_api.h"
|
||||
#include "build_macro.h"
|
||||
#include "ql_rtc.h"
|
||||
#include "talkingq_wss.h"
|
||||
#include "ql_cell_locator.h"
|
||||
|
||||
|
||||
@@ -979,17 +980,17 @@ int save_talkingq_url(uint8_t *buff, int len)
|
||||
#endif
|
||||
int hal_os_get_talkingq_url(char *pdevice_id)
|
||||
{
|
||||
char temp_device_id[64];
|
||||
memset(temp_device_id, 0, sizeof(temp_device_id));
|
||||
hal_kv_get("talkingq_url", temp_device_id, sizeof(temp_device_id));
|
||||
char temp_device_id[TALKINGQ_URL_CAPACITY] = {0};
|
||||
int saved = hal_kv_get("talkingq_url", temp_device_id, sizeof(temp_device_id));
|
||||
temp_device_id[sizeof(temp_device_id) - 1] = 0;
|
||||
|
||||
//read_talkingq_url(temp_device_id,sizeof(temp_device_id));
|
||||
if(strlen(temp_device_id)>0){
|
||||
if(saved > 0 && strlen(temp_device_id)>0 && !talkingq_is_legacy_ws_url(temp_device_id)){
|
||||
strcpy(pdevice_id, temp_device_id);
|
||||
}else{
|
||||
//strcpy(pdevice_id,"ws://api.talkingq.com:8080");
|
||||
//strcpy(pdevice_id,"ws://175.24.73.253:80");
|
||||
strcpy(pdevice_id,"ws://101.35.224.118:8080");
|
||||
strcpy(pdevice_id, TALKINGQ_WSS_URL);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#ifndef __LIBRWS_H__
|
||||
#define __LIBRWS_H__
|
||||
#include "rws_tls_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#ifndef __RWS_COMMON_H__
|
||||
#define __RWS_COMMON_H__ 1
|
||||
|
||||
#include "rws_tls_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "ql_type.h"
|
||||
#include "ql_rtos.h"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef RWS_HANDSHAKE_H
|
||||
#define RWS_HANDSHAKE_H
|
||||
#include <stddef.h>
|
||||
#define RWS_HANDSHAKE_MAX 8192
|
||||
/* 1: valid upgrade, 0: incomplete, -1: rejected. Never needs a NUL terminator. */
|
||||
int rws_check_handshake(const char *data, size_t length, const char *expected_accept,
|
||||
size_t *header_length, int *http_status);
|
||||
#endif
|
||||
@@ -87,9 +87,11 @@ typedef struct _rws_socket_struct
|
||||
char *host;
|
||||
char *path;
|
||||
|
||||
char expected_accept[29];
|
||||
char *sec_ws_accept; // "Sec-WebSocket-Accept" field from handshake
|
||||
|
||||
rws_thread work_thread;
|
||||
rws_bool worker_started;
|
||||
|
||||
int command;
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifndef RWS_TLS_CONFIG_H
|
||||
#define RWS_TLS_CONFIG_H
|
||||
/* Shared by public and private headers so every socket layout agrees. */
|
||||
#define LIBRWS_USING_MBED_TLS 1
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "rws_handshake.h"
|
||||
#include <string.h>
|
||||
|
||||
static int equal_ci(const char *s, size_t n, const char *literal)
|
||||
{
|
||||
size_t i;
|
||||
if (strlen(literal) != n) return 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
unsigned char c = (unsigned char)s[i];
|
||||
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
|
||||
if (c != (unsigned char)literal[i]) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int has_token(const char *s, size_t n, const char *token)
|
||||
{
|
||||
size_t begin = 0, end, next;
|
||||
while (begin < n) {
|
||||
for (end = begin; end < n && s[end] != ','; ++end) {}
|
||||
next = end + 1;
|
||||
while (begin < end && (s[begin] == ' ' || s[begin] == '\t')) ++begin;
|
||||
while (end > begin && (s[end-1] == ' ' || s[end-1] == '\t')) --end;
|
||||
if (equal_ci(s + begin, end - begin, token)) return 1;
|
||||
begin = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rws_check_handshake(const char *data, size_t length, const char *expected_accept,
|
||||
size_t *header_length, int *http_status)
|
||||
{
|
||||
size_t total = 0, i, line, end, colon, first, last;
|
||||
int accept = 0, upgrade = 0, connection = 0;
|
||||
*header_length = 0;
|
||||
*http_status = 0;
|
||||
if (!data) return length ? -1 : 0;
|
||||
for (i = 0; i + 3 < length && i + 4 <= RWS_HANDSHAKE_MAX; ++i) {
|
||||
if (!memcmp(data + i, "\r\n\r\n", 4)) { total = i + 4; break; }
|
||||
}
|
||||
if (!total) return length >= RWS_HANDSHAKE_MAX ? -1 : 0;
|
||||
*header_length = total;
|
||||
for (i = 0; i < total; ++i) {
|
||||
unsigned char c = (unsigned char)data[i];
|
||||
if (c == 0 || (c < 32 && c != '\r' && c != '\n' && c != '\t')) return -1;
|
||||
}
|
||||
for (end = 0; end + 1 < total && memcmp(data + end, "\r\n", 2); ++end) {}
|
||||
if (end < 12 || memcmp(data, "HTTP/1.1 ", 9) ||
|
||||
(end > 12 && data[12] != ' ')) return -1;
|
||||
for (i = 9; i < 12; ++i) {
|
||||
if (data[i] < '0' || data[i] > '9') return -1;
|
||||
*http_status = *http_status * 10 + data[i] - '0';
|
||||
}
|
||||
if (*http_status != 101) return -1;
|
||||
line = end + 2;
|
||||
while (line < total - 2) {
|
||||
for (end = line; end + 1 < total && memcmp(data + end, "\r\n", 2); ++end) {}
|
||||
for (colon = line; colon < end && data[colon] != ':'; ++colon) {}
|
||||
if (colon == end) return -1;
|
||||
first = colon + 1;
|
||||
last = end;
|
||||
while (first < last && (data[first] == ' ' || data[first] == '\t')) ++first;
|
||||
while (last > first && (data[last-1] == ' ' || data[last-1] == '\t')) --last;
|
||||
if (equal_ci(data + line, colon - line, "sec-websocket-accept")) {
|
||||
if (accept || strlen(expected_accept) != last - first ||
|
||||
memcmp(data + first, expected_accept, last - first)) return -1;
|
||||
accept = 1;
|
||||
} else if (equal_ci(data + line, colon - line, "upgrade")) {
|
||||
upgrade |= has_token(data + first, last - first, "websocket");
|
||||
} else if (equal_ci(data + line, colon - line, "connection")) {
|
||||
connection |= has_token(data + first, last - first, "upgrade");
|
||||
} else if (equal_ci(data + line, colon - line, "sec-websocket-extensions") ||
|
||||
equal_ci(data + line, colon - line, "sec-websocket-protocol")) {
|
||||
return -1; /* This client did not request extensions or a subprotocol. */
|
||||
}
|
||||
line = end + 2;
|
||||
}
|
||||
return accept && upgrade && connection ? 1 : -1;
|
||||
}
|
||||
@@ -27,6 +27,13 @@
|
||||
#include <netdb.h>
|
||||
#include "sockets.h"
|
||||
#include "ql_rtos.h"
|
||||
#include <time.h>
|
||||
#include "rws_handshake.h"
|
||||
#ifdef LIBRWS_USING_MBED_TLS
|
||||
#include "mbedtls/base64.h"
|
||||
#include "mbedtls/sha1.h"
|
||||
#include "mbedtls/ssl_internal.h"
|
||||
#endif
|
||||
|
||||
|
||||
const char *k_rws_socket_min_http_ver = "1.1";
|
||||
@@ -127,86 +134,12 @@ void rws_socket_inform_recvd_frames(_rws_socket *s)
|
||||
}
|
||||
}
|
||||
|
||||
void rws_socket_read_handshake_responce_value(const char *str, char **value)
|
||||
{
|
||||
const char *s = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
while (*str == ':' || *str == ' ')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
s = str;
|
||||
while (*s != '\r' && *s != '\n')
|
||||
{
|
||||
s++;
|
||||
len++;
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
*value = rws_string_copy_len(str, len);
|
||||
}
|
||||
}
|
||||
|
||||
rws_bool rws_socket_process_handshake_responce(_rws_socket *s)
|
||||
{
|
||||
const char *str = (const char *)s->received;
|
||||
const char *sub = NULL;
|
||||
// float http_ver = -1;
|
||||
// int http_code = -1;
|
||||
|
||||
rws_error_delete_clean(&s->error);
|
||||
|
||||
// LOG_D("responce herader %s",str);
|
||||
|
||||
sub = strstr(str, "HTTP/");
|
||||
if (!sub)
|
||||
{
|
||||
LOG_E("herader not find HTTP ERROR");
|
||||
return rws_false;
|
||||
}
|
||||
|
||||
sub += 5;
|
||||
#if 0
|
||||
if (rws_sscanf(sub, "%f %i", &http_ver, &http_code) != 2)
|
||||
{
|
||||
LOG_D("responce sub %s",sub);
|
||||
http_ver = -1;
|
||||
http_code = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// "Sec-WebSocket-Accept"
|
||||
sub = strstr(str, k_rws_socket_sec_websocket_accept);
|
||||
if (sub)
|
||||
{
|
||||
sub += strlen(k_rws_socket_sec_websocket_accept);
|
||||
rws_socket_read_handshake_responce_value(sub, &s->sec_ws_accept);
|
||||
}
|
||||
|
||||
// "Sec-WebSocket-Accept"
|
||||
sub = strstr(str, "sec-websocket-accept");
|
||||
if (sub)
|
||||
{
|
||||
sub += strlen(k_rws_socket_sec_websocket_accept);
|
||||
rws_socket_read_handshake_responce_value(sub, &s->sec_ws_accept);
|
||||
}
|
||||
|
||||
// if (http_code != 101 || !s->sec_ws_accept)
|
||||
if (!s->sec_ws_accept)
|
||||
{
|
||||
#if 0
|
||||
s->error = rws_error_new_code_descr(rws_error_code_parse_handshake,
|
||||
(http_code != 101) ? "HTPP code not found or non 101" : "Accept key not found");
|
||||
|
||||
LOG_I("responce herader http_code %d",http_code);
|
||||
if(!s->sec_ws_accept){
|
||||
LOG_E("Accept key not found");
|
||||
}
|
||||
#endif
|
||||
return rws_false;
|
||||
}
|
||||
return rws_true;
|
||||
size_t header_length;
|
||||
int status;
|
||||
return rws_check_handshake((const char *)s->received, s->received_len,
|
||||
s->expected_accept, &header_length, &status) == 1;
|
||||
}
|
||||
|
||||
static int reliable_send(int sock, const void *data, size_t total_len) {
|
||||
@@ -255,6 +188,27 @@ static int reliable_send(int sock, const void *data, size_t total_len) {
|
||||
return sent_bytes;
|
||||
}
|
||||
|
||||
#ifdef LIBRWS_USING_MBED_TLS
|
||||
static int rws_tls_send_all(_rws_socket *s, const unsigned char *data, size_t size)
|
||||
{
|
||||
size_t sent = 0;
|
||||
unsigned int started = ql_rtos_get_systicks();
|
||||
if (!s->ssl) return -1;
|
||||
while (sent < size) {
|
||||
int ret = mbedtls_ssl_write(&s->ssl->ssl_ctx, data + sent, size - sent);
|
||||
if (ret > 0) {
|
||||
sent += (size_t)ret;
|
||||
} else if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
return -1;
|
||||
} else {
|
||||
rws_thread_sleep(5);
|
||||
}
|
||||
if (sent < size && (unsigned int)(ql_rtos_get_systicks() - started) >= 1000) return -1;
|
||||
}
|
||||
return (int)sent;
|
||||
}
|
||||
#endif
|
||||
|
||||
// need close socket on error
|
||||
rws_bool rws_socket_send(_rws_socket *s, const void *data, const size_t data_size)
|
||||
{
|
||||
@@ -265,7 +219,7 @@ rws_bool rws_socket_send(_rws_socket *s, const void *data, const size_t data_siz
|
||||
if (s->scheme && strcmp(s->scheme, "wss") == 0)
|
||||
{
|
||||
LOG_D("[T:%.8d, L:%.5d, %*.*s] try send data with tls", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
sended = mbedtls_ssl_write(&(s->ssl->ssl_ctx), (const unsigned char *)data, (int)data_size);
|
||||
sended = rws_tls_send_all(s, (const unsigned char *)data, data_size);
|
||||
}
|
||||
else
|
||||
#endif /* LIBRWS_USING_MBED_TLS */
|
||||
@@ -289,7 +243,7 @@ rws_bool rws_socket_send(_rws_socket *s, const void *data, const size_t data_siz
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sended > 0)
|
||||
if (sended == (int)data_size)
|
||||
{
|
||||
rws_socket_error_cnt = 0;
|
||||
rws_socket_error_staus = 0;
|
||||
@@ -297,6 +251,15 @@ rws_bool rws_socket_send(_rws_socket *s, const void *data, const size_t data_siz
|
||||
}
|
||||
|
||||
printf("errno:%d\n", errno);
|
||||
#ifdef LIBRWS_USING_MBED_TLS
|
||||
if (s->scheme && strcmp(s->scheme, "wss") == 0) {
|
||||
rws_error_delete_clean(&s->error);
|
||||
s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, "TLS write failed or timed out");
|
||||
rws_socket_close(s);
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
return rws_false;
|
||||
}
|
||||
#endif
|
||||
rws_socket_error_cnt++;
|
||||
if(rws_socket_error_cnt>3){
|
||||
rws_socket_error_staus = 1;
|
||||
@@ -345,7 +308,25 @@ rws_bool rws_socket_recv(_rws_socket *s)
|
||||
if (s->scheme && strcmp(s->scheme, "wss") == 0)
|
||||
{
|
||||
// LOG_D("[T:%.8d, L:%.5d, %*.*s] try recv data with tls", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
if (!s->ssl) {
|
||||
s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, "TLS context is closed");
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
result = rws_false;
|
||||
goto _exit;
|
||||
}
|
||||
len = mbedtls_ssl_read(&(s->ssl->ssl_ctx), (unsigned char *)(s->payload_buff), RWS_RECEIVE_BUFF_SIZE);
|
||||
if (len == MBEDTLS_ERR_SSL_WANT_READ || len == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
/* No TLS data yet: let the upgrade loop wait for the next record. */
|
||||
error_number = 0;
|
||||
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");
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
result = rws_false;
|
||||
goto _exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LIBRWS_USING_MBED_TLS */
|
||||
@@ -385,6 +366,12 @@ rws_bool rws_socket_recv(_rws_socket *s)
|
||||
if (len > 0)
|
||||
{
|
||||
total_len += len;
|
||||
if (s->command == COMMAND_WAIT_HANDSHAKE_RESPONCE &&
|
||||
s->received_len + (size_t)len > RWS_HANDSHAKE_MAX + RWS_RECEIVE_BUFF_SIZE) {
|
||||
s->error = rws_error_new_code_descr(rws_error_code_parse_handshake, "WebSocket headers too large");
|
||||
result = rws_false;
|
||||
goto _exit;
|
||||
}
|
||||
if (s->received_size - s->received_len < len)
|
||||
{
|
||||
// LOG_D("[T:%.8d, L:%.5d, %*.*s] s->received_size = %d, s->received_len = %d", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->received_size, s->received_len);
|
||||
@@ -398,6 +385,7 @@ rws_bool rws_socket_recv(_rws_socket *s)
|
||||
}
|
||||
memcpy(received, s->payload_buff, len);
|
||||
s->received_len += len;
|
||||
if (s->command == COMMAND_WAIT_HANDSHAKE_RESPONCE) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1020,54 +1008,32 @@ void rws_socket_idle_send(_rws_socket *s)
|
||||
|
||||
void rws_socket_wait_handshake_responce(_rws_socket *s)
|
||||
{
|
||||
int cnt = 0;
|
||||
// LOG_I("[T:%.8d, L:%.5d, %*.*s] try wait recv handshake responce", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
|
||||
/* Todo */
|
||||
while (!rws_socket_recv(s))
|
||||
{
|
||||
// LOG_D("[T:%.8d, L:%.5d, %*.*s] no find handshake responce", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
|
||||
if (s->error)
|
||||
{
|
||||
LOG_E("[T:%.8d, L:%.5d, %*.*s] recv responce failed, handshake failed, error = %d", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->error);
|
||||
LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket disconnect", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
return;
|
||||
}
|
||||
if(cnt++>2){
|
||||
s->command = COMMAND_SEND_HANDSHAKE;
|
||||
return;
|
||||
}
|
||||
rws_thread_sleep(1000);
|
||||
unsigned int started = ql_rtos_get_systicks();
|
||||
size_t header_length = 0;
|
||||
int status = 0, result = 0;
|
||||
while (result == 0) {
|
||||
rws_socket_recv(s);
|
||||
if (s->error) break;
|
||||
result = rws_check_handshake((const char *)s->received, s->received_len,
|
||||
s->expected_accept, &header_length, &status);
|
||||
if (result != 0) break;
|
||||
if ((unsigned int)(ql_rtos_get_systicks() - started) >= 2000) break;
|
||||
rws_thread_sleep(10);
|
||||
}
|
||||
|
||||
|
||||
if (s->received_len == 0)
|
||||
{
|
||||
LOG_D("[T:%.8d, L:%.5d, %*.*s] handshake responce len is empty, len = 0", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
// LOG_I("recv len %d",s->received_len);
|
||||
|
||||
// LOG_I("[T:%.8d, L:%.5d, %*.*s] try process handshake responce", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
if (rws_socket_process_handshake_responce(s))
|
||||
{
|
||||
s->received_len = 0;
|
||||
if (result == 1 && !s->error) {
|
||||
s->received_len -= header_length;
|
||||
if (s->received_len)
|
||||
memmove(s->received, (char *)s->received + header_length, s->received_len);
|
||||
s->is_connected = rws_true;
|
||||
s->command = COMMAND_INFORM_CONNECTED;
|
||||
|
||||
// LOG_D("[T:%.8d, L:%.5d, %*.*s] process handshake responce succeed", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket connect", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("WebSocket upgrade verified: HTTP 101\n");
|
||||
} else {
|
||||
LOG_E("WebSocket upgrade failed: HTTP %d (0 means incomplete/invalid headers)\n", status);
|
||||
if (!s->error)
|
||||
s->error = rws_error_new_code_descr(rws_error_code_parse_handshake,
|
||||
"Invalid or timed out WebSocket upgrade");
|
||||
rws_socket_close(s);
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
|
||||
//LOG_E("[T:%.8d, L:%.5d, %*.*s] process handshake responce failed", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket disconnect", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1093,6 +1059,24 @@ void rws_socket_send_handshake(_rws_socket *s)
|
||||
char buff[512];
|
||||
char *ptr = buff;
|
||||
size_t writed = 0;
|
||||
char key[25] = "dGhlIHNhbXBsZSBub25jZQ==";
|
||||
strcpy(s->expected_accept, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
|
||||
#ifdef LIBRWS_USING_MBED_TLS
|
||||
if (s->scheme && !strcmp(s->scheme, "wss")) {
|
||||
unsigned char nonce[16], digest[20];
|
||||
char challenge[61];
|
||||
size_t encoded;
|
||||
if (!s->ssl || mbedtls_ctr_drbg_random(&s->ssl->ctr_drbg, nonce, sizeof(nonce)) ||
|
||||
mbedtls_base64_encode((unsigned char *)key, sizeof(key), &encoded, nonce, sizeof(nonce)))
|
||||
goto key_error;
|
||||
strcpy(challenge, key);
|
||||
strcat(challenge, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
mbedtls_sha1((const unsigned char *)challenge, strlen(challenge), digest);
|
||||
if (mbedtls_base64_encode((unsigned char *)s->expected_accept,
|
||||
sizeof(s->expected_accept), &encoded, digest, sizeof(digest)))
|
||||
goto key_error;
|
||||
}
|
||||
#endif
|
||||
writed = rws_sprintf(ptr, 512, "GET %s HTTP/%s\r\n", s->path, k_rws_socket_min_http_ver);
|
||||
|
||||
if (s->port == 80)
|
||||
@@ -1114,7 +1098,7 @@ void rws_socket_send_handshake(_rws_socket *s)
|
||||
"Sec-WebSocket-Key: %s\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"\r\n",
|
||||
"dGhlIHNhbXBsZSBub25jZQ==");
|
||||
key);
|
||||
|
||||
if (rws_socket_send(s, buff, writed))
|
||||
{
|
||||
@@ -1133,6 +1117,13 @@ void rws_socket_send_handshake(_rws_socket *s)
|
||||
rws_socket_close(s);
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
}
|
||||
return;
|
||||
#ifdef LIBRWS_USING_MBED_TLS
|
||||
key_error:
|
||||
s->error = rws_error_new_code_descr(rws_error_code_send_handshake, "WebSocket nonce generation failed");
|
||||
rws_socket_close(s);
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct addrinfo *rws_socket_connect_getaddr_info(_rws_socket *s)
|
||||
@@ -1313,6 +1304,7 @@ void rws_socket_connect_to_host(_rws_socket *s)
|
||||
ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, &sock_error, &optlen);
|
||||
if(ret == 0 && sock_error == 0)
|
||||
{
|
||||
ret = 1;
|
||||
printf("connect success\r\n");
|
||||
}
|
||||
else
|
||||
@@ -1359,13 +1351,14 @@ void rws_socket_connect_to_host(_rws_socket *s)
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
|
||||
}
|
||||
#endif
|
||||
LOG_I("[T:%.8d, L:%.5d, %*.*s] socket break\n", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
LOG_I("[T:%.8d, L:%.5d, %*.*s] TCP connected; leaving connect loop\n", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_E("[T:%.8d, L:%.5d, %*.*s] socket connect failed\n", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
RWS_SOCK_CLOSE(sock);
|
||||
sock = RWS_INVALID_SOCKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1380,6 +1373,7 @@ void rws_socket_connect_to_host(_rws_socket *s)
|
||||
}
|
||||
|
||||
exit:
|
||||
if (s->socket == RWS_INVALID_SOCKET && sock != RWS_INVALID_SOCKET) RWS_SOCK_CLOSE(sock);
|
||||
freeaddrinfo(result);
|
||||
|
||||
if (s->socket == RWS_INVALID_SOCKET)
|
||||
@@ -1559,7 +1553,7 @@ static void rws_socket_work_th_func(void *user_object)
|
||||
LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_INFORM_DISCONNECTED\n", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
|
||||
|
||||
s->command = COMMAND_END;
|
||||
rws_socket_send_disconnect(s);
|
||||
if (s->is_connected) rws_socket_send_disconnect(s);
|
||||
|
||||
if (s->on_disconnected)
|
||||
{
|
||||
@@ -1619,27 +1613,16 @@ static void rws_socket_work_th_func(void *user_object)
|
||||
rws_bool rws_socket_create_start_work_thread(_rws_socket *s)
|
||||
{
|
||||
rws_error_delete_clean(&s->error);
|
||||
//s->work_thread = rws_thread_create(&rws_socket_work_th_func, s);
|
||||
|
||||
if (rws_socket_thread_status!=0){
|
||||
// rt_thread_delete(rws_work_task);
|
||||
s->command = COMMAND_END;
|
||||
// rws_work_task =NULL;
|
||||
while(rws_socket_thread_status){
|
||||
ql_rtos_task_sleep_ms(20);
|
||||
}
|
||||
}
|
||||
|
||||
s->command = COMMAND_NONE;
|
||||
|
||||
ql_rtos_task_create(&rws_work_task,1024*4,100,"rws_work",
|
||||
rws_socket_work_th_func, s);
|
||||
|
||||
if (rws_work_task)
|
||||
{
|
||||
s->command = COMMAND_CONNECT_TO_HOST;
|
||||
while (rws_socket_thread_status) ql_rtos_task_sleep_ms(20);
|
||||
s->command = COMMAND_CONNECT_TO_HOST;
|
||||
s->worker_started = rws_true;
|
||||
rws_work_task = NULL;
|
||||
/* TLS certificate parsing and crypto need more stack than plain WS. */
|
||||
if (ql_rtos_task_create(&rws_work_task, 1024*16, 100, "rws_work",
|
||||
rws_socket_work_th_func, s) == 0)
|
||||
return rws_true;
|
||||
}
|
||||
s->worker_started = rws_false;
|
||||
s->command = COMMAND_NONE;
|
||||
return rws_false;
|
||||
}
|
||||
|
||||
@@ -1867,36 +1850,88 @@ void rws_debug(void *ctx, int level, const char *file, int line, const char *str
|
||||
LOG_I("%s", str ? str : NULL);
|
||||
}
|
||||
|
||||
// TODO: mbedtls_ssl_set_hostname() should be called.
|
||||
/* Prefer a fast, widely supported full-handshake group on this MCU.
|
||||
* Retain all groups enabled by the shared SDK profile as fallbacks. */
|
||||
static const mbedtls_ecp_group_id rws_tls_preferred_curves[] = {
|
||||
MBEDTLS_ECP_DP_CURVE25519,
|
||||
MBEDTLS_ECP_DP_SECP256R1,
|
||||
MBEDTLS_ECP_DP_SECP384R1,
|
||||
MBEDTLS_ECP_DP_SECP521R1,
|
||||
MBEDTLS_ECP_DP_CURVE448,
|
||||
MBEDTLS_ECP_DP_BP512R1,
|
||||
MBEDTLS_ECP_DP_BP384R1,
|
||||
MBEDTLS_ECP_DP_BP256R1,
|
||||
MBEDTLS_ECP_DP_SECP224R1,
|
||||
MBEDTLS_ECP_DP_SECP224K1,
|
||||
MBEDTLS_ECP_DP_SECP192R1,
|
||||
MBEDTLS_ECP_DP_SECP192K1,
|
||||
MBEDTLS_ECP_DP_NONE
|
||||
};
|
||||
|
||||
static const char *rws_tls_phase_name(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case MBEDTLS_SSL_CLIENT_HELLO: return "client hello";
|
||||
case MBEDTLS_SSL_SERVER_HELLO: return "server hello";
|
||||
case MBEDTLS_SSL_SERVER_CERTIFICATE: return "server certificate";
|
||||
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";
|
||||
default: return "other";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
while (ctx->state != MBEDTLS_SSL_HANDSHAKE_OVER) {
|
||||
unsigned int before = ql_rtos_get_systicks();
|
||||
ret = mbedtls_ssl_handshake_step(ctx);
|
||||
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;
|
||||
if (ret != 0) ++retries;
|
||||
if (ctx->state != state) {
|
||||
if (state == MBEDTLS_SSL_SERVER_KEY_EXCHANGE && ctx->handshake) {
|
||||
mbedtls_ecp_group_id group = ctx->handshake->ecdh_ctx.grp_id;
|
||||
LOG_I("WSS TLS negotiated ECDHE group: %d (X25519=%d, P256=%d, P384=%d, P521=%d)\n",
|
||||
(int)group, (int)MBEDTLS_ECP_DP_CURVE25519,
|
||||
(int)MBEDTLS_ECP_DP_SECP256R1, (int)MBEDTLS_ECP_DP_SECP384R1,
|
||||
(int)MBEDTLS_ECP_DP_SECP521R1);
|
||||
}
|
||||
LOG_I("WSS TLS phase %s (%d): elapsed=%u ms, calls=%u ms, retries=%u\n",
|
||||
rws_tls_phase_name(state), state,
|
||||
(unsigned int)(ql_rtos_get_systicks() - phase_started) * 5,
|
||||
call_ticks * 5, retries);
|
||||
state = ctx->state;
|
||||
phase_started = ql_rtos_get_systicks();
|
||||
call_ticks = retries = 0;
|
||||
}
|
||||
if (ctx->state == MBEDTLS_SSL_HANDSHAKE_OVER) break;
|
||||
if ((unsigned int)(ql_rtos_get_systicks() - started) >= 4000) {
|
||||
ret = MBEDTLS_ERR_SSL_TIMEOUT; /* 20 seconds, 5 ms SDK ticks */
|
||||
break;
|
||||
}
|
||||
if (ret != 0) rws_thread_sleep(10);
|
||||
}
|
||||
LOG_I("WSS TLS handshake total=%u ms, state=%d, ret=%d\n",
|
||||
(unsigned int)(ql_rtos_get_systicks() - started) * 5, ctx->state, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rws_ssl_conn(_rws_socket *s)
|
||||
{
|
||||
int authmode = MBEDTLS_SSL_VERIFY_NONE;
|
||||
const char *pers = "https";
|
||||
int value, ret = 0;
|
||||
const char *pers = "talkingq-wss";
|
||||
const char *stage = "allocate TLS context";
|
||||
int ret = -1;
|
||||
uint32_t flags;
|
||||
_rws_ssl *ssl = NULL;
|
||||
char portstr[16] = {0};
|
||||
|
||||
//value = value;
|
||||
_rws_ssl *ssl;
|
||||
|
||||
s->ssl = rws_malloc_zero(sizeof(_rws_ssl));
|
||||
if (!s->ssl)
|
||||
{
|
||||
LOG_I("Memory malloc error.");
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
if (!s->ssl) goto exit;
|
||||
ssl = s->ssl;
|
||||
|
||||
if (s->server_cert)
|
||||
authmode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
|
||||
/*
|
||||
* Initialize the RNG and the session data
|
||||
*/
|
||||
#if defined(MBEDTLS_DEBUG_C)
|
||||
mbedtls_debug_set_threshold(DEBUG_LEVEL);
|
||||
#endif
|
||||
mbedtls_net_init(&ssl->net_ctx);
|
||||
mbedtls_ssl_init(&ssl->ssl_ctx);
|
||||
mbedtls_ssl_config_init(&ssl->ssl_conf);
|
||||
@@ -1904,212 +1939,93 @@ int rws_ssl_conn(_rws_socket *s)
|
||||
mbedtls_x509_crt_init(&ssl->clicert);
|
||||
mbedtls_pk_init(&ssl->pkey);
|
||||
mbedtls_ctr_drbg_init(&ssl->ctr_drbg);
|
||||
|
||||
/*
|
||||
* 0. Initialize the RNG and the session data
|
||||
*/
|
||||
mbedtls_entropy_init(&ssl->entropy);
|
||||
if ((value = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg,
|
||||
mbedtls_entropy_func,
|
||||
&ssl->entropy,
|
||||
(const unsigned char *)pers,
|
||||
strlen(pers))) != 0)
|
||||
{
|
||||
LOG_I("mbedtls_ctr_drbg_seed() failed, value:-0x%x.", -value);
|
||||
ret = -1;
|
||||
|
||||
if (!s->server_cert || s->server_cert_len <= 0) {
|
||||
LOG_E("WSS requires a trusted root CA\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the Client certificate
|
||||
*/
|
||||
if (s->client_cert && s->client_pk)
|
||||
{
|
||||
ret = mbedtls_x509_crt_parse(&ssl->clicert, (const unsigned char *)s->client_cert, s->client_cert_len);
|
||||
if (ret < 0)
|
||||
{
|
||||
LOG_I("Loading cli_cert failed! mbedtls_x509_crt_parse returned -0x%x.", -ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_pk_parse_key(&ssl->pkey, (const unsigned char *)s->client_pk, s->client_pk_len, NULL, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_I("failed! mbedtls_pk_parse_key returned -0x%x.", -ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the trusted CA
|
||||
*/
|
||||
/* cert_len passed in is gotten from sizeof not strlen */
|
||||
if (s->server_cert && ((value = mbedtls_x509_crt_parse(&ssl->cacert,
|
||||
(const unsigned char *)s->server_cert,
|
||||
s->server_cert_len)) < 0))
|
||||
{
|
||||
LOG_I("mbedtls_x509_crt_parse() failed, value:-0x%x.", -value);
|
||||
ret = -1;
|
||||
if (time(NULL) < 1704067200) {
|
||||
LOG_E("WSS requires valid network/RTC time before certificate verification\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// rws_socket_set_option(ssl->net_ctx.fd, SO_ERROR, 1); // When an error occurs on a socket, set error variable so_error and notify process
|
||||
// rws_socket_set_option(ssl->net_ctx.fd, SO_KEEPALIVE, 1); // Periodically test if connection is alive
|
||||
|
||||
// {
|
||||
// struct timeval timeout;
|
||||
|
||||
// timeout.tv_sec = 1;
|
||||
// timeout.tv_usec = 0;
|
||||
// setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout));
|
||||
// setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
|
||||
// }
|
||||
|
||||
/*
|
||||
* Start the connection
|
||||
*/
|
||||
rws_sprintf(portstr, 16, "%i", s->port);
|
||||
if ((ret = mbedtls_net_connect(&ssl->net_ctx, s->host, portstr, MBEDTLS_NET_PROTO_TCP)) != 0)
|
||||
{
|
||||
LOG_I("failed! mbedtls_net_connect returned %d, port:%s.", ret, portstr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s->received_len = 0;
|
||||
s->socket = ssl->net_ctx.fd;
|
||||
|
||||
/*
|
||||
* Setup stuff
|
||||
*/
|
||||
if ((value = mbedtls_ssl_config_defaults(&ssl->ssl_conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
|
||||
{
|
||||
LOG_I("mbedtls_ssl_config_defaults() failed, value:-0x%x.", -value);
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// TODO: add customerization encryption algorithm
|
||||
memcpy(&ssl->profile, ssl->ssl_conf.cert_profile, sizeof(mbedtls_x509_crt_profile));
|
||||
ssl->profile.allowed_mds = ssl->profile.allowed_mds | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_MD5);
|
||||
mbedtls_ssl_conf_cert_profile(&ssl->ssl_conf, &ssl->profile);
|
||||
|
||||
mbedtls_ssl_conf_authmode(&ssl->ssl_conf, authmode);
|
||||
stage = "seed RNG";
|
||||
ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func,
|
||||
&ssl->entropy, (const unsigned char *)pers, strlen(pers));
|
||||
if (ret != 0) goto exit;
|
||||
stage = "parse root CA";
|
||||
ret = mbedtls_x509_crt_parse(&ssl->cacert, (const unsigned char *)s->server_cert,
|
||||
s->server_cert_len);
|
||||
if (ret != 0) goto exit;
|
||||
LOG_I("WSS root CA parsed successfully\n");
|
||||
stage = "configure TLS";
|
||||
ret = mbedtls_ssl_config_defaults(&ssl->ssl_conf, MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (ret != 0) goto exit;
|
||||
/* Equivalent to mbedtls_ssl_conf_curves(): this SDK does not export its
|
||||
setter to APP. The shared profile and ABI test cover curve_list. */
|
||||
ssl->ssl_conf.curve_list = rws_tls_preferred_curves;
|
||||
LOG_I("WSS TLS full handshake: prefer X25519, P256, P384, P521\n");
|
||||
mbedtls_ssl_conf_authmode(&ssl->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
mbedtls_ssl_conf_ca_chain(&ssl->ssl_conf, &ssl->cacert, NULL);
|
||||
mbedtls_ssl_conf_max_frag_len(&ssl->ssl_conf, MBEDTLS_SSL_MAX_FRAG_LEN_4096);
|
||||
|
||||
if (s->client_cert && (ret = mbedtls_ssl_conf_own_cert(&ssl->ssl_conf, &ssl->clicert, &ssl->pkey)) != 0)
|
||||
{
|
||||
LOG_I(" failed! mbedtls_ssl_conf_own_cert returned %d.", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_min_version(&ssl->ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
|
||||
mbedtls_ssl_conf_rng(&ssl->ssl_conf, mbedtls_ctr_drbg_random, &ssl->ctr_drbg);
|
||||
mbedtls_ssl_conf_dbg(&ssl->ssl_conf, rws_debug, NULL);
|
||||
ret = mbedtls_ssl_setup(&ssl->ssl_ctx, &ssl->ssl_conf);
|
||||
if (ret != 0) goto exit;
|
||||
/* Sets both SNI and the expected certificate hostname. */
|
||||
ret = mbedtls_ssl_set_hostname(&ssl->ssl_ctx, s->host);
|
||||
if (ret != 0) goto exit;
|
||||
|
||||
if ((value = mbedtls_ssl_setup(&ssl->ssl_ctx, &ssl->ssl_conf)) != 0)
|
||||
{
|
||||
LOG_I("mbedtls_ssl_setup() failed, value:-0x%x.", -value);
|
||||
ret = -1;
|
||||
/* Reuse the working PDP profile 1 TCP path. The ASR net_connect API has
|
||||
a vendor-specific CID/port ABI, unlike upstream mbedTLS. */
|
||||
stage = "connect TCP";
|
||||
rws_socket_connect_to_host(s);
|
||||
if (s->socket == RWS_INVALID_SOCKET) {
|
||||
ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ssl_set_hostname(&ssl->ssl_ctx, s->host)) != 0)
|
||||
{
|
||||
LOG_I("failed\n! mbedtls_ssl_set_hostname returned %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ssl->net_ctx.fd = s->socket;
|
||||
#ifdef MBEDTLS_WITH_ASR
|
||||
ssl->net_ctx.cid = 1;
|
||||
#endif
|
||||
stage = "set nonblocking TCP";
|
||||
ret = mbedtls_net_set_nonblock(&ssl->net_ctx);
|
||||
if (ret != 0) goto exit;
|
||||
mbedtls_ssl_set_bio(&ssl->ssl_ctx, &ssl->net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
/*
|
||||
* Handshake
|
||||
*/
|
||||
while ((ret = mbedtls_ssl_handshake(&ssl->ssl_ctx)) != 0)
|
||||
{
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
LOG_I("mbedtls_ssl_handshake() failed, ret:-0x%x.", -ret);
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
LOG_I("mbedtls_ssl_handshake() while");
|
||||
}
|
||||
|
||||
LOG_I("mbedtls_ssl_handshake() ok");
|
||||
|
||||
// Todo
|
||||
// mbedtls_net_set_nonblock(&ssl->net_ctx);
|
||||
|
||||
{
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout));
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 1000;
|
||||
setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the server certificate
|
||||
*/
|
||||
/* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the
|
||||
* handshake would not succeed if the peer's cert is bad. Even if we used
|
||||
* MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */
|
||||
if ((flags = mbedtls_ssl_get_verify_result(&ssl->ssl_ctx)) != 0)
|
||||
{
|
||||
char vrfy_buf[512];
|
||||
LOG_I("svr_cert varification failed. authmode:%d", authmode);
|
||||
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
|
||||
LOG_I("%s", vrfy_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("svr_cert varification ok. authmode:%d", authmode);
|
||||
stage = "TLS handshake / server certificate";
|
||||
ret = rws_tls_handshake_timed(&ssl->ssl_ctx);
|
||||
if (ret != 0) goto exit;
|
||||
flags = mbedtls_ssl_get_verify_result(&ssl->ssl_ctx);
|
||||
if (flags != 0) {
|
||||
LOG_E("WSS certificate verification failed: 0x%08lx\n", (unsigned long)flags);
|
||||
ret = MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
LOG_I("WSS TLS handshake and certificate/hostname verification passed: %s:%d\n", s->host, s->port);
|
||||
s->received_len = 0;
|
||||
s->command = COMMAND_SEND_HANDSHAKE;
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
if (ret != 0)
|
||||
{
|
||||
#ifdef MBEDTLS_ERROR_C
|
||||
char error_buf[100];
|
||||
|
||||
extern void mbedtls_strerror(int ret, char *buf, size_t buflen);
|
||||
mbedtls_strerror(ret, error_buf, 100);
|
||||
LOG_I("Last error was: %d - %s", ret, error_buf);
|
||||
#endif
|
||||
LOG_I("ret=%d.", ret);
|
||||
s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "Failed connect to host");
|
||||
LOG_I("%s: code:%d, error:%s", __FUNCTION__, s->error->code, s->error->description);
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
|
||||
if (s->ssl)
|
||||
{
|
||||
mbedtls_net_free(&s->ssl->net_ctx);
|
||||
mbedtls_x509_crt_free(&s->ssl->cacert);
|
||||
mbedtls_x509_crt_free(&s->ssl->clicert);
|
||||
mbedtls_pk_free(&s->ssl->pkey);
|
||||
mbedtls_ssl_free(&s->ssl->ssl_ctx);
|
||||
mbedtls_ssl_config_free(&s->ssl->ssl_conf);
|
||||
mbedtls_ctr_drbg_free(&s->ssl->ctr_drbg);
|
||||
mbedtls_entropy_free(&s->ssl->entropy);
|
||||
|
||||
rws_free(s->ssl);
|
||||
s->ssl = NULL;
|
||||
}
|
||||
|
||||
s->socket = RWS_INVALID_SOCKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->command = COMMAND_SEND_HANDSHAKE;
|
||||
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) {
|
||||
/* Do not send close_notify for an incomplete handshake. */
|
||||
mbedtls_net_free(&s->ssl->net_ctx);
|
||||
mbedtls_x509_crt_free(&s->ssl->cacert);
|
||||
mbedtls_x509_crt_free(&s->ssl->clicert);
|
||||
mbedtls_pk_free(&s->ssl->pkey);
|
||||
mbedtls_ssl_free(&s->ssl->ssl_ctx);
|
||||
mbedtls_ssl_config_free(&s->ssl->ssl_conf);
|
||||
mbedtls_ctr_drbg_free(&s->ssl->ctr_drbg);
|
||||
mbedtls_entropy_free(&s->ssl->entropy);
|
||||
rws_free(s->ssl);
|
||||
s->ssl = NULL;
|
||||
}
|
||||
s->socket = RWS_INVALID_SOCKET;
|
||||
s->is_connected = rws_false;
|
||||
s->command = COMMAND_INFORM_DISCONNECTED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ void rws_socket_disconnect_and_release(rws_socket socket)
|
||||
s->command = COMMAND_DISCONNECT;
|
||||
rws_mutex_unlock(s->work_mutex);
|
||||
}
|
||||
else if (s->work_thread)
|
||||
else if (s->worker_started || s->work_thread)
|
||||
{
|
||||
// disconnected in loop
|
||||
s->command = COMMAND_END;
|
||||
@@ -104,7 +104,7 @@ void rws_socket_disconnect_and_release(rws_socket socket)
|
||||
{
|
||||
// not in loop
|
||||
rws_mutex_unlock(s->work_mutex);
|
||||
// rws_socket_delete(s);
|
||||
rws_socket_delete(s);
|
||||
}else{
|
||||
rws_mutex_unlock(s->work_mutex);
|
||||
}
|
||||
@@ -408,7 +408,7 @@ rws_bool rws_socket_is_connected(rws_socket socket)
|
||||
#ifdef LIBRWS_USING_MBED_TLS
|
||||
void rws_socket_set_server_cert(rws_socket socket, const char *server_cert, int server_cert_len)
|
||||
{
|
||||
LOG_D("[T:%.8d, L:%.5d, %*.*s] cert:\n%s", ql_rtos_get_systicks(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, server_cert_len, server_cert ? server_cert : "");
|
||||
LOG_D("WSS trust anchor loaded: %d bytes\n", server_cert_len);
|
||||
|
||||
_rws_socket *s = (_rws_socket *)socket;
|
||||
if (s)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
=================================================================*/
|
||||
|
||||
#include "MQTTClient.h"
|
||||
#include "mqtt_connect_diag.h"
|
||||
#include "ql_data_call.h"
|
||||
#include "ql_application.h"
|
||||
#include "sockets.h"
|
||||
@@ -25,7 +26,7 @@
|
||||
|
||||
#define PROFILE_IDX 1
|
||||
//#define DEFAULT_SERVER_DOMAIN "175.24.73.253"
|
||||
#define DEFAULT_SERVER_DOMAIN "101.35.224.118"
|
||||
#define DEFAULT_SERVER_DOMAIN "banban.api.talkingq.com"
|
||||
#define DEFAULT_SERVER_CLIENT_USER "talkingq"
|
||||
#define DEFAULT_SERVER_CLIENT_PASS "talkingq@2026"
|
||||
#define DEFAULT_SERVER_CLIENT_ID "9376265c059e474e92c2e46208ae1dc5"
|
||||
@@ -448,6 +449,8 @@ int app_mqtt_connect()
|
||||
|
||||
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
|
||||
int mqtt_server_port=DEFAULT_SERVER_PORT;
|
||||
unsigned int tcp_started;
|
||||
int tcp_errno;
|
||||
|
||||
MQTT_CONN_LOCK();
|
||||
if(mqtt_connect==1){
|
||||
@@ -462,7 +465,14 @@ int app_mqtt_connect()
|
||||
NetworkInit(&network, NULL, PROFILE_IDX);
|
||||
MQTTClientInit(&client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));
|
||||
char* address = DEFAULT_SERVER_DOMAIN;
|
||||
if ((rc = NetworkConnect(&network, address, mqtt_server_port)) != 0)
|
||||
printf("[MQTT-DIAG] TCP begin host=%s port=%d pdp=%d\r\n",
|
||||
address, mqtt_server_port, app_get_data_call_net_status());
|
||||
tcp_started = ql_rtos_get_systicks();
|
||||
rc = NetworkConnect(&network, address, mqtt_server_port);
|
||||
tcp_errno = rc != 0 ? ql_get_soc_errno() : 0;
|
||||
printf("[MQTT-DIAG] TCP end rc=%d socket=%d elapsed_ms=%u errno_snapshot=%d\r\n",
|
||||
rc, network.my_socket, (unsigned int)(ql_rtos_get_systicks() - tcp_started) * 5U, tcp_errno);
|
||||
if (rc != 0)
|
||||
{
|
||||
RLOGE("Return code from network connect is %d", rc);
|
||||
MQTTClientDeinit(&client);
|
||||
@@ -486,7 +496,8 @@ int app_mqtt_connect()
|
||||
connectData.cleansession = 0;
|
||||
connectData.keepAliveInterval = 60;
|
||||
|
||||
if ((rc = MQTTConnect(&client, &connectData)) != 0)
|
||||
printf("[MQTT-DIAG] saved_device_id=%d (registration needed when 0)\r\n", ret == 0);
|
||||
if ((rc = talkingq_mqtt_connect_diagnosed(&client, &connectData)) != 0)
|
||||
{
|
||||
RLOGE("Return code from MQTT connect is %d", rc);
|
||||
NetworkDisconnect(&network);
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mqtt_connect_diag.h"
|
||||
#include "sockets.h"
|
||||
|
||||
/* Only installed during synchronous CONNECT. Never dump the CONNECT payload:
|
||||
* it contains credentials. Keep only the first four incoming CONNACK bytes. */
|
||||
static struct {
|
||||
int (*read)(Network *, unsigned char *, int, int);
|
||||
int (*write)(Network *, unsigned char *, int, int);
|
||||
unsigned int read_calls, write_calls, received, sent;
|
||||
unsigned char prefix[4];
|
||||
unsigned int prefix_size;
|
||||
} mqtt_diag;
|
||||
|
||||
static unsigned int mqtt_diag_elapsed(unsigned int start)
|
||||
{
|
||||
return (unsigned int)(ql_rtos_get_systicks() - start) * 5U;
|
||||
}
|
||||
|
||||
static int mqtt_diag_read(Network *network, unsigned char *buffer, int size, int timeout)
|
||||
{
|
||||
unsigned int start = ql_rtos_get_systicks();
|
||||
int result = mqtt_diag.read(network, buffer, size, timeout);
|
||||
int socket_error = result <= 0 ? ql_get_soc_errno() : 0;
|
||||
int i;
|
||||
++mqtt_diag.read_calls;
|
||||
if (result > 0) {
|
||||
mqtt_diag.received += (unsigned int)result;
|
||||
for (i = 0; i < result && i < size && mqtt_diag.prefix_size < sizeof(mqtt_diag.prefix); ++i)
|
||||
mqtt_diag.prefix[mqtt_diag.prefix_size++] = buffer[i];
|
||||
}
|
||||
printf("[MQTT-DIAG] read request=%d rc=%d timeout_ms=%d elapsed_ms=%u errno_snapshot=%d\r\n",
|
||||
size, result, timeout, mqtt_diag_elapsed(start), socket_error);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int mqtt_diag_write(Network *network, unsigned char *buffer, int size, int timeout)
|
||||
{
|
||||
unsigned int start = ql_rtos_get_systicks();
|
||||
int result = mqtt_diag.write(network, buffer, size, timeout);
|
||||
int socket_error = result <= 0 ? ql_get_soc_errno() : 0;
|
||||
++mqtt_diag.write_calls;
|
||||
if (result > 0) mqtt_diag.sent += (unsigned int)result;
|
||||
printf("[MQTT-DIAG] write request=%d rc=%d timeout_ms=%d elapsed_ms=%u errno_snapshot=%d\r\n",
|
||||
size, result, timeout, mqtt_diag_elapsed(start), socket_error);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char *mqtt_diag_connack_reason(unsigned char code)
|
||||
{
|
||||
switch (code) {
|
||||
case 0: return "accepted";
|
||||
case 1: return "protocol_version_rejected";
|
||||
case 2: return "client_id_rejected";
|
||||
case 3: return "server_unavailable";
|
||||
case 4: return "bad_username_or_password";
|
||||
case 5: return "not_authorized";
|
||||
default: return "reserved_code";
|
||||
}
|
||||
}
|
||||
|
||||
int talkingq_mqtt_connect_diagnosed(MQTTClient *client, MQTTPacket_connectData *options)
|
||||
{
|
||||
Network *network = client->ipstack;
|
||||
MQTTConnackData connack = {255, 255};
|
||||
unsigned int start;
|
||||
int result;
|
||||
int valid_connack;
|
||||
memset(&mqtt_diag, 0, sizeof(mqtt_diag));
|
||||
mqtt_diag.read = network->mqttread;
|
||||
mqtt_diag.write = network->mqttwrite;
|
||||
if (!mqtt_diag.read || !mqtt_diag.write) {
|
||||
printf("[MQTT-DIAG] missing transport callbacks; calling SDK unchanged\r\n");
|
||||
return MQTTConnectWithResults(client, options, &connack);
|
||||
}
|
||||
printf("[MQTT-DIAG] CONNECT begin version=%u clean=%u keepalive_s=%u timeout_ms=%u already_connected=%d\r\n",
|
||||
(unsigned int)options->MQTTVersion, (unsigned int)options->cleansession,
|
||||
(unsigned int)options->keepAliveInterval, client->command_timeout_ms, client->isconnected);
|
||||
network->mqttread = mqtt_diag_read;
|
||||
network->mqttwrite = mqtt_diag_write;
|
||||
start = ql_rtos_get_systicks();
|
||||
result = MQTTConnectWithResults(client, options, &connack);
|
||||
network->mqttread = mqtt_diag.read;
|
||||
network->mqttwrite = mqtt_diag.write;
|
||||
printf("[MQTT-DIAG] CONNECT end rc=%d elapsed_ms=%u write_calls=%u tx_bytes=%u read_calls=%u rx_bytes=%u\r\n",
|
||||
result, mqtt_diag_elapsed(start), mqtt_diag.write_calls, mqtt_diag.sent,
|
||||
mqtt_diag.read_calls, mqtt_diag.received);
|
||||
valid_connack = mqtt_diag.prefix_size == 4 && mqtt_diag.prefix[0] == 0x20 &&
|
||||
mqtt_diag.prefix[1] == 2 && (mqtt_diag.prefix[2] & 0xfe) == 0 &&
|
||||
mqtt_diag.prefix[3] <= 5 &&
|
||||
(mqtt_diag.prefix[3] == 0 || mqtt_diag.prefix[2] == 0);
|
||||
if (valid_connack) {
|
||||
printf("[MQTT-DIAG] CONNACK code=%u reason=%s session_present=%u\r\n",
|
||||
(unsigned int)mqtt_diag.prefix[3], mqtt_diag_connack_reason(mqtt_diag.prefix[3]),
|
||||
(unsigned int)mqtt_diag.prefix[2]);
|
||||
} else if (mqtt_diag.received) {
|
||||
printf("[MQTT-DIAG] no valid initial CONNACK: received_prefix_bytes=%u\r\n", mqtt_diag.prefix_size);
|
||||
} else {
|
||||
printf("[MQTT-DIAG] no response bytes returned by SDK read\r\n");
|
||||
}
|
||||
if (result != 0 && !mqtt_diag.write_calls)
|
||||
printf("[MQTT-DIAG] failed before transport write; inspect client state/CONNECT serialization\r\n");
|
||||
/* SDK read maps both EOF and some socket errors to -1. The errno snapshot
|
||||
* can be stale; do not claim a broker rejection without a valid CONNACK. */
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "talkingq_wss.h"
|
||||
|
||||
/* ISRG Root X2; SHA-256 fingerprint and provenance in docs/talkingq_wss.md. */
|
||||
const char talkingq_root_ca[] =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV\n"
|
||||
"UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT\n"
|
||||
"UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT\n"
|
||||
"MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS\n"
|
||||
"RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H\n"
|
||||
"ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb\n"
|
||||
"d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
|
||||
"HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF\n"
|
||||
"cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5\n"
|
||||
"U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn\n"
|
||||
"-----END CERTIFICATE-----\n"
|
||||
;
|
||||
const size_t talkingq_root_ca_size = sizeof(talkingq_root_ca);
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "talkingq_wss.h"
|
||||
#include <string.h>
|
||||
|
||||
int talkingq_is_legacy_ws_url(const char *url)
|
||||
{
|
||||
return url && (!strcmp(url, "ws://101.35.224.118:8080") ||
|
||||
!strcmp(url, "ws://101.35.224.118:8080/ws") ||
|
||||
!strcmp(url, "ws://api.talkingq.com:8080") ||
|
||||
!strcmp(url, "ws://175.24.73.253:80"));
|
||||
}
|
||||
|
||||
int talkingq_parse_wss_url(const char *url, char *host, size_t host_size,
|
||||
int *port, char *path, size_t path_size)
|
||||
{
|
||||
const char *begin, *end, *colon, *cursor, *resource;
|
||||
size_t length;
|
||||
unsigned int value = 0;
|
||||
if (!url || !host || !port || !path || strncmp(url, "wss://", 6))
|
||||
return -1;
|
||||
begin = url + 6;
|
||||
end = strchr(begin, '/');
|
||||
if (!end) end = begin + strlen(begin);
|
||||
colon = memchr(begin, ':', (size_t)(end - begin));
|
||||
length = (size_t)((colon ? colon : end) - begin);
|
||||
if (!length || length >= host_size) return -1;
|
||||
for (cursor = begin; cursor < begin + length; ++cursor) {
|
||||
char c = *cursor;
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') || c == '.' || c == '-')) return -1;
|
||||
}
|
||||
if (colon) {
|
||||
if (colon + 1 == end) return -1;
|
||||
for (cursor = colon + 1; cursor < end; ++cursor) {
|
||||
if (*cursor < '0' || *cursor > '9') return -1;
|
||||
value = value * 10 + (unsigned int)(*cursor - '0');
|
||||
if (value > 65535) return -1;
|
||||
}
|
||||
if (!value) return -1;
|
||||
} else {
|
||||
value = 443;
|
||||
}
|
||||
resource = *end ? end : "/ws";
|
||||
if (strlen(resource) >= path_size) return -1;
|
||||
for (cursor = resource; *cursor; ++cursor) {
|
||||
if ((unsigned char)*cursor <= 32 || *cursor == '#' ||
|
||||
(unsigned char)*cursor >= 127) return -1;
|
||||
}
|
||||
memcpy(host, begin, length);
|
||||
host[length] = '\0';
|
||||
strcpy(path, resource);
|
||||
*port = (int)value;
|
||||
return 0;
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <librws.h>
|
||||
#include "cJSON.h"
|
||||
#include "app_inc.h"
|
||||
#include "talkingq_wss.h"
|
||||
#include "ql_rtos.h"
|
||||
#include "ql_application.h"
|
||||
#include "ql_audio.h"
|
||||
@@ -129,6 +130,7 @@ unsigned char get_xiaoice_connected_status(void)
|
||||
|
||||
static void onopen(rws_socket socket)
|
||||
{
|
||||
if (socket != app->socket || !app->init) return;
|
||||
wss_connect_counter=0;
|
||||
|
||||
LOG_D("websocket connected. ");
|
||||
@@ -153,12 +155,14 @@ static void onclose(rws_socket socket)
|
||||
LOG_D("websocket disconnect! ");
|
||||
}
|
||||
|
||||
xiaoice_wss_connect_status = 0;
|
||||
|
||||
rws_socket_disconnect_and_release(app->socket);
|
||||
if (socket != app->socket) return;
|
||||
xiaoice_wss_connect_status = 0;
|
||||
app->socket = NULL;
|
||||
/* The worker owns and releases this socket after the callback. */
|
||||
|
||||
RLOGD("onclose end\r\n");
|
||||
app->init = 0;
|
||||
if (ws_connect_sem) ql_rtos_semaphore_release(ws_connect_sem);
|
||||
|
||||
hal_led_b_off();
|
||||
}
|
||||
@@ -305,8 +309,8 @@ int talkingq_ws_connect()
|
||||
{
|
||||
int result;
|
||||
int ret = -1;
|
||||
char wss_path[56]={0};
|
||||
char ws_talkingq_url[56]={0};
|
||||
char wss_path[TALKINGQ_PATH_CAPACITY]={0};
|
||||
char ws_talkingq_url[TALKINGQ_URL_CAPACITY]={0};
|
||||
int port;
|
||||
// char session_id[56]={0};
|
||||
// char ip_name[56]={0};
|
||||
@@ -329,40 +333,33 @@ int talkingq_ws_connect()
|
||||
ql_rtos_semaphore_create(&ws_connect_sem, 0);
|
||||
}
|
||||
|
||||
sprintf(wss_path,"%s","/ws");
|
||||
|
||||
if (ws_connect_sem) while (ql_rtos_semaphore_wait(ws_connect_sem, 0) == 0) {}
|
||||
hal_os_get_talkingq_url(ws_talkingq_url);
|
||||
printf("ws_talkingq_url %s",ws_talkingq_url);
|
||||
|
||||
if(strncmp(ws_talkingq_url,"ws://",5)){
|
||||
printf("error ws url %s",ws_talkingq_url);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *testp = strstr(ws_talkingq_url+5,":");
|
||||
if(!testp){
|
||||
strcpy(talkingq_host,ws_talkingq_url+5);
|
||||
port = 80;
|
||||
}else{
|
||||
port = atoi(testp+1);
|
||||
*testp = 0;
|
||||
strcpy(talkingq_host,ws_talkingq_url+5);
|
||||
}
|
||||
if (talkingq_parse_wss_url(ws_talkingq_url, talkingq_host, sizeof(talkingq_host),
|
||||
&port, wss_path, sizeof(wss_path)) != 0) {
|
||||
LOG_E("Invalid WSS endpoint; cleartext fallback is disabled\n");
|
||||
app->init = 0;
|
||||
xiaoice_wss_connect_status = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
app->socket = rws_socket_create();
|
||||
if(app->socket == NULL)
|
||||
{
|
||||
app->init = 0;
|
||||
app->init = 0;
|
||||
xiaoice_wss_connect_status = 0;
|
||||
LOG_E("librws socket create failed. ");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
printf("talkingq host %s , port %d",talkingq_host,port);
|
||||
|
||||
//todo wss
|
||||
//rws_socket_set_url(app->socket, "ws", "hz.api.talkingq.com", 8080, wss_path);
|
||||
//118.25.13.180:8080
|
||||
rws_socket_set_url(app->socket, "ws", talkingq_host, port, wss_path);
|
||||
/* Server-authenticated TLS; application authentication stays in onopen. */
|
||||
rws_socket_set_url(app->socket, "wss", talkingq_host, port, wss_path);
|
||||
rws_socket_set_server_cert(app->socket, talkingq_root_ca, talkingq_root_ca_size);
|
||||
|
||||
rws_socket_set_on_connected(app->socket, &onopen);
|
||||
rws_socket_set_on_disconnected(app->socket, &onclose);
|
||||
@@ -374,7 +371,9 @@ int talkingq_ws_connect()
|
||||
ret = rws_socket_connect(app->socket);
|
||||
if(ret == rws_false)
|
||||
{
|
||||
app->init = 0;
|
||||
rws_socket_disconnect_and_release(app->socket);
|
||||
app->socket = NULL;
|
||||
app->init = 0;
|
||||
LOG_E("rws_socket_connect failed. ");
|
||||
ret = -1;
|
||||
}
|
||||
@@ -383,14 +382,17 @@ int talkingq_ws_connect()
|
||||
ret = -1;
|
||||
LOG_D("try rws_socket_connect. ");
|
||||
if(ws_connect_sem){
|
||||
result = ql_rtos_semaphore_wait(ws_connect_sem, 10000);
|
||||
if(result==0){
|
||||
result = ql_rtos_semaphore_wait(ws_connect_sem, 45000);
|
||||
if(result == 0 && app->init && app->socket && rws_socket_is_connected(app->socket)){
|
||||
LOG_I("ws connect okay");
|
||||
wss_connect_counter = 0;
|
||||
ret = 0;
|
||||
}else{
|
||||
app->init = 0;
|
||||
LOG_E("ws connect wait timeout");
|
||||
/* Stop the pending worker before allowing a new attempt. */
|
||||
if (app->socket) rws_socket_disconnect_and_release(app->socket);
|
||||
app->socket = NULL;
|
||||
app->init = 0;
|
||||
LOG_E("ws connect failed or wait timeout");
|
||||
wss_connect_counter++;
|
||||
}
|
||||
}else{
|
||||
@@ -399,7 +401,7 @@ int talkingq_ws_connect()
|
||||
}
|
||||
}
|
||||
|
||||
if(app->init == 1){
|
||||
if(ret == 0 && app->init == 1){
|
||||
xiaoice_wss_connect_status = 2;
|
||||
hal_led_b_on();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user