|
|
|
@@ -27,6 +27,12 @@
|
|
|
|
|
#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"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char *k_rws_socket_min_http_ver = "1.1";
|
|
|
|
@@ -127,86 +133,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 +187,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 +218,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 +242,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 +250,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 +307,21 @@ 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) 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 +361,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 +380,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 +1003,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 +1054,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 +1093,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 +1112,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 +1299,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
|
|
|
|
@@ -1366,6 +1353,7 @@ void rws_socket_connect_to_host(_rws_socket *s)
|
|
|
|
|
|
|
|
|
|
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 +1368,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 +1548,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 +1608,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 +1845,17 @@ 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.
|
|
|
|
|
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";
|
|
|
|
|
int ret = -1;
|
|
|
|
|
unsigned int started;
|
|
|
|
|
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 +1863,89 @@ 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);
|
|
|
|
|
ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func,
|
|
|
|
|
&ssl->entropy, (const unsigned char *)pers, strlen(pers));
|
|
|
|
|
if (ret != 0) goto exit;
|
|
|
|
|
ret = mbedtls_x509_crt_parse(&ssl->cacert, (const unsigned char *)s->server_cert,
|
|
|
|
|
s->server_cert_len);
|
|
|
|
|
if (ret != 0) goto exit;
|
|
|
|
|
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;
|
|
|
|
|
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. */
|
|
|
|
|
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
|
|
|
|
|
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;
|
|
|
|
|
started = ql_rtos_get_systicks();
|
|
|
|
|
while ((ret = mbedtls_ssl_handshake(&ssl->ssl_ctx)) != 0) {
|
|
|
|
|
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) goto exit;
|
|
|
|
|
if ((unsigned int)(ql_rtos_get_systicks() - started) >= 4000) {
|
|
|
|
|
ret = MBEDTLS_ERR_SSL_TIMEOUT; /* 20 seconds, 5 ms SDK ticks */
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_I("mbedtls_ssl_handshake() while");
|
|
|
|
|
rws_thread_sleep(10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
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: %d\n", 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|