RTL00_WEB_VS/RTLGDB/Project/web/websock.c
ADElectronics 764b020238 update
2017-11-28 22:31:40 +03:00

245 lines
7.7 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* FileName: websock.c
* Description: websocket for web ESP8266
* Author: PV`
* (c) PV` 2016
*******************************************************************************/
#include "user_config.h"
#ifdef WEBSOCKET_ENA
#include "autoconf.h"
#include "FreeRTOS.h"
#include "task.h"
#include "diag.h"
#include "tcpsrv/tcp_srv_conn.h"
#include "web_utils.h" // base64encode()
#include "web_srv.h"
//#include "phy/phy.h"
#include "device_lock.h"
#include "lwip/tcp.h"
#include "websock.h"
#include "rtl8195a/rtl_libc.h"
#include "esp_comp.h"
#include "hal_crypto.h"
// HTTP/1.1 101 Web Socket Protocol Handshake\r\n
const uint8 WebSocketHTTPOkKey[] ICACHE_RODATA_ATTR = "HTTP/1.1 101 Switching Protocols\r\nAccess-Control-Allow-Origin: *\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n";
const uint8 WebSocketAddKey[] ICACHE_RODATA_ATTR = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
const uint8 *HTTPUpgrade = "Upgrade:";
const uint8 *HTTPwebsocket = "websocket";
const uint8 *HTTPSecWebSocketKey = "Sec-WebSocket-Key:";
//=============================================================================
// WebSocketAcceptKey()
// 1) взять строковое значение из заголовка Sec-WebSocket-Key и объединить со
// строкой 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
// 2) вычислить бинарный хеш SHA-1 (бинарная строка из 20 символов) от полученной
// в первом пункте строки
// 3) закодировать хеш в Base64
// skey[24+36]:'dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
// cha:'b37a4f2cc0624f1690f64606cf385945b2bec4ea'
// key[28]:'s3pPLMBiTxaQ9kYGzzhZRbK+xOo='
//=============================================================================
uint8 buff[maxsizeWebSocketKey + sizeWebSocketAddKey]; // [68]
bool ICACHE_FLASH_ATTR WebSocketAcceptKey(uint8* dkey, uint8* skey)
{
int len = 0;
bool ret = false;
uint8 keybuf[CRYPTO_SHA1_DIGEST_LENGTH];
uint8 * buff = os_malloc(maxsizeWebSocketKey + sizeWebSocketAddKey);
if(buff) {
while(skey[len] >= '+' && len < maxsizeWebSocketKey) {
buff[len] = skey[len];
len++;
};
if(len > minsizeWebSocketKey) {
rtl_memcpy(&buff[len], WebSocketAddKey, sizeWebSocketAddKey+1);
device_mutex_lock(RT_DEV_LOCK_CRYPTO);
rtl_crypto_sha1(buff, len + sizeWebSocketAddKey, keybuf);
device_mutex_unlock(RT_DEV_LOCK_CRYPTO);
// rtl_cryptoEngine_info();
len = base64encode(dkey, FileNameSize, keybuf, CRYPTO_SHA1_DIGEST_LENGTH);
#if DEBUGSOO > 2
os_printf("\ncha:'");
print_hex_dump(keybuf, CRYPTO_SHA1_DIGEST_LENGTH, '\0');
os_printf("'\n");
os_printf("key[%u]:'%s'\n", len, dkey);
#endif
ret = true;
}
os_free(buff);
}
return ret;
}
//=============================================================================
// websock_mask() размаскирование блока
//=============================================================================
void ICACHE_FLASH_ATTR
WebsocketMask(WS_FRSTAT *ws, uint8 *raw_data, uint32 raw_len)
{
uint32 i, x = ws->cur_len;
#if DEBUGSOO > 3
os_printf("mask[%u]%u ", raw_len, x);
#endif
for (i = 0; i < raw_len; i++) {
raw_data[i] ^= ws->mask.uc[x++ & 3];
}
}
//=============================================================================
// websock_head() разбор заголовка
//=============================================================================
uint32 ICACHE_FLASH_ATTR
WebsocketHead(WS_FRSTAT *ws, uint8 *raw_data, uint32 raw_len)
{
// определить размер заголовка фрейма
uint32 head_len = 2;
if(raw_len < head_len) return 0; // докачивать
uint32 data_len = raw_data[1] & WS_SIZE1_BITS;
if(data_len == 127) head_len = 10;
else if(data_len == 126) head_len = 4;
if(raw_data[1] & WS_MASK_FLG) head_len += 4;
if(raw_len < head_len) return 0; // докачивать
ws->head_len = head_len;
ws->cur_len = 0;
ws->flg = 0;
data_len = raw_data[1] & WS_SIZE1_BITS;
if(data_len >= 126) {
if(data_len == 127) {
uint32 i;
for(i = 3; i < 6; i++) {
if(raw_data[i] != 0) {
ws->status = sw_frs_close;
ws->frame_len = 0;
return WS_CLOSE_MESSAGE_TOO_BIG;
}
}
data_len = (raw_data[6] << 24) | (raw_data[7] << 16) | (raw_data[8] << 8) | raw_data[9];
}
else {
data_len = (raw_data[2] << 8) | raw_data[3];
}
}
if(raw_data[1] & WS_MASK_FLG) {
ws->flg |= WS_FLG_MASK;
ws->mask.uc[0] = raw_data[head_len-4];
ws->mask.uc[1] = raw_data[head_len-3];
ws->mask.uc[2] = raw_data[head_len-2];
ws->mask.uc[3] = raw_data[head_len-1];
}
// else ws->mask = 0;
uint8 opcode = raw_data[0] & WS_OPCODE_BITS;
switch(opcode) {
case WS_OPCODE_PING: // эхо - дублировать прием
raw_data[0] &= ~WS_FRAGMENT_FIN;
raw_data[0] |= WS_OPCODE_PONG;
ws->status = sw_frs_pong;
ws->frame_len = data_len;
break;
case WS_OPCODE_PONG: // эхо - дублировать прием
ws->status = sw_frs_ping;
ws->frame_len = data_len;
break;
case WS_OPCODE_CONTINUE: // продолжить
if(ws->status == sw_frs_pong) {
ws->frame_len = data_len;
break;
}
else ws->frame_len += data_len;
break;
case WS_OPCODE_CLOSE: //
ws->status = sw_frs_close;
ws->frame_len = data_len;
break;
case WS_OPCODE_TEXT:
ws->status = sw_frs_text;
ws->frame_len = data_len;
break;
case WS_OPCODE_BINARY:
ws->status = sw_frs_binary;
ws->frame_len = data_len;
break;
default:
ws->status = sw_frs_close;
ws->frame_len = 0;
return WS_CLOSE_WRONG_TYPE;
}
// uint32 len = mMIN(raw_len - head_len, data_len);
// if((ws->flg & WS_FLG_MASK) != 0) websock_mask(ws, &raw_data[head_len], mMIN(raw_len - head_len, len));
// ws->cur_len += len;
if((raw_data[0] & WS_FRAGMENT_FIN) != 0) { // конец - данные на обработку
ws->flg |= WS_FLG_FIN;
}
#if DEBUGSOO > 1
os_printf("ws#%02xrx[%u] ", raw_data[0], data_len);
#endif
return 1;
/*
if(data_len + head_len <= raw_len) { // весь пакет уже в буфере?
return 1;
}
return 0; // докачивать */
}
//=============================================================================
// websock_tx_frame() - передача фрейма
//=============================================================================
err_t ICACHE_FLASH_ATTR
WebsocketTxFrame(TCP_SERV_CONN *ts_conn, uint32 opcode, uint8 *raw_data, uint32 raw_len)
{
union {
uint8 uc[8];
uint16 uw[4];
uint32 ud[2];
}head;
union {
uint8 uc[4];
uint16 uw[2];
uint32 ud;
}mask;
if(raw_data == NULL) raw_len = 0;
head.ud[0] = opcode;
uint32 head_len;
if(raw_len > 126) {
head.uc[1] = 126;
head.uc[2] = raw_len>>8;
head.uc[3] = raw_len;
head_len = 4;
}
else {
head.uc[1] = raw_len;
head_len = 2;
};
if(opcode & (WS_MASK_FLG << 8)) {
mask.ud ^= rand();
head.uc[1] |= WS_MASK_FLG;
head.uc[head_len] = mask.uc[0];
head.uc[head_len+1] = mask.uc[1];
head.uc[head_len+2] = mask.uc[2];
head.uc[head_len+3] = mask.uc[3];
head_len += 4;
}
uint32 len = tcp_sndbuf(ts_conn->pcb);
err_t err = 1; // ERR_BUF;
if(len >= raw_len + head_len) {
#if DEBUGSOO > 1
os_printf("ws#%02xtx[%u] ", head.uc[0], raw_len);
#endif
ts_conn->flag.nagle_disabled = 0;
tcp_nagle_disable(ts_conn->pcb);
err = tcpsrv_int_sent_data(ts_conn, head.uc, head_len);
ts_conn->flag.nagle_disabled = 1;
if(err == ERR_OK && raw_len != 0) {
if(opcode & (WS_MASK_FLG << 8)) {
uint32 i;
for (i = 0; i < raw_len; i++) {
raw_data[i] ^= mask.uc[i & 3];
}
}
err = tcpsrv_int_sent_data(ts_conn, raw_data, raw_len);
}
}
return err;
}
#endif // WEBSOCKET_ENA