+
+
+
+#include "os_api.h"
+#include "sci_types.h"
+#include "mmk_app.h"
+#include "http_api.h"
+#include "version.h"
+#include "IN_Message.h"
+#include "mmi_appmsg.h"
+
+#include <socket_api.h>
+
+#include "mn_type.h"
+#include "mmk_type.h"
+#include "mmk_timer.h"
+#include "mmi_module.h"
+#include "mmiconnection_export.h"
+#include "mmiphone_export.h"
+#include "mmipdp_export.h"
+#include "mmi_aigc_net_common.h"
+
+
+#ifdef MMI_CUSTOM_AIGC_SUPPORT
+
+int mmi_wb_random_get(void * buf, uint32 len)
+{
+ uint8 * buf_bytes = (uint8 *)buf;
+
+ if (PNULL == buf || 0 == len)
+ {
+ AIGC_NET_DEBUG("[@CHENG_DEBUG][%s][%d]: param error\n",__FUNCTION__,__LINE__);
+ return -1;
+ }
+
+ while (len > 0)
+ {
+ int word = rand();
+ uint32 to_copy = MIN(sizeof(word), len);
+ AIGC_NET_DEBUG("[@CHENG_DEBUG][%s][%d]: random word=%d\n",__FUNCTION__,__LINE__, word);
+
+ SCI_MEMCPY(buf_bytes, &word, to_copy);
+ buf_bytes += to_copy;
+ len -= to_copy;
+ }
+
+ return len;
+}
+
+int mmi_tcp_send(char * data_ptr, int date_len)
+{
+ int ret = 0;
+
+
+ return ret;
+}
+
+int mmi_wb_connect(char * buffer, char * url, char * ip, uint32 port)
+{
+ uint8 random_key[16] = {0};
+ // Size of base64 coded string is equal '((input_size * 4) / 3) + (input_size / 96) + 6' including Z-term
+ uint8 client_key[28] = {0};
+ uint32 outlen = 0;
+ int len = 0;
+
+ if(PNULL == buffer || PNULL == url || PNULL == ip || NULL == port)
+ {
+ AIGC_NET_DEBUG("[@CHENG_DEBUG][%s][%d]: param error\n",__FUNCTION__,__LINE__);
+ return -1;
+ }
+
+ mmi_wb_random_get(random_key, sizeof(random_key));
+ mbedtls_base64_encode(client_key, sizeof(client_key), &outlen, random_key, sizeof(random_key));
+
+ len = sprintf(buffer,
+ /*"GET /?encoding=text HTTP/1.1\r\n"*/
+ "GET %s HTTP/1.1\r\n"
+ "Host: %s:%d\r\n"
+ "Connection: Upgrade\r\n"
+ "Pragma: no-cache\r\n"
+ "Cache-Control: no-cache\r\n"
+ "User-Agent: Websocket Client\r\n"
+ "Upgrade: websocket\r\n"
+ ////"Origin: http://oktools.net\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Accept-Encoding: gzip, deflate\r\n"
+ "Accept-Language: zh-CN,zh;q=0.9\r\n"
+ "Sec-WebSocket-Key: %s\r\n"
+ "Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits\r\n",
+ s_aigc_ws_url,
+ s_aigc_server_ip,
+ s_aigc_server_port,
+ client_key);
+
+
+
+static int ws_connect(wb_esp_transport_handle_t t, const char *host, int port, int timeout_ms)
+{
+ transport_ws_t *ws = wb_esp_transport_get_context_data(t);
+ if (wb_esp_transport_connect(ws->parent, host, port, timeout_ms) < 0) {
+ ESP_LOGE("Error connecting to host %s:%d", host, port);
+ return -1;
+ }
+
+ unsigned char random_key[16];
+ wb_getrandom(random_key, sizeof(random_key), 0);
+ //ESP_LOGE("random_key: %s", random_key);
+
+ // Size of base64 coded string is equal '((input_size * 4) / 3) + (input_size / 96) + 6' including Z-term
+ unsigned char client_key[28] = {0};
+
+ size_t outlen = 0;
+ mbedtls_base64_encode(client_key, sizeof(client_key), &outlen, random_key, sizeof(random_key));
+ int len = snprintf(ws->buffer, DEFAULT_WS_BUFFER,
+ /*"GET /?encoding=text HTTP/1.1\r\n"*/
+ "GET %s HTTP/1.1\r\n"
+ "Host: %s:%d\r\n"
+ "Connection: Upgrade\r\n"
+ "Pragma: no-cache\r\n"
+ "Cache-Control: no-cache\r\n"
+ "User-Agent: ASR Websocket Client\r\n"
+ "Upgrade: websocket\r\n"
+ "Origin: http://oktools.net\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Accept-Encoding: gzip, deflate\r\n"
+ "Accept-Language: zh-CN,zh;q=0.9\r\n"
+ "Sec-WebSocket-Key: %s\r\n"
+ "Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits\r\n",
+ //"\r\n",
+ ws->path,
+ host,
+ port,
+ client_key);
+ if (len <= 0 || len >= DEFAULT_WS_BUFFER) {
+ ESP_LOGE("Error in request generation, %d", len);
+ return -1;
+ }
+ if (ws->sub_protocol) {
+ int r = snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "Sec-WebSocket-Protocol: %s\r\n", ws->sub_protocol);
+ len += r;
+ if (r <= 0 || len >= DEFAULT_WS_BUFFER) {
+ ESP_LOGE("Error in request generation"
+ "(snprintf of subprotocol returned %d, desired request len: %d, buffer size: %d", r, len, DEFAULT_WS_BUFFER);
+ return -1;
+ }
+ }
+ int r = snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "\r\n");
+ len += r;
+ if (r <= 0 || len >= DEFAULT_WS_BUFFER) {
+ ESP_LOGE("Error in request generation"
+ "(snprintf of header terminal returned %d, desired request len: %d, buffer size: %d", r, len, DEFAULT_WS_BUFFER);
+ return -1;
+ }
+ ESP_LOGD("%s, len is %d and Write upgrate request\r\n%s", __FUNCTION__, len, ws->buffer);
+ if (wb_esp_transport_write(ws->parent, ws->buffer, len, timeout_ms) <= 0) {
+ ESP_LOGE("Error write Upgrade header %s", ws->buffer);
+ return -1;
+ }
+ int header_len = 0;
+ do {
+ if ((len = wb_esp_transport_read(ws->parent, ws->buffer + header_len, DEFAULT_WS_BUFFER - header_len, timeout_ms)) <= 0) {
+ ESP_LOGE("Error read response for Upgrade header %s", ws->buffer);
+ return -1;
+ }
+ header_len += len;
+ ws->buffer[header_len] = '\0';
+ ESP_LOGD("Read header chunk %d, current header size: %d", len, header_len);
+ } while (NULL == strstr(ws->buffer, "\r\n\r\n") && header_len < DEFAULT_WS_BUFFER);
+
+ char *server_key = get_http_header(ws->buffer, "Sec-WebSocket-Accept:");
+ if (server_key == NULL) {
+ ESP_LOGE("Sec-WebSocket-Accept not found");
+ return -1;
+ }
+
+ // See mbedtls_sha1_ret() arg size
+ unsigned char expected_server_sha1[20];
+ // Size of base64 coded string see above
+ unsigned char expected_server_key[33] = {0};
+ // If you are interested, see https://tools.ietf.org/html/rfc6455
+ const char expected_server_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ unsigned char expected_server_text[sizeof(client_key) + sizeof(expected_server_magic) + 1];
+ strcpy((char*)expected_server_text, (char*)client_key);
+ strcat((char*)expected_server_text, expected_server_magic);
+
+ size_t key_len = strlen((char*)expected_server_text);
+ mbedtls_sha1_ret(expected_server_text, key_len, expected_server_sha1);
+ mbedtls_base64_encode(expected_server_key, sizeof(expected_server_key), &outlen, expected_server_sha1, sizeof(expected_server_sha1));
+ expected_server_key[ (outlen < sizeof(expected_server_key)) ? outlen : (sizeof(expected_server_key) - 1) ] = 0;
+ ESP_LOGD("server key=%s, send_key=%s, expected_server_key=%s", (char *)server_key, (char*)client_key, expected_server_key);
+ if (strcmp((char*)expected_server_key, (char*)server_key) != 0) {
+ ESP_LOGE("Invalid websocket key");
+ return -1;
+ }
+ return 0;
+}
+
+
+
+
+}
+
+int mmi_wb_send(int opcode, const char * data, int len)
+{
+ char * buffer = (char *)data;
+ char ws_header[MAX_WEBSOCKET_HEADER_SIZE] = {0};
+ char * mask = PNULL;
+ int mask_flag = MMI_AIGC_WS_MASK;
+ int header_len = 0, i = 0;
+ int ret = 0;
+
+ opcode |= MMI_AIGC_WS_OPCODES_FIN;
+
+ header_len = 0;
+ ws_header[header_len++] = opcode;
+
+ if (len <= 125)
+ {
+ ws_header[header_len++] = (uint8_t)(len | mask_flag);
+ }
+ else if (len < 65536)
+ {
+ ws_header[header_len++] = MMI_AIGC_WS_SIZE16 | mask_flag;
+ ws_header[header_len++] = (uint8_t)(len >> 8);
+ ws_header[header_len++] = (uint8_t)(len & 0xFF);
+ }
+ else
+ {
+ ws_header[header_len++] = MMI_AIGC_WS_SIZE64 | mask_flag;
+ /* Support maximum 4 bytes length */
+ ws_header[header_len++] = 0; //(uint8_t)((len >> 56) & 0xFF);
+ ws_header[header_len++] = 0; //(uint8_t)((len >> 48) & 0xFF);
+ ws_header[header_len++] = 0; //(uint8_t)((len >> 40) & 0xFF);
+ ws_header[header_len++] = 0; //(uint8_t)((len >> 32) & 0xFF);
+ ws_header[header_len++] = (uint8_t)((len >> 24) & 0xFF);
+ ws_header[header_len++] = (uint8_t)((len >> 16) & 0xFF);
+ ws_header[header_len++] = (uint8_t)((len >> 8) & 0xFF);
+ ws_header[header_len++] = (uint8_t)((len >> 0) & 0xFF);
+ }
+
+ if(mmi_tcp_send(ws_header, header_len) != header_len)
+ {
+ AIGC_NET_DEBUG("[@CHENG_DEBUG][%s][%d]: send error\n",__FUNCTION__,__LINE__);
+ return -1;
+ }
+
+ if (0 == len)
+ {
+ AIGC_NET_DEBUG("[@CHENG_DEBUG][%s][%d]: no data\n",__FUNCTION__,__LINE__);
+ return 0;
+ }
+
+ if (mask_flag)
+ {
+ mask = &ws_header[header_len];
+ mmi_wb_random_get(ws_header + header_len, 4);
+ header_len += 4;
+
+ for (i = 0; i < len; ++i) {
+ buffer[i] = (buffer[i] ^ mask[i % 4]);
+ }
+ }
+
+ ret = mmi_tcp_send(buffer, len);
+ // in case of masked transport we have to revert back to the original data, as ws layer
+ // does not create its own copy of data to be sent
+ if (mask_flag)
+ {
+ mask = &ws_header[header_len-4];
+ for (i = 0; i < len; ++i) {
+ buffer[i] = (buffer[i] ^ mask[i % 4]);
+ }
+ }
+
+ return ret;
+}
+
+
+
+static int ws_connect(wb_esp_transport_handle_t t, const char *host, int port, int timeout_ms)
+{
+ transport_ws_t *ws = wb_esp_transport_get_context_data(t);
+ if (wb_esp_transport_connect(ws->parent, host, port, timeout_ms) < 0) {
+ ESP_LOGE("Error connecting to host %s:%d", host, port);
+ return -1;
+ }
+
+ unsigned char random_key[16];
+ wb_getrandom(random_key, sizeof(random_key), 0);
+ //ESP_LOGE("random_key: %s", random_key);
+
+ // Size of base64 coded string is equal '((input_size * 4) / 3) + (input_size / 96) + 6' including Z-term
+ unsigned char client_key[28] = {0};
+
+ size_t outlen = 0;
+ mbedtls_base64_encode(client_key, sizeof(client_key), &outlen, random_key, sizeof(random_key));
+ int len = snprintf(ws->buffer, DEFAULT_WS_BUFFER,
+ /*"GET /?encoding=text HTTP/1.1\r\n"*/
+ "GET %s HTTP/1.1\r\n"
+ "Host: %s:%d\r\n"
+ "Connection: Upgrade\r\n"
+ "Pragma: no-cache\r\n"
+ "Cache-Control: no-cache\r\n"
+ "User-Agent: ASR Websocket Client\r\n"
+ "Upgrade: websocket\r\n"
+ "Origin: http://oktools.net\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Accept-Encoding: gzip, deflate\r\n"
+ "Accept-Language: zh-CN,zh;q=0.9\r\n"
+ "Sec-WebSocket-Key: %s\r\n"
+ "Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits\r\n",
+ //"\r\n",
+ ws->path,
+ host,
+ port,
+ client_key);
+ if (len <= 0 || len >= DEFAULT_WS_BUFFER) {
+ ESP_LOGE("Error in request generation, %d", len);
+ return -1;
+ }
+ if (ws->sub_protocol) {
+ int r = snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "Sec-WebSocket-Protocol: %s\r\n", ws->sub_protocol);
+ len += r;
+ if (r <= 0 || len >= DEFAULT_WS_BUFFER) {
+ ESP_LOGE("Error in request generation"
+ "(snprintf of subprotocol returned %d, desired request len: %d, buffer size: %d", r, len, DEFAULT_WS_BUFFER);
+ return -1;
+ }
+ }
+ int r = snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "\r\n");
+ len += r;
+ if (r <= 0 || len >= DEFAULT_WS_BUFFER) {
+ ESP_LOGE("Error in request generation"
+ "(snprintf of header terminal returned %d, desired request len: %d, buffer size: %d", r, len, DEFAULT_WS_BUFFER);
+ return -1;
+ }
+ ESP_LOGD("%s, len is %d and Write upgrate request\r\n%s", __FUNCTION__, len, ws->buffer);
+ if (wb_esp_transport_write(ws->parent, ws->buffer, len, timeout_ms) <= 0) {
+ ESP_LOGE("Error write Upgrade header %s", ws->buffer);
+ return -1;
+ }
+ int header_len = 0;
+ do {
+ if ((len = wb_esp_transport_read(ws->parent, ws->buffer + header_len, DEFAULT_WS_BUFFER - header_len, timeout_ms)) <= 0) {
+ ESP_LOGE("Error read response for Upgrade header %s", ws->buffer);
+ return -1;
+ }
+ header_len += len;
+ ws->buffer[header_len] = '\0';
+ ESP_LOGD("Read header chunk %d, current header size: %d", len, header_len);
+ } while (NULL == strstr(ws->buffer, "\r\n\r\n") && header_len < DEFAULT_WS_BUFFER);
+
+ char *server_key = get_http_header(ws->buffer, "Sec-WebSocket-Accept:");
+ if (server_key == NULL) {
+ ESP_LOGE("Sec-WebSocket-Accept not found");
+ return -1;
+ }
+
+ // See mbedtls_sha1_ret() arg size
+ unsigned char expected_server_sha1[20];
+ // Size of base64 coded string see above
+ unsigned char expected_server_key[33] = {0};
+ // If you are interested, see https://tools.ietf.org/html/rfc6455
+ const char expected_server_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ unsigned char expected_server_text[sizeof(client_key) + sizeof(expected_server_magic) + 1];
+ strcpy((char*)expected_server_text, (char*)client_key);
+ strcat((char*)expected_server_text, expected_server_magic);
+
+ size_t key_len = strlen((char*)expected_server_text);
+ mbedtls_sha1_ret(expected_server_text, key_len, expected_server_sha1);
+ mbedtls_base64_encode(expected_server_key, sizeof(expected_server_key), &outlen, expected_server_sha1, sizeof(expected_server_sha1));
+ expected_server_key[ (outlen < sizeof(expected_server_key)) ? outlen : (sizeof(expected_server_key) - 1) ] = 0;
+ ESP_LOGD("server key=%s, send_key=%s, expected_server_key=%s", (char *)server_key, (char*)client_key, expected_server_key);
+ if (strcmp((char*)expected_server_key, (char*)server_key) != 0) {
+ ESP_LOGE("Invalid websocket key");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int ws_read_payload(char *buffer, int len, int timeout_ms)
+{
+ int i = 0;
+ int bytes_to_read = 0;
+ int rlen = 0;
+
+ if (ws->frame_state.bytes_remaining > len) {
+ ESP_LOGD("Actual data to receive (%d) are longer than ws buffer (%d)", ws->frame_state.bytes_remaining, len);
+ bytes_to_read = len;
+
+ } else {
+ bytes_to_read = ws->frame_state.bytes_remaining;
+ }
+
+ // Receive and process payload
+ if (bytes_to_read != 0 && (rlen = wb_esp_transport_read(ws->parent, buffer, bytes_to_read, timeout_ms)) <= 0) {
+ ESP_LOGE("Error read data");
+ return rlen;
+ }
+ ws->frame_state.bytes_remaining -= rlen;
+
+ if (ws->frame_state.mask_key) {
+ for (i = 0; i < bytes_to_read; i++) {
+ buffer[i] = (buffer[i] ^ ws->frame_state.mask_key[i % 4]);
+ }
+ }
+ return rlen;
+}
+
+
+/* Read and parse the WS header, determine length of payload */
+static int ws_read_header(char *buffer, int len)
+{
+ int payload_len = 0;
+ char ws_header[MAX_WEBSOCKET_HEADER_SIZE] = {0};
+ char * data_ptr = ws_header;
+ char * mask = NULL;
+
+ // Receive and process header first (based on header size)
+ int header = 2;
+ int opcode = 0;
+ int mask_len = 4;
+ char mask_key[4] = {0};
+ int offset = 0;
+
+ memcpy(data_ptr, buffer + offset, header);
+ offset += header;
+
+ opcode = (*data_ptr & 0x0F);
+ data_ptr ++;
+ mask = ((*data_ptr >> 7) & 0x01);
+ payload_len = (*data_ptr & 0x7F);
+ data_ptr++;
+ AIGC_NET_DEBUG("[@CHENG_DEBUG][%s][%d]: opcode=%d,mask=%d,payload_len=%d\n", __FUNCTION__, __LINE__, opcode, mask, payload_len);
+
+ if (payload_len == 126)
+ {
+ // headerLen += 2;
+ memcpy(data_ptr, buffer + offset, header);
+ offset += header;
+
+ payload_len = data_ptr[0] << 8 | data_ptr[1];
+ }
+ else if (payload_len == 127)
+ {
+ // headerLen += 8;
+ header = 8;
+ memcpy(data_ptr, buffer + offset, header);
+ offset += header;
+
+ if (data_ptr[0] != 0 || data_ptr[1] != 0 || data_ptr[2] != 0 || data_ptr[3] != 0)
+ {
+ // really too big!
+ payload_len = 0xFFFFFFFF;
+ }
+ else
+ {
+ payload_len = data_ptr[4] << 24 | data_ptr[5] << 16 | data_ptr[6] << 8 | data_ptr[7];
+ }
+ }
+
+ if (mask)
+ {
+ memcpy(mask_key, buffer + offset, mask_len);
+ offset += mask_len;
+ }
+ else
+ {
+ memset(mask_key, 0, mask_len);
+ }
+
+ ws->frame_state.payload_len = payload_len;
+ ws->frame_state.bytes_remaining = payload_len;
+
+ return payload_len;
+}
+
+int mmi_wb_data_process(MMI_AIGC_WS_FRAME_STATE_T * ws_frame_t, char * buffer, int len)
+{
+ int ret = 0;
+
+ // If message exceeds buffer len then subsequent reads will skip reading header and read whatever is left of the payload
+ if (ws_frame_t.bytes_remaining <= 0)
+ {
+ if ( (rlen = ws_read_header(t, buffer, len, timeout_ms)) <= 0) {
+ // If something when wrong then we prepare for reading a new header
+ ws->frame_state.bytes_remaining = 0;
+ return rlen;
+ }
+
+
+ /* Read and parse the WS header, determine length of payload */
+ {
+ int payload_len = 0;
+ char ws_header[MAX_WEBSOCKET_HEADER_SIZE] = {0};
+ char * data_ptr = ws_header;
+ char * mask = NULL;
+
+ // Receive and process header first (based on header size)
+ int header = 2;
+ int opcode = 0;
+ int mask_len = 4;
+ char mask_key[4] = {0};
+ int offset = 0;
+
+ memcpy(data_ptr, buffer + offset, header);
+ offset += header;
+
+ opcode = (*data_ptr & 0x0F);
+ data_ptr ++;
+ mask = ((*data_ptr >> 7) & 0x01);
+ payload_len = (*data_ptr & 0x7F);
+ data_ptr++;
+ AIGC_NET_DEBUG("[@CHENG_DEBUG][%s][%d]: opcode=%d,mask=%d,payload_len=%d\n", __FUNCTION__, __LINE__, opcode, mask, payload_len);
+
+ if (payload_len == 126)
+ {
+ // headerLen += 2;
+ memcpy(data_ptr, buffer + offset, header);
+ offset += header;
+
+ payload_len = data_ptr[0] << 8 | data_ptr[1];
+ }
+ else if (payload_len == 127)
+ {
+ // headerLen += 8;
+ header = 8;
+ memcpy(data_ptr, buffer + offset, header);
+ offset += header;
+
+ if (data_ptr[0] != 0 || data_ptr[1] != 0 || data_ptr[2] != 0 || data_ptr[3] != 0)
+ {
+ // really too big!
+ payload_len = 0xFFFFFFFF;
+ }
+ else
+ {
+ payload_len = data_ptr[4] << 24 | data_ptr[5] << 16 | data_ptr[6] << 8 | data_ptr[7];
+ }
+ }
+
+ if (mask)
+ {
+ memcpy(mask_key, buffer + offset, mask_len);
+ offset += mask_len;
+ }
+ else
+ {
+ memset(mask_key, 0, mask_len);
+ }
+
+ ws_frame_t->opcode = opcode;
+ memset(ws_frame_t->mask_key, mask_key, mask_len);
+ ws_frame_t->payload_len = payload_len;
+ ws_frame_t->remain_len = payload_len;
+
+ return payload_len;
+ }
+
+
+ }
+ if (s_ws_frame_t.payload_len)
+ {
+ if ( (rlen = ws_read_payload(t, buffer, len, timeout_ms)) <= 0) {
+ ESP_LOGE("Error reading payload data");
+ ws->frame_state.bytes_remaining = 0;
+ return rlen;
+ }
+ }
+
+ return ret;
+}
+
+
+
+#endif
+